Run through black and isort

This commit is contained in:
Jan Dittberner 2021-01-02 06:20:53 +01:00
parent 0af66c6964
commit fdb126996a
8 changed files with 297 additions and 252 deletions

View file

@ -1 +1 @@
__import__('pkg_resources').declare_namespace(__name__) __import__("pkg_resources").declare_namespace(__name__)

View file

@ -1 +1 @@
__import__('pkg_resources').declare_namespace(__name__) __import__("pkg_resources").declare_namespace(__name__)

View file

@ -11,11 +11,9 @@
import re import re
from ipcalc import Network
from docutils import nodes from docutils import nodes
from docutils.parsers.rst import Directive from docutils.parsers.rst import Directive
from ipcalc import Network
from sphinx import addnodes from sphinx import addnodes
from sphinx.domains import Domain, ObjType from sphinx.domains import Domain, ObjType
from sphinx.errors import NoUri from sphinx.errors import NoUri
@ -24,15 +22,15 @@ from sphinx.roles import XRefRole
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.nodes import make_refnode from sphinx.util.nodes import make_refnode
__version__ = '0.3.0' __version__ = "0.4.0"
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def ip_object_anchor(typ, path): def ip_object_anchor(typ, path):
path = re.sub(r'[.:/]', '-', path) path = re.sub(r"[.:/]", "-", path)
return typ.lower() + '-' + path return typ.lower() + "-" + path
class ip_node(nodes.Inline, nodes.TextElement): class ip_node(nodes.Inline, nodes.TextElement):
@ -47,17 +45,16 @@ class IPXRefRole(XRefRole):
""" """
Cross referencing role for the IP domain. Cross referencing role for the IP domain.
""" """
def __init__(self, method, index_type, **kwargs): def __init__(self, method, index_type, **kwargs):
self.method = method self.method = method
self.index_type = index_type self.index_type = index_type
innernodeclass = None innernodeclass = None
if method in ('v4', 'v6'): if method in ("v4", "v6"):
innernodeclass = ip_node innernodeclass = ip_node
super(IPXRefRole, self).__init__( super(IPXRefRole, self).__init__(innernodeclass=innernodeclass, **kwargs)
innernodeclass=innernodeclass, **kwargs)
def __cal__(self, typ, rawtext, text, lineno, inliner, def __cal__(self, typ, rawtext, text, lineno, inliner, options=None, content=None):
options=None, content=None):
if content is None: if content is None:
content = [] content = []
if options is None: if options is None:
@ -66,28 +63,31 @@ class IPXRefRole(XRefRole):
Network(text) Network(text)
except ValueError as e: except ValueError as e:
env = inliner.document.settings.env env = inliner.document.settings.env
logger.warning("invalid ip address/range %s" % text, location=(env.docname, lineno)) logger.warning(
"invalid ip address/range %s" % text, location=(env.docname, lineno)
)
return [nodes.literal(text, text), []] return [nodes.literal(text, text), []]
return super(IPXRefRole, self).__call__( return super(IPXRefRole, self).__call__(
typ, rawtext, text, lineno, inliner, options, content) typ, rawtext, text, lineno, inliner, options, content
)
def process_link(self, env, refnode, has_explicit_title, title, target): def process_link(self, env, refnode, has_explicit_title, title, target):
domaindata = env.domaindata['ip'] domaindata = env.domaindata["ip"]
domaindata[self.method][target] = (target, refnode) domaindata[self.method][target] = (target, refnode)
return title, target return title, target
def result_nodes(self, document, env, node, is_ref): def result_nodes(self, document, env, node, is_ref):
try: try:
node['typ'] = self.method node["typ"] = self.method
indexnode = addnodes.index() indexnode = addnodes.index()
targetid = 'index-%s' % env.new_serialno('index') targetid = "index-%s" % env.new_serialno("index")
targetnode = nodes.target('', '', ids=[targetid]) targetnode = nodes.target("", "", ids=[targetid])
doctitle = list(document.traverse(nodes.title))[0].astext() doctitle = list(document.traverse(nodes.title))[0].astext()
idxtext = "%s; %s" % (node.astext(), doctitle) idxtext = "%s; %s" % (node.astext(), doctitle)
idxtext2 = "%s; %s" % (self.index_type, node.astext()) idxtext2 = "%s; %s" % (self.index_type, node.astext())
indexnode['entries'] = [ indexnode["entries"] = [
('single', idxtext, targetid, '', None), ("single", idxtext, targetid, "", None),
('single', idxtext2, targetid, '', None), ("single", idxtext2, targetid, "", None),
] ]
return [indexnode, targetnode, node], [] return [indexnode, targetnode, node], []
except KeyError as e: except KeyError as e:
@ -104,20 +104,21 @@ class IPRange(Directive):
def handle_rangespec(self, node): def handle_rangespec(self, node):
titlenode = nodes.title() titlenode = nodes.title()
node.append(titlenode) node.append(titlenode)
titlenode.append(nodes.inline('', self.get_prefix_title())) titlenode.append(nodes.inline("", self.get_prefix_title()))
titlenode.append(nodes.literal('', self.rangespec)) titlenode.append(nodes.literal("", self.rangespec))
ids = ip_object_anchor(self.typ, self.rangespec) ids = ip_object_anchor(self.typ, self.rangespec)
node['ids'].append(ids) node["ids"].append(ids)
self.env.domaindata[self.domain][self.typ][ids] = ( self.env.domaindata[self.domain][self.typ][ids] = (
self.env.docname, self.env.docname,
self.options.get('synopsis', '')) self.options.get("synopsis", ""),
)
return ids return ids
def run(self): def run(self):
if ':' in self.name: if ":" in self.name:
self.domain, self.objtype = self.name.split(':', 1) self.domain, self.objtype = self.name.split(":", 1)
else: else:
self.domain, self.objtype = '', self.name self.domain, self.objtype = "", self.name
self.env = self.state.document.settings.env self.env = self.state.document.settings.env
self.rangespec = self.arguments[0] self.rangespec = self.arguments[0]
node = nodes.section() node = nodes.section()
@ -127,97 +128,98 @@ class IPRange(Directive):
else: else:
doctitle = list(self.state.document.traverse(nodes.title))[0].astext() doctitle = list(self.state.document.traverse(nodes.title))[0].astext()
idx_text = "%s; %s" % (self.rangespec, doctitle) idx_text = "%s; %s" % (self.rangespec, doctitle)
self.indexnode = addnodes.index(entries=[ self.indexnode = addnodes.index(
('single', idx_text, name, '', None), entries=[
('single', self.get_index_text(), name, '', None) ("single", idx_text, name, "", None),
]) ("single", self.get_index_text(), name, "", None),
]
)
if self.content: if self.content:
contentnode = nodes.paragraph('') contentnode = nodes.paragraph("")
node.append(contentnode) node.append(contentnode)
self.state.nested_parse( self.state.nested_parse(self.content, self.content_offset, contentnode)
self.content, self.content_offset, contentnode)
iprange = ip_range() iprange = ip_range()
node.append(iprange) node.append(iprange)
iprange['rangespec'] = self.rangespec iprange["rangespec"] = self.rangespec
return [self.indexnode, node] return [self.indexnode, node]
class IPv4Range(IPRange): class IPv4Range(IPRange):
typ = 'v4range' typ = "v4range"
def get_prefix_title(self): def get_prefix_title(self):
return _('IPv4 address range ') return _("IPv4 address range ")
def get_index_text(self): def get_index_text(self):
return "%s; %s" % (_('IPv4 range'), self.rangespec) return "%s; %s" % (_("IPv4 range"), self.rangespec)
class IPv6Range(IPRange): class IPv6Range(IPRange):
typ = 'v6range' typ = "v6range"
def get_prefix_title(self): def get_prefix_title(self):
return _('IPv6 address range ') return _("IPv6 address range ")
def get_index_text(self): def get_index_text(self):
return "%s; %s" % (_('IPv6 range'), self.rangespec) return "%s; %s" % (_("IPv6 range"), self.rangespec)
class IPDomain(Domain): class IPDomain(Domain):
""" """
IP address and range domain. IP address and range domain.
""" """
name = 'ip'
label = 'IP addresses and ranges.' name = "ip"
label = "IP addresses and ranges."
object_types = { object_types = {
'v4': ObjType(_('v4'), 'v4', 'obj'), "v4": ObjType(_("v4"), "v4", "obj"),
'v6': ObjType(_('v6'), 'v6', 'obj'), "v6": ObjType(_("v6"), "v6", "obj"),
'v4range': ObjType(_('v4range'), 'v4range', 'obj'), "v4range": ObjType(_("v4range"), "v4range", "obj"),
'v6range': ObjType(_('v6range'), 'v6range', 'obj'), "v6range": ObjType(_("v6range"), "v6range", "obj"),
} }
directives = { directives = {
'v4range': IPv4Range, "v4range": IPv4Range,
'v6range': IPv6Range, "v6range": IPv6Range,
} }
roles = { roles = {
'v4': IPXRefRole('v4', _('IPv4 address')), "v4": IPXRefRole("v4", _("IPv4 address")),
'v6': IPXRefRole('v6', _('IPv6 address')), "v6": IPXRefRole("v6", _("IPv6 address")),
'v4range': IPXRefRole('v4range', _('IPv4 range')), "v4range": IPXRefRole("v4range", _("IPv4 range")),
'v6range': IPXRefRole('v6range', _('IPv6 range')), "v6range": IPXRefRole("v6range", _("IPv6 range")),
} }
initial_data = { initial_data = {
'v4': {}, "v4": {},
'v6': {}, "v6": {},
'v4range': {}, "v4range": {},
'v6range': {}, "v6range": {},
'ips': [], "ips": [],
} }
def clear_doc(self, docname): def clear_doc(self, docname):
to_remove = [] to_remove = []
for key, value in self.data['v4range'].items(): for key, value in self.data["v4range"].items():
if docname == value[0]: if docname == value[0]:
to_remove.append(key) to_remove.append(key)
for key in to_remove: for key in to_remove:
del self.data['v4range'][key] del self.data["v4range"][key]
to_remove = [] to_remove = []
for key, value in self.data['v6range'].items(): for key, value in self.data["v6range"].items():
if docname == value[0]: if docname == value[0]:
to_remove.append(key) to_remove.append(key)
for key in to_remove: for key in to_remove:
del self.data['v6range'][key] del self.data["v6range"][key]
self.data['ips'] = [ self.data["ips"] = [
item for item in self.data['ips'] if item['docname'] != docname item for item in self.data["ips"] if item["docname"] != docname
] ]
def resolve_xref(self, env, fromdocname, builder, typ, target, node, def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
contnode):
key = ip_object_anchor(typ, target) key = ip_object_anchor(typ, target)
try: try:
info = self.data[typ][key] info = self.data[typ][key]
@ -226,19 +228,20 @@ class IPDomain(Domain):
role = self.roles.get(typ) role = self.roles.get(typ)
if role is None: if role is None:
return None return None
resnode = role.result_nodes(env.get_doctree(fromdocname), resnode = role.result_nodes(env.get_doctree(fromdocname), env, node, True)[
env, node, True)[0][2] 0
][2]
if isinstance(resnode, addnodes.pending_xref): if isinstance(resnode, addnodes.pending_xref):
text = node[0][0] text = node[0][0]
reporter = env.get_doctree(fromdocname).reporter reporter = env.get_doctree(fromdocname).reporter
reporter.warning('Cannot resolve reference to %r' % text, reporter.warning(
line=node.line) "Cannot resolve reference to %r" % text, line=node.line
)
return node.children return node.children
return resnode return resnode
else: else:
title = typ.upper() + ' ' + target title = typ.upper() + " " + target
return make_refnode(builder, fromdocname, info[0], key, return make_refnode(builder, fromdocname, info[0], key, contnode, title)
contnode, title)
@property @property
def items(self): def items(self):
@ -257,13 +260,15 @@ def process_ips(app, doctree):
for node in doctree.traverse(ip_node): for node in doctree.traverse(ip_node):
ip = node.astext() ip = node.astext()
domaindata['ips'].append({ domaindata["ips"].append(
'docname': env.docname, {
'source': node.parent.source or env.doc2path(env.docname), "docname": env.docname,
'lineno': node.parent.line, "source": node.parent.source or env.doc2path(env.docname),
'ip': ip, "lineno": node.parent.line,
'typ': node.parent['typ'], "ip": ip,
}) "typ": node.parent["typ"],
}
)
replacement = nodes.literal(ip, ip) replacement = nodes.literal(ip, ip)
node.replace_self(replacement) node.replace_self(replacement)
@ -285,17 +290,14 @@ def process_ip_nodes(app, doctree, fromdocname):
env = app.builder.env env = app.builder.env
domaindata = env.domaindata[IPDomain.name] domaindata = env.domaindata[IPDomain.name]
header = (_('IP address'), _('Used by')) header = (_("IP address"), _("Used by"))
colwidths = (1, 3) colwidths = (1, 3)
for node in doctree.traverse(ip_range): for node in doctree.traverse(ip_range):
content = [] content = []
net = Network(node['rangespec']) net = Network(node["rangespec"])
ips = {} ips = {}
for key, value in [ for key, value in [(ip_info["ip"], ip_info) for ip_info in domaindata["ips"]]:
(ip_info['ip'], ip_info) for ip_info in
domaindata['ips']
]:
try: try:
if not key in net: if not key in net:
continue continue
@ -313,34 +315,32 @@ def process_ip_nodes(app, doctree, fromdocname):
tgroup += nodes.colspec(colwidth=colwidth) tgroup += nodes.colspec(colwidth=colwidth)
thead = nodes.thead() thead = nodes.thead()
tgroup += thead tgroup += thead
thead += create_table_row([ thead += create_table_row([nodes.paragraph(text=label) for label in header])
nodes.paragraph(text=label) for label in header])
tbody = nodes.tbody() tbody = nodes.tbody()
tgroup += tbody tgroup += tbody
for ip, ip_info in [ for ip, ip_info in [(ip, ips[ip]) for ip in sorted(ips, key=sort_ip)]:
(ip, ips[ip]) for ip in sorted(ips, key=sort_ip)
]:
para = nodes.paragraph() para = nodes.paragraph()
para += nodes.literal('', ip) para += nodes.literal("", ip)
refnode = nodes.paragraph() refnode = nodes.paragraph()
refuris = set() refuris = set()
refnodes = [] refnodes = []
for item in ip_info: for item in ip_info:
ids = ip_object_anchor(item['typ'], item['ip']) ids = ip_object_anchor(item["typ"], item["ip"])
if ids not in para['ids']: if ids not in para["ids"]:
para['ids'].append(ids) para["ids"].append(ids)
domaindata[item['typ']][ids] = (fromdocname, '') domaindata[item["typ"]][ids] = (fromdocname, "")
newnode = nodes.reference('', '', internal=True) newnode = nodes.reference("", "", internal=True)
try: try:
newnode['refuri'] = app.builder.get_relative_uri( newnode["refuri"] = app.builder.get_relative_uri(
fromdocname, item['docname']) fromdocname, item["docname"]
if newnode['refuri'] in refuris: )
if newnode["refuri"] in refuris:
continue continue
refuris.add(newnode['refuri']) refuris.add(newnode["refuri"])
except NoUri: except NoUri:
pass pass
title = env.titles[item['docname']] title = env.titles[item["docname"]]
innernode = nodes.Text(title.astext()) innernode = nodes.Text(title.astext())
newnode.append(innernode) newnode.append(innernode)
refnodes.append(newnode) refnodes.append(newnode)
@ -351,13 +351,13 @@ def process_ip_nodes(app, doctree, fromdocname):
tbody += create_table_row([para, refnode]) tbody += create_table_row([para, refnode])
content.append(table) content.append(table)
else: else:
para = nodes.paragraph(_('No IP addresses in this range')) para = nodes.paragraph(_("No IP addresses in this range"))
content.append(para) content.append(para)
node.replace_self(content) node.replace_self(content)
def setup(app): def setup(app):
app.add_domain(IPDomain) app.add_domain(IPDomain)
app.connect('doctree-read', process_ips) app.connect("doctree-read", process_ips)
app.connect('doctree-resolved', process_ip_nodes) app.connect("doctree-resolved", process_ip_nodes)
return {'version': __version__} return {"version": __version__}

View file

@ -1,16 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from setuptools import setup, find_packages from setuptools import find_packages, setup
version = '0.3.1' version = "0.3.1"
with open('README.rst') as readme: with open("README.rst") as readme:
description = readme.read() + "\n\n" description = readme.read() + "\n\n"
with open('CHANGES.rst') as changes: with open("CHANGES.rst") as changes:
description += changes.read() description += changes.read()
requires = ['Sphinx>=3', 'ipcalc>=1.99'] requires = ["Sphinx>=3", "ipcalc>=1.99"]
setup( setup(
@ -24,9 +24,9 @@ setup(
license="GPLv3+", license="GPLv3+",
url="https://pypi.python.org/pypi/jandd.sphinxext.ip", url="https://pypi.python.org/pypi/jandd.sphinxext.ip",
name="jandd.sphinxext.ip", name="jandd.sphinxext.ip",
namespace_packages=['jandd', 'jandd.sphinxext'], namespace_packages=["jandd", "jandd.sphinxext"],
packages=find_packages(), packages=find_packages(),
platforms='any', platforms="any",
version=version, version=version,
zip_safe=False, zip_safe=False,
classifiers=[ classifiers=[

View file

@ -13,51 +13,51 @@
# All configuration values have a default; values that are commented out # All configuration values have a default; values that are commented out
# serve to show the default. # serve to show the default.
#import sys # import sys
#import os # import os
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('..')) # sys.path.insert(0, os.path.abspath('..'))
# -- General configuration ------------------------------------------------ # -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here. # If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0' # needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = ['jandd.sphinxext.ip'] extensions = ["jandd.sphinxext.ip"]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ["_templates"]
# The suffix(es) of source filenames. # The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string: # You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md'] # source_suffix = ['.rst', '.md']
source_suffix = '.rst' source_suffix = ".rst"
# The encoding of source files. # The encoding of source files.
#source_encoding = 'utf-8-sig' # source_encoding = 'utf-8-sig'
# The master toctree document. # The master toctree document.
master_doc = 'index' master_doc = "index"
# General information about the project. # General information about the project.
project = 'Sphinxext IP Tests' project = "Sphinxext IP Tests"
copyright = '2016, Jan Dittberner' copyright = "2016, Jan Dittberner"
author = 'Jan Dittberner' author = "Jan Dittberner"
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.1.0' version = "0.1.0"
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.1.0' release = "0.1.0"
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
@ -68,38 +68,38 @@ language = None
# There are two options for replacing |today|: either, you set today to some # There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used: # non-false value, then it is used:
#today = '' # today = ''
# Else, today_fmt is used as the format for a strftime call. # Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y' # today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path # This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# The reST default role (used for this markup: `text`) to use for all # The reST default role (used for this markup: `text`) to use for all
# documents. # documents.
#default_role = None # default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text. # If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True # add_function_parentheses = True
# If true, the current module name will be prepended to all description # If true, the current module name will be prepended to all description
# unit titles (such as .. function::). # unit titles (such as .. function::).
#add_module_names = True # add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the # If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default. # output. They are ignored by default.
#show_authors = False # show_authors = False
# The name of the Pygments (syntax highlighting) style to use. # The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx' pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting. # A list of ignored prefixes for module index sorting.
#modindex_common_prefix = [] # modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents. # If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False # keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing. # If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False todo_include_todos = False
@ -109,145 +109,147 @@ todo_include_todos = False
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
html_theme = 'alabaster' html_theme = "alabaster"
# Theme options are theme-specific and customize the look and feel of a theme # Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the # further. For a list of options available for each theme, see the
# documentation. # documentation.
#html_theme_options = {} # html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory. # Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = [] # html_theme_path = []
# The name for this set of Sphinx documents. # The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default. # "<project> v<release> documentation" by default.
#html_title = 'Sphinxext IP Tests v0.1.0' # html_title = 'Sphinxext IP Tests v0.1.0'
# A shorter title for the navigation bar. Default is the same as html_title. # A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None # html_short_title = None
# The name of an image file (relative to this directory) to place at the top # The name of an image file (relative to this directory) to place at the top
# of the sidebar. # of the sidebar.
#html_logo = None # html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of # The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large. # pixels large.
#html_favicon = None # html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css". # so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static'] html_static_path = ["_static"]
# Add any extra paths that contain custom files (such as robots.txt or # Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied # .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation. # directly to the root of the documentation.
#html_extra_path = [] # html_extra_path = []
# If not None, a 'Last updated on:' timestamp is inserted at every page # If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format. # bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'. # The empty string is equivalent to '%b %d, %Y'.
#html_last_updated_fmt = None # html_last_updated_fmt = None
# If true, SmartyPants will be used to convert quotes and dashes to # If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities. # typographically correct entities.
#html_use_smartypants = True # html_use_smartypants = True
# Custom sidebar templates, maps document names to template names. # Custom sidebar templates, maps document names to template names.
#html_sidebars = {} # html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to # Additional templates that should be rendered to pages, maps page names to
# template names. # template names.
#html_additional_pages = {} # html_additional_pages = {}
# If false, no module index is generated. # If false, no module index is generated.
#html_domain_indices = True # html_domain_indices = True
# If false, no index is generated. # If false, no index is generated.
#html_use_index = True # html_use_index = True
# If true, the index is split into individual pages for each letter. # If true, the index is split into individual pages for each letter.
#html_split_index = False # html_split_index = False
# If true, links to the reST sources are added to the pages. # If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True # html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True # html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True # html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will # If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the # contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served. # base URL from which the finished HTML is served.
#html_use_opensearch = '' # html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml"). # This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None # html_file_suffix = None
# Language to be used for generating the HTML full-text search index. # Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages: # Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh'
#html_search_language = 'en' # html_search_language = 'en'
# A dictionary with options for the search language support, empty by default. # A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value. # 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path. # 'zh' user can custom change `jieba` dictionary path.
#html_search_options = {'type': 'default'} # html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that # The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used. # implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js' # html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'SphinxextIPTestsdoc' htmlhelp_basename = "SphinxextIPTestsdoc"
# -- Options for LaTeX output --------------------------------------------- # -- Options for LaTeX output ---------------------------------------------
latex_elements = { latex_elements = {
# The paper size ('letterpaper' or 'a4paper'). # The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper', #'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt',
#'pointsize': '10pt', # Additional stuff for the LaTeX preamble.
#'preamble': '',
# Additional stuff for the LaTeX preamble. # Latex figure (float) alignment
#'preamble': '', #'figure_align': 'htbp',
# Latex figure (float) alignment
#'figure_align': 'htbp',
} }
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, # (source start file, target name, title,
# author, documentclass [howto, manual, or own class]). # author, documentclass [howto, manual, or own class]).
latex_documents = [ latex_documents = [
(master_doc, 'SphinxextIPTests.tex', 'Sphinxext IP Tests Documentation', (
'Jan Dittberner', 'manual'), master_doc,
"SphinxextIPTests.tex",
"Sphinxext IP Tests Documentation",
"Jan Dittberner",
"manual",
),
] ]
# The name of an image file (relative to this directory) to place at the top of # The name of an image file (relative to this directory) to place at the top of
# the title page. # the title page.
#latex_logo = None # latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts, # For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters. # not chapters.
#latex_use_parts = False # latex_use_parts = False
# If true, show page references after internal links. # If true, show page references after internal links.
#latex_show_pagerefs = False # latex_show_pagerefs = False
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
#latex_show_urls = False # latex_show_urls = False
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
#latex_appendices = [] # latex_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#latex_domain_indices = True # latex_domain_indices = True
# -- Options for manual page output --------------------------------------- # -- Options for manual page output ---------------------------------------
@ -255,12 +257,11 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [
(master_doc, 'sphinxextiptests', 'Sphinxext IP Tests Documentation', (master_doc, "sphinxextiptests", "Sphinxext IP Tests Documentation", [author], 1)
[author], 1)
] ]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
#man_show_urls = False # man_show_urls = False
# -- Options for Texinfo output ------------------------------------------- # -- Options for Texinfo output -------------------------------------------
@ -269,19 +270,25 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
(master_doc, 'SphinxextIPTests', 'Sphinxext IP Tests Documentation', (
author, 'SphinxextIPTests', 'One line description of project.', master_doc,
'Miscellaneous'), "SphinxextIPTests",
"Sphinxext IP Tests Documentation",
author,
"SphinxextIPTests",
"One line description of project.",
"Miscellaneous",
),
] ]
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
#texinfo_appendices = [] # texinfo_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#texinfo_domain_indices = True # texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'. # How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote' # texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu. # If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False # texinfo_no_detailmenu = False

View file

@ -11,23 +11,25 @@ This script runs the jandd.sphinxext.ip unit test suite.
""" """
import sys import sys
from os import path
import unittest import unittest
from os import path
def run(extra_args=[]): def run(extra_args=[]):
sys.path.insert(0, path.join(path.dirname(__file__), path.pardir)) sys.path.insert(0, path.join(path.dirname(__file__), path.pardir))
sys.path.insert(1, path.abspath( sys.path.insert(
path.join(path.dirname(__file__), path.pardir, 1,
'jandd', 'sphinxext', 'ip' path.abspath(
)) path.join(path.dirname(__file__), path.pardir, "jandd", "sphinxext", "ip")
),
) )
try: try:
import sphinx import sphinx
except ImportError: except ImportError:
print("The sphinx package is needed to run the jandd.sphinxext.ip " print(
"test suite.") "The sphinx package is needed to run the jandd.sphinxext.ip " "test suite."
)
from .test_ip import TestIPExtension from .test_ip import TestIPExtension
@ -37,5 +39,5 @@ def run(extra_args=[]):
unittest.TextTestRunner(verbosity=2).run(suite) unittest.TextTestRunner(verbosity=2).run(suite)
if __name__ == '__main__': if __name__ == "__main__":
run() run()

View file

@ -1,40 +1,41 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from io import StringIO
from .util import SphinxTestApplication, test_root
import unittest import unittest
from io import StringIO
from .util import SphinxTestApplication, test_root
IP4_ADDRESSES = ['127.0.0.1', '192.168.0.1'] IP4_ADDRESSES = ["127.0.0.1", "192.168.0.1"]
IP6_ADDRESSES = ['::1', '2001:dead:beef::1'] IP6_ADDRESSES = ["::1", "2001:dead:beef::1"]
IP4_RANGES = ['172.16.0.0/24', '192.168.0.0/24'] IP4_RANGES = ["172.16.0.0/24", "192.168.0.0/24"]
IP6_RANGES = ['2001:dead:beef::/64', '2001:dada:b001::/64'] IP6_RANGES = ["2001:dead:beef::/64", "2001:dada:b001::/64"]
class TestIPExtension(unittest.TestCase): class TestIPExtension(unittest.TestCase):
def setUp(self): def setUp(self):
if not (test_root / '_static').exists(): if not (test_root / "_static").exists():
(test_root / '_static').mkdir() (test_root / "_static").mkdir()
self.feed_warnfile = StringIO() self.feed_warnfile = StringIO()
self.app = SphinxTestApplication( self.app = SphinxTestApplication(
buildername='html', warning=self.feed_warnfile, cleanenv=True) buildername="html", warning=self.feed_warnfile, cleanenv=True
)
self.app.build(force_all=True, filenames=[]) self.app.build(force_all=True, filenames=[])
def tearDown(self): def tearDown(self):
self.app.cleanup() self.app.cleanup()
(test_root / '_build').rmtree(True) (test_root / "_build").rmtree(True)
def test_ip_domaindata(self): def test_ip_domaindata(self):
self.assertIn('ip', self.app.env.domaindata) self.assertIn("ip", self.app.env.domaindata)
ipdomdata = self.app.env.domaindata['ip'] ipdomdata = self.app.env.domaindata["ip"]
self.assertIn('v4', ipdomdata) self.assertIn("v4", ipdomdata)
self.assertIn('v6', ipdomdata) self.assertIn("v6", ipdomdata)
self.assertIn('v4range', ipdomdata) self.assertIn("v4range", ipdomdata)
self.assertIn('v6range', ipdomdata) self.assertIn("v6range", ipdomdata)
self.assertIn('ips', ipdomdata) self.assertIn("ips", ipdomdata)
def find_in_index(self, entry): def find_in_index(self, entry):
indexentries = self.app.env.get_domain('index').entries indexentries = self.app.env.get_domain("index").entries
for index in indexentries: for index in indexentries:
for value in indexentries[index]: for value in indexentries[index]:
if value[1] == entry: if value[1] == entry:
@ -42,19 +43,19 @@ class TestIPExtension(unittest.TestCase):
self.fail("%s not found in index" % entry) self.fail("%s not found in index" % entry)
def test_ip4_addresses(self): def test_ip4_addresses(self):
ipv4 = self.app.env.domaindata['ip']['v4'] ipv4 = self.app.env.domaindata["ip"]["v4"]
ips = self.app.env.domaindata['ip']['ips'] ips = self.app.env.domaindata["ip"]["ips"]
for ip in IP4_ADDRESSES: for ip in IP4_ADDRESSES:
self.assertIn(ip, ipv4) self.assertIn(ip, ipv4)
self.assertIn(ip, [item['ip'] for item in ips]) self.assertIn(ip, [item["ip"] for item in ips])
self.find_in_index("IPv4 address; %s" % ip) self.find_in_index("IPv4 address; %s" % ip)
self.find_in_index("%s; Test page 2" % ip) self.find_in_index("%s; Test page 2" % ip)
def test_ip6_addresses(self): def test_ip6_addresses(self):
ipv6 = self.app.env.domaindata['ip']['v6'] ipv6 = self.app.env.domaindata["ip"]["v6"]
ips = self.app.env.domaindata['ip']['ips'] ips = self.app.env.domaindata["ip"]["ips"]
for ip in IP6_ADDRESSES: for ip in IP6_ADDRESSES:
self.assertIn(ip, ipv6) self.assertIn(ip, ipv6)
self.assertIn(ip, [item['ip'] for item in ips]) self.assertIn(ip, [item["ip"] for item in ips])
self.find_in_index("IPv6 address; %s" % ip) self.find_in_index("IPv6 address; %s" % ip)
self.find_in_index("%s; Test page 2" % ip) self.find_in_index("%s; Test page 2" % ip)

View file

@ -17,15 +17,22 @@ from path import Path
from sphinx import application from sphinx import application
__all__ = [ __all__ = [
'test_root', "test_root",
'raises', 'raises_msg', 'Struct', "raises",
'ListOutput', 'SphinxTestApplication', 'with_app', 'gen_with_app', "raises_msg",
'Path', 'with_tempdir', 'write_file', "Struct",
'sprint', "ListOutput",
"SphinxTestApplication",
"with_app",
"gen_with_app",
"Path",
"with_tempdir",
"write_file",
"sprint",
] ]
test_root = Path(__file__).parent.joinpath('root').abspath() test_root = Path(__file__).parent.joinpath("root").abspath()
def _excstr(exc): def _excstr(exc):
@ -44,8 +51,7 @@ def raises(exc, func, *args, **kwds):
except exc: except exc:
pass pass
else: else:
raise AssertionError('%s did not raise %s' % raise AssertionError("%s did not raise %s" % (func.__name__, _excstr(exc)))
(func.__name__, _excstr(exc)))
def raises_msg(exc, msg, func, *args, **kwds): def raises_msg(exc, msg, func, *args, **kwds):
@ -56,10 +62,9 @@ def raises_msg(exc, msg, func, *args, **kwds):
try: try:
func(*args, **kwds) func(*args, **kwds)
except exc as err: except exc as err:
assert msg in str(err), "\"%s\" not in \"%s\"" % (msg, err) assert msg in str(err), '"%s" not in "%s"' % (msg, err)
else: else:
raise AssertionError('%s did not raise %s' % raise AssertionError("%s did not raise %s" % (func.__name__, _excstr(exc)))
(func.__name__, _excstr(exc)))
class Struct(object): class Struct(object):
@ -71,6 +76,7 @@ class ListOutput(object):
""" """
File-like object that collects written text in a list. File-like object that collects written text in a list.
""" """
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.content = [] self.content = []
@ -88,27 +94,38 @@ class SphinxTestApplication(application.Sphinx):
better default values for the initialization parameters. better default values for the initialization parameters.
""" """
def __init__(self, srcdir=None, confdir=None, outdir=None, doctreedir=None, def __init__(
buildername='html', confoverrides=None, self,
status=None, warning=None, freshenv=None, srcdir=None,
warningiserror=None, tags=None, confdir=None,
confname='conf.py', cleanenv=False): outdir=None,
doctreedir=None,
buildername="html",
confoverrides=None,
status=None,
warning=None,
freshenv=None,
warningiserror=None,
tags=None,
confname="conf.py",
cleanenv=False,
):
application.CONFIG_FILENAME = confname application.CONFIG_FILENAME = confname
self.cleanup_trees = [test_root / 'generated'] self.cleanup_trees = [test_root / "generated"]
if srcdir is None: if srcdir is None:
srcdir = test_root srcdir = test_root
if srcdir == '(temp)': if srcdir == "(temp)":
tempdir = Path(tempfile.mkdtemp()) tempdir = Path(tempfile.mkdtemp())
self.cleanup_trees.append(tempdir) self.cleanup_trees.append(tempdir)
temproot = tempdir / 'root' temproot = tempdir / "root"
test_root.copytree(temproot) test_root.copytree(temproot)
srcdir = temproot srcdir = temproot
else: else:
srcdir = Path(srcdir) srcdir = Path(srcdir)
self.builddir = srcdir.joinpath('_build') self.builddir = srcdir.joinpath("_build")
if confdir is None: if confdir is None:
confdir = srcdir confdir = srcdir
if outdir is None: if outdir is None:
@ -117,7 +134,7 @@ class SphinxTestApplication(application.Sphinx):
outdir.makedirs() outdir.makedirs()
self.cleanup_trees.insert(0, outdir) self.cleanup_trees.insert(0, outdir)
if doctreedir is None: if doctreedir is None:
doctreedir = srcdir.joinpath(srcdir, self.builddir, 'doctrees') doctreedir = srcdir.joinpath(srcdir, self.builddir, "doctrees")
if cleanenv: if cleanenv:
self.cleanup_trees.insert(0, doctreedir) self.cleanup_trees.insert(0, doctreedir)
if confoverrides is None: if confoverrides is None:
@ -125,15 +142,26 @@ class SphinxTestApplication(application.Sphinx):
if status is None: if status is None:
status = io.StringIO() status = io.StringIO()
if warning is None: if warning is None:
warning = ListOutput('stderr') warning = ListOutput("stderr")
if freshenv is None: if freshenv is None:
freshenv = False freshenv = False
if warningiserror is None: if warningiserror is None:
warningiserror = False warningiserror = False
application.Sphinx.__init__(self, srcdir, confdir, outdir, doctreedir, application.Sphinx.__init__(
buildername, confoverrides, status, warning, self,
freshenv, warningiserror, tags) srcdir,
confdir,
outdir,
doctreedir,
buildername,
confoverrides,
status,
warning,
freshenv,
warningiserror,
tags,
)
def cleanup(self, doctrees=False): def cleanup(self, doctrees=False):
for tree in self.cleanup_trees: for tree in self.cleanup_trees:
@ -145,6 +173,7 @@ def with_app(*args, **kwargs):
Make a TestApp with args and kwargs, pass it to the test and clean up Make a TestApp with args and kwargs, pass it to the test and clean up
properly. properly.
""" """
def generator(func): def generator(func):
@wraps(func) @wraps(func)
def deco(*args2, **kwargs2): def deco(*args2, **kwargs2):
@ -152,7 +181,9 @@ def with_app(*args, **kwargs):
func(app, *args2, **kwargs2) func(app, *args2, **kwargs2)
# don't execute cleanup if test failed # don't execute cleanup if test failed
app.cleanup() app.cleanup()
return deco return deco
return generator return generator
@ -161,6 +192,7 @@ def gen_with_app(*args, **kwargs):
Make a TestApp with args and kwargs, pass it to the test and clean up Make a TestApp with args and kwargs, pass it to the test and clean up
properly. properly.
""" """
def generator(func): def generator(func):
@wraps(func) @wraps(func)
def deco(*args2, **kwargs2): def deco(*args2, **kwargs2):
@ -169,7 +201,9 @@ def gen_with_app(*args, **kwargs):
yield item yield item
# don't execute cleanup if test failed # don't execute cleanup if test failed
app.cleanup() app.cleanup()
return deco return deco
return generator return generator
@ -178,15 +212,16 @@ def with_tempdir(func):
tempdir = Path(tempfile.mkdtemp()) tempdir = Path(tempfile.mkdtemp())
func(tempdir) func(tempdir)
tempdir.rmtree() tempdir.rmtree()
new_func.__name__ = func.__name__ new_func.__name__ = func.__name__
return new_func return new_func
def write_file(name, contents): def write_file(name, contents):
f = open(str(name), 'wb') f = open(str(name), "wb")
f.write(contents) f.write(contents)
f.close() f.close()
def sprint(*args): def sprint(*args):
sys.stderr.write(' '.join(map(str, args)) + '\n') sys.stderr.write(" ".join(map(str, args)) + "\n")