Merge branch 'release/0.2.0'

* release/0.2.0:
  Improve release metadata
  Add handling for multiple IP occurrences
  Format IP lists as tables
  Fix IP address sorting
  Bump version number
  Fix grammar mistake
  Don't add GPL to long_description
This commit is contained in:
Jan Dittberner 2016-05-04 13:46:53 +02:00
commit 88ffa4fbeb
5 changed files with 108 additions and 31 deletions

View file

@ -1,3 +1,4 @@
==================
jandd.sphinxext.ip 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 *ip* that allows marking IPv4 and IPv6 addresses in documentation and contains
directives to collect information regarding IP addresses in IP ranges. 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 Contributors
------------ ============
* `Jan Dittberner`_ * `Jan Dittberner`_
.. _Jan Dittberner: https://jan.dittberner.info/ .. _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

View file

@ -8,7 +8,6 @@
:copyright: Copyright (c) 2016 Jan Dittberner :copyright: Copyright (c) 2016 Jan Dittberner
:license: GPLv3+, see COPYING file for details. :license: GPLv3+, see COPYING file for details.
""" """
__version__ = '0.1.1'
import re import re
@ -24,15 +23,20 @@ from sphinx.locale import l_
from sphinx.roles import XRefRole from sphinx.roles import XRefRole
from sphinx.util.nodes import make_refnode from sphinx.util.nodes import make_refnode
__version__ = '0.2.0'
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): 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): class IPXRefRole(XRefRole):
@ -42,7 +46,7 @@ class IPXRefRole(XRefRole):
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__(
@ -230,36 +234,85 @@ def process_ips(app, doctree):
node.replace_self(replacement) node.replace_self(replacement)
def sort_ip_info(item): def sort_ip(item):
return item['ip'] return Network(item).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): 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 = (l_('IP address'), l_('Used by'))
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'])
for ip_info in sorted(domaindata['ips'], key=sort_ip_info): ips = {}
if ip_info['ip'] in net: 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))
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, ip_info in [
(ip, ips[ip]) for ip in sorted(ips, key=sort_ip)
]:
para = nodes.paragraph() para = nodes.paragraph()
para += nodes.literal('', ip_info['ip']) para += nodes.literal('', ip)
ids = ip_object_anchor(ip_info['typ'], ip_info['ip']) refnode = nodes.paragraph()
para['ids'].append(ids) refuris = set()
domaindata[ip_info['typ']][ids] = (fromdocname, '') refnodes = []
newnode = nodes.reference('', '', internal=True) for item in ip_info:
try: ids = ip_object_anchor(item['typ'], item['ip'])
newnode['refuri'] = app.builder.get_relative_uri( if ids not in para['ids']:
fromdocname, ip_info['docname']) para['ids'].append(ids)
except NoUri:
pass domaindata[item['typ']][ids] = (fromdocname, '')
title = env.titles[ip_info['docname']] newnode = nodes.reference('', '', internal=True)
innernode = nodes.Text(title.astext()) try:
newnode.append(innernode) newnode['refuri'] = app.builder.get_relative_uri(
para += nodes.Text(" in ") fromdocname, item['docname'])
para += newnode if newnode['refuri'] in refuris:
content.append(para) 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:
para = nodes.paragraph(l_('No IP addresses in this range'))
content.append(para)
node.replace_self(content) node.replace_self(content)

View file

@ -2,14 +2,11 @@
from setuptools import setup, find_packages from setuptools import setup, find_packages
version = '0.1.1' version = '0.2.0'
with open('README.rst') as readme: with open('README.rst') as readme:
description = readme.read() + "\n\n" description = readme.read() + "\n\n"
with open('COPYING') as license:
description += license.read()
requires = ['Sphinx>=1.4', 'ipcalc>=1.99'] requires = ['Sphinx>=1.4', 'ipcalc>=1.99']
tests_requires = ['path.py>=8.2.1'] tests_requires = ['path.py>=8.2.1']
@ -17,12 +14,13 @@ tests_requires = ['path.py>=8.2.1']
setup( setup(
author="Jan Dittberner", author="Jan Dittberner",
author_email="jan@dittberner.info", author_email="jan@dittberner.info",
description="IP address extensions for Sphinx", description="IP address extension for Sphinx",
long_description=description, long_description=description,
include_package_data=True, include_package_data=True,
install_requires=requires, install_requires=requires,
keywords="sphinx extension IP", keywords="sphinx extension IP",
license="GPLv3+", license="GPLv3+",
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(),

View file

@ -13,6 +13,7 @@ Contents:
testpage1 testpage1
testpage2 testpage2
testpage3
Indices and tables Indices and tables

4
tests/root/testpage3.rst Normal file
View file

@ -0,0 +1,4 @@
Test page 3
===========
This page contains :ip:v6:`2001:dead:beef::1` like :doc:`testpage2` does.