[Python-modules-commits] [sphinxcontrib-doxylink] 01/03: Imported Upstream version 1.3
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Fri May 6 10:33:11 UTC 2016
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to branch debian/master
in repository sphinxcontrib-doxylink.
commit 0814f01fccecdd9f76bf712d8355cdf1e4ecb612
Author: Ghislain Antony Vaillant <ghisvail at gmail.com>
Date: Fri May 6 07:56:50 2016 +0100
Imported Upstream version 1.3
---
CHANGES.rst | 48 +++
MANIFEST.in | 3 +
PKG-INFO | 50 +++
README.rst | 28 ++
setup.cfg | 8 +
setup.py | 41 ++
sphinxcontrib/__init__.py | 14 +
sphinxcontrib/doxylink/__init__.py | 2 +
sphinxcontrib/doxylink/doxylink.py | 452 +++++++++++++++++++++
sphinxcontrib/doxylink/parsing.py | 153 +++++++
sphinxcontrib_doxylink.egg-info/PKG-INFO | 50 +++
sphinxcontrib_doxylink.egg-info/SOURCES.txt | 18 +
.../dependency_links.txt | 1 +
.../namespace_packages.txt | 1 +
sphinxcontrib_doxylink.egg-info/not-zip-safe | 1 +
sphinxcontrib_doxylink.egg-info/requires.txt | 2 +
sphinxcontrib_doxylink.egg-info/top_level.txt | 2 +
tests/__init__.py | 0
tests/test_parser.py | 134 ++++++
19 files changed, 1008 insertions(+)
diff --git a/CHANGES.rst b/CHANGES.rst
new file mode 100644
index 0000000..ab55428
--- /dev/null
+++ b/CHANGES.rst
@@ -0,0 +1,48 @@
+1.3 (Sep 13, 2012)
+====================
+
+- Add fix from Matthias Tuma from Shark3 to allow friend declarations inside classes.
+
+1.2 (Nov 3, 2011)
+====================
+
+- Add Python 3 support
+
+1.1 (Feb 19, 2011)
+====================
+
+- Add support for linking directly to struct definitions.
+- Allow to link to functions etc. which are in a header/source file but not a member of a class.
+
+1.0 (Dec 14, 2010)
+====================
+
+- New Dependency: PyParsing (http://pyparsing.wikispaces.com/)
+- Completely new tag file parsing system. Allows for function overloading.
+ The parsed results are cached to speed things up.
+- Full usage documentation. Build with `sphinx-build -W -b html doc html`.
+- Fix problem with mixed slashes when building on Windows.
+
+0.4 (Aug 15, 2010)
+====================
+
+- Allow URLs as base paths for the HTML links.
+- Don't append parentheses if the user has provided them already in their query.
+
+0.3 (Aug 10, 2010)
+====================
+
+- Only parse the tag file once per run. This should increase the speed.
+- Automatically add parentheses to functions if the add_function_parentheses config variable is set.
+
+0.2 (Jul 31, 2010)
+====================
+
+- When a target cannot be found, make the node an `inline` node so there's no link created.
+- No longer require a trailing slash on the `doxylink` config variable HTML link path.
+- Allow doxylinks to work correctly when created from a documentation subdirectory.
+
+0.1 (Jul 22, 2010)
+==================
+
+- Initial release
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..e7c05de
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+include README.rst
+include LICENSE
+include CHANGES.rst
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..f09fc17
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,50 @@
+Metadata-Version: 1.1
+Name: sphinxcontrib-doxylink
+Version: 1.3
+Summary: Sphinx extension for linking to Doxygen documentation.
+Home-page: http://packages.python.org/sphinxcontrib-doxylink
+Author: Matt Williams
+Author-email: matt at milliams.com
+License: BSD
+Download-URL: http://pypi.python.org/pypi/sphinxcontrib-doxylink
+Description: ######################
+ sphinxcontrib-doxylink
+ ######################
+
+ A Sphinx_ extension to link to external Doxygen API documentation.
+
+ Usage
+ -----
+
+ Please refer to the documentation_ for information on using this extension.
+
+ Installation
+ ------------
+
+ This extension can be installed from the Python Package Index::
+
+ pip install sphinxcontrib-doxylink
+
+ Alternatively, you can clone the sphinx-contrib_ repository from BitBucket,
+ and install the extension directly from the repository::
+
+ hg clone http://bitbucket.org/birkenfeld/sphinx-contrib
+ cd sphinx-contrib/doxylink
+ python setup.py install
+
+ .. _`Sphinx`: http://sphinx.pocoo.org/latest
+ .. _`sphinx-contrib`: http://bitbucket.org/birkenfeld/sphinx-contrib
+ .. _`documentation`: http://packages.python.org/sphinxcontrib-doxylink
+
+Keywords: sphinx,doxygen,documentation,c++
+Platform: any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Documentation
+Classifier: Topic :: Utilities
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..13c04ff
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,28 @@
+######################
+sphinxcontrib-doxylink
+######################
+
+A Sphinx_ extension to link to external Doxygen API documentation.
+
+Usage
+-----
+
+Please refer to the documentation_ for information on using this extension.
+
+Installation
+------------
+
+This extension can be installed from the Python Package Index::
+
+ pip install sphinxcontrib-doxylink
+
+Alternatively, you can clone the sphinx-contrib_ repository from BitBucket,
+and install the extension directly from the repository::
+
+ hg clone http://bitbucket.org/birkenfeld/sphinx-contrib
+ cd sphinx-contrib/doxylink
+ python setup.py install
+
+.. _`Sphinx`: http://sphinx.pocoo.org/latest
+.. _`sphinx-contrib`: http://bitbucket.org/birkenfeld/sphinx-contrib
+.. _`documentation`: http://packages.python.org/sphinxcontrib-doxylink
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..3581741
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,8 @@
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
+
+[aliases]
+release = egg_info -RDb ''
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..e34795e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+
+from setuptools import setup, find_packages
+
+with open('README.rst') as stream:
+ long_desc = stream.read()
+
+requires = ['Sphinx>=0.6', 'pyparsing']
+
+setup(
+ name='sphinxcontrib-doxylink',
+ version='1.3',
+ url='http://packages.python.org/sphinxcontrib-doxylink',
+ download_url='http://pypi.python.org/pypi/sphinxcontrib-doxylink',
+ license='BSD',
+ author='Matt Williams',
+ author_email='matt at milliams.com',
+ description='Sphinx extension for linking to Doxygen documentation.',
+ long_description=long_desc,
+ keywords=['sphinx','doxygen','documentation','c++'],
+ zip_safe=False,
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Console',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 3',
+ 'Topic :: Documentation',
+ 'Topic :: Utilities',
+ ],
+ platforms='any',
+ packages=find_packages(),
+ include_package_data=True,
+ install_requires=requires,
+ namespace_packages=['sphinxcontrib'],
+ test_suite="tests",
+ use_2to3=True,
+)
diff --git a/sphinxcontrib/__init__.py b/sphinxcontrib/__init__.py
new file mode 100644
index 0000000..b5a7dc2
--- /dev/null
+++ b/sphinxcontrib/__init__.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinxcontrib
+ ~~~~~~~~~~~~~
+
+ This package is a namespace package that contains all extensions
+ distributed in the ``sphinx-contrib`` distribution.
+
+ :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+__import__('pkg_resources').declare_namespace(__name__)
+
diff --git a/sphinxcontrib/doxylink/__init__.py b/sphinxcontrib/doxylink/__init__.py
new file mode 100644
index 0000000..8414033
--- /dev/null
+++ b/sphinxcontrib/doxylink/__init__.py
@@ -0,0 +1,2 @@
+from doxylink import *
+
diff --git a/sphinxcontrib/doxylink/doxylink.py b/sphinxcontrib/doxylink/doxylink.py
new file mode 100644
index 0000000..69f4c16
--- /dev/null
+++ b/sphinxcontrib/doxylink/doxylink.py
@@ -0,0 +1,452 @@
+# -*- coding: utf-8 -*-
+
+import os
+import xml.etree.ElementTree as ET
+import urlparse
+import re
+import itertools
+
+from docutils import nodes, utils
+from sphinx.util.nodes import split_explicit_title
+from sphinx.util.console import bold, standout
+
+from parsing import normalise, ParseException
+
+def find_url(doc, symbol):
+ """
+ Return the URL for a given symbol.
+
+ This is where the magic happens.
+ This function could be a lot more clever. At present it required the passed symbol to be almost exactly the same as the entries in the Doxygen tag file.
+
+ .. todo::
+
+ Maybe print a list of all possible matches as a warning (but still only return the first)
+
+ :Parameters:
+ doc : xml.etree.ElementTree
+ The XML DOM object
+ symbol : string
+ The symbol to lookup in the file. E.g. something like 'PolyVox::Array' or 'tidyUpMemory'
+
+ :return: String representing the filename part of the URL
+ """
+
+ #First check for an exact match with a top-level object (namespaces, objects etc.)
+
+ #env = inliner.document.settings.env
+
+ matches = []
+ for compound in doc.findall('.//compound'):
+ if compound.find('name').text == symbol:
+ matches += [{'file':compound.find('filename').text, 'kind':compound.get('kind')}]
+
+ if len(matches) > 1:
+ pass
+ #env.warn(env.docname, 'There were multiple matches for `%s`: %s' % (symbol, matches))
+ if len(matches) == 1:
+ return matches[0]
+
+
+ #Strip off first namespace bit of the compound name so that 'ArraySizes' can match 'PolyVox::ArraySizes'
+ for compound in doc.findall('.//compound'):
+ symbol_list = compound.find('name').text.split('::', 1)
+ if len(symbol_list) == 2:
+ reducedsymbol = symbol_list[1]
+ if reducedsymbol == symbol:
+ return {'file':compound.find('filename').text, 'kind':compound.get('kind')}
+
+ #Now split the symbol by '::'. Find an exact match for the first part and then a member match for the second
+ #So PolyVox::Array::operator[] becomes like {namespace: "PolyVox::Array", endsymbol: "operator[]"}
+ symbol_list = symbol.rsplit('::', 1)
+ if len(symbol_list) == 2:
+ namespace = symbol_list[0]
+ endsymbol = symbol_list[1]
+ for compound in doc.findall('.//compound'):
+ if compound.find('name').text == namespace:
+ for member in compound.findall('member'):
+ #If this compound object contains the matching member then return it
+ if member.find('name').text == endsymbol:
+ return {'file':(member.findtext('anchorfile') or compound.findtext('filename')) + '#' + member.find('anchor').text, 'kind':member.get('kind')}
+
+ #Then we'll look at unqualified members
+ for member in doc.findall('.//member'):
+ if member.find('name').text == symbol:
+ return {'file':(member.findtext('anchorfile') or compound.findtext('filename')) + '#' + member.find('anchor').text, 'kind':member.get('kind')}
+
+ return None
+
+def parse_tag_file(doc):
+ """
+ Takes in an XML tree from a Doxygen tag file and returns a dictionary that looks something like:
+
+ .. code-block:: python
+
+ {'PolyVox': {'file': 'namespace_poly_vox.html',
+ 'kind': 'namespace'},
+ 'PolyVox::Array': {'file': 'class_poly_vox_1_1_array.html',
+ 'kind': 'class'},
+ 'PolyVox::Array1DDouble': {'file': 'namespace_poly_vox.html#a7a1f5fd5c4f7fbb4258a495d707b5c13',
+ 'kind': 'typedef'},
+ 'PolyVox::Array1DFloat': {'file': 'namespace_poly_vox.html#a879a120e49733eba1905c33f8a7f131b',
+ 'kind': 'typedef'},
+ 'PolyVox::Array1DInt16': {'file': 'namespace_poly_vox.html#aa1463ece448c6ebed55ab429d6ae3e43',
+ 'kind': 'typedef'},
+ 'QScriptContext::throwError': {'arglist': {'( Error error, const QString & text )': 'qscriptcontext.html#throwError',
+ '( const QString & text )': 'qscriptcontext.html#throwError-2'},
+ 'kind': 'function'},
+ 'QScriptContext::toString': {'arglist': {'()': 'qscriptcontext.html#toString'},
+ 'kind': 'function'}}
+
+ Note the different form for functions. This is required to allow for 'overloading by argument type'.
+
+ To access a filename for a symbol you do:
+
+ .. code-block:: python
+
+ symbol_mapping = mapping[symbol]
+ if symbol_mapping['kind'] == 'function':
+ url = symbol_mapping['arglist'][argument_string]
+ else:
+ url = symbol_mapping['file']
+
+ :Parameters:
+ doc : xml.etree.ElementTree
+ The XML DOM object
+
+ :return: a dictionary mapping fully qualified symbols to files
+ """
+
+ mapping = {}
+ function_list = [] #This is a list of function to be parsed and inserted into mapping at the end of the function.
+ for compound in doc.findall("./compound"):
+ compound_kind = compound.get('kind')
+ if compound_kind != 'namespace' and compound_kind != 'class' and compound_kind!= 'struct' and compound_kind != 'file':
+ continue #Skip everything that isn't a namespace, class, struct or file
+
+ compound_name = compound.findtext('name')
+ compound_filename = compound.findtext('filename')
+
+ #TODO The following is a hack bug fix I think
+ #Doxygen doesn't seem to include the file extension to <compound kind="file"><filename> entries
+ #If it's a 'file' type, check if it _does_ have an extension, if not append '.html'
+ if compound_kind == 'file' and not os.path.splitext(compound_filename)[1]:
+ compound_filename = join(compound_filename, '.html')
+
+ #If it's a compound we can simply add it
+ mapping[compound_name] = {'kind' : compound_kind, 'file' : compound_filename}
+
+ for member in compound.findall('member'):
+
+ #If the member doesn't have an <anchorfile> element, use the parent compounds <filename> instead
+ #This is the way it is in the qt.tag and is perhaps an artefact of old Doxygen
+ anchorfile = member.findtext('anchorfile') or compound_filename
+ member_symbol = join(compound_name, '::', member.findtext('name'))
+ member_kind = member.get('kind')
+ arglist_text = member.findtext('./arglist') #If it has an <arglist> then we assume it's a function. Empty <arglist> returns '', not None. Things like typedefs and enums can have empty arglists
+
+ if arglist_text and member_kind != 'variable' and member_kind != 'typedef' and member_kind != 'enumeration':
+ function_list.append((member_symbol, arglist_text, member_kind, join(anchorfile,'#',member.findtext('anchor'))))
+ else:
+ mapping[member_symbol] = {'kind' : member.get('kind'), 'file' : join(anchorfile,'#',member.findtext('anchor'))}
+
+ for old_tuple, normalised_tuple in zip(function_list, itertools.imap(normalise, (member_tuple[1] for member_tuple in function_list))):
+ member_symbol = old_tuple[0]
+ original_arglist = old_tuple[1]
+ kind = old_tuple[2]
+ anchor_link = old_tuple[3]
+ normalised_arglist = normalised_tuple[1]
+ if normalised_tuple[1] is not None: #This is a 'flag' for a ParseException having happened
+ if mapping.get(member_symbol) and mapping[member_symbol]['kind'] == 'function':
+ mapping[member_symbol]['arglist'][normalised_arglist] = anchor_link
+ else:
+ mapping[member_symbol] = {'kind' : kind, 'arglist' : {normalised_arglist : anchor_link}}
+ else:
+ print('Skipping %s %s%s. Error reported from parser was: %s' % (old_tuple[2], old_tuple[0], old_tuple[1], normalised_tuple[0]))
+
+ #from pprint import pprint; pprint(mapping)
+ return mapping
+
+def find_url2(mapping, symbol):
+ """
+ Return the URL for a given symbol.
+
+ This is where the magic happens.
+
+ .. todo::
+
+ Maybe print a list of all possible matches as a warning (but still only return the first)
+
+ :Parameters:
+ mapping : dictionary
+ A dictionary of the form returned by :py:func:`parse_tag_file`
+ symbol : string
+ The symbol to lookup in the file. E.g. something like 'PolyVox::Array' or 'tidyUpMemory'
+
+ :return: String representing the filename part of the URL
+
+ :raises:
+ LookupError
+ Raised if the symbol could not be matched in the file
+ """
+ #print "\n\nSearching for", symbol
+ try:
+ symbol, normalised_arglist = normalise(symbol)
+ except ParseException as error:
+ raise LookupError(error)
+ #print symbol, normalised_arglist
+
+ #If we have an exact match then return it.
+ if mapping.get(symbol):
+ #print ('Exact match')
+ return return_from_mapping(mapping[symbol], normalised_arglist)
+
+ #If the user didn't pass in any arguments, i.e. `arguments == ''` then they don't care which version of the overloaded funtion they get.
+
+ #First we check for any mapping entries which even slightly match the requested symbol
+ #endswith_list = {}
+ #for item, data in mapping.items():
+ # if item.endswith(symbol):
+ #print symbol + ' : ' + item
+ # endswith_list[item] = data
+ # mapping[item]['file']
+
+ #If we only find one then we return it.
+ #if len(endswith_list) is 1:
+ # return endswith_list.values()[0]['file']
+
+ #print("Still", len(endswith_list), 'possible matches')
+
+ piecewise_list = find_url_piecewise(mapping, symbol)
+
+ #If there is only one match, return it.
+ if len(piecewise_list) is 1:
+ return return_from_mapping(piecewise_list.values()[0], normalised_arglist)
+
+ #print("Still", len(piecewise_list), 'possible matches')
+
+ #If there is more than one item in piecewise_list then there is an ambiguity
+ #Often this is due to the symbol matching the name of the constructor as well as the class name itself
+ classes_list = find_url_classes(piecewise_list, symbol)
+
+ #If there is only one by here we return it.
+ if len(classes_list) is 1:
+ return classes_list.values()[0]
+
+ #print("Still", len(classes_list), 'possible matches')
+
+ #If we exhaused the list by requiring classes, use the list from before the filter.
+ if len(classes_list) == 0:
+ classes_list = piecewise_list
+
+ no_templates_list = find_url_remove_templates(classes_list, symbol)
+
+ if len(no_templates_list) is 1:
+ return return_from_mapping(no_templates_list.values()[0], normalised_arglist)
+
+ #print("Still", len(no_templates_list), 'possible matches')
+
+ #If not found by now, just return the first one in the list
+ if len(no_templates_list) != 0:
+ #TODO return a warning here?
+ return return_from_mapping(no_templates_list.values()[0], normalised_arglist)
+ #Else return None if the list is empty
+ else:
+ LookupError('Could not find a match')
+
+def return_from_mapping(mapping_entry, normalised_arglist=''):
+ """
+ Return a mapping to a single URL in the form. This is needed since mapping entries for functions are more complicated due to function overriding.
+
+ If the mapping to be returned is not a function, this will simply return the mapping entry intact. If the entry is a function it will attempt to get the right version based on the function signature.
+
+ :Parameters:
+ mapping_entry : dict
+ should be a single entry from the large mapping file corresponding to a single symbol. If the symbol is a function, then ``mappingentry['arglist']`` will be a dictionary mapping normalised signatures to URLs
+ normalised_arglist : string
+ the normalised form of the arglist that the user has requested. This can be empty in which case the function will return just the first element of ``mappingentry['arglist']``. This parameter is ignored if ``mappingentry['kind'] != 'function'``
+
+ :return: dictionary something like:
+
+ .. code-block:: python
+
+ {'kind' : 'function', 'file' : 'something.html#foo'}
+
+ """
+ #If it's a function we need to grab the right signature from the arglist.
+ if mapping_entry['kind'] == 'function':
+ #If the user has requested a specific function through specifying an arglist then get the right anchor
+ if normalised_arglist:
+ filename = mapping_entry['arglist'].get(normalised_arglist)
+ if not filename: #If we didn't get the filename because it's not in the mapping then we will just return a random one?
+ #TODO return a warning here!
+ filename = mapping_entry['arglist'].values()[0]
+ else:
+ #Otherwise just return the first entry (if they don't care they get whatever comes first)
+ filename = mapping_entry['arglist'].values()[0]
+
+ return {'kind' : 'function', 'file' : filename}
+ elif mapping_entry.get('arglist'):
+ #This arglist should only be one entry long and that entry should have '' as its key
+ return {'kind' : mapping_entry['kind'], 'file' : mapping_entry['arglist']['']}
+
+ #If it's not a function, then return it raw
+ return mapping_entry
+
+def find_url_piecewise(mapping, symbol):
+ """
+ Match the requested symbol reverse piecewise (split on ``::``) against the tag names to ensure they match exactly (modulo ambiguity)
+ So, if in the mapping there is ``PolyVox::Volume::FloatVolume`` and ``PolyVox::Volume`` they would be split into:
+
+ .. code-block:: python
+
+ ['PolyVox', 'Volume', 'FloatVolume'] and ['PolyVox', 'Volume']
+
+ and reversed:
+
+ .. code-block:: python
+
+ ['FloatVolume', 'Volume', 'PolyVox'] and ['Volume', 'PolyVox']
+
+ and truncated to the shorter of the two:
+
+ .. code-block:: python
+
+ ['FloatVolume', 'Volume'] and ['Volume', 'PolyVox']
+
+ If we're searching for the ``PolyVox::Volume`` symbol we would compare:
+
+ .. code-block:: python
+
+ ['Volume', 'PolyVox'] to ['FloatVolume', 'Volume', 'PolyVox'].
+
+ That doesn't match so we look at the next in the mapping:
+
+ .. code-block:: python
+
+ ['Volume', 'PolyVox'] to ['Volume', 'PolyVox'].
+
+ Good, so we add it to the list
+
+ """
+ piecewise_list = {}
+ for item, data in mapping.items():
+ split_symbol = symbol.split('::')
+ split_item = item.split('::')
+
+ split_symbol.reverse()
+ split_item.reverse()
+
+ min_length = min(len(split_symbol), len(split_item))
+
+ split_symbol = split_symbol[:min_length]
+ split_item = split_item[:min_length]
+
+ #print split_symbol, split_item
+
+ if split_symbol == split_item:
+ #print symbol + ' : ' + item
+ piecewise_list[item] = data
+
+ return piecewise_list
+
+def find_url_classes(mapping, symbol):
+ """Prefer classes over names of constructors"""
+ classes_list = {}
+ for item, data in mapping.items():
+ if data['kind'] == 'class':
+ #print symbol + ' : ' + item
+ classes_list[item] = data
+
+ return classes_list
+
+def find_url_remove_templates(mapping, symbol):
+ """Now, to disambiguate between ``PolyVox::Array< 1, ElementType >::operator[]`` and ``PolyVox::Array::operator[]`` matching ``operator[]``, we will ignore templated (as in C++ templates) tag names by removing names containing ``<``"""
+ no_templates_list = {}
+ for item, data in mapping.items():
+ if '<' not in item:
+ #print symbol + ' : ' + item
+ no_templates_list[item] = data
+
+ return no_templates_list
+
+def join(*args):
+ return ''.join(args)
+
+def create_role(app, tag_filename, rootdir):
+ #Tidy up the root directory path
+ if not rootdir.endswith(('/', '\\')):
+ rootdir = join(rootdir, os.sep)
+
+ try:
+ tag_file = ET.parse(tag_filename)
+
+ cache_name = os.path.basename(tag_filename)
+
+ app.info(bold('Checking tag file cache for %s: ' % cache_name), nonl=True)
+ if not hasattr(app.env, 'doxylink_cache'):
+ # no cache present at all, initialise it
+ app.info('No cache at all, rebuilding...')
+ mapping = parse_tag_file(tag_file)
+ app.env.doxylink_cache = { cache_name : {'mapping' : mapping, 'mtime' : os.path.getmtime(tag_filename)}}
+ elif not app.env.doxylink_cache.get(cache_name):
+ # Main cache is there but the specific sub-cache for this tag file is not
+ app.info('Sub cache is missing, rebuilding...')
+ mapping = parse_tag_file(tag_file)
+ app.env.doxylink_cache[cache_name] = {'mapping' : mapping, 'mtime' : os.path.getmtime(tag_filename)}
+ elif app.env.doxylink_cache[cache_name]['mtime'] < os.path.getmtime(tag_filename):
+ # tag file has been modified since sub-cache creation
+ app.info('Sub-cache is out of date, rebuilding...')
+ mapping = parse_tag_file(tag_file)
+ app.env.doxylink_cache[cache_name] = {'mapping' : mapping, 'mtime' : os.path.getmtime(tag_filename)}
+ else:
+ #The cache is up to date
+ app.info('Sub-cache is up-to-date')
+ except IOError:
+ tag_file = None
+ app.warn(standout('Could not open tag file %s. Make sure your `doxylink` config variable is set correctly.' % tag_filename))
+
+ def find_doxygen_link(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ text = utils.unescape(text)
+ # from :name:`title <part>`
+ has_explicit_title, title, part = split_explicit_title(text)
+ warning_messages = []
+ if tag_file:
+ url = find_url(tag_file, part)
+ try:
+ url = find_url2(app.env.doxylink_cache[cache_name]['mapping'], part)
+ except LookupError as error:
+ warning_messages.append('Error while parsing `%s`. Is not a well-formed C++ function call or symbol. If this is not the case, it is a doxylink bug so please report it. Error reported was: %s' % (part, error))
+ if url:
+
+ #If it's an absolute path then the link will work regardless of the document directory
+ #Also check if it is a URL (i.e. it has a 'scheme' like 'http' or 'file')
+ if os.path.isabs(rootdir) or urlparse.urlparse(rootdir).scheme:
+ full_url = join(rootdir, url['file'])
+ #But otherwise we need to add the relative path of the current document to the root source directory to the link
+ else:
+ relative_path_to_docsrc = os.path.relpath(app.env.srcdir, os.path.dirname(inliner.document.current_source))
+ full_url = join(relative_path_to_docsrc, '/', rootdir, url['file']) #We always use the '/' here rather than os.sep since this is a web link avoids problems like documentation/.\../library/doc/ (mixed slashes)
+
+ if url['kind'] == 'function' and app.config.add_function_parentheses and not normalise(title)[1]:
+ title = join(title, '()')
+
+ pnode = nodes.reference(title, title, internal=False, refuri=full_url)
+ return [pnode], []
+ #By here, no match was found
+ warning_messages.append('Could not find match for `%s` in `%s` tag file' % (part, tag_filename))
+ else:
+ warning_messages.append('Could not find match for `%s` because tag file not found' % (part))
+
+ pnode = nodes.inline(rawsource=title, text=title)
+ return [pnode], [inliner.reporter.warning(message, line=lineno) for message in warning_messages]
+
+ return find_doxygen_link
+
+def setup_doxylink_roles(app):
+ for name, [tag_filename, rootdir] in app.config.doxylink.iteritems():
+ app.add_role(name, create_role(app, tag_filename, rootdir))
+
+def setup(app):
+ app.add_config_value('doxylink', {}, 'env')
+ app.connect('builder-inited', setup_doxylink_roles)
diff --git a/sphinxcontrib/doxylink/parsing.py b/sphinxcontrib/doxylink/parsing.py
new file mode 100644
index 0000000..4e42f44
--- /dev/null
+++ b/sphinxcontrib/doxylink/parsing.py
@@ -0,0 +1,153 @@
+#import multiprocessing
+import itertools
+
+from pyparsing import Word, Literal, alphas, nums, alphanums, OneOrMore, Optional, SkipTo, ParseException, Group, ZeroOrMore, Suppress, Combine, delimitedList, quotedString, nestedExpr, ParseResults, oneOf
+
+# define punctuation - reuse of expressions helps packratting work better
+LPAR,RPAR,LBRACK,RBRACK,COMMA,EQ = map(Literal,"()[],=")
+
+#Qualifier to go in front of type in the argument list (unsigned const int foo)
+qualifier = OneOrMore(oneOf('const unsigned typename struct enum'))
+
+def turn_parseresults_to_list(s, loc, toks):
+ return ParseResults(normalise_templates(toks[0].asList()))
+
+def normalise_templates(toks, isinstance=isinstance, basestring=basestring):
+ s_list = ['<']
+ s_list_append = s_list.append #lookup append func once, instead of many times
+ for tok in toks:
+ if isinstance(tok, basestring): #See if it's a string
+ s_list_append(' ' + tok)
+ else:
+ #If it's not a string
+ s_list_append(normalise_templates(tok))
+ s_list_append(' >')
+ return ''.join(s_list)
+
+#Skip pairs of brackets.
+angle_bracket_pair = nestedExpr(opener='<',closer='>').setParseAction(turn_parseresults_to_list)
+#TODO Fix for nesting brackets
+parentheses_pair = LPAR + SkipTo(RPAR) + RPAR
+square_bracket_pair = LBRACK + SkipTo(RBRACK) + RBRACK
+
+#The raw type of the input, i.e. 'int' in (unsigned const int * foo)
+#TODO I guess this should be a delimited list (by '::') of name and angle brackets
+input_type = Combine(Word(alphanums + ':_') + Optional(angle_bracket_pair + Optional(Word(alphanums + ':_'))))
+
+#A number. e.g. -1, 3.6 or 5
+number = Word('-.' + nums)
+
+#The name of the argument. We will ignore this but it must be matched anyway.
+input_name = OneOrMore(Word(alphanums + '_') | angle_bracket_pair | parentheses_pair | square_bracket_pair)
+
+#Grab the '&', '*' or '**' type bit in (const QString & foo, int ** bar)
+pointer_or_reference = oneOf('* &')
+
+#The '=QString()' or '=false' bit in (int foo = 4, bool bar = false)
+default_value = Literal('=') + OneOrMore(number | quotedString | input_type | parentheses_pair | angle_bracket_pair | square_bracket_pair | Word('|&^'))
+
+#A combination building up the interesting bit -- the argument type, e.g. 'const QString &', 'int' or 'char*'
+argument_type = Optional(qualifier, default='')("qualifier") + \
+ input_type("input_type") + \
+ Optional(pointer_or_reference, default='')("pointer_or_reference1") + \
+ Optional('const')('const_pointer_or_reference') + \
+ Optional(pointer_or_reference, default='')("pointer_or_reference2")
+
+#Argument + variable name + default
+argument = Group(argument_type('argument_type') + Optional(input_name) + Optional(default_value))
+
+#List of arguments in parentheses with an optional 'const' on the end
+arglist = LPAR + delimitedList(argument)('arg_list') + Optional(COMMA + '...')('var_args') + RPAR
+
+def normalise(symbol):
+ """
+ Takes a c++ symbol or funtion and splits it into symbol and a normalised argument list.
+
+ :Parameters:
+ symbol : string
+ A C++ symbol or function definition like ``PolyVox::Volume``, ``Volume::printAll() const``
+
+ :return:
+ a tuple consisting of two strings: ``(qualified function name or symbol, normalised argument list)``
+ """
+
+ try:
+ bracket_location = symbol.index('(')
+ #Split the input string into everything before the opening bracket and everything else
+ function_name = symbol[:bracket_location]
+ arglist_input_string = symbol[bracket_location:]
+ except ValueError:
+ #If there's no brackets, then there's no function signature. This means the passed in symbol is just a type name
+ return symbol, ''
+
+ #This is a very common signature so we'll make a special case for it. It requires no parsing anyway
+ if arglist_input_string.startswith('()'):
+ if arglist_input_string in ('()', '()=0'):
+ return function_name, arglist_input_string
+ elif arglist_input_string in ('() const ', '() const', '() const =0'):
+ return function_name, '() const'
+
+ #By now we're left with something like "(blah, blah)", "(blah, blah) const" or "(blah, blah) const =0"
+ try:
+ closing_bracket_location = arglist_input_string.rindex(')')
+ arglist_suffix = arglist_input_string[closing_bracket_location+1:]
+ arglist_input_string = arglist_input_string[:closing_bracket_location+1]
+ except ValueError:
+ #This shouldn't happen.
+ print 'Could not find closing bracket in %s' % arglist_input_string
+ raise
+
+ try:
+ result = arglist.parseString(arglist_input_string)
+ except ParseException as error:
+ #print symbol
+ #print pe
+ return str(error), None
+ else:
+ #Will be a list or normalised string arguments
+ #e.g. ['OBMol&', 'vector< int >&', 'OBBitVec&', 'OBBitVec&', 'int', 'int']
+ normalised_arg_list = []
+
+ #Cycle through all the matched arguments
+ for arg in result.arg_list:
+ #Here is where we build up our normalised form of the argument
+ argument_string_list = ['']
+ if arg.qualifier:
+ argument_string_list.append(''.join((arg.qualifier,' ')))
+ argument_string_list.append(arg.input_type)
+
+ #Functions can have a funny combination of *, & and const between the type and the name so build up a list of theose here:
+ const_pointer_ref_list = []
+ const_pointer_ref_list.append(arg.pointer_or_reference1)
+ if arg.const_pointer_or_reference:
+ const_pointer_ref_list.append(''.join((' ', arg.const_pointer_or_reference, ' ')))
+ # same here
+ const_pointer_ref_list.append(arg.pointer_or_reference2)
+ #And combine them into a single normalised string and add them to the argument list
+ argument_string_list.extend(const_pointer_ref_list)
+
+ #Finally we join our argument string and add it to our list
+ normalised_arg_list.append(''.join(argument_string_list))
+
+ #If the function contains a variable number of arguments (int foo, ...) then add them on.
+ if result.var_args:
+ normalised_arg_list.append('...')
+
+ #Combine all the arguments and put parentheses around it
+ normalised_arg_list_string = ''.join(['(', ', '.join(normalised_arg_list), ')'])
+
+ #Add a const onto the end
+ if 'const' in arglist_suffix:
+ normalised_arg_list_string += ' const'
+
+ return function_name, normalised_arg_list_string
+
+ #TODO Maybe this should raise an exception?
+ return None
+
+def normalise_list(list_of_symbols):
+ #normalise_pool = multiprocessing.Pool(multiprocessing.cpu_count() * 2)
+ #results = normalise_pool.map(normalise, list_of_symbols)
+ #normalise_pool.terminate()
+ results = itertools.imap(normalise, list_of_symbols)
+ return results
diff --git a/sphinxcontrib_doxylink.egg-info/PKG-INFO b/sphinxcontrib_doxylink.egg-info/PKG-INFO
new file mode 100644
index 0000000..f09fc17
--- /dev/null
+++ b/sphinxcontrib_doxylink.egg-info/PKG-INFO
@@ -0,0 +1,50 @@
+Metadata-Version: 1.1
+Name: sphinxcontrib-doxylink
+Version: 1.3
+Summary: Sphinx extension for linking to Doxygen documentation.
+Home-page: http://packages.python.org/sphinxcontrib-doxylink
+Author: Matt Williams
+Author-email: matt at milliams.com
+License: BSD
+Download-URL: http://pypi.python.org/pypi/sphinxcontrib-doxylink
+Description: ######################
+ sphinxcontrib-doxylink
+ ######################
+
+ A Sphinx_ extension to link to external Doxygen API documentation.
+
+ Usage
+ -----
+
+ Please refer to the documentation_ for information on using this extension.
+
+ Installation
+ ------------
+
+ This extension can be installed from the Python Package Index::
+
+ pip install sphinxcontrib-doxylink
+
+ Alternatively, you can clone the sphinx-contrib_ repository from BitBucket,
+ and install the extension directly from the repository::
+
+ hg clone http://bitbucket.org/birkenfeld/sphinx-contrib
+ cd sphinx-contrib/doxylink
+ python setup.py install
+
+ .. _`Sphinx`: http://sphinx.pocoo.org/latest
+ .. _`sphinx-contrib`: http://bitbucket.org/birkenfeld/sphinx-contrib
+ .. _`documentation`: http://packages.python.org/sphinxcontrib-doxylink
+
+Keywords: sphinx,doxygen,documentation,c++
+Platform: any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Documentation
+Classifier: Topic :: Utilities
diff --git a/sphinxcontrib_doxylink.egg-info/SOURCES.txt b/sphinxcontrib_doxylink.egg-info/SOURCES.txt
new file mode 100644
index 0000000..8e87d5d
--- /dev/null
+++ b/sphinxcontrib_doxylink.egg-info/SOURCES.txt
@@ -0,0 +1,18 @@
+CHANGES.rst
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+sphinxcontrib/__init__.py
+sphinxcontrib/doxylink/__init__.py
+sphinxcontrib/doxylink/doxylink.py
+sphinxcontrib/doxylink/parsing.py
+sphinxcontrib_doxylink.egg-info/PKG-INFO
+sphinxcontrib_doxylink.egg-info/SOURCES.txt
+sphinxcontrib_doxylink.egg-info/dependency_links.txt
+sphinxcontrib_doxylink.egg-info/namespace_packages.txt
+sphinxcontrib_doxylink.egg-info/not-zip-safe
+sphinxcontrib_doxylink.egg-info/requires.txt
+sphinxcontrib_doxylink.egg-info/top_level.txt
+tests/__init__.py
+tests/test_parser.py
\ No newline at end of file
diff --git a/sphinxcontrib_doxylink.egg-info/dependency_links.txt b/sphinxcontrib_doxylink.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/sphinxcontrib_doxylink.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/sphinxcontrib_doxylink.egg-info/namespace_packages.txt b/sphinxcontrib_doxylink.egg-info/namespace_packages.txt
new file mode 100644
index 0000000..aa75604
--- /dev/null
+++ b/sphinxcontrib_doxylink.egg-info/namespace_packages.txt
@@ -0,0 +1 @@
+sphinxcontrib
diff --git a/sphinxcontrib_doxylink.egg-info/not-zip-safe b/sphinxcontrib_doxylink.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/sphinxcontrib_doxylink.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/sphinxcontrib_doxylink.egg-info/requires.txt b/sphinxcontrib_doxylink.egg-info/requires.txt
new file mode 100644
index 0000000..af02715
--- /dev/null
+++ b/sphinxcontrib_doxylink.egg-info/requires.txt
@@ -0,0 +1,2 @@
+Sphinx>=0.6
+pyparsing
\ No newline at end of file
diff --git a/sphinxcontrib_doxylink.egg-info/top_level.txt b/sphinxcontrib_doxylink.egg-info/top_level.txt
new file mode 100644
index 0000000..5318832
... 148 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/sphinxcontrib-doxylink.git
More information about the Python-modules-commits
mailing list