From b81361656a98358fb50172b43bbb7218685a94e9 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Mon, 2 May 2016 21:43:15 +0200 Subject: [PATCH 1/7] Don't add GPL to long_description --- setup.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/setup.py b/setup.py index db7357b..dfe086e 100644 --- a/setup.py +++ b/setup.py @@ -7,9 +7,6 @@ version = '0.1.1' with open('README.rst') as readme: description = readme.read() + "\n\n" -with open('COPYING') as license: - description += license.read() - requires = ['Sphinx>=1.4', 'ipcalc>=1.99'] tests_requires = ['path.py>=8.2.1'] From b54c732af43ef076024ad58316a2048fb53bd579 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 4 May 2016 11:28:39 +0200 Subject: [PATCH 2/7] Fix grammar mistake --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index dfe086e..96562ec 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ tests_requires = ['path.py>=8.2.1'] setup( author="Jan Dittberner", author_email="jan@dittberner.info", - description="IP address extensions for Sphinx", + description="IP address extension for Sphinx", long_description=description, include_package_data=True, install_requires=requires, From ff95c88bc59d25319115abf47e36730263988493 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 4 May 2016 12:27:48 +0200 Subject: [PATCH 3/7] Bump version number --- jandd/sphinxext/ip.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jandd/sphinxext/ip.py b/jandd/sphinxext/ip.py index 8f03776..6ac0a88 100644 --- a/jandd/sphinxext/ip.py +++ b/jandd/sphinxext/ip.py @@ -8,7 +8,7 @@ :copyright: Copyright (c) 2016 Jan Dittberner :license: GPLv3+, see COPYING file for details. """ -__version__ = '0.1.1' +__version__ = '0.2.0' import re diff --git a/setup.py b/setup.py index 96562ec..a999211 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages -version = '0.1.1' +version = '0.2.0' with open('README.rst') as readme: description = readme.read() + "\n\n" From a44fff3e815f43f45e9e822f637ecc8b00016962 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 4 May 2016 12:42:51 +0200 Subject: [PATCH 4/7] Fix IP address sorting IP addresses in IP ranges are now sorted correctly by their numerical value. --- jandd/sphinxext/ip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jandd/sphinxext/ip.py b/jandd/sphinxext/ip.py index 6ac0a88..d66a8ec 100644 --- a/jandd/sphinxext/ip.py +++ b/jandd/sphinxext/ip.py @@ -231,7 +231,7 @@ def process_ips(app, doctree): def sort_ip_info(item): - return item['ip'] + return Network(item['ip']).ip def process_ip_nodes(app, doctree, fromdocname): From f812a91310571e0699b0799241f7255c821d51e6 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 4 May 2016 12:46:00 +0200 Subject: [PATCH 5/7] Format IP lists as tables This commit changes the formatting of IP address lists from paragraph to table markup. The commit fixes PEP8 violations. --- jandd/sphinxext/ip.py | 53 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/jandd/sphinxext/ip.py b/jandd/sphinxext/ip.py index d66a8ec..24b6672 100644 --- a/jandd/sphinxext/ip.py +++ b/jandd/sphinxext/ip.py @@ -8,7 +8,6 @@ :copyright: Copyright (c) 2016 Jan Dittberner :license: GPLv3+, see COPYING file for details. """ -__version__ = '0.2.0' import re @@ -24,15 +23,20 @@ from sphinx.locale import l_ from sphinx.roles import XRefRole from sphinx.util.nodes import make_refnode +__version__ = '0.2.0' + def ip_object_anchor(typ, path): path = re.sub(r'[.:/]', '-', path) return typ.lower() + '-' + path -class ip_node(nodes.Inline, nodes.TextElement): pass +class ip_node(nodes.Inline, nodes.TextElement): + pass -class ip_range(nodes.General, nodes.Element): pass + +class ip_range(nodes.General, nodes.Element): + pass class IPXRefRole(XRefRole): @@ -42,7 +46,7 @@ class IPXRefRole(XRefRole): def __init__(self, method, index_type, **kwargs): self.method = method self.index_type = index_type - innernodeclass=None + innernodeclass = None if method in ('v4', 'v6'): innernodeclass = ip_node super(IPXRefRole, self).__init__( @@ -234,19 +238,46 @@ def sort_ip_info(item): return Network(item['ip']).ip +def create_table_row(rowdata): + row = nodes.row() + for cell in rowdata: + entry = nodes.entry() + row += entry + entry += cell + return row + + def process_ip_nodes(app, doctree, fromdocname): env = app.builder.env domaindata = env.domaindata[IPDomain.name] + header = (l_('IP address'), l_('Used by')) + colwidths = (1, 3) + for node in doctree.traverse(ip_range): content = [] net = Network(node['rangespec']) - for ip_info in sorted(domaindata['ips'], key=sort_ip_info): - if ip_info['ip'] in net: + ips = [ip_info for ip_info in + sorted(domaindata['ips'], key=sort_ip_info) + if ip_info['ip'] in net] + if ips: + table = nodes.table() + tgroup = nodes.tgroup(cols=len(header)) + table += tgroup + for colwidth in colwidths: + tgroup += nodes.colspec(colwidth=colwidth) + thead = nodes.thead() + tgroup += thead + thead += create_table_row([ + nodes.paragraph(text=label) for label in header]) + tbody = nodes.tbody() + tgroup += tbody + for ip_info in ips: para = nodes.paragraph() para += nodes.literal('', ip_info['ip']) ids = ip_object_anchor(ip_info['typ'], ip_info['ip']) para['ids'].append(ids) + domaindata[ip_info['typ']][ids] = (fromdocname, '') newnode = nodes.reference('', '', internal=True) try: @@ -257,9 +288,13 @@ def process_ip_nodes(app, doctree, fromdocname): title = env.titles[ip_info['docname']] innernode = nodes.Text(title.astext()) newnode.append(innernode) - para += nodes.Text(" in ") - para += newnode - content.append(para) + refnode = nodes.paragraph() + refnode.append(newnode) + tbody += create_table_row([para, refnode]) + content.append(table) + else: + para = nodes.paragraph(l_('No IP addresses in this range')) + content.append(para) node.replace_self(content) From dd419f4ae655363e0fecfcfc615b011a4e196d0d Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 4 May 2016 13:19:17 +0200 Subject: [PATCH 6/7] Add handling for multiple IP occurrences This commit adds handling of multiple occurrences of the same IP address in one or more pages. --- jandd/sphinxext/ip.py | 60 ++++++++++++++++++++++++++-------------- tests/root/index.rst | 1 + tests/root/testpage3.rst | 4 +++ 3 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 tests/root/testpage3.rst diff --git a/jandd/sphinxext/ip.py b/jandd/sphinxext/ip.py index 24b6672..0c71bda 100644 --- a/jandd/sphinxext/ip.py +++ b/jandd/sphinxext/ip.py @@ -234,8 +234,8 @@ def process_ips(app, doctree): node.replace_self(replacement) -def sort_ip_info(item): - return Network(item['ip']).ip +def sort_ip(item): + return Network(item).ip def create_table_row(rowdata): @@ -257,9 +257,14 @@ def process_ip_nodes(app, doctree, fromdocname): for node in doctree.traverse(ip_range): content = [] net = Network(node['rangespec']) - ips = [ip_info for ip_info in - sorted(domaindata['ips'], key=sort_ip_info) - if ip_info['ip'] in net] + ips = {} + for key, value in [ + (ip_info['ip'], ip_info) for ip_info in + domaindata['ips'] if ip_info['ip'] in net + ]: + addrlist = ips.get(key, []) + addrlist.append(value) + ips[key] = addrlist if ips: table = nodes.table() tgroup = nodes.tgroup(cols=len(header)) @@ -272,24 +277,37 @@ def process_ip_nodes(app, doctree, fromdocname): nodes.paragraph(text=label) for label in header]) tbody = nodes.tbody() tgroup += tbody - for ip_info in ips: + for ip, ip_info in [ + (ip, ips[ip]) for ip in sorted(ips, key=sort_ip) + ]: para = nodes.paragraph() - para += nodes.literal('', ip_info['ip']) - ids = ip_object_anchor(ip_info['typ'], ip_info['ip']) - para['ids'].append(ids) - - domaindata[ip_info['typ']][ids] = (fromdocname, '') - newnode = nodes.reference('', '', internal=True) - try: - newnode['refuri'] = app.builder.get_relative_uri( - fromdocname, ip_info['docname']) - except NoUri: - pass - title = env.titles[ip_info['docname']] - innernode = nodes.Text(title.astext()) - newnode.append(innernode) + para += nodes.literal('', ip) refnode = nodes.paragraph() - refnode.append(newnode) + refuris = set() + refnodes = [] + for item in ip_info: + ids = ip_object_anchor(item['typ'], item['ip']) + if ids not in para['ids']: + para['ids'].append(ids) + + domaindata[item['typ']][ids] = (fromdocname, '') + newnode = nodes.reference('', '', internal=True) + try: + newnode['refuri'] = app.builder.get_relative_uri( + fromdocname, item['docname']) + if newnode['refuri'] in refuris: + continue + refuris.add(newnode['refuri']) + except NoUri: + pass + title = env.titles[item['docname']] + innernode = nodes.Text(title.astext()) + newnode.append(innernode) + refnodes.append(newnode) + for count in range(len(refnodes)): + refnode.append(refnodes[count]) + if count < len(refnodes) - 1: + refnode.append(nodes.Text(", ")) tbody += create_table_row([para, refnode]) content.append(table) else: diff --git a/tests/root/index.rst b/tests/root/index.rst index 8ada3e1..4b2e15e 100644 --- a/tests/root/index.rst +++ b/tests/root/index.rst @@ -13,6 +13,7 @@ Contents: testpage1 testpage2 + testpage3 Indices and tables diff --git a/tests/root/testpage3.rst b/tests/root/testpage3.rst new file mode 100644 index 0000000..ae38493 --- /dev/null +++ b/tests/root/testpage3.rst @@ -0,0 +1,4 @@ +Test page 3 +=========== + +This page contains :ip:v6:`2001:dead:beef::1` like :doc:`testpage2` does. From 0cd11fb602f11647a1069b03dc7ac8f767cba914 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Wed, 4 May 2016 13:44:09 +0200 Subject: [PATCH 7/7] Improve release metadata This commit adds a URL to setup.py's setup() call and development and change information to README.rst. --- README.rst | 25 +++++++++++++++++++++++-- setup.py | 1 + 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index d8de5b8..97ccd17 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,4 @@ +================== jandd.sphinxext.ip ================== @@ -5,10 +6,30 @@ This is an IP address extension for `Sphinx`_. The extension provides a domain *ip* that allows marking IPv4 and IPv6 addresses in documentation and contains directives to collect information regarding IP addresses in IP ranges. +.. _Sphinx: http://www.sphinx-doc.org/ + +Development +=========== + +The extension is developed in a git repository that can be cloned by running:: + + git clone https://git.dittberner.info/sphinxext-ip.git + +A repository browser is available at +https://git.dittberner.info/?p=sphinxext-ip.git. + Contributors ------------- +============ * `Jan Dittberner`_ .. _Jan Dittberner: https://jan.dittberner.info/ -.. _Sphinx: http://www.sphinx-doc.org/ + +Changes +======= + +0.2.0 - 2016-05-04 +------------------ + +* display IP address lists as tables +* sort IP address lists numericaly diff --git a/setup.py b/setup.py index a999211..b992734 100644 --- a/setup.py +++ b/setup.py @@ -20,6 +20,7 @@ setup( install_requires=requires, keywords="sphinx extension IP", license="GPLv3+", + url="https://pypi.python.org/pypi/jandd.sphinxext.ip", name="jandd.sphinxext.ip", namespace_packages=['jandd', 'jandd.sphinxext'], packages=find_packages(),