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
==================
@ -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

View file

@ -8,7 +8,6 @@
:copyright: Copyright (c) 2016 Jan Dittberner
:license: GPLv3+, see COPYING file for details.
"""
__version__ = '0.1.1'
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__(
@ -230,36 +234,85 @@ def process_ips(app, doctree):
node.replace_self(replacement)
def sort_ip_info(item):
return item['ip']
def sort_ip(item):
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):
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 = {}
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.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.Text(" in ")
para += newnode
content.append(para)
para += nodes.literal('', ip)
refnode = nodes.paragraph()
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:
para = nodes.paragraph(l_('No IP addresses in this range'))
content.append(para)
node.replace_self(content)

View file

@ -2,14 +2,11 @@
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"
with open('COPYING') as license:
description += license.read()
requires = ['Sphinx>=1.4', 'ipcalc>=1.99']
tests_requires = ['path.py>=8.2.1']
@ -17,12 +14,13 @@ 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,
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(),

View file

@ -13,6 +13,7 @@ Contents:
testpage1
testpage2
testpage3
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.