mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
merge with trunk
This commit is contained in:
commit
faeec5cbbb
19
.hgignore
19
.hgignore
@ -1,13 +1,14 @@
|
||||
.*\.pyc
|
||||
.*\.egg
|
||||
.*\.so
|
||||
build/
|
||||
dist/
|
||||
tests/.coverage
|
||||
sphinx/pycode/Grammar.*pickle
|
||||
Sphinx.egg-info/
|
||||
doc/_build/
|
||||
TAGS
|
||||
\.ropeproject/
|
||||
^env/
|
||||
.dir-locals.el
|
||||
\.DS_Store$
|
||||
^build/
|
||||
^dist/
|
||||
^tests/.coverage
|
||||
^sphinx/pycode/Grammar.*pickle
|
||||
^Sphinx.egg-info/
|
||||
^doc/_build/
|
||||
^TAGS
|
||||
^\.ropeproject/
|
||||
^env/
|
||||
|
11
CHANGES
11
CHANGES
@ -1,6 +1,12 @@
|
||||
Release 1.0 (in development)
|
||||
============================
|
||||
|
||||
.. XXX add short info about domains
|
||||
|
||||
* Support for domains has been added.
|
||||
|
||||
* Support for docutils 0.4 has been removed.
|
||||
|
||||
* Added Epub builder.
|
||||
|
||||
* #284: All docinfo metadata is now put into the document metadata, not
|
||||
@ -8,8 +14,13 @@ Release 1.0 (in development)
|
||||
|
||||
* Added new HTML theme ``agogo``, created by Andi Albrecht.
|
||||
|
||||
* The ``toctree()`` callable in templates now has a ``maxdepth``
|
||||
keyword argument to control the depth of the generated tree.
|
||||
|
||||
* Added new minimal theme called scrolls, created by Armin Ronacher.
|
||||
|
||||
* Added Catalan translation, thanks to Pau Fernández.
|
||||
|
||||
* Added ``html_output_encoding`` config value.
|
||||
|
||||
* #200: Added ``Sphinx.add_stylesheet()``.
|
||||
|
2
Makefile
2
Makefile
@ -9,7 +9,7 @@ all: clean-pyc check test
|
||||
check:
|
||||
@$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \
|
||||
-i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \
|
||||
-i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py .
|
||||
-i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py -i env .
|
||||
|
||||
clean: clean-pyc clean-patchfiles
|
||||
|
||||
|
@ -166,7 +166,7 @@ The special document names (and pages generated for them) are:
|
||||
respectively.
|
||||
|
||||
The general index is populated with entries from modules, all index-generating
|
||||
:ref:`description units <desc-units>`, and from :dir:`index` directives.
|
||||
:ref:`object descriptions <desc-units>`, and from :dir:`index` directives.
|
||||
|
||||
The module index contains one entry per :dir:`module` directive.
|
||||
|
||||
|
@ -143,5 +143,6 @@ def setup(app):
|
||||
parse_directive)
|
||||
app.add_description_unit('role', 'role', 'pair: %s; role', parse_role)
|
||||
app.add_description_unit('confval', 'confval',
|
||||
'pair: %s; configuration value')
|
||||
objname='configuration value',
|
||||
indextemplate='pair: %s; configuration value')
|
||||
app.add_description_unit('event', 'event', 'pair: %s; event', parse_event)
|
||||
|
@ -240,6 +240,7 @@ Project information
|
||||
|
||||
Currently supported languages are:
|
||||
|
||||
* ``ca`` -- Catalan
|
||||
* ``cs`` -- Czech
|
||||
* ``de`` -- German
|
||||
* ``en`` -- English
|
||||
@ -297,8 +298,8 @@ Project information
|
||||
.. confval:: add_module_names
|
||||
|
||||
A boolean that decides whether module names are prepended to all
|
||||
:term:`description unit` titles, e.g. for :dir:`function` directives.
|
||||
Default is ``True``.
|
||||
:term:`object` names (for object types where a "module" of some kind is
|
||||
defined), e.g. for :dir:`function` directives. Default is ``True``.
|
||||
|
||||
.. confval:: show_authors
|
||||
|
||||
|
@ -123,26 +123,28 @@ the following public API:
|
||||
|
||||
.. versionadded:: 0.6
|
||||
|
||||
.. method:: Sphinx.add_description_unit(directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None)
|
||||
.. method:: Sphinx.add_object_type(directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None, objname='')
|
||||
|
||||
This method is a very convenient way to add a new type of information that
|
||||
This method is a very convenient way to add a new :term:`object` type that
|
||||
can be cross-referenced. It will do this:
|
||||
|
||||
* Create a new directive (called *directivename*) for a :term:`description
|
||||
unit`. It will automatically add index entries if *indextemplate* is
|
||||
nonempty; if given, it must contain exactly one instance of ``%s``. See
|
||||
the example below for how the template will be interpreted.
|
||||
* Create a new directive (called *directivename*) for documenting an object.
|
||||
It will automatically add index entries if *indextemplate* is nonempty; if
|
||||
given, it must contain exactly one instance of ``%s``. See the example
|
||||
below for how the template will be interpreted.
|
||||
* Create a new role (called *rolename*) to cross-reference to these
|
||||
description units.
|
||||
object descriptions.
|
||||
* If you provide *parse_node*, it must be a function that takes a string and
|
||||
a docutils node, and it must populate the node with children parsed from
|
||||
the string. It must then return the name of the item to be used in
|
||||
cross-referencing and index entries. See the :file:`ext.py` file in the
|
||||
source for this documentation for an example.
|
||||
* The *objname* (if not given, will default to *directivename*) names the
|
||||
type of object. It is used when listing objects, e.g. in search results.
|
||||
|
||||
For example, if you have this call in a custom Sphinx extension::
|
||||
|
||||
app.add_description_unit('directive', 'dir', 'pair: %s; directive')
|
||||
app.add_object_type('directive', 'dir', 'pair: %s; directive')
|
||||
|
||||
you can use this markup in your documents::
|
||||
|
||||
@ -164,12 +166,15 @@ the following public API:
|
||||
``docutils.nodes.emphasis`` or ``docutils.nodes.strong`` -- you can also use
|
||||
``docutils.nodes.generated`` if you want no further text decoration).
|
||||
|
||||
For the role content, you have the same options as for standard Sphinx roles
|
||||
(see :ref:`xref-syntax`).
|
||||
For the role content, you have the same syntactical possibilities as for
|
||||
standard Sphinx roles (see :ref:`xref-syntax`).
|
||||
|
||||
.. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None)
|
||||
This method is also available under the deprecated alias
|
||||
:meth:`add_description_unit`.
|
||||
|
||||
This method is very similar to :meth:`add_description_unit` except that the
|
||||
.. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='')
|
||||
|
||||
This method is very similar to :meth:`add_object_type` except that the
|
||||
directive it generates must be empty, and will produce no output.
|
||||
|
||||
That means that you can add semantic targets to your sources, and refer to
|
||||
|
@ -13,7 +13,6 @@ Writing new builders
|
||||
|
||||
These methods are predefined and will be called from the application:
|
||||
|
||||
.. automethod:: load_env
|
||||
.. automethod:: get_relative_uri
|
||||
.. automethod:: build_all
|
||||
.. automethod:: build_specific
|
||||
|
@ -201,8 +201,7 @@ The ``todo`` directive function looks like this::
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
|
||||
targetid = "todo-%s" % env.index_num
|
||||
env.index_num += 1
|
||||
targetid = "todo-%s" % env.new_serialno('todo')
|
||||
targetnode = nodes.target('', '', ids=[targetid])
|
||||
|
||||
ad = make_admonition(todo, self.name, [_('Todo')], self.options,
|
||||
@ -225,9 +224,10 @@ to the build environment instance using ``self.state.document.settings.env``.
|
||||
|
||||
Then, to act as a link target (from the todolist), the todo directive needs to
|
||||
return a target node in addition to the todo node. The target ID (in HTML, this
|
||||
will be the anchor name) is generated by using ``env.index_num`` which is
|
||||
persistent between directive calls and therefore leads to unique target names.
|
||||
The target node is instantiated without any text (the first two arguments).
|
||||
will be the anchor name) is generated by using ``env.new_serialno`` which is
|
||||
returns a new integer directive on each call and therefore leads to unique
|
||||
target names. The target node is instantiated without any text (the first two
|
||||
arguments).
|
||||
|
||||
An admonition is created using a standard docutils function (wrapped in Sphinx
|
||||
for docutils cross-version compatibility). The first argument gives the node
|
||||
|
10
doc/faq.rst
10
doc/faq.rst
@ -24,6 +24,10 @@ How do I...
|
||||
... add global substitutions or includes?
|
||||
Add them in the :confval:`rst_epilog` config value.
|
||||
|
||||
... display the whole TOC tree in the sidebar?
|
||||
Use the :data:`toctree` callable in a custom layout template, probably in the
|
||||
``sidebartoc`` block.
|
||||
|
||||
... write my own extension?
|
||||
See the :ref:`extension tutorial <exttut>`.
|
||||
|
||||
@ -48,6 +52,12 @@ SCons
|
||||
Glenn Hutchings has written a SCons build script to build Sphinx
|
||||
documentation; it is hosted here: http://bitbucket.org/zondo/sphinx-scons
|
||||
|
||||
PyPI
|
||||
Jannis Leidel wrote a `setuptools command
|
||||
<http://pypi.python.org/pypi/Sphinx-PyPI-upload>`_ that automatically uploads
|
||||
Sphinx documentation to the PyPI package documentation area at
|
||||
http://packages.python.org/.
|
||||
|
||||
github pages
|
||||
You can use `Michael Jones' sphinx-to-github tool
|
||||
<http://github.com/michaeljones/sphinx-to-github/tree/master>`_ to prepare
|
||||
|
@ -19,17 +19,17 @@ Glossary
|
||||
the :term:`source directory`, but can be set differently with the **-c**
|
||||
command-line option.
|
||||
|
||||
description unit
|
||||
The basic building block of Sphinx documentation. Every "description
|
||||
directive" (e.g. :dir:`function` or :dir:`describe`) creates such a unit;
|
||||
and most units can be cross-referenced to.
|
||||
|
||||
environment
|
||||
A structure where information about all documents under the root is saved,
|
||||
and used for cross-referencing. The environment is pickled after the
|
||||
parsing stage, so that successive runs only need to read and parse new and
|
||||
changed documents.
|
||||
|
||||
object
|
||||
The basic building block of Sphinx documentation. Every "object
|
||||
directive" (e.g. :dir:`function` or :dir:`object`) creates such a block;
|
||||
and most objects can be cross-referenced to.
|
||||
|
||||
source directory
|
||||
The directory which, including its subdirectories, contains all source
|
||||
files for one Sphinx project.
|
||||
|
@ -67,10 +67,12 @@ The directives you can use for module declarations are:
|
||||
|
||||
.. _desc-units:
|
||||
|
||||
Object description units
|
||||
------------------------
|
||||
Object descriptions
|
||||
-------------------
|
||||
|
||||
There are a number of directives used to describe specific features provided by
|
||||
.. XXX generalize for domains
|
||||
|
||||
There are a number of directives used to describe specific objects provided by
|
||||
modules. Each directive requires one or more signatures to provide basic
|
||||
information about what is being described, and the content should be the
|
||||
description. The basic version makes entries in the general index; if no index
|
||||
@ -92,6 +94,8 @@ index entries more informative.
|
||||
|
||||
The directives are:
|
||||
|
||||
.. XXX update this
|
||||
|
||||
.. directive:: .. cfunction:: type name(signature)
|
||||
|
||||
Describes a C function. The signature should be given as in C, e.g.::
|
||||
@ -119,8 +123,8 @@ The directives are:
|
||||
Describes a "simple" C macro. Simple macros are macros which are used
|
||||
for code expansion, but which do not take arguments so cannot be described as
|
||||
functions. This is not to be used for simple constant definitions. Examples
|
||||
of its use in the Python documentation include :cmacro:`PyObject_HEAD` and
|
||||
:cmacro:`Py_BEGIN_ALLOW_THREADS`.
|
||||
of its use in the Python documentation include :c:macro:`PyObject_HEAD` and
|
||||
:c:macro:`Py_BEGIN_ALLOW_THREADS`.
|
||||
|
||||
.. directive:: .. ctype:: name
|
||||
|
||||
@ -241,7 +245,7 @@ Info field lists
|
||||
|
||||
.. versionadded:: 0.4
|
||||
|
||||
Inside description unit directives, reST field lists with these fields are
|
||||
Inside object description directives, reST field lists with these fields are
|
||||
recognized and formatted nicely:
|
||||
|
||||
* ``param``, ``parameter``, ``arg``, ``argument``, ``key``, ``keyword``:
|
||||
@ -338,8 +342,8 @@ There is a set of directives allowing documenting command-line programs:
|
||||
.. versionadded:: 0.5
|
||||
|
||||
|
||||
Custom description units
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Custom object types
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There is also a generic version of these directives:
|
||||
|
||||
@ -354,4 +358,4 @@ There is also a generic version of these directives:
|
||||
Describes a Python bytecode instruction.
|
||||
|
||||
Extensions may add more directives like that, using the
|
||||
:func:`~sphinx.application.Sphinx.add_description_unit` method.
|
||||
:func:`~sphinx.application.Sphinx.add_object_type` method.
|
||||
|
@ -364,5 +364,10 @@ are in HTML form), these variables are also available:
|
||||
.. data:: toctree
|
||||
|
||||
A callable yielding the global TOC tree containing the current page, rendered
|
||||
as HTML bullet lists. If the optional keyword argument ``collapse`` is true,
|
||||
all TOC entries that are not ancestors of the current page are collapsed.
|
||||
as HTML bullet lists. Optional keyword arguments:
|
||||
|
||||
* ``collapse`` (true by default): if true, all TOC entries that are not
|
||||
ancestors of the current page are collapsed
|
||||
|
||||
* ``maxdepth`` (defaults to the max depth selected in the toctree directive):
|
||||
the maximum depth of the tree; set it to ``-1`` to allow unlimited depth
|
||||
|
@ -8,6 +8,7 @@ release = egg_info -RDb ''
|
||||
[extract_messages]
|
||||
mapping_file = babel.cfg
|
||||
output_file = sphinx/locale/sphinx.pot
|
||||
keywords = _ l_ lazy_gettext
|
||||
|
||||
[update_catalog]
|
||||
input_file = sphinx/locale/sphinx.pot
|
||||
|
@ -12,7 +12,7 @@
|
||||
import sys
|
||||
from os import path
|
||||
|
||||
__version__ = '1.0'
|
||||
__version__ = '1.0pre'
|
||||
__released__ = '1.0 (hg)' # used when Sphinx builds its own docs
|
||||
|
||||
package_dir = path.abspath(path.dirname(__file__))
|
||||
|
@ -14,7 +14,7 @@ from docutils import nodes
|
||||
# index markup
|
||||
class index(nodes.Invisible, nodes.Inline, nodes.TextElement): pass
|
||||
|
||||
# description units (classdesc, funcdesc etc.)
|
||||
# domain-specific object descriptions (class, function etc.)
|
||||
|
||||
# parent node for signature and content
|
||||
class desc(nodes.Admonition, nodes.Element): pass
|
||||
|
@ -14,21 +14,24 @@
|
||||
import sys
|
||||
import types
|
||||
import posixpath
|
||||
from os import path
|
||||
from cStringIO import StringIO
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives, roles
|
||||
from docutils.parsers.rst import Directive, convert_directive_function, \
|
||||
directives, roles
|
||||
|
||||
import sphinx
|
||||
from sphinx.roles import xfileref_role, innernodetypes
|
||||
from sphinx import package_dir, locale
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import SphinxError, SphinxWarning, ExtensionError
|
||||
from sphinx.domains import ObjType, all_domains
|
||||
from sphinx.domains.std import GenericObject, Target, StandardDomain
|
||||
from sphinx.builders import BUILTIN_BUILDERS
|
||||
from sphinx.directives import GenericDesc, Target, additional_xref_types
|
||||
from sphinx.environment import SphinxStandaloneReader
|
||||
from sphinx.util import pycompat # imported for side-effects
|
||||
from sphinx.environment import BuildEnvironment, SphinxStandaloneReader
|
||||
from sphinx.util import ENOENT, pycompat # pycompat imported for side-effects
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.compat import Directive, directive_dwim
|
||||
from sphinx.util.console import bold
|
||||
|
||||
|
||||
@ -49,6 +52,7 @@ events = {
|
||||
}
|
||||
|
||||
CONFIG_FILENAME = 'conf.py'
|
||||
ENV_PICKLE_FILENAME = 'environment.pickle'
|
||||
|
||||
|
||||
class Sphinx(object):
|
||||
@ -61,6 +65,7 @@ class Sphinx(object):
|
||||
self._listeners = {}
|
||||
self.builderclasses = BUILTIN_BUILDERS.copy()
|
||||
self.builder = None
|
||||
self.env = None
|
||||
|
||||
self.srcdir = srcdir
|
||||
self.confdir = confdir
|
||||
@ -103,8 +108,62 @@ class Sphinx(object):
|
||||
# now that we know all config values, collect them from conf.py
|
||||
self.config.init_values()
|
||||
|
||||
# set up translation infrastructure
|
||||
self._init_i18n()
|
||||
# set up the build environment
|
||||
self._init_env(freshenv)
|
||||
# set up the builder
|
||||
self._init_builder(buildername)
|
||||
|
||||
def _init_i18n(self):
|
||||
"""
|
||||
Load translated strings from the configured localedirs if
|
||||
enabled in the configuration.
|
||||
"""
|
||||
if self.config.language is not None:
|
||||
self.info(bold('loading translations [%s]... ' %
|
||||
self.config.language), nonl=True)
|
||||
locale_dirs = [None, path.join(package_dir, 'locale')] + \
|
||||
[path.join(self.srcdir, x) for x in self.config.locale_dirs]
|
||||
else:
|
||||
locale_dirs = []
|
||||
self.translator, has_translation = locale.init(locale_dirs,
|
||||
self.config.language)
|
||||
if self.config.language is not None:
|
||||
if has_translation:
|
||||
self.info('done')
|
||||
else:
|
||||
self.info('locale not available')
|
||||
|
||||
def _init_env(self, freshenv):
|
||||
if freshenv:
|
||||
self.env = BuildEnvironment(self.srcdir, self.doctreedir,
|
||||
self.config)
|
||||
self.env.find_files(self.config)
|
||||
for domain in all_domains.keys():
|
||||
self.env.domains[domain] = all_domains[domain](self.env)
|
||||
else:
|
||||
try:
|
||||
self.info(bold('loading pickled environment... '), nonl=True)
|
||||
self.env = BuildEnvironment.frompickle(self.config,
|
||||
path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.env.domains = {}
|
||||
for domain in all_domains.keys():
|
||||
# this can raise if the data version doesn't fit
|
||||
self.env.domains[domain] = all_domains[domain](self.env)
|
||||
self.info('done')
|
||||
except Exception, err:
|
||||
if type(err) is IOError and err.errno == ENOENT:
|
||||
self.info('not yet created')
|
||||
else:
|
||||
self.info('failed: %s' % err)
|
||||
return self._init_env(freshenv=True)
|
||||
|
||||
self.env.set_warnfunc(self.warn)
|
||||
|
||||
def _init_builder(self, buildername):
|
||||
if buildername is None:
|
||||
print >>status, 'No builder selected, using default: html'
|
||||
print >>self._status, 'No builder selected, using default: html'
|
||||
buildername = 'html'
|
||||
if buildername not in self.builderclasses:
|
||||
raise SphinxError('Builder name %s not registered' % buildername)
|
||||
@ -115,9 +174,7 @@ class Sphinx(object):
|
||||
mod, cls = builderclass
|
||||
builderclass = getattr(
|
||||
__import__('sphinx.builders.' + mod, None, None, [cls]), cls)
|
||||
self.builder = builderclass(self, freshenv=freshenv)
|
||||
self.builder.tags = self.tags
|
||||
self.builder.tags.add(self.builder.format)
|
||||
self.builder = builderclass(self)
|
||||
self.emit('builder-inited')
|
||||
|
||||
def build(self, all_files, filenames):
|
||||
@ -277,17 +334,21 @@ class Sphinx(object):
|
||||
if depart:
|
||||
setattr(translator, 'depart_'+node.__name__, depart)
|
||||
|
||||
def add_directive(self, name, obj, content=None, arguments=None, **options):
|
||||
def _directive_helper(self, obj, content=None, arguments=None, **options):
|
||||
if isinstance(obj, clstypes) and issubclass(obj, Directive):
|
||||
if content or arguments or options:
|
||||
raise ExtensionError('when adding directive classes, no '
|
||||
'additional arguments may be given')
|
||||
directives.register_directive(name, directive_dwim(obj))
|
||||
return obj
|
||||
else:
|
||||
obj.content = content
|
||||
obj.arguments = arguments
|
||||
obj.arguments = arguments or (0, 0, False)
|
||||
obj.options = options
|
||||
directives.register_directive(name, obj)
|
||||
return convert_directive_function(obj)
|
||||
|
||||
def add_directive(self, name, obj, content=None, arguments=None, **options):
|
||||
directives.register_directive(
|
||||
name, self._directive_helper(obj, content, arguments, **options))
|
||||
|
||||
def add_role(self, name, role):
|
||||
roles.register_local_role(name, role)
|
||||
@ -298,23 +359,52 @@ class Sphinx(object):
|
||||
role = roles.GenericRole(name, nodeclass)
|
||||
roles.register_local_role(name, role)
|
||||
|
||||
def add_description_unit(self, directivename, rolename, indextemplate='',
|
||||
parse_node=None, ref_nodeclass=None):
|
||||
additional_xref_types[directivename] = (rolename, indextemplate,
|
||||
parse_node)
|
||||
directives.register_directive(directivename,
|
||||
directive_dwim(GenericDesc))
|
||||
roles.register_local_role(rolename, xfileref_role)
|
||||
if ref_nodeclass is not None:
|
||||
innernodetypes[rolename] = ref_nodeclass
|
||||
def add_domain(self, domain):
|
||||
# XXX needs to be documented
|
||||
# XXX what about subclassing and overriding?
|
||||
if domain.name in all_domains:
|
||||
raise ExtensionError('domain %s already registered' % domain.name)
|
||||
all_domains[domain.name] = domain
|
||||
|
||||
def add_directive_to_domain(self, domain, name, obj,
|
||||
content=None, arguments=None, **options):
|
||||
# XXX needs to be documented
|
||||
if domain not in all_domains:
|
||||
raise ExtensionError('domain %s not yet registered' % domain)
|
||||
all_domains[domain].directives[name] = \
|
||||
self._directive_helper(obj, content, arguments, **options)
|
||||
|
||||
def add_role_to_domain(self, domain, name, role):
|
||||
# XXX needs to be documented
|
||||
if domain not in all_domains:
|
||||
raise ExtensionError('domain %s not yet registered' % domain)
|
||||
all_domains[domain].roles[name] = role
|
||||
|
||||
def add_object_type(self, directivename, rolename, indextemplate='',
|
||||
parse_node=None, ref_nodeclass=None, objname=''):
|
||||
StandardDomain.object_types[directivename] = \
|
||||
ObjType(objname or directivename, rolename)
|
||||
# create a subclass of GenericObject as the new directive
|
||||
new_directive = type(directivename, (GenericObject, object),
|
||||
{'indextemplate': indextemplate,
|
||||
'parse_node': staticmethod(parse_node)})
|
||||
StandardDomain.directives[directivename] = new_directive
|
||||
# XXX support more options?
|
||||
StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass)
|
||||
|
||||
# backwards compatible alias
|
||||
add_description_unit = add_object_type
|
||||
|
||||
def add_crossref_type(self, directivename, rolename, indextemplate='',
|
||||
ref_nodeclass=None):
|
||||
additional_xref_types[directivename] = (rolename, indextemplate, None)
|
||||
directives.register_directive(directivename, directive_dwim(Target))
|
||||
roles.register_local_role(rolename, xfileref_role)
|
||||
if ref_nodeclass is not None:
|
||||
innernodetypes[rolename] = ref_nodeclass
|
||||
ref_nodeclass=None, objname=''):
|
||||
StandardDomain.object_types[directivename] = \
|
||||
ObjType(objname or directivename, rolename)
|
||||
# create a subclass of Target as the new directive
|
||||
new_directive = type(directivename, (Target, object),
|
||||
{'indextemplate': indextemplate})
|
||||
StandardDomain.directives[directivename] = new_directive
|
||||
# XXX support more options?
|
||||
StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass)
|
||||
|
||||
def add_transform(self, transform):
|
||||
SphinxStandaloneReader.transforms.append(transform)
|
||||
|
@ -15,9 +15,7 @@ from os import path
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx import package_dir, locale
|
||||
from sphinx.util import SEP, ENOENT, relative_uri
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.util import SEP, relative_uri
|
||||
from sphinx.util.console import bold, purple, darkgreen, term_width_line
|
||||
|
||||
# side effect: registers roles and directives
|
||||
@ -25,9 +23,6 @@ from sphinx import roles
|
||||
from sphinx import directives
|
||||
|
||||
|
||||
ENV_PICKLE_FILENAME = 'environment.pickle'
|
||||
|
||||
|
||||
class Builder(object):
|
||||
"""
|
||||
Builds target formats from the reST sources.
|
||||
@ -38,7 +33,8 @@ class Builder(object):
|
||||
# builder's output format, or '' if no document output is produced
|
||||
format = ''
|
||||
|
||||
def __init__(self, app, env=None, freshenv=False):
|
||||
def __init__(self, app):
|
||||
self.env = app.env
|
||||
self.srcdir = app.srcdir
|
||||
self.confdir = app.confdir
|
||||
self.outdir = app.outdir
|
||||
@ -50,21 +46,15 @@ class Builder(object):
|
||||
self.warn = app.warn
|
||||
self.info = app.info
|
||||
self.config = app.config
|
||||
|
||||
self.load_i18n()
|
||||
self.tags = app.tags
|
||||
self.tags.add(self.format)
|
||||
|
||||
# images that need to be copied over (source -> dest)
|
||||
self.images = {}
|
||||
|
||||
# if None, this is set in load_env()
|
||||
self.env = env
|
||||
self.freshenv = freshenv
|
||||
|
||||
self.init()
|
||||
self.load_env()
|
||||
|
||||
# helper methods
|
||||
|
||||
def init(self):
|
||||
"""
|
||||
Load necessary templates and perform initialization. The default
|
||||
@ -167,62 +157,6 @@ class Builder(object):
|
||||
|
||||
# build methods
|
||||
|
||||
def load_i18n(self):
|
||||
"""
|
||||
Load translated strings from the configured localedirs if
|
||||
enabled in the configuration.
|
||||
"""
|
||||
self.translator = None
|
||||
if self.config.language is not None:
|
||||
self.info(bold('loading translations [%s]... ' %
|
||||
self.config.language), nonl=True)
|
||||
# the None entry is the system's default locale path
|
||||
locale_dirs = [None, path.join(package_dir, 'locale')] + \
|
||||
[path.join(self.srcdir, x) for x in self.config.locale_dirs]
|
||||
for dir_ in locale_dirs:
|
||||
try:
|
||||
trans = gettext.translation('sphinx', localedir=dir_,
|
||||
languages=[self.config.language])
|
||||
if self.translator is None:
|
||||
self.translator = trans
|
||||
else:
|
||||
self.translator._catalog.update(trans._catalog)
|
||||
except Exception:
|
||||
# Language couldn't be found in the specified path
|
||||
pass
|
||||
if self.translator is not None:
|
||||
self.info('done')
|
||||
else:
|
||||
self.info('locale not available')
|
||||
if self.translator is None:
|
||||
self.translator = gettext.NullTranslations()
|
||||
self.translator.install(unicode=True)
|
||||
locale.init() # translate common labels
|
||||
|
||||
def load_env(self):
|
||||
"""Set up the build environment."""
|
||||
if self.env:
|
||||
return
|
||||
if not self.freshenv:
|
||||
try:
|
||||
self.info(bold('loading pickled environment... '), nonl=True)
|
||||
self.env = BuildEnvironment.frompickle(self.config,
|
||||
path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.info('done')
|
||||
except Exception, err:
|
||||
if type(err) is IOError and err.errno == ENOENT:
|
||||
self.info('not found')
|
||||
else:
|
||||
self.info('failed: %s' % err)
|
||||
self.env = BuildEnvironment(self.srcdir, self.doctreedir,
|
||||
self.config)
|
||||
self.env.find_files(self.config)
|
||||
else:
|
||||
self.env = BuildEnvironment(self.srcdir, self.doctreedir,
|
||||
self.config)
|
||||
self.env.find_files(self.config)
|
||||
self.env.set_warnfunc(self.warn)
|
||||
|
||||
def build_all(self):
|
||||
"""Build all source files."""
|
||||
self.build(None, summary='all source files', method='all')
|
||||
@ -302,6 +236,7 @@ class Builder(object):
|
||||
|
||||
if updated_docnames:
|
||||
# save the environment
|
||||
from sphinx.application import ENV_PICKLE_FILENAME
|
||||
self.info(bold('pickling environment... '), nonl=True)
|
||||
self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.info('done')
|
||||
|
@ -12,6 +12,7 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import cgi
|
||||
import sys
|
||||
from os import path
|
||||
@ -30,7 +31,7 @@ except ImportError:
|
||||
try:
|
||||
import elementtree.ElementTree as etree
|
||||
except ImportError:
|
||||
import cElementTree.ElemenTree as etree
|
||||
import cElementTree as etree
|
||||
|
||||
try:
|
||||
import gzip
|
||||
@ -114,11 +115,14 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
|
||||
else:
|
||||
for i, ref in enumerate(refs):
|
||||
etree.SubElement(functions, 'function',
|
||||
name="%s [%d]" % (title, i), link=ref)
|
||||
name="[%d] %s" % (i, title),
|
||||
link=ref)
|
||||
|
||||
if subitems:
|
||||
parent_title = re.sub(r'\s*\(.*\)\s*$', '', title)
|
||||
for subitem in subitems:
|
||||
write_index(subitem[0], subitem[1], [])
|
||||
write_index("%s %s" % (parent_title, subitem[0]),
|
||||
subitem[1], [])
|
||||
|
||||
for (key, group) in index:
|
||||
for title, (refs, subitems) in group:
|
||||
|
@ -10,6 +10,7 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
import zlib
|
||||
import codecs
|
||||
import posixpath
|
||||
import cPickle as pickle
|
||||
@ -33,7 +34,8 @@ from sphinx.util import SEP, os_path, relative_uri, ensuredir, \
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.search import js_index
|
||||
from sphinx.theming import Theme
|
||||
from sphinx.builders import Builder, ENV_PICKLE_FILENAME
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.application import ENV_PICKLE_FILENAME
|
||||
from sphinx.highlighting import PygmentsBridge
|
||||
from sphinx.util.console import bold
|
||||
from sphinx.writers.html import HTMLWriter, HTMLTranslator, \
|
||||
@ -243,7 +245,9 @@ class StandaloneHTMLBuilder(Builder):
|
||||
rellinks = []
|
||||
if self.config.html_use_index:
|
||||
rellinks.append(('genindex', _('General Index'), 'I', _('index')))
|
||||
if self.config.html_use_modindex and self.env.modules:
|
||||
# XXX generalization of modindex?
|
||||
if self.config.html_use_modindex and \
|
||||
self.env.domaindata['py']['modules']:
|
||||
rellinks.append(('modindex', _('Global Module Index'),
|
||||
'M', _('modules')))
|
||||
|
||||
@ -407,12 +411,13 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
# the global module index
|
||||
|
||||
if self.config.html_use_modindex and self.env.modules:
|
||||
moduleindex = self.env.domaindata['py']['modules']
|
||||
if self.config.html_use_modindex and moduleindex:
|
||||
# the sorted list of all modules, for the global module index
|
||||
modules = sorted(((mn, (self.get_relative_uri('modindex', fn) +
|
||||
'#module-' + mn, sy, pl, dep))
|
||||
for (mn, (fn, sy, pl, dep)) in
|
||||
self.env.modules.iteritems()),
|
||||
moduleindex.iteritems()),
|
||||
key=lambda x: x[0].lower())
|
||||
# collect all platforms
|
||||
platforms = set()
|
||||
@ -642,7 +647,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
if self.indexer is not None and title:
|
||||
self.indexer.feed(pagename, title, doctree)
|
||||
|
||||
def _get_local_toctree(self, docname, collapse=True):
|
||||
def _get_local_toctree(self, docname, collapse=True, maxdepth=0):
|
||||
return self.render_partial(self.env.get_toctree_for(
|
||||
docname, self, collapse))['fragment']
|
||||
|
||||
@ -711,16 +716,22 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.info('done')
|
||||
|
||||
self.info(bold('dumping object inventory... '), nonl=True)
|
||||
f = open(path.join(self.outdir, INVENTORY_FILENAME), 'w')
|
||||
f = open(path.join(self.outdir, INVENTORY_FILENAME), 'wb')
|
||||
try:
|
||||
f.write('# Sphinx inventory version 1\n')
|
||||
f.write('# Sphinx inventory version 2\n')
|
||||
f.write('# Project: %s\n' % self.config.project.encode('utf-8'))
|
||||
f.write('# Version: %s\n' % self.config.version)
|
||||
for modname, info in self.env.modules.iteritems():
|
||||
f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0])))
|
||||
for refname, (docname, desctype) in self.env.descrefs.iteritems():
|
||||
f.write('%s %s %s\n' % (refname, desctype,
|
||||
self.get_target_uri(docname)))
|
||||
f.write('# The remainder of this file is compressed using zlib.\n')
|
||||
compressor = zlib.compressobj(9)
|
||||
for domainname, domain in self.env.domains.iteritems():
|
||||
for name, type, docname, anchor, prio in domain.get_objects():
|
||||
if anchor.endswith(name):
|
||||
# this can shorten the inventory by as much as 25%
|
||||
anchor = anchor[:-len(name)] + '$'
|
||||
f.write(compressor.compress(
|
||||
'%s %s:%s %s %s\n' % (name, domainname, type, prio,
|
||||
self.get_target_uri(docname) + '#' + anchor)))
|
||||
f.write(compressor.flush())
|
||||
finally:
|
||||
f.close()
|
||||
self.info('done')
|
||||
|
@ -55,6 +55,7 @@ class Config(object):
|
||||
modindex_common_prefix = ([], 'html'),
|
||||
rst_epilog = (None, 'env'),
|
||||
trim_doctest_flags = (True, 'env'),
|
||||
default_domain = ('py', 'env'),
|
||||
|
||||
# HTML options
|
||||
html_theme = ('default', 'html'),
|
||||
@ -127,6 +128,10 @@ class Config(object):
|
||||
latex_docclass = ({}, None),
|
||||
# now deprecated - use latex_elements
|
||||
latex_preamble = ('', None),
|
||||
|
||||
# text options
|
||||
text_sectionchars = ('*=-~"+`', 'text'),
|
||||
text_windows_newlines = (False, 'text'),
|
||||
)
|
||||
|
||||
def __init__(self, dirname, filename, overrides, tags):
|
||||
|
@ -9,11 +9,16 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from docutils.parsers.rst import directives
|
||||
import re
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
from docutils.parsers.rst.directives import images
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.locale import l_
|
||||
|
||||
# import and register directives
|
||||
from sphinx.directives.desc import *
|
||||
from sphinx.directives.code import *
|
||||
from sphinx.directives.other import *
|
||||
|
||||
@ -25,3 +30,263 @@ try:
|
||||
except AttributeError:
|
||||
images.figure.options['figwidth'] = \
|
||||
directives.length_or_percentage_or_unitless
|
||||
|
||||
|
||||
def _is_only_paragraph(node):
|
||||
"""True if the node only contains one paragraph (and system messages)."""
|
||||
if len(node) == 0:
|
||||
return False
|
||||
elif len(node) > 1:
|
||||
for subnode in node[1:]:
|
||||
if not isinstance(subnode, nodes.system_message):
|
||||
return False
|
||||
if isinstance(node[0], nodes.paragraph):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# RE to strip backslash escapes
|
||||
strip_backslash_re = re.compile(r'\\(?=[^\\])')
|
||||
|
||||
|
||||
class ObjectDescription(Directive):
|
||||
"""
|
||||
Directive to describe a class, function or similar object. Not used
|
||||
directly, but subclassed to add custom behavior.
|
||||
"""
|
||||
|
||||
has_content = True
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
'noindex': directives.flag,
|
||||
'module': directives.unchanged,
|
||||
}
|
||||
|
||||
# XXX make this more domain specific
|
||||
|
||||
doc_fields_with_arg = {
|
||||
'param': '%param',
|
||||
'parameter': '%param',
|
||||
'arg': '%param',
|
||||
'argument': '%param',
|
||||
'keyword': '%param',
|
||||
'kwarg': '%param',
|
||||
'kwparam': '%param',
|
||||
'type': '%type',
|
||||
'raises': l_('Raises'),
|
||||
'raise': l_('Raises'),
|
||||
'exception': l_('Raises'),
|
||||
'except': l_('Raises'),
|
||||
'var': l_('Variable'),
|
||||
'ivar': l_('Variable'),
|
||||
'cvar': l_('Variable'),
|
||||
'returns': l_('Returns'),
|
||||
'return': l_('Returns'),
|
||||
}
|
||||
|
||||
doc_fields_with_linked_arg = ('raises', 'raise', 'exception', 'except')
|
||||
|
||||
doc_fields_without_arg = {
|
||||
'returns': l_('Returns'),
|
||||
'return': l_('Returns'),
|
||||
'rtype': l_('Return type'),
|
||||
}
|
||||
|
||||
def handle_doc_fields(self, node):
|
||||
"""
|
||||
Convert field lists with known keys inside the description content into
|
||||
better-looking equivalents.
|
||||
"""
|
||||
# don't traverse, only handle field lists that are immediate children
|
||||
for child in node.children:
|
||||
if not isinstance(child, nodes.field_list):
|
||||
continue
|
||||
params = []
|
||||
pfield = None
|
||||
param_nodes = {}
|
||||
param_types = {}
|
||||
new_list = nodes.field_list()
|
||||
for field in child:
|
||||
fname, fbody = field
|
||||
try:
|
||||
typ, obj = fname.astext().split(None, 1)
|
||||
typdesc = self.doc_fields_with_arg[typ]
|
||||
if _is_only_paragraph(fbody):
|
||||
children = fbody.children[0].children
|
||||
else:
|
||||
children = fbody.children
|
||||
if typdesc == '%param':
|
||||
if not params:
|
||||
# add the field that later gets all the parameters
|
||||
pfield = nodes.field()
|
||||
new_list += pfield
|
||||
dlitem = nodes.list_item()
|
||||
dlpar = nodes.paragraph()
|
||||
dlpar += nodes.emphasis(obj, obj)
|
||||
dlpar += nodes.Text(' -- ', ' -- ')
|
||||
dlpar += children
|
||||
param_nodes[obj] = dlpar
|
||||
dlitem += dlpar
|
||||
params.append(dlitem)
|
||||
elif typdesc == '%type':
|
||||
typenodes = fbody.children
|
||||
if _is_only_paragraph(fbody):
|
||||
typenodes = ([nodes.Text(' (')] +
|
||||
typenodes[0].children +
|
||||
[nodes.Text(')')])
|
||||
param_types[obj] = typenodes
|
||||
else:
|
||||
fieldname = typdesc + ' '
|
||||
nfield = nodes.field()
|
||||
nfieldname = nodes.field_name(fieldname, fieldname)
|
||||
nfield += nfieldname
|
||||
node = nfieldname
|
||||
if typ in self.doc_fields_with_linked_arg:
|
||||
# XXX currmodule/currclass
|
||||
node = addnodes.pending_xref(
|
||||
obj, reftype='obj', refexplicit=False,
|
||||
reftarget=obj)
|
||||
#, modname=self.env.currmodule
|
||||
#, classname=self.env.currclass
|
||||
nfieldname += node
|
||||
node += nodes.Text(obj, obj)
|
||||
nfield += nodes.field_body()
|
||||
nfield[1] += fbody.children
|
||||
new_list += nfield
|
||||
except (KeyError, ValueError):
|
||||
fnametext = fname.astext()
|
||||
try:
|
||||
typ = self.doc_fields_without_arg[fnametext]
|
||||
except KeyError:
|
||||
# at least capitalize the field name
|
||||
typ = fnametext.capitalize()
|
||||
fname[0] = nodes.Text(typ)
|
||||
new_list += field
|
||||
if params:
|
||||
if len(params) == 1:
|
||||
pfield += nodes.field_name('', _('Parameter'))
|
||||
pfield += nodes.field_body()
|
||||
pfield[1] += params[0][0]
|
||||
else:
|
||||
pfield += nodes.field_name('', _('Parameters'))
|
||||
pfield += nodes.field_body()
|
||||
pfield[1] += nodes.bullet_list()
|
||||
pfield[1][0].extend(params)
|
||||
|
||||
for param, type in param_types.iteritems():
|
||||
if param in param_nodes:
|
||||
param_nodes[param][1:1] = type
|
||||
child.replace_self(new_list)
|
||||
|
||||
def get_signatures(self):
|
||||
"""
|
||||
Retrieve the signatures to document from the directive arguments.
|
||||
"""
|
||||
# remove backslashes to support (dummy) escapes; helps Vim highlighting
|
||||
return [strip_backslash_re.sub('', sig.strip())
|
||||
for sig in self.arguments[0].split('\n')]
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""
|
||||
Parse the signature *sig* into individual nodes and append them to
|
||||
*signode*. If ValueError is raised, parsing is aborted and the whole
|
||||
*sig* is put into a single desc_name node.
|
||||
"""
|
||||
raise ValueError
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
"""
|
||||
Add cross-reference IDs and entries to self.indexnode, if applicable.
|
||||
"""
|
||||
return # do nothing by default
|
||||
|
||||
def before_content(self):
|
||||
"""
|
||||
Called before parsing content. Used to set information about the current
|
||||
directive context on the build environment.
|
||||
"""
|
||||
pass
|
||||
|
||||
def after_content(self):
|
||||
"""
|
||||
Called after parsing content. Used to reset information about the
|
||||
current directive context on the build environment.
|
||||
"""
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
if ':' in self.name:
|
||||
self.domain, self.objtype = self.name.split(':', 1)
|
||||
else:
|
||||
self.domain, self.objtype = '', self.name
|
||||
self.env = self.state.document.settings.env
|
||||
self.indexnode = addnodes.index(entries=[])
|
||||
|
||||
node = addnodes.desc()
|
||||
node.document = self.state.document
|
||||
node['domain'] = self.domain
|
||||
# 'desctype' is a backwards compatible attribute
|
||||
node['objtype'] = node['desctype'] = self.objtype
|
||||
node['noindex'] = noindex = ('noindex' in self.options)
|
||||
|
||||
self.names = []
|
||||
signatures = self.get_signatures()
|
||||
for i, sig in enumerate(signatures):
|
||||
# add a signature node for each signature in the current unit
|
||||
# and add a reference target for it
|
||||
signode = addnodes.desc_signature(sig, '')
|
||||
signode['first'] = False
|
||||
node.append(signode)
|
||||
try:
|
||||
# name can also be a tuple, e.g. (classname, objname)
|
||||
name = self.parse_signature(sig, signode)
|
||||
except ValueError, err:
|
||||
# signature parsing failed
|
||||
signode.clear()
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
continue # we don't want an index entry here
|
||||
if not noindex and name not in self.names:
|
||||
# only add target and index entry if this is the first
|
||||
# description of the object with this name in this desc block
|
||||
self.names.append(name)
|
||||
self.add_target_and_index(name, sig, signode)
|
||||
|
||||
contentnode = addnodes.desc_content()
|
||||
node.append(contentnode)
|
||||
if self.names:
|
||||
# needed for association of version{added,changed} directives
|
||||
self.env.doc_read_data['object'] = self.names[0]
|
||||
self.before_content()
|
||||
self.state.nested_parse(self.content, self.content_offset, contentnode)
|
||||
self.handle_doc_fields(contentnode)
|
||||
self.env.doc_read_data['object'] = None
|
||||
self.after_content()
|
||||
return [self.indexnode, node]
|
||||
|
||||
# backwards compatible old name
|
||||
DescDirective = ObjectDescription
|
||||
|
||||
|
||||
class DefaultDomain(Directive):
|
||||
"""
|
||||
Directive to (re-)set the default domain for this source file.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
domain_name = arguments[0]
|
||||
env.doc_read_data['default_domain'] = env.domains.get(domain_name)
|
||||
|
||||
|
||||
directives.register_directive('default-domain', DefaultDomain)
|
||||
directives.register_directive('describe', ObjectDescription)
|
||||
# new, more consistent, name
|
||||
directives.register_directive('object', ObjectDescription)
|
||||
|
@ -13,11 +13,10 @@ import codecs
|
||||
from os import path
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import parselinenos
|
||||
from sphinx.util.compat import Directive, directive_dwim
|
||||
|
||||
|
||||
class Highlight(Directive):
|
||||
@ -184,8 +183,8 @@ class LiteralInclude(Directive):
|
||||
return [retnode]
|
||||
|
||||
|
||||
directives.register_directive('highlight', directive_dwim(Highlight))
|
||||
directives.register_directive('highlightlang', directive_dwim(Highlight)) # old
|
||||
directives.register_directive('code-block', directive_dwim(CodeBlock))
|
||||
directives.register_directive('sourcecode', directive_dwim(CodeBlock))
|
||||
directives.register_directive('literalinclude', directive_dwim(LiteralInclude))
|
||||
directives.register_directive('highlight', Highlight)
|
||||
directives.register_directive('highlightlang', Highlight) # old
|
||||
directives.register_directive('code-block', CodeBlock)
|
||||
directives.register_directive('sourcecode', CodeBlock)
|
||||
directives.register_directive('literalinclude', LiteralInclude)
|
||||
|
@ -1,771 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.directives.desc
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
import string
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import ws_re
|
||||
from sphinx.util.compat import Directive, directive_dwim
|
||||
|
||||
|
||||
def _is_only_paragraph(node):
|
||||
"""True if the node only contains one paragraph (and system messages)."""
|
||||
if len(node) == 0:
|
||||
return False
|
||||
elif len(node) > 1:
|
||||
for subnode in node[1:]:
|
||||
if not isinstance(subnode, nodes.system_message):
|
||||
return False
|
||||
if isinstance(node[0], nodes.paragraph):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# REs for Python signatures
|
||||
py_sig_re = re.compile(
|
||||
r'''^ ([\w.]*\.)? # class name(s)
|
||||
(\w+) \s* # thing name
|
||||
(?: \((.*)\) # optional: arguments
|
||||
(?:\s* -> \s* (.*))? # return annotation
|
||||
)? $ # and nothing more
|
||||
''', re.VERBOSE)
|
||||
|
||||
py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
|
||||
|
||||
# REs for C signatures
|
||||
c_sig_re = re.compile(
|
||||
r'''^([^(]*?) # return type
|
||||
([\w:]+) \s* # thing name (colon allowed for C++ class names)
|
||||
(?: \((.*)\) )? # optionally arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_sig_re = re.compile(
|
||||
r'''^([^(]+?) # return type
|
||||
(\( [^()]+ \)) \s* # name in parentheses
|
||||
\( (.*) \) # arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_name_re = re.compile(r'^\(\s*\*\s*(.*?)\s*\)$')
|
||||
|
||||
# RE for option descriptions
|
||||
option_desc_re = re.compile(
|
||||
r'((?:/|-|--)[-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
|
||||
|
||||
# RE to split at word boundaries
|
||||
wsplit_re = re.compile(r'(\W+)')
|
||||
|
||||
# RE to strip backslash escapes
|
||||
strip_backslash_re = re.compile(r'\\(?=[^\\])')
|
||||
|
||||
|
||||
class DescDirective(Directive):
|
||||
"""
|
||||
Directive to describe a class, function or similar object. Not used
|
||||
directly, but subclassed to add custom behavior.
|
||||
"""
|
||||
|
||||
has_content = True
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
'noindex': directives.flag,
|
||||
'module': directives.unchanged,
|
||||
}
|
||||
|
||||
_ = lambda x: x # make gettext extraction in constants possible
|
||||
|
||||
doc_fields_with_arg = {
|
||||
'param': '%param',
|
||||
'parameter': '%param',
|
||||
'arg': '%param',
|
||||
'argument': '%param',
|
||||
'keyword': '%param',
|
||||
'kwarg': '%param',
|
||||
'kwparam': '%param',
|
||||
'type': '%type',
|
||||
'raises': _('Raises'),
|
||||
'raise': 'Raises',
|
||||
'exception': 'Raises',
|
||||
'except': 'Raises',
|
||||
'var': _('Variable'),
|
||||
'ivar': 'Variable',
|
||||
'cvar': 'Variable',
|
||||
'returns': _('Returns'),
|
||||
'return': 'Returns',
|
||||
}
|
||||
|
||||
doc_fields_with_linked_arg = ('raises', 'raise', 'exception', 'except')
|
||||
|
||||
doc_fields_without_arg = {
|
||||
'returns': 'Returns',
|
||||
'return': 'Returns',
|
||||
'rtype': _('Return type'),
|
||||
}
|
||||
|
||||
def handle_doc_fields(self, node):
|
||||
"""
|
||||
Convert field lists with known keys inside the description content into
|
||||
better-looking equivalents.
|
||||
"""
|
||||
# don't traverse, only handle field lists that are immediate children
|
||||
for child in node.children:
|
||||
if not isinstance(child, nodes.field_list):
|
||||
continue
|
||||
params = []
|
||||
pfield = None
|
||||
param_nodes = {}
|
||||
param_types = {}
|
||||
new_list = nodes.field_list()
|
||||
for field in child:
|
||||
fname, fbody = field
|
||||
try:
|
||||
typ, obj = fname.astext().split(None, 1)
|
||||
typdesc = _(self.doc_fields_with_arg[typ])
|
||||
if _is_only_paragraph(fbody):
|
||||
children = fbody.children[0].children
|
||||
else:
|
||||
children = fbody.children
|
||||
if typdesc == '%param':
|
||||
if not params:
|
||||
# add the field that later gets all the parameters
|
||||
pfield = nodes.field()
|
||||
new_list += pfield
|
||||
dlitem = nodes.list_item()
|
||||
dlpar = nodes.paragraph()
|
||||
dlpar += nodes.emphasis(obj, obj)
|
||||
dlpar += nodes.Text(' -- ', ' -- ')
|
||||
dlpar += children
|
||||
param_nodes[obj] = dlpar
|
||||
dlitem += dlpar
|
||||
params.append(dlitem)
|
||||
elif typdesc == '%type':
|
||||
typenodes = fbody.children
|
||||
if _is_only_paragraph(fbody):
|
||||
typenodes = ([nodes.Text(' (')] +
|
||||
typenodes[0].children +
|
||||
[nodes.Text(')')])
|
||||
param_types[obj] = typenodes
|
||||
else:
|
||||
fieldname = typdesc + ' '
|
||||
nfield = nodes.field()
|
||||
nfieldname = nodes.field_name(fieldname, fieldname)
|
||||
nfield += nfieldname
|
||||
node = nfieldname
|
||||
if typ in self.doc_fields_with_linked_arg:
|
||||
node = addnodes.pending_xref(
|
||||
obj, reftype='obj', refcaption=False,
|
||||
reftarget=obj, modname=self.env.currmodule,
|
||||
classname=self.env.currclass)
|
||||
nfieldname += node
|
||||
node += nodes.Text(obj, obj)
|
||||
nfield += nodes.field_body()
|
||||
nfield[1] += fbody.children
|
||||
new_list += nfield
|
||||
except (KeyError, ValueError):
|
||||
fnametext = fname.astext()
|
||||
try:
|
||||
typ = _(self.doc_fields_without_arg[fnametext])
|
||||
except KeyError:
|
||||
# at least capitalize the field name
|
||||
typ = fnametext.capitalize()
|
||||
fname[0] = nodes.Text(typ)
|
||||
new_list += field
|
||||
if params:
|
||||
if len(params) == 1:
|
||||
pfield += nodes.field_name('', _('Parameter'))
|
||||
pfield += nodes.field_body()
|
||||
pfield[1] += params[0][0]
|
||||
else:
|
||||
pfield += nodes.field_name('', _('Parameters'))
|
||||
pfield += nodes.field_body()
|
||||
pfield[1] += nodes.bullet_list()
|
||||
pfield[1][0].extend(params)
|
||||
|
||||
for param, type in param_types.iteritems():
|
||||
if param in param_nodes:
|
||||
param_nodes[param][1:1] = type
|
||||
child.replace_self(new_list)
|
||||
|
||||
def get_signatures(self):
|
||||
"""
|
||||
Retrieve the signatures to document from the directive arguments.
|
||||
"""
|
||||
# remove backslashes to support (dummy) escapes; helps Vim highlighting
|
||||
return [strip_backslash_re.sub('', sig.strip())
|
||||
for sig in self.arguments[0].split('\n')]
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""
|
||||
Parse the signature *sig* into individual nodes and append them to
|
||||
*signode*. If ValueError is raised, parsing is aborted and the whole
|
||||
*sig* is put into a single desc_name node.
|
||||
"""
|
||||
raise ValueError
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
"""
|
||||
Add cross-reference IDs and entries to self.indexnode, if applicable.
|
||||
"""
|
||||
return # do nothing by default
|
||||
|
||||
def before_content(self):
|
||||
"""
|
||||
Called before parsing content. Used to set information about the current
|
||||
directive context on the build environment.
|
||||
"""
|
||||
pass
|
||||
|
||||
def after_content(self):
|
||||
"""
|
||||
Called after parsing content. Used to reset information about the
|
||||
current directive context on the build environment.
|
||||
"""
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
self.desctype = self.name
|
||||
self.env = self.state.document.settings.env
|
||||
self.indexnode = addnodes.index(entries=[])
|
||||
|
||||
node = addnodes.desc()
|
||||
node.document = self.state.document
|
||||
node['desctype'] = self.desctype
|
||||
node['noindex'] = noindex = ('noindex' in self.options)
|
||||
|
||||
self.names = []
|
||||
signatures = self.get_signatures()
|
||||
for i, sig in enumerate(signatures):
|
||||
# add a signature node for each signature in the current unit
|
||||
# and add a reference target for it
|
||||
signode = addnodes.desc_signature(sig, '')
|
||||
signode['first'] = False
|
||||
node.append(signode)
|
||||
try:
|
||||
# name can also be a tuple, e.g. (classname, objname)
|
||||
name = self.parse_signature(sig, signode)
|
||||
except ValueError, err:
|
||||
# signature parsing failed
|
||||
signode.clear()
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
continue # we don't want an index entry here
|
||||
if not noindex and name not in self.names:
|
||||
# only add target and index entry if this is the first
|
||||
# description of the object with this name in this desc block
|
||||
self.names.append(name)
|
||||
self.add_target_and_index(name, sig, signode)
|
||||
|
||||
contentnode = addnodes.desc_content()
|
||||
node.append(contentnode)
|
||||
if self.names:
|
||||
# needed for association of version{added,changed} directives
|
||||
self.env.currdesc = self.names[0]
|
||||
self.before_content()
|
||||
self.state.nested_parse(self.content, self.content_offset, contentnode)
|
||||
self.handle_doc_fields(contentnode)
|
||||
self.env.currdesc = None
|
||||
self.after_content()
|
||||
return [self.indexnode, node]
|
||||
|
||||
|
||||
class PythonDesc(DescDirective):
|
||||
"""
|
||||
Description of a general Python object.
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
"""
|
||||
May return a prefix to put before the object name in the signature.
|
||||
"""
|
||||
return ''
|
||||
|
||||
def needs_arglist(self):
|
||||
"""
|
||||
May return true if an empty argument list is to be generated even if
|
||||
the document contains none.
|
||||
"""
|
||||
return False
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""
|
||||
Transform a Python signature into RST nodes.
|
||||
Returns (fully qualified name of the thing, classname if any).
|
||||
|
||||
If inside a class, the current class name is handled intelligently:
|
||||
* it is stripped from the displayed name if present
|
||||
* it is added to the full name (return value) if not present
|
||||
"""
|
||||
m = py_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError
|
||||
classname, name, arglist, retann = m.groups()
|
||||
|
||||
if self.env.currclass:
|
||||
add_module = False
|
||||
if classname and classname.startswith(self.env.currclass):
|
||||
fullname = classname + name
|
||||
# class name is given again in the signature
|
||||
classname = classname[len(self.env.currclass):].lstrip('.')
|
||||
elif classname:
|
||||
# class name is given in the signature, but different
|
||||
# (shouldn't happen)
|
||||
fullname = self.env.currclass + '.' + classname + name
|
||||
else:
|
||||
# class name is not given in the signature
|
||||
fullname = self.env.currclass + '.' + name
|
||||
else:
|
||||
add_module = True
|
||||
fullname = classname and classname + name or name
|
||||
|
||||
prefix = self.get_signature_prefix(sig)
|
||||
if prefix:
|
||||
signode += addnodes.desc_annotation(prefix, prefix)
|
||||
|
||||
if classname:
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
# exceptions are a special case, since they are documented in the
|
||||
# 'exceptions' module.
|
||||
elif add_module and self.env.config.add_module_names:
|
||||
modname = self.options.get('module', self.env.currmodule)
|
||||
if modname and modname != 'exceptions':
|
||||
nodetext = modname + '.'
|
||||
signode += addnodes.desc_addname(nodetext, nodetext)
|
||||
|
||||
signode += addnodes.desc_name(name, name)
|
||||
if not arglist:
|
||||
if self.needs_arglist():
|
||||
# for callables, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
signode += addnodes.desc_parameterlist()
|
||||
|
||||
stack = [signode[-1]]
|
||||
for token in py_paramlist_re.split(arglist):
|
||||
if token == '[':
|
||||
opt = addnodes.desc_optional()
|
||||
stack[-1] += opt
|
||||
stack.append(opt)
|
||||
elif token == ']':
|
||||
try:
|
||||
stack.pop()
|
||||
except IndexError:
|
||||
raise ValueError
|
||||
elif not token or token == ',' or token.isspace():
|
||||
pass
|
||||
else:
|
||||
token = token.strip()
|
||||
stack[-1] += addnodes.desc_parameter(token, token)
|
||||
if len(stack) != 1:
|
||||
raise ValueError
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
|
||||
def get_index_text(self, modname, name):
|
||||
"""
|
||||
Return the text for the index entry of the object.
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def add_target_and_index(self, name_cls, sig, signode):
|
||||
modname = self.options.get('module', self.env.currmodule)
|
||||
fullname = (modname and modname + '.' or '') + name_cls[0]
|
||||
# note target
|
||||
if fullname not in self.state.document.ids:
|
||||
signode['names'].append(fullname)
|
||||
signode['ids'].append(fullname)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(fullname, self.desctype, self.lineno)
|
||||
|
||||
indextext = self.get_index_text(modname, name_cls)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext,
|
||||
fullname, fullname))
|
||||
|
||||
def before_content(self):
|
||||
# needed for automatic qualification of members (reset in subclasses)
|
||||
self.clsname_set = False
|
||||
|
||||
def after_content(self):
|
||||
if self.clsname_set:
|
||||
self.env.currclass = None
|
||||
|
||||
|
||||
class ModulelevelDesc(PythonDesc):
|
||||
"""
|
||||
Description of an object on module level (functions, data).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.desctype == 'function'
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.desctype == 'function':
|
||||
if not modname:
|
||||
return _('%s() (built-in function)') % name_cls[0]
|
||||
return _('%s() (in module %s)') % (name_cls[0], modname)
|
||||
elif self.desctype == 'data':
|
||||
if not modname:
|
||||
return _('%s (built-in variable)') % name_cls[0]
|
||||
return _('%s (in module %s)') % (name_cls[0], modname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class ClasslikeDesc(PythonDesc):
|
||||
"""
|
||||
Description of a class-like object (classes, interfaces, exceptions).
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
return self.desctype + ' '
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.desctype == 'class':
|
||||
if not modname:
|
||||
return _('%s (built-in class)') % name_cls[0]
|
||||
return _('%s (class in %s)') % (name_cls[0], modname)
|
||||
elif self.desctype == 'exception':
|
||||
return name_cls[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PythonDesc.before_content(self)
|
||||
if self.names:
|
||||
self.env.currclass = self.names[0][0]
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class ClassmemberDesc(PythonDesc):
|
||||
"""
|
||||
Description of a class member (methods, attributes).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.desctype.endswith('method')
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
if self.desctype == 'staticmethod':
|
||||
return 'static '
|
||||
elif self.desctype == 'classmethod':
|
||||
return 'classmethod '
|
||||
return ''
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
name, cls = name_cls
|
||||
add_modules = self.env.config.add_module_names
|
||||
if self.desctype == 'method':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s method)') % (methname, modname, clsname)
|
||||
else:
|
||||
return _('%s() (%s method)') % (methname, clsname)
|
||||
elif self.desctype == 'staticmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s static method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s static method)') % (methname, clsname)
|
||||
elif self.desctype == 'classmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return '%s() (in module %s)' % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname:
|
||||
return '%s() (%s.%s class method)' % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return '%s() (%s class method)' % (methname, clsname)
|
||||
elif self.desctype == 'attribute':
|
||||
try:
|
||||
clsname, attrname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s (in module %s)') % (name, modname)
|
||||
else:
|
||||
return name
|
||||
if modname and add_modules:
|
||||
return _('%s (%s.%s attribute)') % (attrname, modname, clsname)
|
||||
else:
|
||||
return _('%s (%s attribute)') % (attrname, clsname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PythonDesc.before_content(self)
|
||||
if self.names and self.names[-1][1] and not self.env.currclass:
|
||||
self.env.currclass = self.names[-1][1].strip('.')
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class CDesc(DescDirective):
|
||||
"""
|
||||
Description of a C language object.
|
||||
"""
|
||||
|
||||
# These C types aren't described anywhere, so don't try to create
|
||||
# a cross-reference to them
|
||||
stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct'))
|
||||
|
||||
def _parse_type(self, node, ctype):
|
||||
# add cross-ref nodes for all words
|
||||
for part in filter(None, wsplit_re.split(ctype)):
|
||||
tnode = nodes.Text(part, part)
|
||||
if part[0] in string.ascii_letters+'_' and \
|
||||
part not in self.stopwords:
|
||||
pnode = addnodes.pending_xref(
|
||||
'', reftype='ctype', reftarget=part,
|
||||
modname=None, classname=None)
|
||||
pnode += tnode
|
||||
node += pnode
|
||||
else:
|
||||
node += tnode
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""Transform a C (or C++) signature into RST nodes."""
|
||||
# first try the function pointer signature regex, it's more specific
|
||||
m = c_funcptr_sig_re.match(sig)
|
||||
if m is None:
|
||||
m = c_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError('no match')
|
||||
rettype, name, arglist, const = m.groups()
|
||||
|
||||
signode += addnodes.desc_type('', '')
|
||||
self._parse_type(signode[-1], rettype)
|
||||
try:
|
||||
classname, funcname = name.split('::', 1)
|
||||
classname += '::'
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
signode += addnodes.desc_name(funcname, funcname)
|
||||
# name (the full name) is still both parts
|
||||
except ValueError:
|
||||
signode += addnodes.desc_name(name, name)
|
||||
# clean up parentheses from canonical name
|
||||
m = c_funcptr_name_re.match(name)
|
||||
if m:
|
||||
name = m.group(1)
|
||||
if not arglist:
|
||||
if self.desctype == 'cfunction':
|
||||
# for functions, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup
|
||||
# this messes up function pointer types, but not too badly ;)
|
||||
args = arglist.split(',')
|
||||
for arg in args:
|
||||
arg = arg.strip()
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
try:
|
||||
ctype, argname = arg.rsplit(' ', 1)
|
||||
except ValueError:
|
||||
# no argument name given, only the type
|
||||
self._parse_type(param, arg)
|
||||
else:
|
||||
self._parse_type(param, ctype)
|
||||
param += nodes.emphasis(' '+argname, ' '+argname)
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
def get_index_text(self, name):
|
||||
if self.desctype == 'cfunction':
|
||||
return _('%s (C function)') % name
|
||||
elif self.desctype == 'cmember':
|
||||
return _('%s (C member)') % name
|
||||
elif self.desctype == 'cmacro':
|
||||
return _('%s (C macro)') % name
|
||||
elif self.desctype == 'ctype':
|
||||
return _('%s (C type)') % name
|
||||
elif self.desctype == 'cvar':
|
||||
return _('%s (C variable)') % name
|
||||
else:
|
||||
return ''
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
# note target
|
||||
if name not in self.state.document.ids:
|
||||
signode['names'].append(name)
|
||||
signode['ids'].append(name)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.env.note_descref(name, self.desctype, self.lineno)
|
||||
|
||||
indextext = self.get_index_text(name)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext, name, name))
|
||||
|
||||
|
||||
class CmdoptionDesc(DescDirective):
|
||||
"""
|
||||
Description of a command-line option (.. cmdoption).
|
||||
"""
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""Transform an option description into RST nodes."""
|
||||
count = 0
|
||||
firstname = ''
|
||||
for m in option_desc_re.finditer(sig):
|
||||
optname, args = m.groups()
|
||||
if count:
|
||||
signode += addnodes.desc_addname(', ', ', ')
|
||||
signode += addnodes.desc_name(optname, optname)
|
||||
signode += addnodes.desc_addname(args, args)
|
||||
if not count:
|
||||
firstname = optname
|
||||
count += 1
|
||||
if not firstname:
|
||||
raise ValueError
|
||||
return firstname
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
targetname = name.replace('/', '-')
|
||||
if self.env.currprogram:
|
||||
targetname = '-' + self.env.currprogram + targetname
|
||||
targetname = 'cmdoption' + targetname
|
||||
signode['ids'].append(targetname)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.indexnode['entries'].append(
|
||||
('pair', _('%scommand line option; %s') %
|
||||
((self.env.currprogram and
|
||||
self.env.currprogram + ' ' or ''), sig),
|
||||
targetname, targetname))
|
||||
self.env.note_progoption(name, targetname)
|
||||
|
||||
|
||||
class GenericDesc(DescDirective):
|
||||
"""
|
||||
A generic x-ref directive registered with Sphinx.add_description_unit().
|
||||
"""
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
parse_node = additional_xref_types[self.desctype][2]
|
||||
if parse_node:
|
||||
name = parse_node(self.env, sig, signode)
|
||||
else:
|
||||
signode.clear()
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
# normalize whitespace like xfileref_role does
|
||||
name = ws_re.sub('', sig)
|
||||
return name
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
rolename, indextemplate = additional_xref_types[self.desctype][:2]
|
||||
targetname = '%s-%s' % (rolename, name)
|
||||
signode['ids'].append(targetname)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
if indextemplate:
|
||||
indexentry = _(indextemplate) % (name,)
|
||||
indextype = 'single'
|
||||
colon = indexentry.find(':')
|
||||
if colon != -1:
|
||||
indextype = indexentry[:colon].strip()
|
||||
indexentry = indexentry[colon+1:].strip()
|
||||
self.indexnode['entries'].append((indextype, indexentry,
|
||||
targetname, targetname))
|
||||
self.env.note_reftarget(rolename, name, targetname)
|
||||
|
||||
|
||||
class Target(Directive):
|
||||
"""
|
||||
Generic target for user-defined cross-reference types.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
rolename, indextemplate, foo = additional_xref_types[self.name]
|
||||
# normalize whitespace in fullname like xfileref_role does
|
||||
fullname = ws_re.sub('', self.arguments[0].strip())
|
||||
targetname = '%s-%s' % (rolename, fullname)
|
||||
node = nodes.target('', '', ids=[targetname])
|
||||
self.state.document.note_explicit_target(node)
|
||||
ret = [node]
|
||||
if indextemplate:
|
||||
indexentry = indextemplate % (fullname,)
|
||||
indextype = 'single'
|
||||
colon = indexentry.find(':')
|
||||
if colon != -1:
|
||||
indextype = indexentry[:colon].strip()
|
||||
indexentry = indexentry[colon+1:].strip()
|
||||
inode = addnodes.index(entries=[(indextype, indexentry,
|
||||
targetname, targetname)])
|
||||
ret.insert(0, inode)
|
||||
env.note_reftarget(rolename, fullname, targetname)
|
||||
return ret
|
||||
|
||||
# Note: the target directive is not registered here, it is used by the
|
||||
# application when registering additional xref types.
|
||||
|
||||
_ = lambda x: x
|
||||
|
||||
# Generic cross-reference types; they can be registered in the application;
|
||||
# the directives are either desc_directive or target_directive.
|
||||
additional_xref_types = {
|
||||
# directive name: (role name, index text, function to parse the desc node)
|
||||
'envvar': ('envvar', _('environment variable; %s'), None),
|
||||
}
|
||||
|
||||
del _
|
||||
|
||||
|
||||
directives.register_directive('describe', directive_dwim(DescDirective))
|
||||
|
||||
directives.register_directive('function', directive_dwim(ModulelevelDesc))
|
||||
directives.register_directive('data', directive_dwim(ModulelevelDesc))
|
||||
directives.register_directive('class', directive_dwim(ClasslikeDesc))
|
||||
directives.register_directive('exception', directive_dwim(ClasslikeDesc))
|
||||
directives.register_directive('method', directive_dwim(ClassmemberDesc))
|
||||
directives.register_directive('classmethod', directive_dwim(ClassmemberDesc))
|
||||
directives.register_directive('staticmethod', directive_dwim(ClassmemberDesc))
|
||||
directives.register_directive('attribute', directive_dwim(ClassmemberDesc))
|
||||
|
||||
directives.register_directive('cfunction', directive_dwim(CDesc))
|
||||
directives.register_directive('cmember', directive_dwim(CDesc))
|
||||
directives.register_directive('cmacro', directive_dwim(CDesc))
|
||||
directives.register_directive('ctype', directive_dwim(CDesc))
|
||||
directives.register_directive('cvar', directive_dwim(CDesc))
|
||||
|
||||
directives.register_directive('cmdoption', directive_dwim(CmdoptionDesc))
|
||||
directives.register_directive('envvar', directive_dwim(GenericDesc))
|
@ -10,13 +10,13 @@
|
||||
import re
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.locale import pairindextypes
|
||||
from sphinx.util import patfilter, ws_re, url_re, docname_join, \
|
||||
explicit_title_re
|
||||
from sphinx.util.compat import Directive, directive_dwim, make_admonition
|
||||
from sphinx.util.compat import make_admonition
|
||||
|
||||
|
||||
class TocTree(Directive):
|
||||
@ -104,75 +104,6 @@ class TocTree(Directive):
|
||||
return ret
|
||||
|
||||
|
||||
class Module(Directive):
|
||||
"""
|
||||
Directive to mark description of a new module.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'platform': lambda x: x,
|
||||
'synopsis': lambda x: x,
|
||||
'noindex': directives.flag,
|
||||
'deprecated': directives.flag,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
noindex = 'noindex' in self.options
|
||||
env.currmodule = modname
|
||||
env.note_module(modname, self.options.get('synopsis', ''),
|
||||
self.options.get('platform', ''),
|
||||
'deprecated' in self.options)
|
||||
modulenode = addnodes.module()
|
||||
modulenode['modname'] = modname
|
||||
modulenode['synopsis'] = self.options.get('synopsis', '')
|
||||
targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
|
||||
self.state.document.note_explicit_target(targetnode)
|
||||
ret = [modulenode, targetnode]
|
||||
if 'platform' in self.options:
|
||||
platform = self.options['platform']
|
||||
modulenode['platform'] = platform
|
||||
node = nodes.paragraph()
|
||||
node += nodes.emphasis('', _('Platforms: '))
|
||||
node += nodes.Text(platform, platform)
|
||||
ret.append(node)
|
||||
# the synopsis isn't printed; in fact, it is only used in the
|
||||
# modindex currently
|
||||
if not noindex:
|
||||
indextext = _('%s (module)') % modname
|
||||
inode = addnodes.index(entries=[('single', indextext,
|
||||
'module-' + modname, modname)])
|
||||
ret.insert(0, inode)
|
||||
return ret
|
||||
|
||||
|
||||
class CurrentModule(Directive):
|
||||
"""
|
||||
This directive is just to tell Sphinx that we're documenting
|
||||
stuff in module foo, but links to module foo won't lead here.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
if modname == 'None':
|
||||
env.currmodule = None
|
||||
else:
|
||||
env.currmodule = modname
|
||||
return []
|
||||
|
||||
|
||||
class Author(Directive):
|
||||
"""
|
||||
Directive to give the name of the author of the current document
|
||||
@ -205,27 +136,6 @@ class Author(Directive):
|
||||
return [para] + messages
|
||||
|
||||
|
||||
class Program(Directive):
|
||||
"""
|
||||
Directive to name the program for which options are documented.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
program = ws_re.sub('-', self.arguments[0].strip())
|
||||
if program == 'None':
|
||||
env.currprogram = None
|
||||
else:
|
||||
env.currprogram = program
|
||||
return []
|
||||
|
||||
|
||||
class Index(Directive):
|
||||
"""
|
||||
Directive to add entries to the index.
|
||||
@ -244,8 +154,7 @@ class Index(Directive):
|
||||
def run(self):
|
||||
arguments = self.arguments[0].split('\n')
|
||||
env = self.state.document.settings.env
|
||||
targetid = 'index-%s' % env.index_num
|
||||
env.index_num += 1
|
||||
targetid = 'index-%s' % env.new_serialno('index')
|
||||
targetnode = nodes.target('', '', ids=[targetid])
|
||||
self.state.document.note_explicit_target(targetnode)
|
||||
indexnode = addnodes.index()
|
||||
@ -302,7 +211,11 @@ class VersionChange(Directive):
|
||||
else:
|
||||
ret = [node]
|
||||
env = self.state.document.settings.env
|
||||
env.note_versionchange(node['type'], node['version'], node, self.lineno)
|
||||
env.versionchanges.setdefault(node['version'], []).append(
|
||||
(node['type'], env.doc_read_data['docname'], self.lineno,
|
||||
env.doc_read_data.get('py_module'),
|
||||
env.doc_read_data.get('object'),
|
||||
node.astext()))
|
||||
return ret
|
||||
|
||||
|
||||
@ -332,66 +245,6 @@ class SeeAlso(Directive):
|
||||
return ret
|
||||
|
||||
|
||||
token_re = re.compile('`([a-z_]+)`')
|
||||
|
||||
def token_xrefs(text, env):
|
||||
retnodes = []
|
||||
pos = 0
|
||||
for m in token_re.finditer(text):
|
||||
if m.start() > pos:
|
||||
txt = text[pos:m.start()]
|
||||
retnodes.append(nodes.Text(txt, txt))
|
||||
refnode = addnodes.pending_xref(m.group(1))
|
||||
refnode['reftype'] = 'token'
|
||||
refnode['reftarget'] = m.group(1)
|
||||
refnode['modname'] = env.currmodule
|
||||
refnode['classname'] = env.currclass
|
||||
refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
|
||||
retnodes.append(refnode)
|
||||
pos = m.end()
|
||||
if pos < len(text):
|
||||
retnodes.append(nodes.Text(text[pos:], text[pos:]))
|
||||
return retnodes
|
||||
|
||||
class ProductionList(Directive):
|
||||
"""
|
||||
Directive to list grammar productions.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
node = addnodes.productionlist()
|
||||
messages = []
|
||||
i = 0
|
||||
|
||||
for rule in self.arguments[0].split('\n'):
|
||||
if i == 0 and ':' not in rule:
|
||||
# production group
|
||||
continue
|
||||
i += 1
|
||||
try:
|
||||
name, tokens = rule.split(':', 1)
|
||||
except ValueError:
|
||||
break
|
||||
subnode = addnodes.production()
|
||||
subnode['tokenname'] = name.strip()
|
||||
if subnode['tokenname']:
|
||||
idname = 'grammar-token-%s' % subnode['tokenname']
|
||||
if idname not in self.state.document.ids:
|
||||
subnode['ids'].append(idname)
|
||||
self.state.document.note_implicit_target(subnode, subnode)
|
||||
env.note_reftarget('token', subnode['tokenname'], idname)
|
||||
subnode.extend(token_xrefs(tokens, env))
|
||||
node.append(subnode)
|
||||
return [node] + messages
|
||||
|
||||
|
||||
class TabularColumns(Directive):
|
||||
"""
|
||||
Directive to give an explicit tabulary column definition to LaTeX.
|
||||
@ -409,57 +262,6 @@ class TabularColumns(Directive):
|
||||
return [node]
|
||||
|
||||
|
||||
class Glossary(Directive):
|
||||
"""
|
||||
Directive to create a glossary with cross-reference targets
|
||||
for :term: roles.
|
||||
"""
|
||||
|
||||
has_content = True
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'sorted': directives.flag,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
node = addnodes.glossary()
|
||||
node.document = self.state.document
|
||||
self.state.nested_parse(self.content, self.content_offset, node)
|
||||
|
||||
# the content should be definition lists
|
||||
dls = [child for child in node
|
||||
if isinstance(child, nodes.definition_list)]
|
||||
# now, extract definition terms to enable cross-reference creation
|
||||
new_dl = nodes.definition_list()
|
||||
new_dl['classes'].append('glossary')
|
||||
items = []
|
||||
for dl in dls:
|
||||
for li in dl.children:
|
||||
if not li.children or not isinstance(li[0], nodes.term):
|
||||
continue
|
||||
termtext = li.children[0].astext()
|
||||
new_id = 'term-' + nodes.make_id(termtext)
|
||||
if new_id in env.gloss_entries:
|
||||
new_id = 'term-' + str(len(env.gloss_entries))
|
||||
env.gloss_entries.add(new_id)
|
||||
li[0]['names'].append(new_id)
|
||||
li[0]['ids'].append(new_id)
|
||||
env.note_reftarget('term', termtext.lower(), new_id)
|
||||
# add an index entry too
|
||||
indexnode = addnodes.index()
|
||||
indexnode['entries'] = [('single', termtext, new_id, termtext)]
|
||||
li.insert(0, indexnode)
|
||||
items.append((termtext, li))
|
||||
if 'sorted' in self.options:
|
||||
items.sort(key=lambda x: x[0].lower())
|
||||
new_dl.extend(item[1] for item in items)
|
||||
node.children = [new_dl]
|
||||
return [node]
|
||||
|
||||
|
||||
class Centered(Directive):
|
||||
"""
|
||||
Directive to create a centered line of bold text.
|
||||
@ -562,36 +364,21 @@ class Only(Directive):
|
||||
return [node]
|
||||
|
||||
|
||||
directives.register_directive('toctree', directive_dwim(TocTree))
|
||||
directives.register_directive('module', directive_dwim(Module))
|
||||
directives.register_directive('currentmodule', directive_dwim(CurrentModule))
|
||||
directives.register_directive('sectionauthor', directive_dwim(Author))
|
||||
directives.register_directive('moduleauthor', directive_dwim(Author))
|
||||
directives.register_directive('program', directive_dwim(Program))
|
||||
directives.register_directive('index', directive_dwim(Index))
|
||||
directives.register_directive('deprecated', directive_dwim(VersionChange))
|
||||
directives.register_directive('versionadded', directive_dwim(VersionChange))
|
||||
directives.register_directive('versionchanged', directive_dwim(VersionChange))
|
||||
directives.register_directive('seealso', directive_dwim(SeeAlso))
|
||||
directives.register_directive('productionlist', directive_dwim(ProductionList))
|
||||
directives.register_directive('tabularcolumns', directive_dwim(TabularColumns))
|
||||
directives.register_directive('glossary', directive_dwim(Glossary))
|
||||
directives.register_directive('centered', directive_dwim(Centered))
|
||||
directives.register_directive('acks', directive_dwim(Acks))
|
||||
directives.register_directive('hlist', directive_dwim(HList))
|
||||
directives.register_directive('only', directive_dwim(Only))
|
||||
directives.register_directive('toctree', TocTree)
|
||||
directives.register_directive('sectionauthor', Author)
|
||||
directives.register_directive('moduleauthor', Author)
|
||||
directives.register_directive('index', Index)
|
||||
directives.register_directive('deprecated', VersionChange)
|
||||
directives.register_directive('versionadded', VersionChange)
|
||||
directives.register_directive('versionchanged', VersionChange)
|
||||
directives.register_directive('seealso', SeeAlso)
|
||||
directives.register_directive('tabularcolumns', TabularColumns)
|
||||
directives.register_directive('centered', Centered)
|
||||
directives.register_directive('acks', Acks)
|
||||
directives.register_directive('hlist', HList)
|
||||
directives.register_directive('only', Only)
|
||||
|
||||
# register the standard rst class directive under a different name
|
||||
|
||||
try:
|
||||
# docutils 0.4
|
||||
from docutils.parsers.rst.directives.misc import class_directive
|
||||
directives.register_directive('cssclass', class_directive)
|
||||
except ImportError:
|
||||
try:
|
||||
# docutils 0.5
|
||||
from docutils.parsers.rst.directives.misc import Class
|
||||
directives.register_directive('cssclass', Class)
|
||||
except ImportError:
|
||||
# whatever :)
|
||||
pass
|
||||
# only for backwards compatibility now
|
||||
from docutils.parsers.rst.directives.misc import Class
|
||||
directives.register_directive('cssclass', Class)
|
||||
|
180
sphinx/domains/__init__.py
Normal file
180
sphinx/domains/__init__.py
Normal file
@ -0,0 +1,180 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.domains
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Support for domains, which are groupings of description directives
|
||||
and roles describing e.g. constructs of one programming language.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
||||
class ObjType(object):
|
||||
"""
|
||||
XXX add docstring
|
||||
"""
|
||||
|
||||
known_attrs = {
|
||||
'searchprio': 1,
|
||||
}
|
||||
|
||||
def __init__(self, lname, *roles, **attrs):
|
||||
self.lname = lname
|
||||
self.roles = roles
|
||||
self.attrs = self.known_attrs.copy()
|
||||
self.attrs.update(attrs)
|
||||
|
||||
|
||||
class Domain(object):
|
||||
"""
|
||||
A Domain is meant to be a group of "object" description directives for
|
||||
objects of a similar nature, and corresponding roles to create references to
|
||||
them. Examples would be Python modules, classes, functions etc., elements
|
||||
of a templating language, Sphinx roles and directives, etc.
|
||||
|
||||
Each domain has a separate storage for information about existing objects
|
||||
and how to reference them in `data`, which must be a dictionary. It also
|
||||
must implement several functions that expose the object information in a
|
||||
uniform way to parts of Sphinx that allow the user to reference or search
|
||||
for objects in a domain-agnostic way.
|
||||
|
||||
About `self.data`: since all object and cross-referencing information is
|
||||
stored on a BuildEnvironment instance, the `domain.data` object is also
|
||||
stored in the `env.domaindata` dict under the key `domain.name`. Before the
|
||||
build process starts, every active domain is instantiated and given the
|
||||
environment object; the `domaindata` dict must then either be nonexistent or
|
||||
a dictionary whose 'version' key is equal to the domain class'
|
||||
`data_version` attribute. Otherwise, `IOError` is raised and the pickled
|
||||
environment is discarded.
|
||||
"""
|
||||
|
||||
#: domain name: should be short, but unique
|
||||
name = ''
|
||||
#: domain label: longer, more descriptive (used in messages)
|
||||
label = ''
|
||||
#: type (usually directive) name -> ObjType instance
|
||||
object_types = {}
|
||||
#: directive name -> directive class
|
||||
directives = {}
|
||||
#: role name -> role callable
|
||||
roles = {}
|
||||
|
||||
#: data value for a fresh environment
|
||||
initial_data = {}
|
||||
#: data version
|
||||
data_version = 0
|
||||
|
||||
def __init__(self, env):
|
||||
self.env = env
|
||||
if self.name not in env.domaindata:
|
||||
assert isinstance(self.initial_data, dict)
|
||||
new_data = self.initial_data.copy()
|
||||
new_data['version'] = self.data_version
|
||||
self.data = env.domaindata[self.name] = new_data
|
||||
else:
|
||||
self.data = env.domaindata[self.name]
|
||||
if self.data['version'] != self.data_version:
|
||||
raise IOError('data of %r domain out of date' % self.label)
|
||||
self._role_cache = {}
|
||||
self._directive_cache = {}
|
||||
self._role2type = {}
|
||||
for name, obj in self.object_types.iteritems():
|
||||
for rolename in obj.roles:
|
||||
self._role2type.setdefault(rolename, []).append(name)
|
||||
self.objtypes_for_role = self._role2type.get
|
||||
|
||||
def role(self, name):
|
||||
"""
|
||||
Return a role adapter function that always gives the registered
|
||||
role its full name ('domain:name') as the first argument.
|
||||
"""
|
||||
if name in self._role_cache:
|
||||
return self._role_cache[name]
|
||||
if name not in self.roles:
|
||||
return None
|
||||
fullname = '%s:%s' % (self.name, name)
|
||||
def role_adapter(typ, rawtext, text, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
return self.roles[name](fullname, rawtext, text, lineno,
|
||||
inliner, options, content)
|
||||
self._role_cache[name] = role_adapter
|
||||
return role_adapter
|
||||
|
||||
def directive(self, name):
|
||||
"""
|
||||
Return a directive adapter class that always gives the registered
|
||||
directive its full name ('domain:name') as ``self.name``.
|
||||
"""
|
||||
if name in self._directive_cache:
|
||||
return self._directive_cache[name]
|
||||
if name not in self.directives:
|
||||
return None
|
||||
fullname = '%s:%s' % (self.name, name)
|
||||
BaseDirective = self.directives[name]
|
||||
class DirectiveAdapter(BaseDirective):
|
||||
def run(self):
|
||||
self.name = fullname
|
||||
return BaseDirective.run(self)
|
||||
self._directive_cache[name] = DirectiveAdapter
|
||||
return DirectiveAdapter
|
||||
|
||||
# methods that should be overwritten
|
||||
|
||||
def clear_doc(self, docname):
|
||||
"""
|
||||
Remove traces of a document in the domain-specific inventories.
|
||||
"""
|
||||
pass
|
||||
|
||||
# XXX way for individual docs to override methods in an existing domain?
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
"""
|
||||
Resolve the ``pending_xref`` *node* with the given *typ* and *target*.
|
||||
|
||||
This method should return a new node, to replace the xref node,
|
||||
containing the *contnode* which is the markup content of the
|
||||
cross-reference.
|
||||
|
||||
If no resolution can be found, None can be returned; the xref node will
|
||||
then given to the 'missing-reference' event, and if that yields no
|
||||
resolution, replaced by *contnode*.
|
||||
|
||||
The method can also raise `sphinx.environment.NoUri` to suppress the
|
||||
'missing-reference' event being emitted.
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_objects(self):
|
||||
"""
|
||||
Return an iterable of "object descriptions", which are tuples with
|
||||
five items:
|
||||
|
||||
* `name` -- fully qualified name
|
||||
* `type` -- object type, a key in ``self.object_types``
|
||||
* `docname` -- the document where it is to be found
|
||||
* `anchor` -- the anchor name for the object
|
||||
* `priority` -- how "important" the object is (determines placement
|
||||
in search results)
|
||||
|
||||
1: default priority (placed before full-text matches)
|
||||
0: object is important (placed before default-priority objects)
|
||||
2: object is unimportant (placed after full-text matches)
|
||||
-1: object should not show up in search at all
|
||||
"""
|
||||
return []
|
||||
|
||||
|
||||
from sphinx.domains.c import CDomain
|
||||
from sphinx.domains.std import StandardDomain
|
||||
from sphinx.domains.python import PythonDomain
|
||||
|
||||
# this contains all registered domains
|
||||
all_domains = {
|
||||
'std': StandardDomain,
|
||||
'py': PythonDomain,
|
||||
'c': CDomain,
|
||||
}
|
204
sphinx/domains/c.py
Normal file
204
sphinx/domains/c.py
Normal file
@ -0,0 +1,204 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.domains.c
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The C language domain.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
import string
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.locale import l_
|
||||
from sphinx.domains import Domain, ObjType
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.util import make_refnode
|
||||
from sphinx.util.compat import Directive
|
||||
|
||||
|
||||
# RE to split at word boundaries
|
||||
wsplit_re = re.compile(r'(\W+)')
|
||||
|
||||
# REs for C signatures
|
||||
c_sig_re = re.compile(
|
||||
r'''^([^(]*?) # return type
|
||||
([\w:.]+) \s* # thing name (colon allowed for C++ class names)
|
||||
(?: \((.*)\) )? # optionally arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_sig_re = re.compile(
|
||||
r'''^([^(]+?) # return type
|
||||
(\( [^()]+ \)) \s* # name in parentheses
|
||||
\( (.*) \) # arguments
|
||||
(\s+const)? $ # const specifier
|
||||
''', re.VERBOSE)
|
||||
c_funcptr_name_re = re.compile(r'^\(\s*\*\s*(.*?)\s*\)$')
|
||||
|
||||
|
||||
class CObject(ObjectDescription):
|
||||
"""
|
||||
Description of a C language object.
|
||||
"""
|
||||
|
||||
# These C types aren't described anywhere, so don't try to create
|
||||
# a cross-reference to them
|
||||
stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct'))
|
||||
|
||||
def _parse_type(self, node, ctype):
|
||||
# add cross-ref nodes for all words
|
||||
for part in filter(None, wsplit_re.split(ctype)):
|
||||
tnode = nodes.Text(part, part)
|
||||
if part[0] in string.ascii_letters+'_' and \
|
||||
part not in self.stopwords:
|
||||
pnode = addnodes.pending_xref(
|
||||
'', refdomain='c', reftype='type', reftarget=part,
|
||||
modname=None, classname=None)
|
||||
pnode += tnode
|
||||
node += pnode
|
||||
else:
|
||||
node += tnode
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""Transform a C (or C++) signature into RST nodes."""
|
||||
# first try the function pointer signature regex, it's more specific
|
||||
m = c_funcptr_sig_re.match(sig)
|
||||
if m is None:
|
||||
m = c_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError('no match')
|
||||
rettype, name, arglist, const = m.groups()
|
||||
|
||||
signode += addnodes.desc_type('', '')
|
||||
self._parse_type(signode[-1], rettype)
|
||||
try:
|
||||
classname, funcname = name.split('::', 1)
|
||||
classname += '::'
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
signode += addnodes.desc_name(funcname, funcname)
|
||||
# name (the full name) is still both parts
|
||||
except ValueError:
|
||||
signode += addnodes.desc_name(name, name)
|
||||
# clean up parentheses from canonical name
|
||||
m = c_funcptr_name_re.match(name)
|
||||
if m:
|
||||
name = m.group(1)
|
||||
if not arglist:
|
||||
if self.objtype == 'function':
|
||||
# for functions, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup
|
||||
# this messes up function pointer types, but not too badly ;)
|
||||
args = arglist.split(',')
|
||||
for arg in args:
|
||||
arg = arg.strip()
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
try:
|
||||
ctype, argname = arg.rsplit(' ', 1)
|
||||
except ValueError:
|
||||
# no argument name given, only the type
|
||||
self._parse_type(param, arg)
|
||||
else:
|
||||
self._parse_type(param, ctype)
|
||||
param += nodes.emphasis(' '+argname, ' '+argname)
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
if const:
|
||||
signode += addnodes.desc_addname(const, const)
|
||||
return name
|
||||
|
||||
def get_index_text(self, name):
|
||||
if self.objtype == 'function':
|
||||
return _('%s (C function)') % name
|
||||
elif self.objtype == 'member':
|
||||
return _('%s (C member)') % name
|
||||
elif self.objtype == 'macro':
|
||||
return _('%s (C macro)') % name
|
||||
elif self.objtype == 'type':
|
||||
return _('%s (C type)') % name
|
||||
elif self.objtype == 'var':
|
||||
return _('%s (C variable)') % name
|
||||
else:
|
||||
return ''
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
# note target
|
||||
if name not in self.state.document.ids:
|
||||
signode['names'].append(name)
|
||||
signode['ids'].append(name)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
inv = self.env.domaindata['c']['objects']
|
||||
if name in inv:
|
||||
self.env.warn(
|
||||
self.env.docname,
|
||||
'duplicate C object description of %s, ' % name +
|
||||
'other instance in ' + self.env.doc2path(inv[name][0]),
|
||||
self.lineno)
|
||||
inv[name] = (self.env.docname, self.objtype)
|
||||
|
||||
indextext = self.get_index_text(name)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext, name, name))
|
||||
|
||||
|
||||
class CDomain(Domain):
|
||||
"""C language domain."""
|
||||
name = 'c'
|
||||
label = 'C'
|
||||
object_types = {
|
||||
'function': ObjType(l_('C function'), 'func'),
|
||||
'member': ObjType(l_('C member'), 'member'),
|
||||
'macro': ObjType(l_('C macro'), 'macro'),
|
||||
'type': ObjType(l_('C type'), 'type'),
|
||||
'var': ObjType(l_('C variable'), 'data'),
|
||||
}
|
||||
|
||||
directives = {
|
||||
'function': CObject,
|
||||
'member': CObject,
|
||||
'macro': CObject,
|
||||
'type': CObject,
|
||||
'var': CObject,
|
||||
}
|
||||
roles = {
|
||||
'func' : XRefRole(fix_parens=True),
|
||||
'member': XRefRole(),
|
||||
'macro': XRefRole(),
|
||||
'data': XRefRole(),
|
||||
'type': XRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
'objects': {}, # fullname -> docname, objtype
|
||||
}
|
||||
|
||||
def clear_doc(self, docname):
|
||||
for fullname, (fn, _) in self.data['objects'].items():
|
||||
if fn == docname:
|
||||
del self.data['objects'][fullname]
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
# strip pointer asterisk
|
||||
target = target.rstrip(' *')
|
||||
if target not in self.data['objects']:
|
||||
return None
|
||||
obj = self.data['objects'][target]
|
||||
return make_refnode(builder, fromdocname, obj[0], target,
|
||||
contnode, target)
|
||||
|
||||
def get_objects(self):
|
||||
for refname, (docname, type) in self.data['objects'].iteritems():
|
||||
yield (refname, type, docname, refname, 1)
|
514
sphinx/domains/python.py
Normal file
514
sphinx/domains/python.py
Normal file
@ -0,0 +1,514 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.domains.python
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Python domain.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.locale import l_
|
||||
from sphinx.domains import Domain, ObjType
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.util import make_refnode
|
||||
from sphinx.util.compat import Directive
|
||||
|
||||
|
||||
# REs for Python signatures
|
||||
py_sig_re = re.compile(
|
||||
r'''^ ([\w.]*\.)? # class name(s)
|
||||
(\w+) \s* # thing name
|
||||
(?: \((.*)\) # optional: arguments
|
||||
(?:\s* -> \s* (.*))? # return annotation
|
||||
)? $ # and nothing more
|
||||
''', re.VERBOSE)
|
||||
|
||||
py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
|
||||
|
||||
|
||||
class PyObject(ObjectDescription):
|
||||
"""
|
||||
Description of a general Python object.
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
"""
|
||||
May return a prefix to put before the object name in the signature.
|
||||
"""
|
||||
return ''
|
||||
|
||||
def needs_arglist(self):
|
||||
"""
|
||||
May return true if an empty argument list is to be generated even if
|
||||
the document contains none.
|
||||
"""
|
||||
return False
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""
|
||||
Transform a Python signature into RST nodes.
|
||||
Returns (fully qualified name of the thing, classname if any).
|
||||
|
||||
If inside a class, the current class name is handled intelligently:
|
||||
* it is stripped from the displayed name if present
|
||||
* it is added to the full name (return value) if not present
|
||||
"""
|
||||
m = py_sig_re.match(sig)
|
||||
if m is None:
|
||||
raise ValueError
|
||||
classname, name, arglist, retann = m.groups()
|
||||
|
||||
currclass = self.env.doc_read_data.get('py_class')
|
||||
if currclass:
|
||||
add_module = False
|
||||
if classname and classname.startswith(currclass):
|
||||
fullname = classname + name
|
||||
# class name is given again in the signature
|
||||
classname = classname[len(currclass):].lstrip('.')
|
||||
elif classname:
|
||||
# class name is given in the signature, but different
|
||||
# (shouldn't happen)
|
||||
fullname = currclass + '.' + classname + name
|
||||
else:
|
||||
# class name is not given in the signature
|
||||
fullname = currclass + '.' + name
|
||||
else:
|
||||
add_module = True
|
||||
fullname = classname and classname + name or name
|
||||
|
||||
prefix = self.get_signature_prefix(sig)
|
||||
if prefix:
|
||||
signode += addnodes.desc_annotation(prefix, prefix)
|
||||
|
||||
if classname:
|
||||
signode += addnodes.desc_addname(classname, classname)
|
||||
# exceptions are a special case, since they are documented in the
|
||||
# 'exceptions' module.
|
||||
elif add_module and self.env.config.add_module_names:
|
||||
modname = self.options.get(
|
||||
'module', self.env.doc_read_data.get('py_module'))
|
||||
if modname and modname != 'exceptions':
|
||||
nodetext = modname + '.'
|
||||
signode += addnodes.desc_addname(nodetext, nodetext)
|
||||
|
||||
signode += addnodes.desc_name(name, name)
|
||||
if not arglist:
|
||||
if self.needs_arglist():
|
||||
# for callables, add an empty parameter list
|
||||
signode += addnodes.desc_parameterlist()
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
signode += addnodes.desc_parameterlist()
|
||||
|
||||
stack = [signode[-1]]
|
||||
for token in py_paramlist_re.split(arglist):
|
||||
if token == '[':
|
||||
opt = addnodes.desc_optional()
|
||||
stack[-1] += opt
|
||||
stack.append(opt)
|
||||
elif token == ']':
|
||||
try:
|
||||
stack.pop()
|
||||
except IndexError:
|
||||
raise ValueError
|
||||
elif not token or token == ',' or token.isspace():
|
||||
pass
|
||||
else:
|
||||
token = token.strip()
|
||||
stack[-1] += addnodes.desc_parameter(token, token)
|
||||
if len(stack) != 1:
|
||||
raise ValueError
|
||||
if retann:
|
||||
signode += addnodes.desc_returns(retann, retann)
|
||||
return fullname, classname
|
||||
|
||||
def get_index_text(self, modname, name):
|
||||
"""
|
||||
Return the text for the index entry of the object.
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def add_target_and_index(self, name_cls, sig, signode):
|
||||
modname = self.options.get(
|
||||
'module', self.env.doc_read_data.get('py_module'))
|
||||
fullname = (modname and modname + '.' or '') + name_cls[0]
|
||||
# note target
|
||||
if fullname not in self.state.document.ids:
|
||||
signode['names'].append(fullname)
|
||||
signode['ids'].append(fullname)
|
||||
signode['first'] = (not self.names)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
objects = self.env.domaindata['py']['objects']
|
||||
if fullname in objects:
|
||||
self.env.warn(
|
||||
self.env.docname,
|
||||
'duplicate object description of %s, ' % fullname +
|
||||
'other instance in ' +
|
||||
self.env.doc2path(objects[fullname][0]),
|
||||
self.lineno)
|
||||
objects[fullname] = (self.env.docname, self.objtype)
|
||||
|
||||
indextext = self.get_index_text(modname, name_cls)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext,
|
||||
fullname, fullname))
|
||||
|
||||
def before_content(self):
|
||||
# needed for automatic qualification of members (reset in subclasses)
|
||||
self.clsname_set = False
|
||||
|
||||
def after_content(self):
|
||||
if self.clsname_set:
|
||||
self.env.doc_read_data['py_class'] = None
|
||||
|
||||
|
||||
class PyModulelevel(PyObject):
|
||||
"""
|
||||
Description of an object on module level (functions, data).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.objtype == 'function'
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.objtype == 'function':
|
||||
if not modname:
|
||||
return _('%s() (built-in function)') % name_cls[0]
|
||||
return _('%s() (in module %s)') % (name_cls[0], modname)
|
||||
elif self.objtype == 'data':
|
||||
if not modname:
|
||||
return _('%s (built-in variable)') % name_cls[0]
|
||||
return _('%s (in module %s)') % (name_cls[0], modname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class PyClasslike(PyObject):
|
||||
"""
|
||||
Description of a class-like object (classes, interfaces, exceptions).
|
||||
"""
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
return self.objtype + ' '
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
if self.objtype == 'class':
|
||||
if not modname:
|
||||
return _('%s (built-in class)') % name_cls[0]
|
||||
return _('%s (class in %s)') % (name_cls[0], modname)
|
||||
elif self.objtype == 'exception':
|
||||
return name_cls[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PyObject.before_content(self)
|
||||
if self.names:
|
||||
self.env.doc_read_data['py_class'] = self.names[0][0]
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class PyClassmember(PyObject):
|
||||
"""
|
||||
Description of a class member (methods, attributes).
|
||||
"""
|
||||
|
||||
def needs_arglist(self):
|
||||
return self.objtype.endswith('method')
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
if self.objtype == 'staticmethod':
|
||||
return 'static '
|
||||
elif self.objtype == 'classmethod':
|
||||
return 'classmethod '
|
||||
return ''
|
||||
|
||||
def get_index_text(self, modname, name_cls):
|
||||
name, cls = name_cls
|
||||
add_modules = self.env.config.add_module_names
|
||||
if self.objtype == 'method':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s method)') % (methname, modname, clsname)
|
||||
else:
|
||||
return _('%s() (%s method)') % (methname, clsname)
|
||||
elif self.objtype == 'staticmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s static method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s static method)') % (methname, clsname)
|
||||
elif self.objtype == 'classmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname:
|
||||
return _('%s() (%s.%s class method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s class method)') % (methname, clsname)
|
||||
elif self.objtype == 'attribute':
|
||||
try:
|
||||
clsname, attrname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s (in module %s)') % (name, modname)
|
||||
else:
|
||||
return name
|
||||
if modname and add_modules:
|
||||
return _('%s (%s.%s attribute)') % (attrname, modname, clsname)
|
||||
else:
|
||||
return _('%s (%s attribute)') % (attrname, clsname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
PyObject.before_content(self)
|
||||
lastname = self.names and self.names[-1][1]
|
||||
if lastname and not self.env.doc_read_data.get('py_class'):
|
||||
self.env.doc_read_data['py_class'] = lastname.strip('.')
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class PyModule(Directive):
|
||||
"""
|
||||
Directive to mark description of a new module.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'platform': lambda x: x,
|
||||
'synopsis': lambda x: x,
|
||||
'noindex': directives.flag,
|
||||
'deprecated': directives.flag,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
noindex = 'noindex' in self.options
|
||||
env.doc_read_data['py_module'] = modname
|
||||
env.domaindata['py']['modules'][modname] = \
|
||||
(env.docname, self.options.get('synopsis', ''),
|
||||
self.options.get('platform', ''), 'deprecated' in self.options)
|
||||
modulenode = addnodes.module()
|
||||
modulenode['modname'] = modname
|
||||
modulenode['synopsis'] = self.options.get('synopsis', '')
|
||||
targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
|
||||
self.state.document.note_explicit_target(targetnode)
|
||||
ret = [modulenode, targetnode]
|
||||
if 'platform' in self.options:
|
||||
platform = self.options['platform']
|
||||
modulenode['platform'] = platform
|
||||
node = nodes.paragraph()
|
||||
node += nodes.emphasis('', _('Platforms: '))
|
||||
node += nodes.Text(platform, platform)
|
||||
ret.append(node)
|
||||
# the synopsis isn't printed; in fact, it is only used in the
|
||||
# modindex currently
|
||||
if not noindex:
|
||||
indextext = _('%s (module)') % modname
|
||||
inode = addnodes.index(entries=[('single', indextext,
|
||||
'module-' + modname, modname)])
|
||||
ret.insert(0, inode)
|
||||
return ret
|
||||
|
||||
|
||||
class PyCurrentModule(Directive):
|
||||
"""
|
||||
This directive is just to tell Sphinx that we're documenting
|
||||
stuff in module foo, but links to module foo won't lead here.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
if modname == 'None':
|
||||
env.doc_read_data['py_module'] = None
|
||||
else:
|
||||
env.doc_read_data['py_module'] = modname
|
||||
return []
|
||||
|
||||
|
||||
class PyXRefRole(XRefRole):
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
refnode['py_module'] = env.doc_read_data.get('py_module')
|
||||
refnode['py_class'] = env.doc_read_data.get('py_class')
|
||||
if not has_explicit_title:
|
||||
title = title.lstrip('.') # only has a meaning for the target
|
||||
target = target.lstrip('~') # only has a meaning for the title
|
||||
# if the first character is a tilde, don't display the module/class
|
||||
# parts of the contents
|
||||
if title[0:1] == '~':
|
||||
title = title[1:]
|
||||
dot = title.rfind('.')
|
||||
if dot != -1:
|
||||
title = title[dot+1:]
|
||||
# if the first character is a dot, search more specific namespaces first
|
||||
# else search builtins first
|
||||
if target[0:1] == '.':
|
||||
target = target[1:]
|
||||
refnode['refspecific'] = True
|
||||
return title, target
|
||||
|
||||
|
||||
class PythonDomain(Domain):
|
||||
"""Python language domain."""
|
||||
name = 'py'
|
||||
label = 'Python'
|
||||
object_types = {
|
||||
'function': ObjType(l_('function'), 'func', 'obj'),
|
||||
'data': ObjType(l_('data'), 'data', 'obj'),
|
||||
'class': ObjType(l_('class'), 'class', 'obj'),
|
||||
'exception': ObjType(l_('exception'), 'exc', 'obj'),
|
||||
'method': ObjType(l_('method'), 'meth', 'obj'),
|
||||
'attribute': ObjType(l_('attribute'), 'attr', 'obj'),
|
||||
'module': ObjType(l_('module'), 'mod', 'obj'),
|
||||
}
|
||||
|
||||
directives = {
|
||||
'function': PyModulelevel,
|
||||
'data': PyModulelevel,
|
||||
'class': PyClasslike,
|
||||
'exception': PyClasslike,
|
||||
'method': PyClassmember,
|
||||
'classmethod': PyClassmember,
|
||||
'staticmethod': PyClassmember,
|
||||
'attribute': PyClassmember,
|
||||
'module': PyModule,
|
||||
'currentmodule': PyCurrentModule,
|
||||
}
|
||||
roles = {
|
||||
'data': PyXRefRole(),
|
||||
'exc': PyXRefRole(),
|
||||
'func': PyXRefRole(fix_parens=True),
|
||||
'class': PyXRefRole(),
|
||||
'const': PyXRefRole(),
|
||||
'attr': PyXRefRole(),
|
||||
'meth': PyXRefRole(fix_parens=True),
|
||||
'mod': PyXRefRole(),
|
||||
'obj': PyXRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
'objects': {}, # fullname -> docname, objtype
|
||||
'modules': {}, # modname -> docname, synopsis, platform, deprecated
|
||||
}
|
||||
|
||||
def clear_doc(self, docname):
|
||||
for fullname, (fn, _) in self.data['objects'].items():
|
||||
if fn == docname:
|
||||
del self.data['objects'][fullname]
|
||||
for modname, (fn, _, _, _) in self.data['modules'].items():
|
||||
if fn == docname:
|
||||
del self.data['modules'][modname]
|
||||
|
||||
def find_obj(self, env, modname, classname, name, type, searchorder=0):
|
||||
"""
|
||||
Find a Python object for "name", perhaps using the given module and/or
|
||||
classname.
|
||||
"""
|
||||
# skip parens
|
||||
if name[-2:] == '()':
|
||||
name = name[:-2]
|
||||
|
||||
if not name:
|
||||
return None, None
|
||||
|
||||
objects = self.data['objects']
|
||||
|
||||
newname = None
|
||||
if searchorder == 1:
|
||||
if modname and classname and \
|
||||
modname + '.' + classname + '.' + name in objects:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
elif modname and modname + '.' + name in objects:
|
||||
newname = modname + '.' + name
|
||||
elif name in objects:
|
||||
newname = name
|
||||
else:
|
||||
if name in objects:
|
||||
newname = name
|
||||
elif modname and modname + '.' + name in objects:
|
||||
newname = modname + '.' + name
|
||||
elif modname and classname and \
|
||||
modname + '.' + classname + '.' + name in objects:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
# special case: builtin exceptions have module "exceptions" set
|
||||
elif type == 'exc' and '.' not in name and \
|
||||
'exceptions.' + name in objects:
|
||||
newname = 'exceptions.' + name
|
||||
# special case: object methods
|
||||
elif type in ('func', 'meth') and '.' not in name and \
|
||||
'object.' + name in objects:
|
||||
newname = 'object.' + name
|
||||
if newname is None:
|
||||
return None, None
|
||||
return newname, objects[newname]
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
if (typ == 'mod' or
|
||||
typ == 'obj' and target in self.data['modules']):
|
||||
docname, synopsis, platform, deprecated = \
|
||||
self.data['modules'].get(target, ('','','', ''))
|
||||
if not docname:
|
||||
return None
|
||||
else:
|
||||
title = '%s%s%s' % ((platform and '(%s) ' % platform),
|
||||
synopsis,
|
||||
(deprecated and ' (deprecated)' or ''))
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
'module-' + target, contnode, title)
|
||||
else:
|
||||
modname = node.get('py_module')
|
||||
clsname = node.get('py_class')
|
||||
searchorder = node.hasattr('refspecific') and 1 or 0
|
||||
name, obj = self.find_obj(env, modname, clsname,
|
||||
target, typ, searchorder)
|
||||
if not obj:
|
||||
return None
|
||||
else:
|
||||
return make_refnode(builder, fromdocname, obj[0], name,
|
||||
contnode, name)
|
||||
|
||||
def get_objects(self):
|
||||
for modname, info in self.data['modules'].iteritems():
|
||||
yield (modname, 'module', info[0], 'module-' + modname, 0)
|
||||
for refname, (docname, type) in self.data['objects'].iteritems():
|
||||
yield (refname, type, docname, refname, 1)
|
384
sphinx/domains/std.py
Normal file
384
sphinx/domains/std.py
Normal file
@ -0,0 +1,384 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.domains.std
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The standard domain.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from docutils import nodes, utils
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.locale import l_
|
||||
from sphinx.domains import Domain, ObjType
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.util import make_refnode, ws_re
|
||||
from sphinx.util.compat import Directive
|
||||
|
||||
|
||||
# RE for option descriptions
|
||||
option_desc_re = re.compile(
|
||||
r'((?:/|-|--)[-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
|
||||
|
||||
|
||||
class GenericObject(ObjectDescription):
|
||||
"""
|
||||
A generic x-ref directive registered with Sphinx.add_object_type().
|
||||
"""
|
||||
indextemplate = ''
|
||||
parse_node = None
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
if self.parse_node:
|
||||
name = self.parse_node(self.env, sig, signode)
|
||||
else:
|
||||
signode.clear()
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
# normalize whitespace like XRefRole does
|
||||
name = ws_re.sub('', sig)
|
||||
return name
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
targetname = '%s-%s' % (self.objtype, name)
|
||||
signode['ids'].append(targetname)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
if self.indextemplate:
|
||||
colon = self.indextemplate.find(':')
|
||||
if colon != -1:
|
||||
indextype = self.indextemplate[:colon].strip()
|
||||
indexentry = self.indextemplate[colon+1:].strip() % (name,)
|
||||
else:
|
||||
indextype = 'single'
|
||||
indexentry = self.indextemplate % (name,)
|
||||
self.indexnode['entries'].append((indextype, indexentry,
|
||||
targetname, targetname))
|
||||
self.env.domaindata['std']['objects'][self.objtype, name] = \
|
||||
self.env.docname, targetname
|
||||
|
||||
|
||||
class EnvVar(GenericObject):
|
||||
indextemplate = l_('environment variable; %s')
|
||||
|
||||
|
||||
class EnvVarXRefRole(XRefRole):
|
||||
"""
|
||||
Cross-referencing role for environment variables (adds an index entry).
|
||||
"""
|
||||
|
||||
def result_nodes(self, document, env, node, is_ref):
|
||||
if not is_ref:
|
||||
return [node], []
|
||||
varname = node['reftarget']
|
||||
tgtid = 'index-%s' % env.new_serialno('index')
|
||||
indexnode = addnodes.index()
|
||||
indexnode['entries'] = [
|
||||
('single', varname, tgtid, varname),
|
||||
('single', _('environment variable; %s') % varname, tgtid, varname)
|
||||
]
|
||||
targetnode = nodes.target('', '', ids=[tgtid])
|
||||
document.note_explicit_target(targetnode)
|
||||
return [indexnode, targetnode, node], []
|
||||
|
||||
|
||||
class Target(Directive):
|
||||
"""
|
||||
Generic target for user-defined cross-reference types.
|
||||
"""
|
||||
indextemplate = ''
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
# normalize whitespace in fullname like XRefRole does
|
||||
fullname = ws_re.sub('', self.arguments[0].strip())
|
||||
targetname = '%s-%s' % (self.name, fullname)
|
||||
node = nodes.target('', '', ids=[targetname])
|
||||
self.state.document.note_explicit_target(node)
|
||||
ret = [node]
|
||||
if self.indextemplate:
|
||||
indexentry = self.indextemplate % (fullname,)
|
||||
indextype = 'single'
|
||||
colon = indexentry.find(':')
|
||||
if colon != -1:
|
||||
indextype = indexentry[:colon].strip()
|
||||
indexentry = indexentry[colon+1:].strip()
|
||||
inode = addnodes.index(entries=[(indextype, indexentry,
|
||||
targetname, targetname)])
|
||||
ret.insert(0, inode)
|
||||
env.domaindata['std']['objects'][self.name, fullname] = \
|
||||
env.docname, targetname
|
||||
return ret
|
||||
|
||||
|
||||
class Cmdoption(ObjectDescription):
|
||||
"""
|
||||
Description of a command-line option (.. cmdoption).
|
||||
"""
|
||||
|
||||
def parse_signature(self, sig, signode):
|
||||
"""Transform an option description into RST nodes."""
|
||||
count = 0
|
||||
firstname = ''
|
||||
for m in option_desc_re.finditer(sig):
|
||||
optname, args = m.groups()
|
||||
if count:
|
||||
signode += addnodes.desc_addname(', ', ', ')
|
||||
signode += addnodes.desc_name(optname, optname)
|
||||
signode += addnodes.desc_addname(args, args)
|
||||
if not count:
|
||||
firstname = optname
|
||||
count += 1
|
||||
if not firstname:
|
||||
raise ValueError
|
||||
return firstname
|
||||
|
||||
def add_target_and_index(self, name, sig, signode):
|
||||
targetname = name.replace('/', '-')
|
||||
currprogram = self.env.doc_read_data.get('std_program')
|
||||
if currprogram:
|
||||
targetname = '-' + currprogram + targetname
|
||||
targetname = 'cmdoption' + targetname
|
||||
signode['ids'].append(targetname)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
self.indexnode['entries'].append(
|
||||
('pair', _('%scommand line option; %s') %
|
||||
((currprogram and currprogram + ' ' or ''), sig),
|
||||
targetname, targetname))
|
||||
self.env.domaindata['std']['progoptions'][currprogram, name] = \
|
||||
self.env.docname, targetname
|
||||
|
||||
|
||||
class Program(Directive):
|
||||
"""
|
||||
Directive to name the program for which options are documented.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
program = ws_re.sub('-', self.arguments[0].strip())
|
||||
if program == 'None':
|
||||
env.doc_read_data['std_program'] = None
|
||||
else:
|
||||
env.doc_read_data['std_program'] = program
|
||||
return []
|
||||
|
||||
|
||||
class OptionXRefRole(XRefRole):
|
||||
innernodeclass = addnodes.literal_emphasis
|
||||
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
program = env.doc_read_data.get('std_program')
|
||||
if not has_explicit_title:
|
||||
if ' ' in title and not (title.startswith('/') or
|
||||
title.startswith('-')):
|
||||
program, target = re.split(' (?=-|--|/)', title, 1)
|
||||
program = ws_re.sub('-', program)
|
||||
target = target.strip()
|
||||
elif ' ' in target:
|
||||
program, target = re.split(' (?=-|--|/)', target, 1)
|
||||
program = ws_re.sub('-', program)
|
||||
refnode['refprogram'] = program
|
||||
return title, target
|
||||
|
||||
|
||||
class Glossary(Directive):
|
||||
"""
|
||||
Directive to create a glossary with cross-reference targets
|
||||
for :term: roles.
|
||||
"""
|
||||
|
||||
has_content = True
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'sorted': directives.flag,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
objects = env.domaindata['std']['objects']
|
||||
gloss_entries = env.doc_read_data.setdefault('gloss_entries', set())
|
||||
node = addnodes.glossary()
|
||||
node.document = self.state.document
|
||||
self.state.nested_parse(self.content, self.content_offset, node)
|
||||
|
||||
# the content should be definition lists
|
||||
dls = [child for child in node
|
||||
if isinstance(child, nodes.definition_list)]
|
||||
# now, extract definition terms to enable cross-reference creation
|
||||
new_dl = nodes.definition_list()
|
||||
new_dl['classes'].append('glossary')
|
||||
items = []
|
||||
for dl in dls:
|
||||
for li in dl.children:
|
||||
if not li.children or not isinstance(li[0], nodes.term):
|
||||
continue
|
||||
termtext = li.children[0].astext()
|
||||
new_id = 'term-' + nodes.make_id(termtext)
|
||||
if new_id in gloss_entries:
|
||||
new_id = 'term-' + str(len(gloss_entries))
|
||||
gloss_entries.add(new_id)
|
||||
li[0]['names'].append(new_id)
|
||||
li[0]['ids'].append(new_id)
|
||||
objects['term', termtext.lower()] = env.docname, new_id
|
||||
# add an index entry too
|
||||
indexnode = addnodes.index()
|
||||
indexnode['entries'] = [('single', termtext, new_id, termtext)]
|
||||
li.insert(0, indexnode)
|
||||
items.append((termtext, li))
|
||||
if 'sorted' in self.options:
|
||||
items.sort(key=lambda x: x[0].lower())
|
||||
new_dl.extend(item[1] for item in items)
|
||||
node.children = [new_dl]
|
||||
return [node]
|
||||
|
||||
|
||||
token_re = re.compile('`([a-z_][a-z0-9_]*)`')
|
||||
|
||||
def token_xrefs(text):
|
||||
retnodes = []
|
||||
pos = 0
|
||||
for m in token_re.finditer(text):
|
||||
if m.start() > pos:
|
||||
txt = text[pos:m.start()]
|
||||
retnodes.append(nodes.Text(txt, txt))
|
||||
refnode = addnodes.pending_xref(
|
||||
m.group(1), reftype='token', refdomain='std', reftarget=m.group(1))
|
||||
refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
|
||||
retnodes.append(refnode)
|
||||
pos = m.end()
|
||||
if pos < len(text):
|
||||
retnodes.append(nodes.Text(text[pos:], text[pos:]))
|
||||
return retnodes
|
||||
|
||||
|
||||
class ProductionList(Directive):
|
||||
"""
|
||||
Directive to list grammar productions.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
objects = env.domaindata['std']['objects']
|
||||
node = addnodes.productionlist()
|
||||
messages = []
|
||||
i = 0
|
||||
|
||||
for rule in self.arguments[0].split('\n'):
|
||||
if i == 0 and ':' not in rule:
|
||||
# production group
|
||||
continue
|
||||
i += 1
|
||||
try:
|
||||
name, tokens = rule.split(':', 1)
|
||||
except ValueError:
|
||||
break
|
||||
subnode = addnodes.production()
|
||||
subnode['tokenname'] = name.strip()
|
||||
if subnode['tokenname']:
|
||||
idname = 'grammar-token-%s' % subnode['tokenname']
|
||||
if idname not in self.state.document.ids:
|
||||
subnode['ids'].append(idname)
|
||||
self.state.document.note_implicit_target(subnode, subnode)
|
||||
objects['token', subnode['tokenname']] = env.docname, idname
|
||||
subnode.extend(token_xrefs(tokens))
|
||||
node.append(subnode)
|
||||
return [node] + messages
|
||||
|
||||
|
||||
class StandardDomain(Domain):
|
||||
"""
|
||||
Domain for all objects that don't fit into another domain or are added
|
||||
via the application interface.
|
||||
"""
|
||||
|
||||
name = 'std'
|
||||
label = 'Default'
|
||||
|
||||
object_types = {
|
||||
'term': ObjType(l_('glossary term'), 'term', searchprio=-1),
|
||||
'token': ObjType(l_('grammar token'), 'token', searchprio=-1),
|
||||
'envvar': ObjType(l_('environment variable'), 'envvar'),
|
||||
'cmdoption': ObjType(l_('program option'), 'option'),
|
||||
}
|
||||
|
||||
directives = {
|
||||
'program': Program,
|
||||
'cmdoption': Cmdoption,
|
||||
'envvar': EnvVar,
|
||||
'glossary': Glossary,
|
||||
'productionlist': ProductionList,
|
||||
}
|
||||
roles = {
|
||||
'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
|
||||
'envvar': EnvVarXRefRole(),
|
||||
'token': XRefRole(),
|
||||
'term': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
|
||||
}
|
||||
|
||||
initial_data = {
|
||||
'progoptions': {}, # (program, name) -> docname, labelid
|
||||
'objects': {}, # (type, name) -> docname, labelid
|
||||
}
|
||||
|
||||
def clear_doc(self, docname):
|
||||
for key, (fn, _) in self.data['progoptions'].items():
|
||||
if fn == docname:
|
||||
del self.data['progoptions'][key]
|
||||
for key, (fn, _) in self.data['objects'].items():
|
||||
if fn == docname:
|
||||
del self.data['objects'][key]
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
if typ == 'option':
|
||||
progname = node['refprogram']
|
||||
docname, labelid = self.data['progoptions'].get((progname, target),
|
||||
('', ''))
|
||||
if not docname:
|
||||
return None
|
||||
else:
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
else:
|
||||
docname, labelid = self.data['objects'].get((typ, target), ('', ''))
|
||||
if not docname:
|
||||
if typ == 'term':
|
||||
env.warn(fromdocname, 'term not in glossary: %s' % target,
|
||||
node.line)
|
||||
return None
|
||||
else:
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
|
||||
def get_objects(self):
|
||||
for (prog, option), info in self.data['progoptions'].iteritems():
|
||||
yield (option, 'option', info[0], info[1], 1)
|
||||
for (type, name), info in self.data['objects'].iteritems():
|
||||
yield (name, type, info[0], info[1],
|
||||
self.object_types[type].attrs['searchprio'])
|
@ -26,7 +26,7 @@ from docutils.io import FileInput, NullOutput
|
||||
from docutils.core import Publisher
|
||||
from docutils.utils import Reporter, relative_path
|
||||
from docutils.readers import standalone
|
||||
from docutils.parsers.rst import roles
|
||||
from docutils.parsers.rst import roles, directives
|
||||
from docutils.parsers.rst.languages import en as english
|
||||
from docutils.parsers.rst.directives.html import MetaBody
|
||||
from docutils.writers import UnfilteredWriter
|
||||
@ -35,9 +35,41 @@ from docutils.transforms.parts import ContentsFilter
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import movefile, get_matching_docs, SEP, ustrftime, \
|
||||
docname_join, FilenameUniqDict, url_re
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.directives import additional_xref_types
|
||||
docname_join, FilenameUniqDict, url_re, make_refnode
|
||||
from sphinx.errors import SphinxError, ExtensionError
|
||||
|
||||
|
||||
orig_role_function = roles.role
|
||||
orig_directive_function = directives.directive
|
||||
|
||||
class ElementLookupError(Exception): pass
|
||||
|
||||
def lookup_domain_element(env, type, name):
|
||||
"""Lookup a markup element (directive or role), given its name which can
|
||||
be a full name (with domain).
|
||||
"""
|
||||
name = name.lower()
|
||||
# explicit domain given?
|
||||
if ':' in name:
|
||||
domain_name, name = name.split(':', 1)
|
||||
if domain_name in env.domains:
|
||||
domain = env.domains[domain_name]
|
||||
element = getattr(domain, type)(name)
|
||||
if element is not None:
|
||||
return element, []
|
||||
# else look in the default domain
|
||||
else:
|
||||
def_domain = env.doc_read_data.get('default_domain')
|
||||
if def_domain is not None:
|
||||
element = getattr(def_domain, type)(name)
|
||||
if element is not None:
|
||||
return element, []
|
||||
# always look in the std domain
|
||||
element = getattr(env.domains['std'], type)(name)
|
||||
if element is not None:
|
||||
return element, []
|
||||
raise ElementLookupError
|
||||
|
||||
|
||||
default_settings = {
|
||||
'embed_stylesheet': False,
|
||||
@ -51,7 +83,7 @@ default_settings = {
|
||||
|
||||
# This is increased every time an environment attribute is added
|
||||
# or changed to properly invalidate pickle files.
|
||||
ENV_VERSION = 30
|
||||
ENV_VERSION = 32
|
||||
|
||||
|
||||
default_substitutions = set([
|
||||
@ -202,9 +234,9 @@ class BuildEnvironment:
|
||||
env = pickle.load(picklefile)
|
||||
finally:
|
||||
picklefile.close()
|
||||
env.config.values = config.values
|
||||
if env.version != ENV_VERSION:
|
||||
raise IOError('env version not current')
|
||||
env.config.values = config.values
|
||||
return env
|
||||
|
||||
def topickle(self, filename):
|
||||
@ -213,6 +245,8 @@ class BuildEnvironment:
|
||||
self.set_warnfunc(None)
|
||||
values = self.config.values
|
||||
del self.config.values
|
||||
domains = self.domains
|
||||
del self.domains
|
||||
# first write to a temporary file, so that if dumping fails,
|
||||
# the existing environment won't be overwritten
|
||||
picklefile = open(filename + '.tmp', 'wb')
|
||||
@ -229,6 +263,7 @@ class BuildEnvironment:
|
||||
picklefile.close()
|
||||
movefile(filename + '.tmp', filename)
|
||||
# reset attributes
|
||||
self.domains = domains
|
||||
self.config.values = values
|
||||
self.set_warnfunc(warnfunc)
|
||||
|
||||
@ -242,6 +277,9 @@ class BuildEnvironment:
|
||||
# the application object; only set while update() runs
|
||||
self.app = None
|
||||
|
||||
# all the registered domains, set by the application
|
||||
self.domains = {}
|
||||
|
||||
# the docutils settings for building
|
||||
self.settings = default_settings.copy()
|
||||
self.settings['env'] = self
|
||||
@ -280,16 +318,13 @@ class BuildEnvironment:
|
||||
self.glob_toctrees = set() # docnames that have :glob: toctrees
|
||||
self.numbered_toctrees = set() # docnames that have :numbered: toctrees
|
||||
|
||||
# domain-specific inventories, here to be pickled
|
||||
self.domaindata = {} # domainname -> domain-specific dict
|
||||
|
||||
# X-ref target inventory
|
||||
self.descrefs = {} # fullname -> docname, desctype
|
||||
self.filemodules = {} # docname -> [modules]
|
||||
self.modules = {} # modname -> docname, synopsis,
|
||||
# platform, deprecated
|
||||
self.labels = {} # labelname -> docname, labelid, sectionname
|
||||
self.anonlabels = {} # labelname -> docname, labelid
|
||||
self.progoptions = {} # (program, name) -> docname, labelid
|
||||
self.reftargets = {} # (type, name) -> docname, labelid
|
||||
# type: term, token, envvar, citation
|
||||
self.citations = {} # citation name -> docname, labelid
|
||||
|
||||
# Other inventories
|
||||
self.indexentries = {} # docname -> list of
|
||||
@ -301,14 +336,8 @@ class BuildEnvironment:
|
||||
self.images = FilenameUniqDict()
|
||||
self.dlfiles = FilenameUniqDict()
|
||||
|
||||
# These are set while parsing a file
|
||||
self.docname = None # current document name
|
||||
self.currmodule = None # current module name
|
||||
self.currclass = None # current class name
|
||||
self.currdesc = None # current descref name
|
||||
self.currprogram = None # current program name
|
||||
self.index_num = 0 # autonumber for index targets
|
||||
self.gloss_entries = set() # existing definition labels
|
||||
# temporary data storage while reading a document
|
||||
self.doc_read_data = {}
|
||||
|
||||
# Some magically present labels
|
||||
def add_magic_label(name, description):
|
||||
@ -342,7 +371,6 @@ class BuildEnvironment:
|
||||
self.toc_secnumbers.pop(docname, None)
|
||||
self.toc_num_entries.pop(docname, None)
|
||||
self.toctree_includes.pop(docname, None)
|
||||
self.filemodules.pop(docname, None)
|
||||
self.indexentries.pop(docname, None)
|
||||
self.glob_toctrees.discard(docname)
|
||||
self.numbered_toctrees.discard(docname)
|
||||
@ -353,25 +381,20 @@ class BuildEnvironment:
|
||||
fnset.discard(docname)
|
||||
if not fnset:
|
||||
del self.files_to_rebuild[subfn]
|
||||
for fullname, (fn, _) in self.descrefs.items():
|
||||
if fn == docname:
|
||||
del self.descrefs[fullname]
|
||||
for modname, (fn, _, _, _) in self.modules.items():
|
||||
if fn == docname:
|
||||
del self.modules[modname]
|
||||
for labelname, (fn, _, _) in self.labels.items():
|
||||
if fn == docname:
|
||||
del self.labels[labelname]
|
||||
for key, (fn, _) in self.reftargets.items():
|
||||
for key, (fn, _) in self.citations.items():
|
||||
if fn == docname:
|
||||
del self.reftargets[key]
|
||||
for key, (fn, _) in self.progoptions.items():
|
||||
if fn == docname:
|
||||
del self.progoptions[key]
|
||||
del self.citations[key]
|
||||
for version, changes in self.versionchanges.items():
|
||||
new = [change for change in changes if change[1] != docname]
|
||||
changes[:] = new
|
||||
|
||||
# XXX why does this not work inside the if?
|
||||
for domain in self.domains.values():
|
||||
domain.clear_doc(docname)
|
||||
|
||||
def doc2path(self, docname, base=True, suffix=None):
|
||||
"""
|
||||
Return the filename for the document name.
|
||||
@ -543,6 +566,26 @@ class BuildEnvironment:
|
||||
error.object[error.end:lineend]), lineno)
|
||||
return (u'?', error.end)
|
||||
|
||||
def patch_lookup_functions(self):
|
||||
"""
|
||||
Monkey-patch directive and role dispatch, so that domain-specific
|
||||
markup takes precedence.
|
||||
"""
|
||||
def directive(name, lang_module, document):
|
||||
try:
|
||||
return lookup_domain_element(self, 'directive', name)
|
||||
except ElementLookupError:
|
||||
return orig_directive_function(name, lang_module, document)
|
||||
|
||||
def role(name, lang_module, lineno, reporter):
|
||||
try:
|
||||
return lookup_domain_element(self, 'role', name)
|
||||
except ElementLookupError:
|
||||
return orig_role_function(name, lang_module, lineno, reporter)
|
||||
|
||||
directives.directive = directive
|
||||
roles.role = role
|
||||
|
||||
def read_doc(self, docname, src_path=None, save_parsed=True, app=None):
|
||||
"""
|
||||
Parse a file and add/update inventory entries for the doctree.
|
||||
@ -551,6 +594,7 @@ class BuildEnvironment:
|
||||
# remove all inventory entries for that file
|
||||
if app:
|
||||
app.emit('env-purge-doc', self, docname)
|
||||
|
||||
self.clear_doc(docname)
|
||||
|
||||
if src_path is None:
|
||||
@ -565,12 +609,16 @@ class BuildEnvironment:
|
||||
self.warn(docname, 'default role %s not found' %
|
||||
self.config.default_role)
|
||||
|
||||
self.docname = docname
|
||||
self.doc_read_data['docname'] = docname
|
||||
# defaults to the global default, but can be re-set in a document
|
||||
self.doc_read_data['default_domain'] = \
|
||||
self.domains.get(self.config.default_domain)
|
||||
|
||||
self.settings['input_encoding'] = self.config.source_encoding
|
||||
self.settings['trim_footnote_reference_space'] = \
|
||||
self.config.trim_footnote_reference_space
|
||||
|
||||
codecs.register_error('sphinx', self.warn_and_replace)
|
||||
self.patch_lookup_functions()
|
||||
|
||||
codecs.register_error('sphinx', self.warn_and_replace)
|
||||
|
||||
@ -603,6 +651,8 @@ class BuildEnvironment:
|
||||
doctree = pub.document
|
||||
except UnicodeError, err:
|
||||
raise SphinxError(str(err))
|
||||
|
||||
# post-processing
|
||||
self.filter_messages(doctree)
|
||||
self.process_dependencies(docname, doctree)
|
||||
self.process_images(docname, doctree)
|
||||
@ -614,12 +664,13 @@ class BuildEnvironment:
|
||||
self.note_citations_from(docname, doctree)
|
||||
self.build_toc_from(docname, doctree)
|
||||
|
||||
# store time of reading, used to find outdated files
|
||||
self.all_docs[docname] = time.time()
|
||||
|
||||
# allow extension-specific post-processing
|
||||
if app:
|
||||
app.emit('doctree-read', doctree)
|
||||
|
||||
# store time of reading, used to find outdated files
|
||||
self.all_docs[docname] = time.time()
|
||||
|
||||
# make it picklable
|
||||
doctree.reporter = None
|
||||
doctree.transformer = None
|
||||
@ -631,10 +682,7 @@ class BuildEnvironment:
|
||||
metanode.__class__ = addnodes.meta
|
||||
|
||||
# cleanup
|
||||
self.docname = None
|
||||
self.currmodule = None
|
||||
self.currclass = None
|
||||
self.gloss_entries = set()
|
||||
self.doc_read_data.clear()
|
||||
|
||||
if save_parsed:
|
||||
# save the parsed doctree
|
||||
@ -651,6 +699,35 @@ class BuildEnvironment:
|
||||
else:
|
||||
return doctree
|
||||
|
||||
# utilities to use while reading a document
|
||||
|
||||
@property
|
||||
def docname(self):
|
||||
"""Backwards compatible alias."""
|
||||
return self.doc_read_data['docname']
|
||||
|
||||
@property
|
||||
def currmodule(self):
|
||||
"""Backwards compatible alias."""
|
||||
return self.doc_read_data.get('py_module')
|
||||
|
||||
@property
|
||||
def currclass(self):
|
||||
"""Backwards compatible alias."""
|
||||
return self.doc_read_data.get('py_class')
|
||||
|
||||
def new_serialno(self, category=''):
|
||||
"""Return a serial number, e.g. for index entry targets."""
|
||||
key = category + 'serialno'
|
||||
cur = self.doc_read_data.get(key, 0)
|
||||
self.doc_read_data[key] = cur + 1
|
||||
return cur
|
||||
|
||||
def note_dependency(self, filename):
|
||||
self.dependencies.setdefault(self.docname, set()).add(filename)
|
||||
|
||||
# post-processing of read doctrees
|
||||
|
||||
def filter_messages(self, doctree):
|
||||
"""
|
||||
Filter system messages from a doctree.
|
||||
@ -812,7 +889,7 @@ class BuildEnvironment:
|
||||
if name.isdigit() or node.has_key('refuri') or \
|
||||
node.tagname.startswith('desc_'):
|
||||
# ignore footnote labels, labels automatically generated from a
|
||||
# link and description units
|
||||
# link and object descriptions
|
||||
continue
|
||||
if name in self.labels:
|
||||
self.warn(docname, 'duplicate label %s, ' % name +
|
||||
@ -842,11 +919,11 @@ class BuildEnvironment:
|
||||
def note_citations_from(self, docname, document):
|
||||
for node in document.traverse(nodes.citation):
|
||||
label = node[0].astext()
|
||||
if ('citation', label) in self.reftargets:
|
||||
if label in self.citations:
|
||||
self.warn(docname, 'duplicate citation %s, ' % label +
|
||||
'other instance in %s' % self.doc2path(
|
||||
self.reftargets['citation', label][0]), node.line)
|
||||
self.reftargets['citation', label] = (docname, node['ids'][0])
|
||||
self.citations[label][0]), node.line)
|
||||
self.citations[label] = (docname, node['ids'][0])
|
||||
|
||||
def note_toctree(self, docname, toctreenode):
|
||||
"""Note a TOC tree directive in a document and gather information about
|
||||
@ -934,45 +1011,23 @@ class BuildEnvironment:
|
||||
node['refuri'] = node['anchorname'] or '#'
|
||||
return toc
|
||||
|
||||
def get_toctree_for(self, docname, builder, collapse):
|
||||
def get_toctree_for(self, docname, builder, collapse, maxdepth=0):
|
||||
"""Return the global TOC nodetree."""
|
||||
doctree = self.get_doctree(self.config.master_doc)
|
||||
for toctreenode in doctree.traverse(addnodes.toctree):
|
||||
result = self.resolve_toctree(docname, builder, toctreenode,
|
||||
prune=True, collapse=collapse)
|
||||
prune=True, collapse=collapse,
|
||||
maxdepth=maxdepth)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# -------
|
||||
# these are called from docutils directives and therefore use self.docname
|
||||
#
|
||||
def note_descref(self, fullname, desctype, line):
|
||||
if fullname in self.descrefs:
|
||||
self.warn(self.docname,
|
||||
'duplicate canonical description name %s, ' % fullname +
|
||||
'other instance in ' +
|
||||
self.doc2path(self.descrefs[fullname][0]),
|
||||
line)
|
||||
self.descrefs[fullname] = (self.docname, desctype)
|
||||
|
||||
def note_module(self, modname, synopsis, platform, deprecated):
|
||||
self.modules[modname] = (self.docname, synopsis, platform, deprecated)
|
||||
self.filemodules.setdefault(self.docname, []).append(modname)
|
||||
|
||||
def note_progoption(self, optname, labelid):
|
||||
self.progoptions[self.currprogram, optname] = (self.docname, labelid)
|
||||
|
||||
def note_reftarget(self, type, name, labelid):
|
||||
self.reftargets[type, name] = (self.docname, labelid)
|
||||
|
||||
def note_versionchange(self, type, version, node, lineno):
|
||||
self.versionchanges.setdefault(version, []).append(
|
||||
(type, self.docname, lineno, self.currmodule, self.currdesc,
|
||||
node.astext()))
|
||||
|
||||
def note_dependency(self, filename):
|
||||
self.dependencies.setdefault(self.docname, set()).add(filename)
|
||||
# -------
|
||||
def get_domain(self, domainname):
|
||||
"""Return the domain instance with the specified name.
|
||||
Raises an ExtensionError if the domain is not registered."""
|
||||
try:
|
||||
return self.domains[domainname]
|
||||
except KeyError:
|
||||
raise ExtensionError('Domain %r is not registered' % domainname)
|
||||
|
||||
# --------- RESOLVING REFERENCES AND TOCTREES ------------------------------
|
||||
|
||||
@ -1156,15 +1211,7 @@ class BuildEnvironment:
|
||||
docname, refnode['refuri']) + refnode['anchorname']
|
||||
return newnode
|
||||
|
||||
descroles = frozenset(('data', 'exc', 'func', 'class', 'const',
|
||||
'attr', 'obj', 'meth', 'cfunc', 'cmember',
|
||||
'cdata', 'ctype', 'cmacro'))
|
||||
|
||||
def resolve_references(self, doctree, fromdocname, builder):
|
||||
reftarget_roles = set(('token', 'term', 'citation'))
|
||||
# add all custom xref types too
|
||||
reftarget_roles.update(i[0] for i in additional_xref_types.values())
|
||||
|
||||
for node in doctree.traverse(addnodes.pending_xref):
|
||||
contnode = node[0].deepcopy()
|
||||
newnode = None
|
||||
@ -1173,8 +1220,17 @@ class BuildEnvironment:
|
||||
target = node['reftarget']
|
||||
|
||||
try:
|
||||
if typ == 'ref':
|
||||
if node['refcaption']:
|
||||
if node.has_key('refdomain') and node['refdomain']:
|
||||
# let the domain try to resolve the reference
|
||||
try:
|
||||
domain = self.domains[node['refdomain']]
|
||||
except KeyError:
|
||||
raise NoUri
|
||||
newnode = domain.resolve_xref(self, fromdocname, builder,
|
||||
typ, target, node, contnode)
|
||||
# really hardwired reference types
|
||||
elif typ == 'ref':
|
||||
if node['refexplicit']:
|
||||
# reference to anonymous label; the reference uses
|
||||
# the supplied link caption
|
||||
docname, labelid = self.anonlabels.get(target, ('',''))
|
||||
@ -1221,7 +1277,7 @@ class BuildEnvironment:
|
||||
node.line)
|
||||
newnode = contnode
|
||||
else:
|
||||
if node['refcaption']:
|
||||
if node['refexplicit']:
|
||||
# reference with explicit title
|
||||
caption = node.astext()
|
||||
else:
|
||||
@ -1231,101 +1287,35 @@ class BuildEnvironment:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname)
|
||||
newnode.append(innernode)
|
||||
elif typ == 'citation':
|
||||
docname, labelid = self.citations.get(target, ('', ''))
|
||||
if not docname:
|
||||
self.warn(fromdocname,
|
||||
'citation not found: %s' % target, node.line)
|
||||
newnode = None
|
||||
else:
|
||||
newnode = make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
elif typ == 'keyword':
|
||||
# keywords are referenced by named labels
|
||||
# keywords are oddballs: they are referenced by named labels
|
||||
docname, labelid, _ = self.labels.get(target, ('','',''))
|
||||
if not docname:
|
||||
#self.warn(fromdocname, 'unknown keyword: %s' % target)
|
||||
newnode = contnode
|
||||
newnode = None
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname) + '#' + labelid
|
||||
newnode.append(contnode)
|
||||
elif typ == 'option':
|
||||
progname = node['refprogram']
|
||||
docname, labelid = self.progoptions.get((progname, target),
|
||||
('', ''))
|
||||
if not docname:
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname) + '#' + labelid
|
||||
newnode.append(contnode)
|
||||
elif typ in reftarget_roles:
|
||||
docname, labelid = self.reftargets.get((typ, target),
|
||||
('', ''))
|
||||
if not docname:
|
||||
if typ == 'term':
|
||||
self.warn(fromdocname,
|
||||
'term not in glossary: %s' % target,
|
||||
node.line)
|
||||
elif typ == 'citation':
|
||||
self.warn(fromdocname,
|
||||
'citation not found: %s' % target,
|
||||
node.line)
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname, typ) + '#' + labelid
|
||||
newnode.append(contnode)
|
||||
elif typ == 'mod' or \
|
||||
typ == 'obj' and target in self.modules:
|
||||
docname, synopsis, platform, deprecated = \
|
||||
self.modules.get(target, ('','','', ''))
|
||||
if not docname:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
if not newnode:
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname) + '#module-' + target
|
||||
newnode['reftitle'] = '%s%s%s' % (
|
||||
(platform and '(%s) ' % platform),
|
||||
synopsis, (deprecated and ' (deprecated)' or ''))
|
||||
newnode.append(contnode)
|
||||
elif typ in self.descroles:
|
||||
# "descrefs"
|
||||
modname = node['modname']
|
||||
clsname = node['classname']
|
||||
searchorder = node.hasattr('refspecific') and 1 or 0
|
||||
name, desc = self.find_desc(modname, clsname,
|
||||
target, typ, searchorder)
|
||||
if not desc:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
if not newnode:
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if desc[0] == fromdocname:
|
||||
newnode['refid'] = name
|
||||
else:
|
||||
newnode['refuri'] = (
|
||||
builder.get_relative_uri(fromdocname, desc[0])
|
||||
+ '#' + name)
|
||||
newnode['reftitle'] = name
|
||||
newnode.append(contnode)
|
||||
newnode = make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
else:
|
||||
raise RuntimeError('unknown xfileref node encountered: %s'
|
||||
% node)
|
||||
|
||||
# no new node found? try the missing-reference event
|
||||
if newnode is None:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
except NoUri:
|
||||
newnode = contnode
|
||||
if newnode:
|
||||
node.replace_self(newnode)
|
||||
node.replace_self(newnode or contnode)
|
||||
|
||||
for node in doctree.traverse(addnodes.only):
|
||||
try:
|
||||
@ -1556,116 +1546,3 @@ class BuildEnvironment:
|
||||
# the master file is not included anywhere ;)
|
||||
continue
|
||||
self.warn(docname, 'document isn\'t included in any toctree')
|
||||
|
||||
# --------- QUERYING -------------------------------------------------------
|
||||
|
||||
def find_desc(self, modname, classname, name, type, searchorder=0):
|
||||
"""Find a description node matching "name", perhaps using
|
||||
the given module and/or classname."""
|
||||
# skip parens
|
||||
if name[-2:] == '()':
|
||||
name = name[:-2]
|
||||
|
||||
if not name:
|
||||
return None, None
|
||||
|
||||
# don't add module and class names for C things
|
||||
if type[0] == 'c' and type not in ('class', 'const'):
|
||||
# skip trailing star and whitespace
|
||||
name = name.rstrip(' *')
|
||||
if name in self.descrefs and self.descrefs[name][1][0] == 'c':
|
||||
return name, self.descrefs[name]
|
||||
return None, None
|
||||
|
||||
newname = None
|
||||
if searchorder == 1:
|
||||
if modname and classname and \
|
||||
modname + '.' + classname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
elif modname and modname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + name
|
||||
elif name in self.descrefs:
|
||||
newname = name
|
||||
else:
|
||||
if name in self.descrefs:
|
||||
newname = name
|
||||
elif modname and modname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + name
|
||||
elif modname and classname and \
|
||||
modname + '.' + classname + '.' + name in self.descrefs:
|
||||
newname = modname + '.' + classname + '.' + name
|
||||
# special case: builtin exceptions have module "exceptions" set
|
||||
elif type == 'exc' and '.' not in name and \
|
||||
'exceptions.' + name in self.descrefs:
|
||||
newname = 'exceptions.' + name
|
||||
# special case: object methods
|
||||
elif type in ('func', 'meth') and '.' not in name and \
|
||||
'object.' + name in self.descrefs:
|
||||
newname = 'object.' + name
|
||||
if newname is None:
|
||||
return None, None
|
||||
return newname, self.descrefs[newname]
|
||||
|
||||
def find_keyword(self, keyword, avoid_fuzzy=False, cutoff=0.6, n=20):
|
||||
"""
|
||||
Find keyword matches for a keyword. If there's an exact match,
|
||||
just return it, else return a list of fuzzy matches if avoid_fuzzy
|
||||
isn't True.
|
||||
|
||||
Keywords searched are: first modules, then descrefs.
|
||||
|
||||
Returns: None if nothing found
|
||||
(type, docname, anchorname) if exact match found
|
||||
list of (quality, type, docname, anchorname, description)
|
||||
if fuzzy
|
||||
"""
|
||||
|
||||
if keyword in self.modules:
|
||||
docname, title, system, deprecated = self.modules[keyword]
|
||||
return 'module', docname, 'module-' + keyword
|
||||
if keyword in self.descrefs:
|
||||
docname, ref_type = self.descrefs[keyword]
|
||||
return ref_type, docname, keyword
|
||||
# special cases
|
||||
if '.' not in keyword:
|
||||
# exceptions are documented in the exceptions module
|
||||
if 'exceptions.'+keyword in self.descrefs:
|
||||
docname, ref_type = self.descrefs['exceptions.'+keyword]
|
||||
return ref_type, docname, 'exceptions.'+keyword
|
||||
# special methods are documented as object methods
|
||||
if 'object.'+keyword in self.descrefs:
|
||||
docname, ref_type = self.descrefs['object.'+keyword]
|
||||
return ref_type, docname, 'object.'+keyword
|
||||
|
||||
if avoid_fuzzy:
|
||||
return
|
||||
|
||||
# find fuzzy matches
|
||||
s = difflib.SequenceMatcher()
|
||||
s.set_seq2(keyword.lower())
|
||||
|
||||
def possibilities():
|
||||
for title, (fn, desc, _, _) in self.modules.iteritems():
|
||||
yield ('module', fn, 'module-'+title, desc)
|
||||
for title, (fn, desctype) in self.descrefs.iteritems():
|
||||
yield (desctype, fn, title, '')
|
||||
|
||||
def dotsearch(string):
|
||||
parts = string.lower().split('.')
|
||||
for idx in xrange(0, len(parts)):
|
||||
yield '.'.join(parts[idx:])
|
||||
|
||||
result = []
|
||||
for type, docname, title, desc in possibilities():
|
||||
best_res = 0
|
||||
for part in dotsearch(title):
|
||||
s.set_seq1(part)
|
||||
if s.real_quick_ratio() >= cutoff and \
|
||||
s.quick_ratio() >= cutoff and \
|
||||
s.ratio() >= cutoff and \
|
||||
s.ratio() > best_res:
|
||||
best_res = s.ratio()
|
||||
if best_res:
|
||||
result.append((best_res, type, docname, title, desc))
|
||||
|
||||
return heapq.nlargest(n, result)
|
||||
|
@ -392,9 +392,11 @@ class Documenter(object):
|
||||
|
||||
def add_directive_header(self, sig):
|
||||
"""Add the directive header and options to the generated content."""
|
||||
domain = getattr(self, 'domain', 'py')
|
||||
directive = getattr(self, 'directivetype', self.objtype)
|
||||
name = self.format_name()
|
||||
self.add_line(u'.. %s:: %s%s' % (directive, name, sig), '<autodoc>')
|
||||
self.add_line(u'.. %s:%s:: %s%s' % (domain, directive, name, sig),
|
||||
'<autodoc>')
|
||||
if self.options.noindex:
|
||||
self.add_line(u' :noindex:', '<autodoc>')
|
||||
if self.objpath:
|
||||
@ -548,9 +550,9 @@ class Documenter(object):
|
||||
do all members, else those given by *self.options.members*.
|
||||
"""
|
||||
# set current namespace for finding members
|
||||
self.env.autodoc_current_module = self.modname
|
||||
self.env.doc_read_data['autodoc_module'] = self.modname
|
||||
if self.objpath:
|
||||
self.env.autodoc_current_class = self.objpath[0]
|
||||
self.env.doc_read_data['autodoc_class'] = self.objpath[0]
|
||||
|
||||
want_all = all_members or self.options.inherited_members or \
|
||||
self.options.members is ALL
|
||||
@ -591,8 +593,8 @@ class Documenter(object):
|
||||
check_module=members_check_module)
|
||||
|
||||
# reset current objects
|
||||
self.env.autodoc_current_module = None
|
||||
self.env.autodoc_current_class = None
|
||||
self.env.doc_read_data['autodoc_module'] = None
|
||||
self.env.doc_read_data['autodoc_class'] = None
|
||||
|
||||
def generate(self, more_content=None, real_modname=None,
|
||||
check_module=False, all_members=False):
|
||||
@ -750,11 +752,10 @@ class ModuleLevelDocumenter(Documenter):
|
||||
else:
|
||||
# if documenting a toplevel object without explicit module,
|
||||
# it can be contained in another auto directive ...
|
||||
if hasattr(self.env, 'autodoc_current_module'):
|
||||
modname = self.env.autodoc_current_module
|
||||
modname = self.env.doc_read_data.get('autodoc_module')
|
||||
# ... or in the scope of a module directive
|
||||
if not modname:
|
||||
modname = self.env.currmodule
|
||||
modname = self.env.doc_read_data.get('py_module')
|
||||
# ... else, it stays None, which means invalid
|
||||
return modname, parents + [base]
|
||||
|
||||
@ -773,21 +774,20 @@ class ClassLevelDocumenter(Documenter):
|
||||
# if documenting a class-level object without path,
|
||||
# there must be a current class, either from a parent
|
||||
# auto directive ...
|
||||
if hasattr(self.env, 'autodoc_current_class'):
|
||||
mod_cls = self.env.autodoc_current_class
|
||||
mod_cls = self.env.doc_read_data.get('autodoc_class')
|
||||
# ... or from a class directive
|
||||
if mod_cls is None:
|
||||
mod_cls = self.env.currclass
|
||||
mod_cls = self.env.doc_read_data.get('py_class')
|
||||
# ... if still None, there's no way to know
|
||||
if mod_cls is None:
|
||||
return None, []
|
||||
modname, cls = rpartition(mod_cls, '.')
|
||||
parents = [cls]
|
||||
# if the module name is still missing, get it like above
|
||||
if not modname and hasattr(self.env, 'autodoc_current_module'):
|
||||
modname = self.env.autodoc_current_module
|
||||
if not modname:
|
||||
modname = self.env.currmodule
|
||||
modname = self.env.doc_read_data.get('autodoc_module')
|
||||
if not modname:
|
||||
modname = self.env.doc_read_data.get('py_module')
|
||||
# ... else, it stays None, which means invalid
|
||||
return modname, parents + [base]
|
||||
|
||||
@ -1091,7 +1091,7 @@ class AutoDirective(Directive):
|
||||
# record all filenames as dependencies -- this will at least
|
||||
# partially make automatic invalidation possible
|
||||
for fn in self.filename_set:
|
||||
self.env.note_dependency(fn)
|
||||
self.state.document.settings.record_dependencies.add(fn)
|
||||
|
||||
# use a custom reporter that correctly assigns lines to source
|
||||
# filename/description and lineno
|
||||
|
@ -228,8 +228,9 @@ class Autosummary(Directive):
|
||||
env = self.state.document.settings.env
|
||||
|
||||
prefixes = ['']
|
||||
if env.currmodule:
|
||||
prefixes.insert(0, env.currmodule)
|
||||
currmodule = env.doc_read_data.get('py_module')
|
||||
if currmodule:
|
||||
prefixes.insert(0, currmodule)
|
||||
|
||||
items = []
|
||||
|
||||
@ -443,8 +444,9 @@ def autolink_role(typ, rawtext, etext, lineno, inliner,
|
||||
Expands to ':obj:`text`' if `text` is an object that can be imported;
|
||||
otherwise expands to '*text*'.
|
||||
"""
|
||||
r = roles.xfileref_role('obj', rawtext, etext, lineno, inliner,
|
||||
options, content)
|
||||
env = inliner.document.settings.env
|
||||
r = env.get_domain('py').role('obj')(
|
||||
'obj', rawtext, etext, lineno, inliner, options, content)
|
||||
pnode = r[0][0]
|
||||
|
||||
prefixes = [None]
|
||||
|
@ -79,6 +79,7 @@ class CoverageBuilder(Builder):
|
||||
|
||||
def build_c_coverage(self):
|
||||
# Fetch all the info from the header files
|
||||
c_objects = self.env.domaindata['c']['objects']
|
||||
for filename in self.c_sourcefiles:
|
||||
undoc = []
|
||||
f = open(filename, 'r')
|
||||
@ -88,7 +89,7 @@ class CoverageBuilder(Builder):
|
||||
match = regex.match(line)
|
||||
if match:
|
||||
name = match.groups()[0]
|
||||
if name not in self.env.descrefs:
|
||||
if name not in c_objects:
|
||||
for exp in self.c_ignorexps.get(key, ()):
|
||||
if exp.match(name):
|
||||
break
|
||||
@ -116,7 +117,10 @@ class CoverageBuilder(Builder):
|
||||
op.close()
|
||||
|
||||
def build_py_coverage(self):
|
||||
for mod_name in self.env.modules:
|
||||
objects = self.env.domaindata['py']['objects']
|
||||
modules = self.env.domaindata['py']['modules']
|
||||
|
||||
for mod_name in modules:
|
||||
ignore = False
|
||||
for exp in self.mod_ignorexps:
|
||||
if exp.match(mod_name):
|
||||
@ -151,7 +155,7 @@ class CoverageBuilder(Builder):
|
||||
full_name = '%s.%s' % (mod_name, name)
|
||||
|
||||
if inspect.isfunction(obj):
|
||||
if full_name not in self.env.descrefs:
|
||||
if full_name not in objects:
|
||||
for exp in self.fun_ignorexps:
|
||||
if exp.match(name):
|
||||
break
|
||||
@ -162,7 +166,7 @@ class CoverageBuilder(Builder):
|
||||
if exp.match(name):
|
||||
break
|
||||
else:
|
||||
if full_name not in self.env.descrefs:
|
||||
if full_name not in objects:
|
||||
# not documented at all
|
||||
classes[name] = []
|
||||
continue
|
||||
@ -176,7 +180,7 @@ class CoverageBuilder(Builder):
|
||||
continue
|
||||
|
||||
full_attr_name = '%s.%s' % (full_name, attr_name)
|
||||
if full_attr_name not in self.env.descrefs:
|
||||
if full_attr_name not in objects:
|
||||
attrs.append(attr_name)
|
||||
|
||||
if attrs:
|
||||
|
@ -47,7 +47,6 @@ except ImportError:
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx.roles import xfileref_role
|
||||
from sphinx.ext.graphviz import render_dot_html, render_dot_latex
|
||||
from sphinx.util.compat import Directive
|
||||
|
||||
@ -280,10 +279,12 @@ class InheritanceDiagram(Directive):
|
||||
node.document = self.state.document
|
||||
env = self.state.document.settings.env
|
||||
class_names = self.arguments[0].split()
|
||||
class_role = env.get_domain('py').role('class')
|
||||
|
||||
# Create a graph starting with the list of classes
|
||||
try:
|
||||
graph = InheritanceGraph(class_names, env.currmodule)
|
||||
graph = InheritanceGraph(class_names,
|
||||
env.doc_read_data.get('py_module'))
|
||||
except InheritanceException, err:
|
||||
return [node.document.reporter.warning(err.args[0],
|
||||
line=self.lineno)]
|
||||
@ -293,7 +294,7 @@ class InheritanceDiagram(Directive):
|
||||
# references to real URLs later. These nodes will eventually be
|
||||
# removed from the doctree after we're done with them.
|
||||
for name in graph.get_all_class_names():
|
||||
refnodes, x = xfileref_role(
|
||||
refnodes, x = class_role(
|
||||
'class', ':class:`%s`' % name, name, 0, self.state)
|
||||
node.extend(refnodes)
|
||||
# Store the graph object so we can use it to generate the
|
||||
|
@ -3,17 +3,17 @@
|
||||
sphinx.ext.intersphinx
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Insert links to Python objects documented in remote Sphinx documentation.
|
||||
Insert links to objects documented in remote Sphinx documentation.
|
||||
|
||||
This works as follows:
|
||||
|
||||
* Each Sphinx HTML build creates a file named "objects.inv" that contains
|
||||
a mapping from Python identifiers to URIs relative to the HTML set's root.
|
||||
* Each Sphinx HTML build creates a file named "objects.inv" that contains a
|
||||
mapping from object names to URIs relative to the HTML set's root.
|
||||
|
||||
* Projects using the Intersphinx extension can specify links to such mapping
|
||||
files in the `intersphinx_mapping` config value. The mapping will then be
|
||||
used to resolve otherwise missing references to Python objects into links
|
||||
to the other documentation.
|
||||
used to resolve otherwise missing references to objects into links to the
|
||||
other documentation.
|
||||
|
||||
* By default, the mapping file is assumed to be at the same location as the
|
||||
rest of the documentation; however, the location of the mapping file can
|
||||
@ -25,6 +25,7 @@
|
||||
"""
|
||||
|
||||
import time
|
||||
import zlib
|
||||
import urllib2
|
||||
import posixpath
|
||||
from os import path
|
||||
@ -41,12 +42,68 @@ if hasattr(urllib2, 'HTTPSHandler'):
|
||||
urllib2.install_opener(urllib2.build_opener(*handlers))
|
||||
|
||||
|
||||
def read_inventory_v1(f, uri, join):
|
||||
invdata = {}
|
||||
line = f.next()
|
||||
projname = line.rstrip()[11:].decode('utf-8')
|
||||
line = f.next()
|
||||
version = line.rstrip()[11:]
|
||||
for line in f:
|
||||
name, type, location = line.rstrip().split(None, 2)
|
||||
location = join(uri, location)
|
||||
# version 1 did not add anchors to the location
|
||||
if type == 'mod':
|
||||
type = 'py:module'
|
||||
location += '#module-' + name
|
||||
else:
|
||||
type = 'py:' + type
|
||||
location += '#' + name
|
||||
invdata.setdefault(type, {})[name] = (projname, version, location)
|
||||
return invdata
|
||||
|
||||
|
||||
def read_inventory_v2(f, uri, join, bufsize=16*1024):
|
||||
invdata = {}
|
||||
line = f.readline()
|
||||
projname = line.rstrip()[11:].decode('utf-8')
|
||||
line = f.readline()
|
||||
version = line.rstrip()[11:]
|
||||
line = f.readline()
|
||||
if 'zlib' not in line:
|
||||
raise ValueError
|
||||
|
||||
def read_chunks():
|
||||
decompressor = zlib.decompressobj()
|
||||
for chunk in iter(lambda: f.read(bufsize), ''):
|
||||
yield decompressor.decompress(chunk)
|
||||
yield decompressor.flush()
|
||||
|
||||
def split_lines(iter):
|
||||
buf = ''
|
||||
for chunk in iter:
|
||||
buf += chunk
|
||||
lineend = buf.find('\n')
|
||||
while lineend != -1:
|
||||
yield buf[:lineend]
|
||||
buf = buf[lineend+1:]
|
||||
lineend = buf.find('\n')
|
||||
assert not buf
|
||||
|
||||
for line in split_lines(read_chunks()):
|
||||
name, type, prio, location = line.rstrip().split(None, 3)
|
||||
if location.endswith('$'):
|
||||
location = location[:-1] + name
|
||||
location = join(uri, location)
|
||||
invdata.setdefault(type, {})[name] = (projname, version, location)
|
||||
return invdata
|
||||
|
||||
|
||||
def fetch_inventory(app, uri, inv):
|
||||
"""Fetch, parse and return an intersphinx inventory file."""
|
||||
invdata = {}
|
||||
# both *uri* (base URI of the links to generate) and *inv* (actual
|
||||
# location of the inventory file) can be local or remote URIs
|
||||
localuri = uri.find('://') == -1
|
||||
join = localuri and path.join or posixpath.join
|
||||
try:
|
||||
if inv.find('://') != -1:
|
||||
f = urllib2.urlopen(inv)
|
||||
@ -57,24 +114,21 @@ def fetch_inventory(app, uri, inv):
|
||||
'%s: %s' % (inv, err.__class__, err))
|
||||
return
|
||||
try:
|
||||
line = f.next()
|
||||
if line.rstrip() != '# Sphinx inventory version 1':
|
||||
raise ValueError('unknown or unsupported inventory version')
|
||||
line = f.next()
|
||||
projname = line.rstrip()[11:].decode('utf-8')
|
||||
line = f.next()
|
||||
version = line.rstrip()[11:]
|
||||
for line in f:
|
||||
name, type, location = line.rstrip().split(None, 2)
|
||||
if localuri:
|
||||
location = path.join(uri, location)
|
||||
line = f.readline().rstrip()
|
||||
try:
|
||||
if line == '# Sphinx inventory version 1':
|
||||
invdata = read_inventory_v1(f, uri, join)
|
||||
elif line == '# Sphinx inventory version 2':
|
||||
invdata = read_inventory_v2(f, uri, join)
|
||||
else:
|
||||
location = posixpath.join(uri, location)
|
||||
invdata[name] = (type, projname, version, location)
|
||||
f.close()
|
||||
raise ValueError
|
||||
f.close()
|
||||
except ValueError:
|
||||
f.close()
|
||||
raise ValueError('unknown or unsupported inventory version')
|
||||
except Exception, err:
|
||||
app.warn('intersphinx inventory %r not readable due to '
|
||||
'%s: %s' % (inv, err.__class__, err))
|
||||
'%s: %s' % (inv, err.__class__.__name__, err))
|
||||
else:
|
||||
return invdata
|
||||
|
||||
@ -110,31 +164,24 @@ def load_mappings(app):
|
||||
|
||||
def missing_reference(app, env, node, contnode):
|
||||
"""Attempt to resolve a missing reference via intersphinx references."""
|
||||
type = node['reftype']
|
||||
domain = node.get('refdomain')
|
||||
if not domain:
|
||||
# only objects in domains are in the inventory
|
||||
return
|
||||
target = node['reftarget']
|
||||
if type == 'mod':
|
||||
type, proj, version, uri = env.intersphinx_inventory.get(target,
|
||||
('','','',''))
|
||||
if type != 'mod':
|
||||
return None
|
||||
target = 'module-' + target # for link anchor
|
||||
objtypes = env.domains[domain].objtypes_for_role(node['reftype'])
|
||||
if not objtypes:
|
||||
return
|
||||
for objtype in objtypes:
|
||||
fulltype = '%s:%s' % (domain, objtype)
|
||||
if fulltype in env.intersphinx_inventory and \
|
||||
target in env.intersphinx_inventory[fulltype]:
|
||||
break
|
||||
else:
|
||||
if target[-2:] == '()':
|
||||
target = target[:-2]
|
||||
target = target.rstrip(' *')
|
||||
# special case: exceptions and object methods
|
||||
if type == 'exc' and '.' not in target and \
|
||||
'exceptions.' + target in env.intersphinx_inventory:
|
||||
target = 'exceptions.' + target
|
||||
elif type in ('func', 'meth') and '.' not in target and \
|
||||
'object.' + target in env.intersphinx_inventory:
|
||||
target = 'object.' + target
|
||||
if target not in env.intersphinx_inventory:
|
||||
return None
|
||||
type, proj, version, uri = env.intersphinx_inventory[target]
|
||||
# print "Intersphinx hit:", target, uri
|
||||
return
|
||||
proj, version, uri = env.intersphinx_inventory[fulltype][target]
|
||||
newnode = nodes.reference('', '')
|
||||
newnode['refuri'] = uri + '#' + target
|
||||
newnode['refuri'] = uri
|
||||
newnode['reftitle'] = '(in %s v%s)' % (proj, version)
|
||||
newnode['class'] = 'external-xref'
|
||||
newnode.append(contnode)
|
||||
|
@ -69,7 +69,7 @@ class Refcounts(dict):
|
||||
def add_refcount_annotations(self, app, doctree):
|
||||
for node in doctree.traverse(addnodes.desc_content):
|
||||
par = node.parent
|
||||
if par['desctype'] != 'cfunction':
|
||||
if par['domain'] != 'c' or par['objtype'] != 'function':
|
||||
continue
|
||||
if not par[0].has_key('names') or not par[0]['names']:
|
||||
continue
|
||||
|
@ -34,9 +34,7 @@ class Todo(Directive):
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
|
||||
targetid = "todo-%s" % env.index_num
|
||||
env.index_num += 1
|
||||
targetid = 'index-%s' % env.new_serialno('index')
|
||||
targetnode = nodes.target('', '', ids=[targetid])
|
||||
|
||||
ad = make_admonition(todo_node, self.name, [_('Todo')], self.options,
|
||||
|
@ -93,7 +93,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
||||
# make the paths into loaders
|
||||
self.loaders = map(SphinxFileSystemLoader, chain)
|
||||
|
||||
use_i18n = builder.translator is not None
|
||||
use_i18n = builder.app.translator is not None
|
||||
extensions = use_i18n and ['jinja2.ext.i18n'] or []
|
||||
self.environment = SandboxedEnvironment(loader=self,
|
||||
extensions=extensions)
|
||||
@ -101,7 +101,8 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
||||
self.environment.globals['debug'] = contextfunction(pformat)
|
||||
self.environment.globals['accesskey'] = contextfunction(accesskey)
|
||||
if use_i18n:
|
||||
self.environment.install_gettext_translations(builder.translator)
|
||||
self.environment.install_gettext_translations(
|
||||
builder.app.translator)
|
||||
|
||||
def render(self, template, context):
|
||||
return self.environment.get_template(template).render(context)
|
||||
|
@ -8,41 +8,179 @@
|
||||
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import gettext
|
||||
import UserString
|
||||
|
||||
from sphinx import package_dir
|
||||
|
||||
|
||||
class _TranslationProxy(UserString.UserString, object):
|
||||
"""Class for proxy strings from gettext translations. This is a helper
|
||||
for the lazy_* functions from this module.
|
||||
|
||||
The proxy implementation attempts to be as complete as possible, so that
|
||||
the lazy objects should mostly work as expected, for example for sorting.
|
||||
|
||||
This inherits from UserString because some docutils versions use UserString
|
||||
for their Text nodes, which then checks its argument for being either a
|
||||
basestring or UserString, otherwise calls str() -- not unicode() -- on it.
|
||||
This also inherits from object to make the __new__ method work.
|
||||
"""
|
||||
__slots__ = ('_func', '_args')
|
||||
|
||||
def __new__(cls, func, *args):
|
||||
if not args:
|
||||
# not called with "function" and "arguments", but a plain string
|
||||
return unicode(func)
|
||||
return object.__new__(cls)
|
||||
|
||||
def __init__(self, func, *args):
|
||||
self._func = func
|
||||
self._args = args
|
||||
|
||||
data = property(lambda x: x._func(*x._args))
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.data
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(self.data)
|
||||
|
||||
def __dir__(self):
|
||||
return dir(unicode)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.data)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.data)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.data)
|
||||
|
||||
def __add__(self, other):
|
||||
return self.data + other
|
||||
|
||||
def __radd__(self, other):
|
||||
return other + self.data
|
||||
|
||||
def __mod__(self, other):
|
||||
return self.data % other
|
||||
|
||||
def __rmod__(self, other):
|
||||
return other % self.data
|
||||
|
||||
def __mul__(self, other):
|
||||
return self.data * other
|
||||
|
||||
def __rmul__(self, other):
|
||||
return other * self.data
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.data < other
|
||||
|
||||
def __le__(self, other):
|
||||
return self.data <= other
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.data == other
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.data != other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.data > other
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.data >= other
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name == '__members__':
|
||||
return self.__dir__()
|
||||
return getattr(self.data, name)
|
||||
|
||||
def __getstate__(self):
|
||||
return self._func, self._args
|
||||
|
||||
def __setstate__(self, tup):
|
||||
self._func, self._args = tup
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.data[key]
|
||||
|
||||
def __copy__(self):
|
||||
return self
|
||||
|
||||
def __repr__(self):
|
||||
try:
|
||||
return 'i' + repr(unicode(self.data))
|
||||
except:
|
||||
return '<%s broken>' % self.__class__.__name__
|
||||
|
||||
def mygettext(string):
|
||||
"""Used instead of _ when creating TranslationProxies, because _ is
|
||||
not bound yet at that time."""
|
||||
return _(string)
|
||||
|
||||
def lazy_gettext(string):
|
||||
"""A lazy version of `gettext`."""
|
||||
#if isinstance(string, _TranslationProxy):
|
||||
# return string
|
||||
return _TranslationProxy(mygettext, string)
|
||||
|
||||
l_ = lazy_gettext
|
||||
|
||||
_ = lambda x: x
|
||||
|
||||
admonitionlabels = {
|
||||
'attention': _('Attention'),
|
||||
'caution': _('Caution'),
|
||||
'danger': _('Danger'),
|
||||
'error': _('Error'),
|
||||
'hint': _('Hint'),
|
||||
'important': _('Important'),
|
||||
'note': _('Note'),
|
||||
'seealso': _('See Also'),
|
||||
'tip': _('Tip'),
|
||||
'warning': _('Warning'),
|
||||
'attention': l_('Attention'),
|
||||
'caution': l_('Caution'),
|
||||
'danger': l_('Danger'),
|
||||
'error': l_('Error'),
|
||||
'hint': l_('Hint'),
|
||||
'important': l_('Important'),
|
||||
'note': l_('Note'),
|
||||
'seealso': l_('See Also'),
|
||||
'tip': l_('Tip'),
|
||||
'warning': l_('Warning'),
|
||||
}
|
||||
|
||||
versionlabels = {
|
||||
'versionadded': _('New in version %s'),
|
||||
'versionchanged': _('Changed in version %s'),
|
||||
'deprecated': _('Deprecated since version %s'),
|
||||
'versionadded': l_('New in version %s'),
|
||||
'versionchanged': l_('Changed in version %s'),
|
||||
'deprecated': l_('Deprecated since version %s'),
|
||||
}
|
||||
|
||||
pairindextypes = {
|
||||
'module': _('module'),
|
||||
'keyword': _('keyword'),
|
||||
'operator': _('operator'),
|
||||
'object': _('object'),
|
||||
'exception': _('exception'),
|
||||
'statement': _('statement'),
|
||||
'builtin': _('built-in function'),
|
||||
'module': l_('module'),
|
||||
'keyword': l_('keyword'),
|
||||
'operator': l_('operator'),
|
||||
'object': l_('object'),
|
||||
'exception': l_('exception'),
|
||||
'statement': l_('statement'),
|
||||
'builtin': l_('built-in function'),
|
||||
}
|
||||
|
||||
del _
|
||||
|
||||
def init():
|
||||
for dct in (admonitionlabels, versionlabels, pairindextypes):
|
||||
for key in dct:
|
||||
dct[key] = _(dct[key])
|
||||
def init(locale_dirs, language):
|
||||
# the None entry is the system's default locale path
|
||||
translator = None
|
||||
has_translation = True
|
||||
for dir_ in locale_dirs:
|
||||
try:
|
||||
trans = gettext.translation('sphinx', localedir=dir_,
|
||||
languages=[language])
|
||||
if translator is None:
|
||||
translator = trans
|
||||
else:
|
||||
translator._catalog.update(trans._catalog)
|
||||
except Exception:
|
||||
# Language couldn't be found in the specified path
|
||||
pass
|
||||
if translator is None:
|
||||
translator = gettext.NullTranslations()
|
||||
has_translation = False
|
||||
translator.install(unicode=True)
|
||||
return translator, has_translation
|
||||
|
1
sphinx/locale/ca/LC_MESSAGES/sphinx.js
Normal file
1
sphinx/locale/ca/LC_MESSAGES/sphinx.js
Normal file
@ -0,0 +1 @@
|
||||
Documentation.addTranslations({"locale": "ca", "plural_expr": "(n != 1)", "messages": {"Search Results": "Resultats de la Cerca", "Preparing search...": "Preparant la cerca...", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "La teva cerca no ha donat resultats. Assegura't que totes les paraules estan ben escrites i que has seleccionat prou categories.", "Search finished, found %s page(s) matching the search query.": "Cerca finalitzada, s'han trobat %s p\u00e0gin(a/es) de resultats.", ", in ": ", a ", "Permalink to this headline": "Link permanent a aquest t\u00edtol", "Searching": "Cercant", "Permalink to this definition": "Link permanent a aquesta definici\u00f3", "module, in ": "m\u00f2dule, a ", "Hide Search Matches": "Oculta Resultats de Cerca"}});
|
BIN
sphinx/locale/ca/LC_MESSAGES/sphinx.mo
Normal file
BIN
sphinx/locale/ca/LC_MESSAGES/sphinx.mo
Normal file
Binary file not shown.
606
sphinx/locale/ca/LC_MESSAGES/sphinx.po
Normal file
606
sphinx/locale/ca/LC_MESSAGES/sphinx.po
Normal file
@ -0,0 +1,606 @@
|
||||
# Catalan translations for Sphinx.
|
||||
# Copyright (C) 2009 ORGANIZATION
|
||||
# This file is distributed under the same license as the Sphinx project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx 1.0\n"
|
||||
"Report-Msgid-Bugs-To: pau.fernandez@upc.edu\n"
|
||||
"POT-Creation-Date: 2009-05-22 18:51+0200\n"
|
||||
"PO-Revision-Date: 2009-06-07 14:20+0200\n"
|
||||
"Last-Translator: Pau Fernández <pau.fernandez@upc.edu>\n"
|
||||
"Language-Team: ca <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 0.9.4\n"
|
||||
|
||||
#: sphinx/environment.py:104 sphinx/writers/latex.py:184
|
||||
#, python-format
|
||||
msgid "%B %d, %Y"
|
||||
msgstr "%d de %B de %Y"
|
||||
|
||||
#: sphinx/environment.py:323 sphinx/themes/basic/genindex-single.html:2
|
||||
#: sphinx/themes/basic/genindex-split.html:2
|
||||
#: sphinx/themes/basic/genindex-split.html:5
|
||||
#: sphinx/themes/basic/genindex.html:2 sphinx/themes/basic/genindex.html:5
|
||||
#: sphinx/themes/basic/genindex.html:48 sphinx/themes/basic/layout.html:131
|
||||
#: sphinx/writers/latex.py:190
|
||||
msgid "Index"
|
||||
msgstr "Índex"
|
||||
|
||||
#: sphinx/environment.py:324 sphinx/writers/latex.py:189
|
||||
msgid "Module Index"
|
||||
msgstr "Índex de Mòduls"
|
||||
|
||||
#: sphinx/environment.py:325 sphinx/themes/basic/defindex.html:16
|
||||
msgid "Search Page"
|
||||
msgstr "Pàgina de Cerca"
|
||||
|
||||
#: sphinx/roles.py:55 sphinx/directives/desc.py:747
|
||||
#, python-format
|
||||
msgid "environment variable; %s"
|
||||
msgstr "variable d'entorn; %s"
|
||||
|
||||
#: sphinx/roles.py:62
|
||||
#, python-format
|
||||
msgid "Python Enhancement Proposals!PEP %s"
|
||||
msgstr "Python Enhancement Proposals!PEP %s"
|
||||
|
||||
#: sphinx/builders/changes.py:71
|
||||
msgid "Builtins"
|
||||
msgstr "Mòduls Interns"
|
||||
|
||||
#: sphinx/builders/changes.py:73
|
||||
msgid "Module level"
|
||||
msgstr "Nivell de mòdul"
|
||||
|
||||
#: sphinx/builders/html.py:219
|
||||
#, python-format
|
||||
msgid "%b %d, %Y"
|
||||
msgstr "%d %b, %Y"
|
||||
|
||||
#: sphinx/builders/html.py:238 sphinx/themes/basic/defindex.html:21
|
||||
msgid "General Index"
|
||||
msgstr "Índex General"
|
||||
|
||||
#: sphinx/builders/html.py:238
|
||||
msgid "index"
|
||||
msgstr "índex"
|
||||
|
||||
#: sphinx/builders/html.py:240 sphinx/builders/htmlhelp.py:184
|
||||
#: sphinx/builders/qthelp.py:132 sphinx/themes/basic/defindex.html:19
|
||||
#: sphinx/themes/basic/modindex.html:2 sphinx/themes/basic/modindex.html:13
|
||||
msgid "Global Module Index"
|
||||
msgstr "Índex Global de Mòduls"
|
||||
|
||||
#: sphinx/builders/html.py:241
|
||||
msgid "modules"
|
||||
msgstr "mòduls"
|
||||
|
||||
#: sphinx/builders/html.py:296
|
||||
msgid "next"
|
||||
msgstr "següent"
|
||||
|
||||
#: sphinx/builders/html.py:305
|
||||
msgid "previous"
|
||||
msgstr "anterior"
|
||||
|
||||
#: sphinx/builders/latex.py:162
|
||||
msgid " (in "
|
||||
msgstr " (a "
|
||||
|
||||
#: sphinx/directives/desc.py:97
|
||||
msgid "Raises"
|
||||
msgstr "Llença"
|
||||
|
||||
#: sphinx/directives/desc.py:101
|
||||
msgid "Variable"
|
||||
msgstr "Variable"
|
||||
|
||||
#: sphinx/directives/desc.py:104
|
||||
msgid "Returns"
|
||||
msgstr "Retorna"
|
||||
|
||||
#: sphinx/directives/desc.py:113
|
||||
msgid "Return type"
|
||||
msgstr "Tipus de retorn"
|
||||
|
||||
#: sphinx/directives/desc.py:186
|
||||
msgid "Parameter"
|
||||
msgstr "Paràmetre"
|
||||
|
||||
#: sphinx/directives/desc.py:190
|
||||
msgid "Parameters"
|
||||
msgstr "Paràmetres"
|
||||
|
||||
#: sphinx/directives/desc.py:418
|
||||
#, python-format
|
||||
msgid "%s() (built-in function)"
|
||||
msgstr "%s() (funció interna)"
|
||||
|
||||
#: sphinx/directives/desc.py:419 sphinx/directives/desc.py:476
|
||||
#: sphinx/directives/desc.py:488
|
||||
#, python-format
|
||||
msgid "%s() (in module %s)"
|
||||
msgstr "%s() (al mòdul %s)"
|
||||
|
||||
#: sphinx/directives/desc.py:422
|
||||
#, python-format
|
||||
msgid "%s (built-in variable)"
|
||||
msgstr "%s (variable interna)"
|
||||
|
||||
#: sphinx/directives/desc.py:423 sphinx/directives/desc.py:514
|
||||
#, python-format
|
||||
msgid "%s (in module %s)"
|
||||
msgstr "%s (al mòdul %s)"
|
||||
|
||||
#: sphinx/directives/desc.py:439
|
||||
#, python-format
|
||||
msgid "%s (built-in class)"
|
||||
msgstr "%s (classe interna)"
|
||||
|
||||
#: sphinx/directives/desc.py:440
|
||||
#, python-format
|
||||
msgid "%s (class in %s)"
|
||||
msgstr "%s (class a %s)"
|
||||
|
||||
#: sphinx/directives/desc.py:480
|
||||
#, python-format
|
||||
msgid "%s() (%s.%s method)"
|
||||
msgstr "%s() (mètode %s.%s)"
|
||||
|
||||
#: sphinx/directives/desc.py:482
|
||||
#, python-format
|
||||
msgid "%s() (%s method)"
|
||||
msgstr "%s() (mètode %s)"
|
||||
|
||||
#: sphinx/directives/desc.py:492
|
||||
#, python-format
|
||||
msgid "%s() (%s.%s static method)"
|
||||
msgstr "%s() (mètode estàtic %s.%s)"
|
||||
|
||||
#: sphinx/directives/desc.py:495
|
||||
#, python-format
|
||||
msgid "%s() (%s static method)"
|
||||
msgstr "%s() (mètode estàtic %s)"
|
||||
|
||||
#: sphinx/directives/desc.py:518
|
||||
#, python-format
|
||||
msgid "%s (%s.%s attribute)"
|
||||
msgstr "%s (atribut %s.%s)"
|
||||
|
||||
#: sphinx/directives/desc.py:520
|
||||
#, python-format
|
||||
msgid "%s (%s attribute)"
|
||||
msgstr "%s (atribut %s)"
|
||||
|
||||
#: sphinx/directives/desc.py:609
|
||||
#, python-format
|
||||
msgid "%s (C function)"
|
||||
msgstr "%s (funció de C)"
|
||||
|
||||
#: sphinx/directives/desc.py:611
|
||||
#, python-format
|
||||
msgid "%s (C member)"
|
||||
msgstr "%s (membre de C)"
|
||||
|
||||
#: sphinx/directives/desc.py:613
|
||||
#, python-format
|
||||
msgid "%s (C macro)"
|
||||
msgstr "%s (macro de C)"
|
||||
|
||||
#: sphinx/directives/desc.py:615
|
||||
#, python-format
|
||||
msgid "%s (C type)"
|
||||
msgstr "%s (tipus de C)"
|
||||
|
||||
#: sphinx/directives/desc.py:617
|
||||
#, python-format
|
||||
msgid "%s (C variable)"
|
||||
msgstr "%s (variable de C)"
|
||||
|
||||
#: sphinx/directives/desc.py:665
|
||||
#, python-format
|
||||
msgid "%scommand line option; %s"
|
||||
msgstr "opció de línia de comandes %s; %s"
|
||||
|
||||
#: sphinx/directives/other.py:138
|
||||
msgid "Platforms: "
|
||||
msgstr "Plataformes: "
|
||||
|
||||
#: sphinx/directives/other.py:144
|
||||
#, python-format
|
||||
msgid "%s (module)"
|
||||
msgstr "%s (mòdul)"
|
||||
|
||||
#: sphinx/directives/other.py:193
|
||||
msgid "Section author: "
|
||||
msgstr "Autor de la secció:"
|
||||
|
||||
#: sphinx/directives/other.py:195
|
||||
msgid "Module author: "
|
||||
msgstr "Autor del mòdul: "
|
||||
|
||||
#: sphinx/directives/other.py:197
|
||||
msgid "Author: "
|
||||
msgstr "Autor: "
|
||||
|
||||
#: sphinx/directives/other.py:317
|
||||
msgid "See also"
|
||||
msgstr "Vegeu també"
|
||||
|
||||
#: sphinx/ext/autodoc.py:888
|
||||
#, python-format
|
||||
msgid " Bases: %s"
|
||||
msgstr " Bases: %s"
|
||||
|
||||
#: sphinx/ext/autodoc.py:919
|
||||
#, python-format
|
||||
msgid "alias of :class:`%s`"
|
||||
msgstr "àlies de :class:`%s`"
|
||||
|
||||
#: sphinx/ext/todo.py:41
|
||||
msgid "Todo"
|
||||
msgstr "Pendent"
|
||||
|
||||
#: sphinx/ext/todo.py:99
|
||||
#, python-format
|
||||
msgid "(The original entry is located in %s, line %d and can be found "
|
||||
msgstr "(La entrada original està a %s, línia %d i es pot trobar "
|
||||
|
||||
#: sphinx/ext/todo.py:105
|
||||
msgid "here"
|
||||
msgstr "aquí"
|
||||
|
||||
#: sphinx/locale/__init__.py:15
|
||||
msgid "Attention"
|
||||
msgstr "Atenció"
|
||||
|
||||
#: sphinx/locale/__init__.py:16
|
||||
msgid "Caution"
|
||||
msgstr "Compte"
|
||||
|
||||
#: sphinx/locale/__init__.py:17
|
||||
msgid "Danger"
|
||||
msgstr "Perill"
|
||||
|
||||
#: sphinx/locale/__init__.py:18
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
#: sphinx/locale/__init__.py:19
|
||||
msgid "Hint"
|
||||
msgstr "Suggerència"
|
||||
|
||||
#: sphinx/locale/__init__.py:20
|
||||
msgid "Important"
|
||||
msgstr "Important"
|
||||
|
||||
#: sphinx/locale/__init__.py:21
|
||||
msgid "Note"
|
||||
msgstr "Nota"
|
||||
|
||||
#: sphinx/locale/__init__.py:22
|
||||
msgid "See Also"
|
||||
msgstr "Vegeu També"
|
||||
|
||||
#: sphinx/locale/__init__.py:23
|
||||
msgid "Tip"
|
||||
msgstr "Truc"
|
||||
|
||||
#: sphinx/locale/__init__.py:24
|
||||
msgid "Warning"
|
||||
msgstr "Avís"
|
||||
|
||||
#: sphinx/locale/__init__.py:28
|
||||
#, python-format
|
||||
msgid "New in version %s"
|
||||
msgstr "Novetat de la versió %s"
|
||||
|
||||
#: sphinx/locale/__init__.py:29
|
||||
#, python-format
|
||||
msgid "Changed in version %s"
|
||||
msgstr "Canviat a la versió %s"
|
||||
|
||||
#: sphinx/locale/__init__.py:30
|
||||
#, python-format
|
||||
msgid "Deprecated since version %s"
|
||||
msgstr "Obsolet desde la versió %s"
|
||||
|
||||
#: sphinx/locale/__init__.py:34
|
||||
msgid "module"
|
||||
msgstr "mòdul"
|
||||
|
||||
#: sphinx/locale/__init__.py:35
|
||||
msgid "keyword"
|
||||
msgstr "paraula clau"
|
||||
|
||||
#: sphinx/locale/__init__.py:36
|
||||
msgid "operator"
|
||||
msgstr "operador"
|
||||
|
||||
#: sphinx/locale/__init__.py:37
|
||||
msgid "object"
|
||||
msgstr "objecte"
|
||||
|
||||
#: sphinx/locale/__init__.py:38
|
||||
msgid "exception"
|
||||
msgstr "excepció"
|
||||
|
||||
#: sphinx/locale/__init__.py:39
|
||||
msgid "statement"
|
||||
msgstr "sentència"
|
||||
|
||||
#: sphinx/locale/__init__.py:40
|
||||
msgid "built-in function"
|
||||
msgstr "funció interna"
|
||||
|
||||
#: sphinx/themes/basic/defindex.html:2
|
||||
msgid "Overview"
|
||||
msgstr "Resum"
|
||||
|
||||
#: sphinx/themes/basic/defindex.html:11
|
||||
msgid "Indices and tables:"
|
||||
msgstr "Índexs i taules:"
|
||||
|
||||
#: sphinx/themes/basic/defindex.html:14
|
||||
msgid "Complete Table of Contents"
|
||||
msgstr "Taula de Contingut Completa"
|
||||
|
||||
#: sphinx/themes/basic/defindex.html:15
|
||||
msgid "lists all sections and subsections"
|
||||
msgstr "llista totes les seccions i subseccions"
|
||||
|
||||
#: sphinx/themes/basic/defindex.html:17
|
||||
msgid "search this documentation"
|
||||
msgstr "cerca aquesta documentació"
|
||||
|
||||
#: sphinx/themes/basic/defindex.html:20
|
||||
msgid "quick access to all modules"
|
||||
msgstr "accés ràpid a tots els mòduls"
|
||||
|
||||
#: sphinx/themes/basic/defindex.html:22
|
||||
msgid "all functions, classes, terms"
|
||||
msgstr "totes les funcions, classes, termes"
|
||||
|
||||
#: sphinx/themes/basic/genindex-single.html:5
|
||||
#, python-format
|
||||
msgid "Index – %(key)s"
|
||||
msgstr "Índes – %(key)s"
|
||||
|
||||
#: sphinx/themes/basic/genindex-single.html:44
|
||||
#: sphinx/themes/basic/genindex-split.html:14
|
||||
#: sphinx/themes/basic/genindex-split.html:27
|
||||
#: sphinx/themes/basic/genindex.html:54
|
||||
msgid "Full index on one page"
|
||||
msgstr "Índex complet en una pàgina"
|
||||
|
||||
#: sphinx/themes/basic/genindex-split.html:7
|
||||
msgid "Index pages by letter"
|
||||
msgstr "Pàgines d'índex per lletra"
|
||||
|
||||
#: sphinx/themes/basic/genindex-split.html:15
|
||||
msgid "can be huge"
|
||||
msgstr "pot ser gegant"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:10
|
||||
msgid "Navigation"
|
||||
msgstr "Navegació"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:42
|
||||
msgid "Table Of Contents"
|
||||
msgstr "Taula de Contingut"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:48
|
||||
msgid "Previous topic"
|
||||
msgstr "Tema anterior"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:50
|
||||
msgid "previous chapter"
|
||||
msgstr "capítol anterior"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:53
|
||||
msgid "Next topic"
|
||||
msgstr "Tema següent"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:55
|
||||
msgid "next chapter"
|
||||
msgstr "capítol següent"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:60
|
||||
msgid "This Page"
|
||||
msgstr "Aquesta Pàgina"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:63
|
||||
msgid "Show Source"
|
||||
msgstr "Mostra Codi Font"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:73
|
||||
msgid "Quick search"
|
||||
msgstr "Cerca ràpida"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:76
|
||||
msgid "Go"
|
||||
msgstr "Ves a"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:81
|
||||
msgid "Enter search terms or a module, class or function name."
|
||||
msgstr "Entra paraules de cerca o el nom d'un mòdul, classe o funció."
|
||||
|
||||
#: sphinx/themes/basic/layout.html:119
|
||||
#, python-format
|
||||
msgid "Search within %(docstitle)s"
|
||||
msgstr "Cerca dins de %(docstitle)s"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:128
|
||||
msgid "About these documents"
|
||||
msgstr "Quant a aquests documents"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:134 sphinx/themes/basic/search.html:2
|
||||
#: sphinx/themes/basic/search.html:5
|
||||
msgid "Search"
|
||||
msgstr "Cerca"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:137
|
||||
msgid "Copyright"
|
||||
msgstr "Copyright"
|
||||
|
||||
#: sphinx/themes/basic/layout.html:184
|
||||
#, python-format
|
||||
msgid "© <a href=\"%(path)s\">Copyright</a> %(copyright)s."
|
||||
msgstr "© <a href=\\\"%(path)s\\\">Copyright</a> %(copyright)s."
|
||||
|
||||
#: sphinx/themes/basic/layout.html:186
|
||||
#, python-format
|
||||
msgid "© Copyright %(copyright)s."
|
||||
msgstr "© Copyright %(copyright)s."
|
||||
|
||||
#: sphinx/themes/basic/layout.html:190
|
||||
#, python-format
|
||||
msgid "Last updated on %(last_updated)s."
|
||||
msgstr "Última actualització el %(last_updated)s."
|
||||
|
||||
#: sphinx/themes/basic/layout.html:193
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Created using <a href=\"http://sphinx.pocoo.org/\">Sphinx</a> "
|
||||
"%(sphinx_version)s."
|
||||
msgstr ""
|
||||
"Creat amb <a href=\"http://sphinx.pocoo.org/\">Sphinx</a> "
|
||||
"%(sphinx_version)s."
|
||||
|
||||
#: sphinx/themes/basic/modindex.html:36
|
||||
msgid "Deprecated"
|
||||
msgstr "Obsolet"
|
||||
|
||||
#: sphinx/themes/basic/opensearch.xml:4
|
||||
#, python-format
|
||||
msgid "Search %(docstitle)s"
|
||||
msgstr "Cercar a %(docstitle)s"
|
||||
|
||||
#: sphinx/themes/basic/search.html:9
|
||||
msgid ""
|
||||
"Please activate JavaScript to enable the search\n"
|
||||
" functionality."
|
||||
msgstr ""
|
||||
"Activa JavaScript per utilitzar la funcionalitat\n"
|
||||
"de cerca."
|
||||
|
||||
#: sphinx/themes/basic/search.html:14
|
||||
msgid ""
|
||||
"From here you can search these documents. Enter your search\n"
|
||||
" words into the box below and click \"search\". Note that the search\n"
|
||||
" function will automatically search for all of the words. Pages\n"
|
||||
" containing fewer words won't appear in the result list."
|
||||
msgstr ""
|
||||
"Des d'aquí pots fer cerques en aquests documents. Entra les \n"
|
||||
"paraules de la teva cerca i clica el botó \"cerca\". Tingues en compte\n"
|
||||
"que la cerca inclourà totes les paraules que posis. Les pàgines que no\n"
|
||||
"tenen totes les paraules no sortiràn."
|
||||
|
||||
#: sphinx/themes/basic/search.html:21
|
||||
msgid "search"
|
||||
msgstr "cerca"
|
||||
|
||||
#: sphinx/themes/basic/search.html:25
|
||||
#: sphinx/themes/basic/static/searchtools.js:462
|
||||
msgid "Search Results"
|
||||
msgstr "Resultats de la Cerca"
|
||||
|
||||
#: sphinx/themes/basic/search.html:27
|
||||
msgid "Your search did not match any results."
|
||||
msgstr "La teva cerca no té resultats."
|
||||
|
||||
#: sphinx/themes/basic/changes/frameset.html:5
|
||||
#: sphinx/themes/basic/changes/versionchanges.html:12
|
||||
#, python-format
|
||||
msgid "Changes in Version %(version)s — %(docstitle)s"
|
||||
msgstr "Canvis a la Versió %(version)s — %(docstitle)s"
|
||||
|
||||
#: sphinx/themes/basic/changes/rstsource.html:5
|
||||
#, python-format
|
||||
msgid "%(filename)s — %(docstitle)s"
|
||||
msgstr "%(filename)s — %(docstitle)s"
|
||||
|
||||
#: sphinx/themes/basic/changes/versionchanges.html:17
|
||||
#, python-format
|
||||
msgid "Automatically generated list of changes in version %(version)s"
|
||||
msgstr "Llista de canvis de la versió %(version)s generada automàticament"
|
||||
|
||||
#: sphinx/themes/basic/changes/versionchanges.html:18
|
||||
msgid "Library changes"
|
||||
msgstr "Canvis a la llibreria"
|
||||
|
||||
#: sphinx/themes/basic/changes/versionchanges.html:23
|
||||
msgid "C API changes"
|
||||
msgstr "Canvis a la API de C"
|
||||
|
||||
#: sphinx/themes/basic/changes/versionchanges.html:25
|
||||
msgid "Other changes"
|
||||
msgstr "Altres canvis"
|
||||
|
||||
#: sphinx/themes/basic/static/doctools.js:139 sphinx/writers/html.py:473
|
||||
#: sphinx/writers/html.py:478
|
||||
msgid "Permalink to this headline"
|
||||
msgstr "Link permanent a aquest títol"
|
||||
|
||||
#: sphinx/themes/basic/static/doctools.js:145 sphinx/writers/html.py:80
|
||||
msgid "Permalink to this definition"
|
||||
msgstr "Link permanent a aquesta definició"
|
||||
|
||||
#: sphinx/themes/basic/static/doctools.js:174
|
||||
msgid "Hide Search Matches"
|
||||
msgstr "Oculta Resultats de Cerca"
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:274
|
||||
msgid "Searching"
|
||||
msgstr "Cercant"
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:279
|
||||
msgid "Preparing search..."
|
||||
msgstr "Preparant la cerca..."
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:347
|
||||
msgid "module, in "
|
||||
msgstr "mòdule, a "
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:356
|
||||
msgid ", in "
|
||||
msgstr ", a "
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:464
|
||||
msgid ""
|
||||
"Your search did not match any documents. Please make sure that all words "
|
||||
"are spelled correctly and that you've selected enough categories."
|
||||
msgstr ""
|
||||
"La teva cerca no ha donat resultats. Assegura't que totes les paraules "
|
||||
"estan ben escrites i que has seleccionat prou categories."
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:466
|
||||
#, python-format
|
||||
msgid "Search finished, found %s page(s) matching the search query."
|
||||
msgstr "Cerca finalitzada, s'han trobat %s pàgin(a/es) de resultats."
|
||||
|
||||
#: sphinx/writers/latex.py:187
|
||||
msgid "Release"
|
||||
msgstr "Versió"
|
||||
|
||||
#: sphinx/writers/latex.py:639
|
||||
msgid "continued from previous page"
|
||||
msgstr "ve de la pàgina anterior"
|
||||
|
||||
#: sphinx/writers/latex.py:643
|
||||
msgid "Continued on next page"
|
||||
msgstr "Continua a la pàgina següent"
|
||||
|
||||
#: sphinx/writers/text.py:166
|
||||
#, python-format
|
||||
msgid "Platform: %s"
|
||||
msgstr "Plataforma: %s"
|
||||
|
||||
#: sphinx/writers/text.py:428
|
||||
msgid "[image]"
|
||||
msgstr "[imatge]"
|
||||
|
@ -6,9 +6,9 @@
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Sphinx 1.0\n"
|
||||
"Project-Id-Version: Sphinx 1.0pre/[?1034h2e1ab15e035e\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2009-08-06 23:04+0200\n"
|
||||
"POT-Creation-Date: 2009-11-08 16:28+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -17,12 +17,12 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 0.9.4\n"
|
||||
|
||||
#: sphinx/environment.py:103 sphinx/writers/latex.py:184
|
||||
#: sphinx/environment.py:130 sphinx/writers/latex.py:184
|
||||
#, python-format
|
||||
msgid "%B %d, %Y"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/environment.py:324 sphinx/themes/basic/genindex-single.html:2
|
||||
#: sphinx/environment.py:348 sphinx/themes/basic/genindex-single.html:2
|
||||
#: sphinx/themes/basic/genindex-split.html:2
|
||||
#: sphinx/themes/basic/genindex-split.html:5
|
||||
#: sphinx/themes/basic/genindex.html:2 sphinx/themes/basic/genindex.html:5
|
||||
@ -31,60 +31,56 @@ msgstr ""
|
||||
msgid "Index"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/environment.py:325 sphinx/writers/latex.py:189
|
||||
#: sphinx/environment.py:349 sphinx/writers/latex.py:189
|
||||
msgid "Module Index"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/environment.py:326 sphinx/themes/basic/defindex.html:16
|
||||
#: sphinx/environment.py:350 sphinx/themes/basic/defindex.html:16
|
||||
msgid "Search Page"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/roles.py:55 sphinx/directives/desc.py:747
|
||||
#, python-format
|
||||
msgid "environment variable; %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/roles.py:62
|
||||
#: sphinx/roles.py:167
|
||||
#, python-format
|
||||
msgid "Python Enhancement Proposals!PEP %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/changes.py:71
|
||||
#: sphinx/builders/changes.py:70
|
||||
msgid "Builtins"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/changes.py:73
|
||||
#: sphinx/builders/changes.py:72
|
||||
msgid "Module level"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/html.py:222
|
||||
#: sphinx/builders/html.py:224
|
||||
#, python-format
|
||||
msgid "%b %d, %Y"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/html.py:241 sphinx/themes/basic/defindex.html:21
|
||||
#: sphinx/builders/html.py:243 sphinx/themes/basic/defindex.html:21
|
||||
msgid "General Index"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/html.py:241
|
||||
#: sphinx/builders/html.py:243
|
||||
msgid "index"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/html.py:243 sphinx/builders/htmlhelp.py:219
|
||||
#: sphinx/builders/html.py:247 sphinx/builders/htmlhelp.py:220
|
||||
#: sphinx/builders/qthelp.py:133 sphinx/themes/basic/defindex.html:19
|
||||
#: sphinx/themes/basic/modindex.html:2 sphinx/themes/basic/modindex.html:13
|
||||
#: sphinx/themes/scrolls/modindex.html:2 sphinx/themes/scrolls/modindex.html:13
|
||||
msgid "Global Module Index"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/html.py:244
|
||||
#: sphinx/builders/html.py:248
|
||||
msgid "modules"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/html.py:300
|
||||
#: sphinx/builders/html.py:304
|
||||
msgid "next"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/builders/html.py:309
|
||||
#: sphinx/builders/html.py:313
|
||||
msgid "previous"
|
||||
msgstr ""
|
||||
|
||||
@ -92,249 +88,323 @@ msgstr ""
|
||||
msgid " (in "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:97
|
||||
#: sphinx/directives/__init__.py:78 sphinx/directives/__init__.py:79
|
||||
#: sphinx/directives/__init__.py:80 sphinx/directives/__init__.py:81
|
||||
msgid "Raises"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:101
|
||||
#: sphinx/directives/__init__.py:82 sphinx/directives/__init__.py:83
|
||||
#: sphinx/directives/__init__.py:84
|
||||
msgid "Variable"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:104
|
||||
#: sphinx/directives/__init__.py:85 sphinx/directives/__init__.py:86
|
||||
#: sphinx/directives/__init__.py:92 sphinx/directives/__init__.py:93
|
||||
msgid "Returns"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:113
|
||||
#: sphinx/directives/__init__.py:94
|
||||
msgid "Return type"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:186
|
||||
#: sphinx/directives/__init__.py:169
|
||||
msgid "Parameter"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:190
|
||||
#: sphinx/directives/__init__.py:173
|
||||
msgid "Parameters"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:418
|
||||
#, python-format
|
||||
msgid "%s() (built-in function)"
|
||||
#: sphinx/directives/other.py:127
|
||||
msgid "Section author: "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:419 sphinx/directives/desc.py:476
|
||||
#: sphinx/directives/desc.py:488
|
||||
#, python-format
|
||||
msgid "%s() (in module %s)"
|
||||
#: sphinx/directives/other.py:129
|
||||
msgid "Module author: "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:422
|
||||
#, python-format
|
||||
msgid "%s (built-in variable)"
|
||||
#: sphinx/directives/other.py:131
|
||||
msgid "Author: "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:423 sphinx/directives/desc.py:514
|
||||
#, python-format
|
||||
msgid "%s (in module %s)"
|
||||
#: sphinx/directives/other.py:233
|
||||
msgid "See also"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:439
|
||||
#, python-format
|
||||
msgid "%s (built-in class)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:440
|
||||
#, python-format
|
||||
msgid "%s (class in %s)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:480
|
||||
#, python-format
|
||||
msgid "%s() (%s.%s method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:482
|
||||
#, python-format
|
||||
msgid "%s() (%s method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:492
|
||||
#, python-format
|
||||
msgid "%s() (%s.%s static method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:495
|
||||
#, python-format
|
||||
msgid "%s() (%s static method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:518
|
||||
#, python-format
|
||||
msgid "%s (%s.%s attribute)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:520
|
||||
#, python-format
|
||||
msgid "%s (%s attribute)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:609
|
||||
#: sphinx/domains/c.py:124
|
||||
#, python-format
|
||||
msgid "%s (C function)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:611
|
||||
#: sphinx/domains/c.py:126
|
||||
#, python-format
|
||||
msgid "%s (C member)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:613
|
||||
#: sphinx/domains/c.py:128
|
||||
#, python-format
|
||||
msgid "%s (C macro)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:615
|
||||
#: sphinx/domains/c.py:130
|
||||
#, python-format
|
||||
msgid "%s (C type)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:617
|
||||
#: sphinx/domains/c.py:132
|
||||
#, python-format
|
||||
msgid "%s (C variable)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/desc.py:665
|
||||
#, python-format
|
||||
msgid "%scommand line option; %s"
|
||||
#: sphinx/domains/c.py:162
|
||||
msgid "C function"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/other.py:140
|
||||
#: sphinx/domains/c.py:163
|
||||
msgid "C member"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/c.py:164
|
||||
msgid "C macro"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/c.py:165
|
||||
msgid "C type"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/c.py:166
|
||||
msgid "C variable"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:186
|
||||
#, python-format
|
||||
msgid "%s() (built-in function)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:187 sphinx/domains/python.py:244
|
||||
#: sphinx/domains/python.py:256 sphinx/domains/python.py:269
|
||||
#, python-format
|
||||
msgid "%s() (in module %s)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:190
|
||||
#, python-format
|
||||
msgid "%s (built-in variable)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:191 sphinx/domains/python.py:282
|
||||
#, python-format
|
||||
msgid "%s (in module %s)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:207
|
||||
#, python-format
|
||||
msgid "%s (built-in class)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:208
|
||||
#, python-format
|
||||
msgid "%s (class in %s)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:248
|
||||
#, python-format
|
||||
msgid "%s() (%s.%s method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:250
|
||||
#, python-format
|
||||
msgid "%s() (%s method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:260
|
||||
#, python-format
|
||||
msgid "%s() (%s.%s static method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:263
|
||||
#, python-format
|
||||
msgid "%s() (%s static method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:273
|
||||
#, python-format
|
||||
msgid "%s() (%s.%s class method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:276
|
||||
#, python-format
|
||||
msgid "%s() (%s class method)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:286
|
||||
#, python-format
|
||||
msgid "%s (%s.%s attribute)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:288
|
||||
#, python-format
|
||||
msgid "%s (%s attribute)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:334
|
||||
msgid "Platforms: "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/other.py:146
|
||||
#: sphinx/domains/python.py:340
|
||||
#, python-format
|
||||
msgid "%s (module)"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/other.py:195
|
||||
msgid "Section author: "
|
||||
#: sphinx/domains/python.py:396
|
||||
msgid "function"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/other.py:197
|
||||
msgid "Module author: "
|
||||
#: sphinx/domains/python.py:397
|
||||
msgid "data"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/other.py:199
|
||||
msgid "Author: "
|
||||
#: sphinx/domains/python.py:398
|
||||
msgid "class"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/directives/other.py:319
|
||||
msgid "See also"
|
||||
#: sphinx/domains/python.py:399 sphinx/locale/__init__.py:161
|
||||
msgid "exception"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/ext/autodoc.py:889
|
||||
#: sphinx/domains/python.py:400
|
||||
msgid "method"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:401
|
||||
msgid "attribute"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/python.py:402 sphinx/locale/__init__.py:157
|
||||
msgid "module"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/std.py:67 sphinx/domains/std.py:83
|
||||
#, python-format
|
||||
msgid "environment variable; %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/std.py:156
|
||||
#, python-format
|
||||
msgid "%scommand line option; %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/std.py:324
|
||||
msgid "glossary term"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/std.py:325
|
||||
msgid "grammar token"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/std.py:326
|
||||
msgid "environment variable"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/domains/std.py:327
|
||||
msgid "program option"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/ext/autodoc.py:892
|
||||
#, python-format
|
||||
msgid " Bases: %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/ext/autodoc.py:922
|
||||
#: sphinx/ext/autodoc.py:925
|
||||
#, python-format
|
||||
msgid "alias of :class:`%s`"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/ext/todo.py:41
|
||||
#: sphinx/ext/todo.py:40
|
||||
msgid "Todo"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/ext/todo.py:99
|
||||
#: sphinx/ext/todo.py:98
|
||||
#, python-format
|
||||
msgid "(The original entry is located in %s, line %d and can be found "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/ext/todo.py:105
|
||||
#: sphinx/ext/todo.py:104
|
||||
msgid "here"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:15
|
||||
#: sphinx/locale/__init__.py:138
|
||||
msgid "Attention"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:16
|
||||
#: sphinx/locale/__init__.py:139
|
||||
msgid "Caution"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:17
|
||||
#: sphinx/locale/__init__.py:140
|
||||
msgid "Danger"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:18
|
||||
#: sphinx/locale/__init__.py:141
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:19
|
||||
#: sphinx/locale/__init__.py:142
|
||||
msgid "Hint"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:20
|
||||
#: sphinx/locale/__init__.py:143
|
||||
msgid "Important"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:21
|
||||
#: sphinx/locale/__init__.py:144
|
||||
msgid "Note"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:22
|
||||
#: sphinx/locale/__init__.py:145
|
||||
msgid "See Also"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:23
|
||||
#: sphinx/locale/__init__.py:146
|
||||
msgid "Tip"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:24
|
||||
#: sphinx/locale/__init__.py:147
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:28
|
||||
#: sphinx/locale/__init__.py:151
|
||||
#, python-format
|
||||
msgid "New in version %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:29
|
||||
#: sphinx/locale/__init__.py:152
|
||||
#, python-format
|
||||
msgid "Changed in version %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:30
|
||||
#: sphinx/locale/__init__.py:153
|
||||
#, python-format
|
||||
msgid "Deprecated since version %s"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:34
|
||||
msgid "module"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:35
|
||||
#: sphinx/locale/__init__.py:158
|
||||
msgid "keyword"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:36
|
||||
#: sphinx/locale/__init__.py:159
|
||||
msgid "operator"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:37
|
||||
#: sphinx/locale/__init__.py:160
|
||||
msgid "object"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:38
|
||||
msgid "exception"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:39
|
||||
#: sphinx/locale/__init__.py:162
|
||||
msgid "statement"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/locale/__init__.py:40
|
||||
#: sphinx/locale/__init__.py:163
|
||||
msgid "built-in function"
|
||||
msgstr ""
|
||||
|
||||
@ -448,29 +518,29 @@ msgstr ""
|
||||
msgid "Copyright"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/layout.html:187
|
||||
#: sphinx/themes/basic/layout.html:187 sphinx/themes/scrolls/layout.html:83
|
||||
#, python-format
|
||||
msgid "© <a href=\"%(path)s\">Copyright</a> %(copyright)s."
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/layout.html:189
|
||||
#: sphinx/themes/basic/layout.html:189 sphinx/themes/scrolls/layout.html:85
|
||||
#, python-format
|
||||
msgid "© Copyright %(copyright)s."
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/layout.html:193
|
||||
#: sphinx/themes/basic/layout.html:193 sphinx/themes/scrolls/layout.html:89
|
||||
#, python-format
|
||||
msgid "Last updated on %(last_updated)s."
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/layout.html:196
|
||||
#: sphinx/themes/basic/layout.html:196 sphinx/themes/scrolls/layout.html:92
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Created using <a href=\"http://sphinx.pocoo.org/\">Sphinx</a> "
|
||||
"%(sphinx_version)s."
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/modindex.html:36
|
||||
#: sphinx/themes/basic/modindex.html:36 sphinx/themes/scrolls/modindex.html:37
|
||||
msgid "Deprecated"
|
||||
msgstr ""
|
||||
|
||||
@ -498,7 +568,7 @@ msgid "search"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/search.html:25
|
||||
#: sphinx/themes/basic/static/searchtools.js:462
|
||||
#: sphinx/themes/basic/static/searchtools.js:473
|
||||
msgid "Search Results"
|
||||
msgstr ""
|
||||
|
||||
@ -534,16 +604,16 @@ msgstr ""
|
||||
msgid "Other changes"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/static/doctools.js:139 sphinx/writers/html.py:473
|
||||
#: sphinx/writers/html.py:478
|
||||
#: sphinx/themes/basic/static/doctools.js:138 sphinx/writers/html.py:462
|
||||
#: sphinx/writers/html.py:467
|
||||
msgid "Permalink to this headline"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/static/doctools.js:145 sphinx/writers/html.py:80
|
||||
#: sphinx/themes/basic/static/doctools.js:144 sphinx/writers/html.py:80
|
||||
msgid "Permalink to this definition"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/static/doctools.js:174
|
||||
#: sphinx/themes/basic/static/doctools.js:173
|
||||
msgid "Hide Search Matches"
|
||||
msgstr ""
|
||||
|
||||
@ -555,21 +625,17 @@ msgstr ""
|
||||
msgid "Preparing search..."
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:347
|
||||
msgid "module, in "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:356
|
||||
#: sphinx/themes/basic/static/searchtools.js:352
|
||||
msgid ", in "
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:464
|
||||
#: sphinx/themes/basic/static/searchtools.js:475
|
||||
msgid ""
|
||||
"Your search did not match any documents. Please make sure that all words "
|
||||
"are spelled correctly and that you've selected enough categories."
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/themes/basic/static/searchtools.js:466
|
||||
#: sphinx/themes/basic/static/searchtools.js:477
|
||||
#, python-format
|
||||
msgid "Search finished, found %s page(s) matching the search query."
|
||||
msgstr ""
|
||||
@ -578,15 +644,15 @@ msgstr ""
|
||||
msgid "Release"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/writers/latex.py:578
|
||||
#: sphinx/writers/latex.py:579
|
||||
msgid "Footnotes"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/writers/latex.py:646
|
||||
#: sphinx/writers/latex.py:647
|
||||
msgid "continued from previous page"
|
||||
msgstr ""
|
||||
|
||||
#: sphinx/writers/latex.py:651
|
||||
#: sphinx/writers/latex.py:652
|
||||
msgid "Continued on next page"
|
||||
msgstr ""
|
||||
|
||||
|
274
sphinx/roles.py
274
sphinx/roles.py
@ -10,6 +10,7 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
import warnings
|
||||
|
||||
from docutils import nodes, utils
|
||||
from docutils.parsers.rst import roles
|
||||
@ -28,7 +29,7 @@ generic_docroles = {
|
||||
'manpage' : addnodes.literal_emphasis,
|
||||
'mimetype' : addnodes.literal_emphasis,
|
||||
'newsgroup' : addnodes.literal_emphasis,
|
||||
'program' : nodes.strong,
|
||||
'program' : nodes.strong, # XXX should be an x-ref
|
||||
'regexp' : nodes.literal,
|
||||
}
|
||||
|
||||
@ -37,27 +38,131 @@ for rolename, nodeclass in generic_docroles.iteritems():
|
||||
roles.register_local_role(rolename, role)
|
||||
|
||||
|
||||
# -- generic cross-reference role ----------------------------------------------
|
||||
|
||||
class XRefRole(object):
|
||||
"""
|
||||
A generic cross-referencing role. To create a callable that can be used as
|
||||
a role function, create an instance of this class.
|
||||
|
||||
The general features of this role are:
|
||||
|
||||
* Automatic creation of a reference and a content node.
|
||||
* Optional separation of title and target with `title <target>`.
|
||||
* The implementation is a class rather than a function to make
|
||||
customization easier.
|
||||
|
||||
Customization can be done in two ways:
|
||||
|
||||
* Supplying constructor parameters:
|
||||
* `fix_parens` to normalize parentheses (strip from target, and add to
|
||||
title if configured)
|
||||
* `lowercase` to lowercase the target
|
||||
* `nodeclass` and `innernodeclass` select the node classes for
|
||||
the reference and the content node
|
||||
|
||||
* Subclassing and overwriting `process_link()` and/or `result_nodes()`.
|
||||
"""
|
||||
|
||||
nodeclass = addnodes.pending_xref
|
||||
innernodeclass = nodes.literal
|
||||
|
||||
def __init__(self, fix_parens=False, lowercase=False,
|
||||
nodeclass=None, innernodeclass=None):
|
||||
self.fix_parens = fix_parens
|
||||
self.lowercase = lowercase
|
||||
if nodeclass is not None:
|
||||
self.nodeclass = nodeclass
|
||||
if innernodeclass is not None:
|
||||
self.innernodeclass = innernodeclass
|
||||
|
||||
def _fix_parens(self, env, has_explicit_title, title, target):
|
||||
if not has_explicit_title:
|
||||
if title.endswith('()'):
|
||||
# remove parentheses
|
||||
title = title[:-2]
|
||||
if env.config.add_function_parentheses:
|
||||
# add them back to all occurrences if configured
|
||||
title += '()'
|
||||
# remove parentheses from the target too
|
||||
if target.endswith('()'):
|
||||
target = target[:-2]
|
||||
return title, target
|
||||
|
||||
def __call__(self, typ, rawtext, text, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
env = inliner.document.settings.env
|
||||
if not typ:
|
||||
typ = env.config.default_role
|
||||
else:
|
||||
typ = typ.lower()
|
||||
if ':' not in typ:
|
||||
domain, role = '', typ
|
||||
else:
|
||||
domain, role = typ.split(':', 1)
|
||||
text = utils.unescape(text)
|
||||
# if the first character is a bang, don't cross-reference at all
|
||||
if text[0:1] == '!':
|
||||
if self.fix_parens:
|
||||
text, _ = self._fix_parens(env, False, text[1:], "")
|
||||
innernode = self.innernodeclass(rawtext, text, classes=['xref'])
|
||||
return self.result_nodes(inliner.document, env, innernode,
|
||||
is_ref=False)
|
||||
# split title and target in role content
|
||||
has_explicit_title, title, target = split_explicit_title(text)
|
||||
# fix-up title and target
|
||||
if self.lowercase:
|
||||
target = target.lower()
|
||||
if self.fix_parens:
|
||||
title, target = self._fix_parens(
|
||||
env, has_explicit_title, title, target)
|
||||
# create the reference node
|
||||
refnode = self.nodeclass(rawtext, reftype=role, refdomain=domain,
|
||||
refexplicit=has_explicit_title)
|
||||
# we may need the line number for warnings
|
||||
refnode.line = lineno
|
||||
title, target = self.process_link(
|
||||
env, refnode, has_explicit_title, title, target)
|
||||
# now that the target and title are finally determined, set them
|
||||
refnode['reftarget'] = target
|
||||
refnode += self.innernodeclass(rawtext, title, classes=['xref'])
|
||||
# result_nodes allow further modification of return values
|
||||
return self.result_nodes(inliner.document, env, refnode, is_ref=True)
|
||||
|
||||
# methods that can be overwritten
|
||||
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
"""
|
||||
Called after parsing title and target text, and creating the reference
|
||||
node (given in *refnode*). This method can alter the reference node and
|
||||
must return a new (or the same) ``(title, target)`` tuple.
|
||||
"""
|
||||
return title, ws_re.sub(' ', target)
|
||||
|
||||
def result_nodes(self, document, env, node, is_ref):
|
||||
"""
|
||||
Called before returning the finished nodes. *node* is the reference
|
||||
node if one was created (*is_ref* is then true), else the content node.
|
||||
This method can add other nodes and must return a ``(nodes, messages)``
|
||||
tuple (the usual return value of a role function).
|
||||
"""
|
||||
return [node], []
|
||||
|
||||
|
||||
def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
"""Role for PEP/RFC references that generate an index entry."""
|
||||
env = inliner.document.settings.env
|
||||
if not typ:
|
||||
typ = env.config.default_role
|
||||
else:
|
||||
typ = typ.lower()
|
||||
text = utils.unescape(etext)
|
||||
targetid = 'index-%s' % env.index_num
|
||||
env.index_num += 1
|
||||
targetid = 'index-%s' % env.new_serialno('index')
|
||||
indexnode = addnodes.index()
|
||||
targetnode = nodes.target('', '', ids=[targetid])
|
||||
inliner.document.note_explicit_target(targetnode)
|
||||
if typ == 'envvar':
|
||||
indexnode['entries'] = [('single', text, targetid, text),
|
||||
('single', _('environment variable; %s') % text,
|
||||
targetid, text)]
|
||||
xref_nodes = xfileref_role(typ, rawtext, etext, lineno, inliner,
|
||||
options, content)[0]
|
||||
return [indexnode, targetnode] + xref_nodes, []
|
||||
elif typ == 'pep':
|
||||
if typ == 'pep':
|
||||
indexnode['entries'] = [
|
||||
('single', _('Python Enhancement Proposals!PEP %s') % text,
|
||||
targetid, 'PEP %s' % text)]
|
||||
@ -89,117 +194,12 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
|
||||
rn += sn
|
||||
return [indexnode, targetnode, rn], []
|
||||
|
||||
roles.register_local_role('envvar', indexmarkup_role)
|
||||
roles.register_local_role('pep', indexmarkup_role)
|
||||
roles.register_local_role('rfc', indexmarkup_role)
|
||||
|
||||
|
||||
# default is `literal`
|
||||
innernodetypes = {
|
||||
'ref': nodes.emphasis,
|
||||
'term': nodes.emphasis,
|
||||
'token': nodes.strong,
|
||||
'envvar': nodes.strong,
|
||||
'download': nodes.strong,
|
||||
'option': addnodes.literal_emphasis,
|
||||
}
|
||||
|
||||
def _fix_parens(typ, text, env):
|
||||
if typ in ('func', 'meth', 'cfunc'):
|
||||
if text.endswith('()'):
|
||||
# remove parentheses
|
||||
text = text[:-2]
|
||||
if env.config.add_function_parentheses:
|
||||
# add them back to all occurrences if configured
|
||||
text += '()'
|
||||
return text
|
||||
|
||||
def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
env = inliner.document.settings.env
|
||||
if not typ:
|
||||
typ = env.config.default_role
|
||||
else:
|
||||
typ = typ.lower()
|
||||
text = utils.unescape(text)
|
||||
# if the first character is a bang, don't cross-reference at all
|
||||
if text[0:1] == '!':
|
||||
text = _fix_parens(typ, text[1:], env)
|
||||
return [innernodetypes.get(typ, nodes.literal)(
|
||||
rawtext, text, classes=['xref'])], []
|
||||
# we want a cross-reference, create the reference node
|
||||
nodeclass = (typ == 'download') and addnodes.download_reference or \
|
||||
addnodes.pending_xref
|
||||
pnode = nodeclass(rawtext, reftype=typ, refcaption=False,
|
||||
modname=env.currmodule, classname=env.currclass)
|
||||
# we may need the line number for warnings
|
||||
pnode.line = lineno
|
||||
# look if explicit title and target are given with `foo <bar>` syntax
|
||||
has_explicit_title, title, target = split_explicit_title(text)
|
||||
if has_explicit_title:
|
||||
pnode['refcaption'] = True
|
||||
# special target for Python object cross-references
|
||||
if typ in ('data', 'exc', 'func', 'class', 'const', 'attr',
|
||||
'meth', 'mod', 'obj'):
|
||||
# fix-up parentheses in link title
|
||||
if not has_explicit_title:
|
||||
title = title.lstrip('.') # only has a meaning for the target
|
||||
target = target.lstrip('~') # only has a meaning for the title
|
||||
title = _fix_parens(typ, title, env)
|
||||
# if the first character is a tilde, don't display the module/class
|
||||
# parts of the contents
|
||||
if title[0:1] == '~':
|
||||
title = title[1:]
|
||||
dot = title.rfind('.')
|
||||
if dot != -1:
|
||||
title = title[dot+1:]
|
||||
# remove parentheses from the target too
|
||||
if target.endswith('()'):
|
||||
target = target[:-2]
|
||||
# if the first character is a dot, search more specific namespaces first
|
||||
# else search builtins first
|
||||
if target[0:1] == '.':
|
||||
target = target[1:]
|
||||
pnode['refspecific'] = True
|
||||
# some other special cases for the target
|
||||
elif typ == 'option':
|
||||
program = env.currprogram
|
||||
if not has_explicit_title:
|
||||
if ' ' in title and not (title.startswith('/') or
|
||||
title.startswith('-')):
|
||||
program, target = re.split(' (?=-|--|/)', title, 1)
|
||||
program = ws_re.sub('-', program)
|
||||
target = target.strip()
|
||||
elif ' ' in target:
|
||||
program, target = re.split(' (?=-|--|/)', target, 1)
|
||||
program = ws_re.sub('-', program)
|
||||
pnode['refprogram'] = program
|
||||
elif typ == 'term':
|
||||
# normalize whitespace in definition terms (if the term reference is
|
||||
# broken over a line, a newline will be in target)
|
||||
target = ws_re.sub(' ', target).lower()
|
||||
elif typ == 'ref':
|
||||
# reST label names are always lowercased
|
||||
target = ws_re.sub('', target).lower()
|
||||
elif typ == 'cfunc':
|
||||
# fix-up parens for C functions too
|
||||
if not has_explicit_title:
|
||||
title = _fix_parens(typ, title, env)
|
||||
# remove parentheses from the target too
|
||||
if target.endswith('()'):
|
||||
target = target[:-2]
|
||||
else:
|
||||
# remove all whitespace to avoid referencing problems
|
||||
target = ws_re.sub('', target)
|
||||
pnode['reftarget'] = target
|
||||
pnode += innernodetypes.get(typ, nodes.literal)(rawtext, title,
|
||||
classes=['xref'])
|
||||
return [pnode], []
|
||||
|
||||
|
||||
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
return [nodes.emphasis(
|
||||
rawtext,
|
||||
utils.unescape(text).replace('-->', u'\N{TRIANGULAR BULLET}'))], []
|
||||
return role
|
||||
|
||||
|
||||
_litvar_re = re.compile('{([^}]+)}')
|
||||
@ -233,30 +233,17 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
|
||||
|
||||
specific_docroles = {
|
||||
'data': xfileref_role,
|
||||
'exc': xfileref_role,
|
||||
'func': xfileref_role,
|
||||
'class': xfileref_role,
|
||||
'const': xfileref_role,
|
||||
'attr': xfileref_role,
|
||||
'meth': xfileref_role,
|
||||
'obj': xfileref_role,
|
||||
'cfunc' : xfileref_role,
|
||||
'cmember': xfileref_role,
|
||||
'cdata': xfileref_role,
|
||||
'ctype': xfileref_role,
|
||||
'cmacro': xfileref_role,
|
||||
|
||||
'mod': xfileref_role,
|
||||
|
||||
'keyword': xfileref_role,
|
||||
'ref': xfileref_role,
|
||||
'token': xfileref_role,
|
||||
'term': xfileref_role,
|
||||
'option': xfileref_role,
|
||||
'doc': xfileref_role,
|
||||
'download': xfileref_role,
|
||||
# links to download references
|
||||
'download': XRefRole(nodeclass=addnodes.download_reference),
|
||||
# links to headings or arbitrary labels
|
||||
'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis),
|
||||
# links to documents
|
||||
'doc': XRefRole(),
|
||||
# links to labels, without a different title
|
||||
'keyword': XRefRole(),
|
||||
|
||||
'pep': indexmarkup_role,
|
||||
'rfc': indexmarkup_role,
|
||||
'menuselection': menusel_role,
|
||||
'file': emph_literal_role,
|
||||
'samp': emph_literal_role,
|
||||
@ -265,3 +252,10 @@ specific_docroles = {
|
||||
|
||||
for rolename, func in specific_docroles.iteritems():
|
||||
roles.register_local_role(rolename, func)
|
||||
|
||||
|
||||
# backwards compatibility alias
|
||||
def xfileref_role(*args, **kwds):
|
||||
warnings.warn('xfileref_role is deprecated, use XRefRole',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
return XRefRole()(*args, **kwds)
|
||||
|
@ -119,8 +119,10 @@ class IndexBuilder(object):
|
||||
self._titles = {}
|
||||
# stemmed word -> set(filenames)
|
||||
self._mapping = {}
|
||||
# desctypes -> index
|
||||
self._desctypes = {}
|
||||
# objtype -> index
|
||||
self._objtypes = {}
|
||||
# objtype index -> objname (localized)
|
||||
self._objnames = {}
|
||||
|
||||
def load(self, stream, format):
|
||||
"""Reconstruct from frozen data."""
|
||||
@ -138,7 +140,7 @@ class IndexBuilder(object):
|
||||
self._mapping[k] = set([index2fn[v]])
|
||||
else:
|
||||
self._mapping[k] = set(index2fn[i] for i in v)
|
||||
# no need to load keywords/desctypes
|
||||
# no need to load keywords/objtypes
|
||||
|
||||
def dump(self, stream, format):
|
||||
"""Dump the frozen index to a stream."""
|
||||
@ -146,27 +148,30 @@ class IndexBuilder(object):
|
||||
format = self.formats[format]
|
||||
format.dump(self.freeze(), stream)
|
||||
|
||||
def get_modules(self, fn2index):
|
||||
def get_objects(self, fn2index):
|
||||
rv = {}
|
||||
for name, (doc, _, _, _) in self.env.modules.iteritems():
|
||||
if doc in fn2index:
|
||||
rv[name] = fn2index[doc]
|
||||
return rv
|
||||
|
||||
def get_descrefs(self, fn2index):
|
||||
rv = {}
|
||||
dt = self._desctypes
|
||||
for fullname, (doc, desctype) in self.env.descrefs.iteritems():
|
||||
if doc not in fn2index:
|
||||
continue
|
||||
prefix, name = rpartition(fullname, '.')
|
||||
pdict = rv.setdefault(prefix, {})
|
||||
try:
|
||||
i = dt[desctype]
|
||||
except KeyError:
|
||||
i = len(dt)
|
||||
dt[desctype] = i
|
||||
pdict[name] = (fn2index[doc], i)
|
||||
ot = self._objtypes
|
||||
on = self._objnames
|
||||
for domainname, domain in self.env.domains.iteritems():
|
||||
for fullname, type, docname, anchor, prio in domain.get_objects():
|
||||
if docname not in fn2index:
|
||||
continue
|
||||
if prio < 0:
|
||||
continue
|
||||
# XXX splitting at dot is kind of Python specific
|
||||
prefix, name = rpartition(fullname, '.')
|
||||
pdict = rv.setdefault(prefix, {})
|
||||
try:
|
||||
i = ot[domainname, type]
|
||||
except KeyError:
|
||||
i = len(ot)
|
||||
ot[domainname, type] = i
|
||||
otype = domain.object_types.get(type)
|
||||
if otype:
|
||||
on[i] = str(otype.lname) # fire translation proxies
|
||||
else:
|
||||
on[i] = type
|
||||
pdict[name] = (fn2index[docname], i, prio)
|
||||
return rv
|
||||
|
||||
def get_terms(self, fn2index):
|
||||
@ -185,14 +190,13 @@ class IndexBuilder(object):
|
||||
filenames = self._titles.keys()
|
||||
titles = self._titles.values()
|
||||
fn2index = dict((f, i) for (i, f) in enumerate(filenames))
|
||||
return dict(
|
||||
filenames=filenames,
|
||||
titles=titles,
|
||||
terms=self.get_terms(fn2index),
|
||||
descrefs=self.get_descrefs(fn2index),
|
||||
modules=self.get_modules(fn2index),
|
||||
desctypes=dict((v, k) for (k, v) in self._desctypes.items()),
|
||||
)
|
||||
terms = self.get_terms(fn2index)
|
||||
objects = self.get_objects(fn2index) # populates _objtypes
|
||||
objtypes = dict((v, k[0] + ':' + k[1])
|
||||
for (k, v) in self._objtypes.iteritems())
|
||||
objnames = self._objnames
|
||||
return dict(filenames=filenames, titles=titles, terms=terms,
|
||||
objects=objects, objtypes=objtypes, objnames=objnames)
|
||||
|
||||
def prune(self, filenames):
|
||||
"""Remove data for all filenames not in the list."""
|
||||
|
@ -1,12 +1,11 @@
|
||||
/// XXX: make it cross browser
|
||||
|
||||
/**
|
||||
* make the code below compatible with browsers without
|
||||
* an installed firebug like debugger
|
||||
*/
|
||||
if (!window.console || !console.firebug) {
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
|
||||
"group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
|
||||
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
|
||||
"profile", "profileEnd"];
|
||||
window.console = {};
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
window.console[names[i]] = function() {}
|
||||
|
@ -330,31 +330,33 @@ var Search = {
|
||||
var filenames = this._index.filenames;
|
||||
var titles = this._index.titles;
|
||||
var terms = this._index.terms;
|
||||
var descrefs = this._index.descrefs;
|
||||
var modules = this._index.modules;
|
||||
var desctypes = this._index.desctypes;
|
||||
var objects = this._index.objects;
|
||||
var objtypes = this._index.objtypes;
|
||||
var objnames = this._index.objnames;
|
||||
var fileMap = {};
|
||||
var files = null;
|
||||
// different result priorities
|
||||
var importantResults = [];
|
||||
var objectResults = [];
|
||||
var regularResults = [];
|
||||
var unimportantResults = [];
|
||||
$('#search-progress').empty();
|
||||
|
||||
// lookup as object
|
||||
if (object != null) {
|
||||
for (var module in modules) {
|
||||
if (module.indexOf(object) > -1) {
|
||||
fn = modules[module];
|
||||
descr = _('module, in ') + titles[fn];
|
||||
objectResults.push([filenames[fn], module, '#module-'+module, descr]);
|
||||
}
|
||||
}
|
||||
for (var prefix in descrefs) {
|
||||
for (var name in descrefs[prefix]) {
|
||||
for (var prefix in objects) {
|
||||
for (var name in objects[prefix]) {
|
||||
var fullname = (prefix ? prefix + '.' : '') + name;
|
||||
if (fullname.toLowerCase().indexOf(object) > -1) {
|
||||
match = descrefs[prefix][name];
|
||||
descr = desctypes[match[1]] + _(', in ') + titles[match[0]];
|
||||
objectResults.push([filenames[match[0]], fullname, '#'+fullname, descr]);
|
||||
match = objects[prefix][name];
|
||||
descr = objnames[match[1]] + _(', in ') + titles[match[0]];
|
||||
// XXX the generated anchors are not generally correct
|
||||
result = [filenames[match[0]], fullname, '#'+fullname, descr];
|
||||
switch (match[2]) {
|
||||
case 1: objectResults.push(result); break;
|
||||
case 0: importantResults.push(result); break;
|
||||
case 2: unimportantResults.push(result); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -365,6 +367,14 @@ var Search = {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
|
||||
importantResults.sort(function(a, b) {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
|
||||
unimportantResults.sort(function(a, b) {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
|
||||
|
||||
// perform the search on the required terms
|
||||
for (var i = 0; i < searchterms.length; i++) {
|
||||
@ -420,8 +430,9 @@ var Search = {
|
||||
return (left > right) ? -1 : ((left < right) ? 1 : 0);
|
||||
});
|
||||
|
||||
// combine both
|
||||
var results = regularResults.concat(objectResults);
|
||||
// combine all results
|
||||
var results = unimportantResults.concat(regularResults)
|
||||
.concat(objectResults).concat(importantResults);
|
||||
|
||||
// print the results
|
||||
var resultCount = results.length;
|
||||
|
@ -24,6 +24,8 @@ import traceback
|
||||
from os import path
|
||||
|
||||
import docutils
|
||||
from docutils import nodes
|
||||
|
||||
import sphinx
|
||||
|
||||
# Errnos that we need.
|
||||
@ -451,6 +453,21 @@ def split_explicit_title(text):
|
||||
return True, match.group(1), match.group(2)
|
||||
return False, text, text
|
||||
|
||||
|
||||
def make_refnode(builder, fromdocname, todocname, targetid, child, title=None):
|
||||
"""Shortcut to create a reference node."""
|
||||
node = nodes.reference('', '')
|
||||
if fromdocname == todocname:
|
||||
node['refid'] = targetid
|
||||
else:
|
||||
node['refuri'] = (builder.get_relative_uri(fromdocname, todocname)
|
||||
+ '#' + targetid)
|
||||
if title:
|
||||
node['reftitle'] = title
|
||||
node.append(child)
|
||||
return node
|
||||
|
||||
|
||||
# monkey-patch Node.traverse to get more speed
|
||||
# traverse() is called so many times during a build that it saves
|
||||
# on average 20-25% overall build time!
|
||||
@ -480,8 +497,7 @@ def _new_traverse(self, condition=None,
|
||||
return self._old_traverse(condition, include_self,
|
||||
descend, siblings, ascend)
|
||||
|
||||
import docutils.nodes
|
||||
docutils.nodes.Node._old_traverse = docutils.nodes.Node.traverse
|
||||
docutils.nodes.Node._all_traverse = _all_traverse
|
||||
docutils.nodes.Node._fast_traverse = _fast_traverse
|
||||
docutils.nodes.Node.traverse = _new_traverse
|
||||
nodes.Node._old_traverse = nodes.Node.traverse
|
||||
nodes.Node._all_traverse = _all_traverse
|
||||
nodes.Node._fast_traverse = _fast_traverse
|
||||
nodes.Node.traverse = _new_traverse
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
# function missing in 0.5 SVN
|
||||
# function missing in docutils 0.5
|
||||
def make_admonition(node_class, name, arguments, options, content, lineno,
|
||||
content_offset, block_text, state, state_machine):
|
||||
#if not content:
|
||||
@ -35,64 +35,13 @@ def make_admonition(node_class, name, arguments, options, content, lineno,
|
||||
return [admonition_node]
|
||||
|
||||
|
||||
# support the class-style Directive interface even when using docutils 0.4
|
||||
# backwards-compatibility aliases for helpers in older Sphinx versions that
|
||||
# supported the docutils 0.4 directive function interface
|
||||
|
||||
try:
|
||||
from docutils.parsers.rst import Directive
|
||||
from docutils.parsers.rst import Directive
|
||||
|
||||
except ImportError:
|
||||
class Directive(object):
|
||||
"""
|
||||
Fake Directive class to allow Sphinx directives to be written in
|
||||
class style.
|
||||
"""
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = None
|
||||
has_content = False
|
||||
|
||||
def __init__(self, name, arguments, options, content, lineno,
|
||||
content_offset, block_text, state, state_machine):
|
||||
self.name = name
|
||||
self.arguments = arguments
|
||||
self.options = options
|
||||
self.content = content
|
||||
self.lineno = lineno
|
||||
self.content_offset = content_offset
|
||||
self.block_text = block_text
|
||||
self.state = state
|
||||
self.state_machine = state_machine
|
||||
|
||||
def run(self):
|
||||
raise NotImplementedError('Must override run() is subclass.')
|
||||
|
||||
def directive_dwim(obj):
|
||||
"""
|
||||
Return something usable with register_directive(), regardless if
|
||||
class or function. For that, we need to convert classes to a
|
||||
function for docutils 0.4.
|
||||
"""
|
||||
if isinstance(obj, type) and issubclass(obj, Directive):
|
||||
def _class_directive(name, arguments, options, content,
|
||||
lineno, content_offset, block_text,
|
||||
state, state_machine):
|
||||
return obj(name, arguments, options, content,
|
||||
lineno, content_offset, block_text,
|
||||
state, state_machine).run()
|
||||
_class_directive.options = obj.option_spec
|
||||
_class_directive.content = obj.has_content
|
||||
_class_directive.arguments = (obj.required_arguments,
|
||||
obj.optional_arguments,
|
||||
obj.final_argument_whitespace)
|
||||
return _class_directive
|
||||
return obj
|
||||
|
||||
else:
|
||||
def directive_dwim(obj):
|
||||
"""
|
||||
Return something usable with register_directive(), regardless if
|
||||
class or function. Nothing to do here, because docutils 0.5 takes
|
||||
care of converting functions itself.
|
||||
"""
|
||||
return obj
|
||||
def directive_dwim(obj):
|
||||
import warnings
|
||||
warnings.warn('directive_dwim is deprecated and no longer needed',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
return obj
|
||||
|
@ -61,7 +61,7 @@ class HTMLTranslator(BaseTranslator):
|
||||
self.add_permalinks = builder.config.html_add_permalinks
|
||||
|
||||
def visit_desc(self, node):
|
||||
self.body.append(self.starttag(node, 'dl', CLASS=node['desctype']))
|
||||
self.body.append(self.starttag(node, 'dl', CLASS=node['objtype']))
|
||||
def depart_desc(self, node):
|
||||
self.body.append('</dl>\n\n')
|
||||
|
||||
@ -69,7 +69,7 @@ class HTMLTranslator(BaseTranslator):
|
||||
# the id is set automatically
|
||||
self.body.append(self.starttag(node, 'dt'))
|
||||
# anchor for per-desc interactive data
|
||||
if node.parent['desctype'] != 'describe' \
|
||||
if node.parent['objtype'] != 'describe' \
|
||||
and node['ids'] and node['first']:
|
||||
self.body.append('<!--[%s]-->' % node['ids'][0])
|
||||
def depart_desc_signature(self, node):
|
||||
@ -189,21 +189,10 @@ class HTMLTranslator(BaseTranslator):
|
||||
numbers = self.builder.secnumbers[anchorname]
|
||||
self.body.append('.'.join(map(str, numbers)) + '. ')
|
||||
|
||||
# overwritten for docutils 0.4
|
||||
if hasattr(BaseTranslator, 'start_tag_with_title'):
|
||||
def visit_section(self, node):
|
||||
# the 0.5 version, to get the id attribute in the <div> tag
|
||||
self.section_level += 1
|
||||
self.body.append(self.starttag(node, 'div', CLASS='section'))
|
||||
|
||||
def visit_title(self, node):
|
||||
# don't move the id attribute inside the <h> tag
|
||||
BaseTranslator.visit_title(self, node, move_ids=0)
|
||||
self.add_secnumber(node)
|
||||
else:
|
||||
def visit_title(self, node):
|
||||
BaseTranslator.visit_title(self, node)
|
||||
self.add_secnumber(node)
|
||||
# overwritten
|
||||
def visit_title(self, node):
|
||||
BaseTranslator.visit_title(self, node)
|
||||
self.add_secnumber(node)
|
||||
|
||||
# overwritten
|
||||
def visit_literal_block(self, node):
|
||||
|
@ -123,7 +123,7 @@ class Table(object):
|
||||
|
||||
class Desc(object):
|
||||
def __init__(self, node):
|
||||
self.env = LaTeXTranslator.desc_map.get(node['desctype'], 'describe')
|
||||
self.env = LaTeXTranslator.desc_map.get(node['objtype'], 'describe')
|
||||
self.type = self.cls = self.name = self.params = \
|
||||
self.annotation = self.returns = ''
|
||||
self.count = 0
|
||||
@ -428,6 +428,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
def depart_subtitle(self, node):
|
||||
self.body.append(self.context.pop())
|
||||
|
||||
# XXX update this
|
||||
desc_map = {
|
||||
'function' : 'funcdesc',
|
||||
'class': 'classdesc',
|
||||
@ -462,7 +463,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
def depart_desc_signature(self, node):
|
||||
d = self.descstack[-1]
|
||||
d.cls = d.cls.rstrip('.')
|
||||
if node.parent['desctype'] != 'describe' and node['ids']:
|
||||
if node.parent['objtype'] != 'describe' and node['ids']:
|
||||
hyper = '\\hypertarget{%s}{}' % node['ids'][0]
|
||||
else:
|
||||
hyper = ''
|
||||
|
@ -174,8 +174,8 @@ class TextTranslator(nodes.NodeVisitor):
|
||||
|
||||
def visit_desc_signature(self, node):
|
||||
self.new_state(0)
|
||||
if node.parent['desctype'] in ('class', 'exception'):
|
||||
self.add_text('%s ' % node.parent['desctype'])
|
||||
if node.parent['objtype'] in ('class', 'exception'):
|
||||
self.add_text('%s ' % node.parent['objtype'])
|
||||
def depart_desc_signature(self, node):
|
||||
# XXX: wrap signatures in a way that makes sense
|
||||
self.end_state(wrap=False, end=None)
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
{# html_context variable from conf.py #}
|
||||
<meta name="hc" content="{{ hckey }}" />
|
||||
@ -6,3 +7,9 @@
|
||||
<meta name="hc_co" content="{{ hckey_co }}" />
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebartoc %}
|
||||
{# display global TOC in addition to local TOC #}
|
||||
{{ super() }}
|
||||
{{ toctree(collapse=False, maxdepth=-1) }}
|
||||
{% endblock %}
|
@ -25,6 +25,7 @@ today_fmt = '%B %d, %Y'
|
||||
exclude_trees = ['_build']
|
||||
keep_warnings = True
|
||||
pygments_style = 'sphinx'
|
||||
show_authors = True
|
||||
|
||||
rst_epilog = '.. |subst| replace:: global substitution'
|
||||
|
||||
@ -49,6 +50,7 @@ latex_additional_files = ['svgimg.svg']
|
||||
value_from_conf_py = 84
|
||||
|
||||
coverage_c_path = ['special/*.h']
|
||||
# XXX cfunction?
|
||||
coverage_c_regexes = {'cfunction': r'^PyAPI_FUNC\(.*\)\s+([^_][\w_]+)'}
|
||||
|
||||
autosummary_generate = ['autosummary']
|
||||
@ -59,7 +61,12 @@ extlinks = {'issue': ('http://bugs.python.org/issue%s', 'issue '),
|
||||
# modify tags from conf.py
|
||||
tags.add('confpytag')
|
||||
|
||||
|
||||
# -- extension API
|
||||
|
||||
from docutils import nodes
|
||||
from sphinx import addnodes
|
||||
from sphinx.util.compat import Directive
|
||||
|
||||
def userdesc_parse(env, sig, signode):
|
||||
x, y = sig.split(':')
|
||||
@ -68,7 +75,18 @@ def userdesc_parse(env, sig, signode):
|
||||
signode[-1] += addnodes.desc_parameter(y, y)
|
||||
return x
|
||||
|
||||
def functional_directive(name, arguments, options, content, lineno,
|
||||
content_offset, block_text, state, state_machine):
|
||||
return [nodes.strong(text='from function: %s' % options['opt'])]
|
||||
|
||||
class ClassDirective(Directive):
|
||||
option_spec = {'opt': lambda x: x}
|
||||
def run(self):
|
||||
return [nodes.strong(text='from class: %s' % self.options['opt'])]
|
||||
|
||||
def setup(app):
|
||||
app.add_config_value('value_from_conf_py', 42, False)
|
||||
app.add_description_unit('userdesc', 'userdescrole', '%s (userdesc)',
|
||||
userdesc_parse)
|
||||
app.add_directive('funcdir', functional_directive, opt=lambda x: x)
|
||||
app.add_directive('clsdir', ClassDirective)
|
||||
app.add_object_type('userdesc', 'userdescrole', '%s (userdesc)',
|
||||
userdesc_parse, objname='user desc')
|
||||
|
@ -11,12 +11,13 @@ Contents:
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
extapi
|
||||
images
|
||||
subdir/images
|
||||
subdir/includes
|
||||
includes
|
||||
markup
|
||||
desc
|
||||
objects
|
||||
bom
|
||||
math
|
||||
autodoc
|
||||
|
10
tests/root/extapi.txt
Normal file
10
tests/root/extapi.txt
Normal file
@ -0,0 +1,10 @@
|
||||
Extension API tests
|
||||
===================
|
||||
|
||||
Testing directives:
|
||||
|
||||
.. funcdir::
|
||||
:opt: Foo
|
||||
|
||||
.. clsdir::
|
||||
:opt: Bar
|
@ -5,7 +5,11 @@
|
||||
Testing various markup
|
||||
======================
|
||||
|
||||
Meta markup
|
||||
-----------
|
||||
|
||||
.. sectionauthor:: Georg Brandl
|
||||
.. moduleauthor:: Georg Brandl
|
||||
|
||||
.. contents:: TOC
|
||||
|
||||
@ -13,7 +17,11 @@ Testing various markup
|
||||
:author: Me
|
||||
:keywords: docs, sphinx
|
||||
|
||||
A |subst|.
|
||||
|
||||
Generic reST
|
||||
------------
|
||||
|
||||
A |subst| (the definition is in rst_epilog).
|
||||
|
||||
.. _label:
|
||||
|
||||
@ -21,22 +29,14 @@ A |subst|.
|
||||
|
||||
some code
|
||||
|
||||
Admonitions
|
||||
-----------
|
||||
Option list:
|
||||
|
||||
.. note:: Note
|
||||
Note text.
|
||||
|
||||
.. warning:: Warning
|
||||
|
||||
Warning text.
|
||||
|
||||
.. tip::
|
||||
Tip text.
|
||||
-h help
|
||||
--help also help
|
||||
|
||||
|
||||
Body directives
|
||||
---------------
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
.. topic:: Title
|
||||
|
||||
@ -69,7 +69,67 @@ Body directives
|
||||
|
||||
b
|
||||
|
||||
|
||||
|
||||
Admonitions
|
||||
^^^^^^^^^^^
|
||||
|
||||
.. admonition:: My Admonition
|
||||
|
||||
Admonition text.
|
||||
|
||||
.. note::
|
||||
Note text.
|
||||
|
||||
.. warning::
|
||||
|
||||
Warning text.
|
||||
|
||||
.. tip::
|
||||
Tip text.
|
||||
|
||||
|
||||
Inline markup
|
||||
-------------
|
||||
|
||||
*Generic inline markup*
|
||||
|
||||
* :command:`command`
|
||||
* :dfn:`dfn`
|
||||
* :guilabel:`guilabel`
|
||||
* :kbd:`kbd`
|
||||
* :mailheader:`mailheader`
|
||||
* :makevar:`makevar`
|
||||
* :manpage:`manpage`
|
||||
* :mimetype:`mimetype`
|
||||
* :newsgroup:`newsgroup`
|
||||
* :program:`program`
|
||||
* :regexp:`regexp`
|
||||
* :menuselection:`File --> Close`
|
||||
* :file:`a/{varpart}/b`
|
||||
* :samp:`print {i}`
|
||||
|
||||
*Linking inline markup*
|
||||
|
||||
* :pep:`8`
|
||||
* :rfc:`1`
|
||||
* :envvar:`HOME`
|
||||
* :keyword:`with`
|
||||
* :token:`try statement <try_stmt>`
|
||||
* :doc:`subdir/includes`
|
||||
* ``:download:`` is tested in includes.txt
|
||||
* :option:`Python -c option <python -c>`
|
||||
|
||||
Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`.
|
||||
|
||||
|
||||
.. _with:
|
||||
|
||||
With
|
||||
----
|
||||
|
||||
(Empty section.)
|
||||
|
||||
|
||||
Tables
|
||||
------
|
||||
|
||||
@ -96,6 +156,17 @@ Version markup
|
||||
Boring stuff.
|
||||
|
||||
|
||||
Code blocks
|
||||
-----------
|
||||
|
||||
.. code-block:: ruby
|
||||
:linenos:
|
||||
|
||||
def ruby?
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
Misc stuff
|
||||
----------
|
||||
|
||||
@ -124,11 +195,6 @@ This is a side note.
|
||||
|
||||
This tests :CLASS:`role names in uppercase`.
|
||||
|
||||
Option list:
|
||||
|
||||
-h help
|
||||
--help also help
|
||||
|
||||
.. centered:: LICENSE AGREEMENT
|
||||
|
||||
.. acks::
|
||||
@ -146,7 +212,7 @@ Option list:
|
||||
Particle with half-integer spin.
|
||||
|
||||
.. productionlist::
|
||||
try_stmt: try1_stmt | try2_stmt
|
||||
try_stmt: `try1_stmt` | `try2_stmt`
|
||||
try1_stmt: "try" ":" `suite`
|
||||
: ("except" [`expression` ["," `target`]] ":" `suite`)+
|
||||
: ["else" ":" `suite`]
|
||||
@ -154,7 +220,6 @@ Option list:
|
||||
try2_stmt: "try" ":" `suite`
|
||||
: "finally" ":" `suite`
|
||||
|
||||
Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`.
|
||||
|
||||
Index markup
|
||||
------------
|
||||
@ -180,11 +245,6 @@ Invalid index markup...
|
||||
Testing öäü...
|
||||
|
||||
|
||||
Object markup
|
||||
-------------
|
||||
|
||||
:cfunc:`CFunction`.
|
||||
|
||||
Only directive
|
||||
--------------
|
||||
|
||||
@ -208,3 +268,4 @@ Only directive
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#] Like footnotes.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
Testing description units
|
||||
=========================
|
||||
Testing object descriptions
|
||||
===========================
|
||||
|
||||
.. function:: func_without_module(a, b, *c[, d])
|
||||
|
||||
@ -43,22 +43,42 @@ Testing description units
|
||||
C items
|
||||
=======
|
||||
|
||||
.. cfunction:: Sphinx_DoSomething()
|
||||
.. c:function:: Sphinx_DoSomething()
|
||||
|
||||
.. cmember:: SphinxStruct.member
|
||||
.. c:member:: SphinxStruct.member
|
||||
|
||||
.. cmacro:: SPHINX_USE_PYTHON
|
||||
.. c:macro:: SPHINX_USE_PYTHON
|
||||
|
||||
.. ctype:: SphinxType
|
||||
.. c:type:: SphinxType
|
||||
|
||||
.. cvar:: sphinx_global
|
||||
.. c:var:: sphinx_global
|
||||
|
||||
|
||||
Testing references
|
||||
==================
|
||||
References
|
||||
==========
|
||||
|
||||
Referencing :class:`mod.Cls` or :Class:`mod.Cls` should be the same.
|
||||
|
||||
With target: :c:func:`Sphinx_DoSomething()` (parentheses are handled),
|
||||
:c:member:`SphinxStruct.member`, :c:macro:`SPHINX_USE_PYTHON`,
|
||||
:c:type:`SphinxType *` (pointer is handled), :c:data:`sphinx_global`.
|
||||
|
||||
Without target: :c:func:`CFunction`. :c:func:`!malloc`.
|
||||
|
||||
|
||||
Others
|
||||
======
|
||||
|
||||
.. envvar:: HOME
|
||||
|
||||
.. program:: python
|
||||
|
||||
.. cmdoption:: -c command
|
||||
|
||||
.. program:: perl
|
||||
|
||||
.. cmdoption:: -c
|
||||
|
||||
|
||||
User markup
|
||||
===========
|
@ -97,28 +97,28 @@ def test_parse_name():
|
||||
verify('function', 'util.raises', ('util', ['raises'], None, None))
|
||||
verify('function', 'util.raises(exc) -> None',
|
||||
('util', ['raises'], 'exc', 'None'))
|
||||
directive.env.autodoc_current_module = 'util'
|
||||
directive.env.doc_read_data['autodoc_module'] = 'util'
|
||||
verify('function', 'raises', ('util', ['raises'], None, None))
|
||||
directive.env.autodoc_current_module = None
|
||||
directive.env.currmodule = 'util'
|
||||
del directive.env.doc_read_data['autodoc_module']
|
||||
directive.env.doc_read_data['py_module'] = 'util'
|
||||
verify('function', 'raises', ('util', ['raises'], None, None))
|
||||
verify('class', 'TestApp', ('util', ['TestApp'], None, None))
|
||||
|
||||
# for members
|
||||
directive.env.currmodule = 'foo'
|
||||
directive.env.doc_read_data['py_module'] = 'foo'
|
||||
verify('method', 'util.TestApp.cleanup',
|
||||
('util', ['TestApp', 'cleanup'], None, None))
|
||||
directive.env.currmodule = 'util'
|
||||
directive.env.currclass = 'Foo'
|
||||
directive.env.autodoc_current_class = 'TestApp'
|
||||
directive.env.doc_read_data['py_module'] = 'util'
|
||||
directive.env.doc_read_data['py_class'] = 'Foo'
|
||||
directive.env.doc_read_data['autodoc_class'] = 'TestApp'
|
||||
verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None))
|
||||
verify('method', 'TestApp.cleanup',
|
||||
('util', ['TestApp', 'cleanup'], None, None))
|
||||
|
||||
# and clean up
|
||||
directive.env.currmodule = None
|
||||
directive.env.currclass = None
|
||||
directive.env.autodoc_current_class = None
|
||||
del directive.env.doc_read_data['py_module']
|
||||
del directive.env.doc_read_data['py_class']
|
||||
del directive.env.doc_read_data['autodoc_class']
|
||||
|
||||
|
||||
def test_format_signature():
|
||||
@ -306,7 +306,7 @@ def test_new_documenter():
|
||||
del directive.result[:]
|
||||
|
||||
options.members = ['integer']
|
||||
assert_result_contains('.. data:: integer', 'module', 'test_autodoc')
|
||||
assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc')
|
||||
|
||||
|
||||
def test_generate():
|
||||
@ -353,7 +353,7 @@ def test_generate():
|
||||
'function', 'util.foobar', more_content=None)
|
||||
|
||||
# test auto and given content mixing
|
||||
directive.env.currmodule = 'test_autodoc'
|
||||
directive.env.doc_read_data['py_module'] = 'test_autodoc'
|
||||
assert_result_contains(' Function.', 'method', 'Class.meth')
|
||||
add_content = ViewList()
|
||||
add_content.append('Content.', '', 0)
|
||||
@ -394,7 +394,8 @@ def test_generate():
|
||||
|
||||
options.members = []
|
||||
# test module flags
|
||||
assert_result_contains('.. module:: test_autodoc', 'module', 'test_autodoc')
|
||||
assert_result_contains('.. py:module:: test_autodoc',
|
||||
'module', 'test_autodoc')
|
||||
options.synopsis = 'Synopsis'
|
||||
assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc')
|
||||
options.deprecated = True
|
||||
@ -403,9 +404,9 @@ def test_generate():
|
||||
assert_result_contains(' :platform: Platform', 'module', 'test_autodoc')
|
||||
# test if __all__ is respected for modules
|
||||
options.members = ALL
|
||||
assert_result_contains('.. class:: Class', 'module', 'test_autodoc')
|
||||
assert_result_contains('.. py:class:: Class', 'module', 'test_autodoc')
|
||||
try:
|
||||
assert_result_contains('.. exception:: CustomEx',
|
||||
assert_result_contains('.. py:exception:: CustomEx',
|
||||
'module', 'test_autodoc')
|
||||
except AssertionError:
|
||||
pass
|
||||
@ -419,7 +420,7 @@ def test_generate():
|
||||
assert_result_contains(' :noindex:', 'class', 'Base')
|
||||
|
||||
# okay, now let's get serious about mixing Python and C signature stuff
|
||||
assert_result_contains('.. class:: CustomDict', 'class', 'CustomDict',
|
||||
assert_result_contains('.. py:class:: CustomDict', 'class', 'CustomDict',
|
||||
all_members=True)
|
||||
|
||||
# test inner class handling
|
||||
@ -433,7 +434,7 @@ def test_generate():
|
||||
'attribute', 'test_autodoc.Class.descr')
|
||||
|
||||
# test generation for C modules (which have no source file)
|
||||
directive.env.currmodule = 'time'
|
||||
directive.env.doc_read_data['py_module'] = 'time'
|
||||
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
|
||||
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
|
||||
|
||||
|
@ -13,28 +13,19 @@ import os
|
||||
import re
|
||||
import sys
|
||||
import difflib
|
||||
import htmlentitydefs
|
||||
from StringIO import StringIO
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
from util import *
|
||||
from etree13 import ElementTree as ET
|
||||
|
||||
try:
|
||||
import pygments
|
||||
except ImportError:
|
||||
pygments = None
|
||||
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.builders.latex import LaTeXBuilder
|
||||
from sphinx.writers.latex import LaTeXTranslator
|
||||
|
||||
from util import *
|
||||
|
||||
|
||||
def teardown_module():
|
||||
(test_root / '_build').rmtree(True)
|
||||
|
||||
|
||||
html_warnfile = StringIO()
|
||||
latex_warnfile = StringIO()
|
||||
|
||||
ENV_WARNINGS = """\
|
||||
@ -46,164 +37,11 @@ included file u'wrongenc.inc' seems to be wrong, try giving an :encoding: option
|
||||
%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png
|
||||
"""
|
||||
|
||||
HTML_WARNINGS = ENV_WARNINGS + """\
|
||||
%(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.*'
|
||||
%(root)s/markup.txt:: WARNING: invalid index entry u''
|
||||
%(root)s/markup.txt:: WARNING: invalid pair index entry u''
|
||||
%(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; '
|
||||
"""
|
||||
|
||||
LATEX_WARNINGS = ENV_WARNINGS + """\
|
||||
None:None: WARNING: no matching candidate for image URI u'foo.*'
|
||||
WARNING: invalid pair index entry u''
|
||||
"""
|
||||
|
||||
HTML_XPATH = {
|
||||
'images.html': {
|
||||
".//img[@src='_images/img.png']": '',
|
||||
".//img[@src='_images/img1.png']": '',
|
||||
".//img[@src='_images/simg.png']": '',
|
||||
".//object[@data='_images/svgimg.svg']": '',
|
||||
".//embed[@src='_images/svgimg.svg']": '',
|
||||
},
|
||||
'subdir/images.html': {
|
||||
".//img[@src='../_images/img1.png']": '',
|
||||
".//img[@src='../_images/rimg.png']": '',
|
||||
},
|
||||
'subdir/includes.html': {
|
||||
".//a[@href='../_downloads/img.png']": '',
|
||||
},
|
||||
'includes.html': {
|
||||
".//pre": u'Max Strauß',
|
||||
".//a[@href='_downloads/img.png']": '',
|
||||
".//a[@href='_downloads/img1.png']": '',
|
||||
".//pre": u'"quotes"',
|
||||
".//pre": u"'included'",
|
||||
},
|
||||
'autodoc.html': {
|
||||
".//dt[@id='test_autodoc.Class']": '',
|
||||
".//dt[@id='test_autodoc.function']/em": r'\*\*kwds',
|
||||
".//dd": r'Return spam\.',
|
||||
},
|
||||
'markup.html': {
|
||||
".//meta[@name='author'][@content='Me']": '',
|
||||
".//meta[@name='keywords'][@content='docs, sphinx']": '',
|
||||
".//a[@href='contents.html#ref1']": '',
|
||||
".//div[@id='label']": '',
|
||||
".//span[@class='option']": '--help',
|
||||
".//p": 'A global substitution.',
|
||||
".//p": 'In HTML.',
|
||||
".//p": 'In both.',
|
||||
".//p": 'Always present',
|
||||
".//title": 'set by title directive',
|
||||
".//span[@class='pre']": 'CFunction()',
|
||||
},
|
||||
'desc.html': {
|
||||
".//dt[@id='mod.Cls.meth1']": '',
|
||||
".//dt[@id='errmod.Error']": '',
|
||||
".//a[@href='#mod.Cls']": '',
|
||||
".//dl[@class='userdesc']": '',
|
||||
".//dt[@id='userdescrole-myobj']": '',
|
||||
".//a[@href='#userdescrole-myobj']": '',
|
||||
},
|
||||
'contents.html': {
|
||||
".//meta[@name='hc'][@content='hcval']": '',
|
||||
".//meta[@name='hc_co'][@content='hcval_co']": '',
|
||||
".//meta[@name='testopt'][@content='testoverride']": '',
|
||||
#".//td[@class='label']": r'\[Ref1\]', # docutils 0.5 only
|
||||
".//td[@class='label']": '',
|
||||
".//li[@class='toctree-l1']/a": 'Testing various markup',
|
||||
".//li[@class='toctree-l2']/a": 'Admonitions',
|
||||
".//title": 'Sphinx <Tests>',
|
||||
".//div[@class='footer']": 'Georg Brandl & Team',
|
||||
".//a[@href='http://python.org/']": '',
|
||||
},
|
||||
'bom.html': {
|
||||
".//title": " File with UTF-8 BOM",
|
||||
},
|
||||
'extensions.html': {
|
||||
".//a[@href='http://python.org/dev/']": "http://python.org/dev/",
|
||||
".//a[@href='http://bugs.python.org/issue1000']": "issue 1000",
|
||||
".//a[@href='http://bugs.python.org/issue1042']": "explicit caption",
|
||||
},
|
||||
'_static/statictmpl.html': {
|
||||
".//project": 'Sphinx <Tests>',
|
||||
},
|
||||
}
|
||||
|
||||
if pygments:
|
||||
HTML_XPATH['includes.html'].update({
|
||||
".//pre/span[@class='s']": u'üöä',
|
||||
".//div[@class='inc-pyobj1 highlight-text']/div/pre":
|
||||
r'^class Foo:\n pass\n\s*$',
|
||||
".//div[@class='inc-pyobj2 highlight-text']/div/pre":
|
||||
r'^ def baz\(\):\n pass\n\s*$',
|
||||
".//div[@class='inc-lines highlight-text']/div/pre":
|
||||
r'^class Foo:\n pass\nclass Bar:\n$',
|
||||
".//div[@class='inc-startend highlight-text']/div/pre":
|
||||
ur'^foo = u"Including Unicode characters: üöä"\n$',
|
||||
".//div[@class='inc-preappend highlight-text']/div/pre":
|
||||
r'(?m)^START CODE$',
|
||||
".//div[@class='inc-pyobj-dedent highlight-python']/div/pre/span":
|
||||
r'def',
|
||||
})
|
||||
HTML_XPATH['subdir/includes.html'].update({
|
||||
".//pre/span": 'line 1',
|
||||
".//pre/span": 'line 2',
|
||||
})
|
||||
|
||||
class NslessParser(ET.XMLParser):
|
||||
"""XMLParser that throws away namespaces in tag names."""
|
||||
|
||||
def _fixname(self, key):
|
||||
try:
|
||||
return self._names[key]
|
||||
except KeyError:
|
||||
name = key
|
||||
br = name.find('}')
|
||||
if br > 0:
|
||||
name = name[br+1:]
|
||||
self._names[key] = name = self._fixtext(name)
|
||||
return name
|
||||
|
||||
|
||||
def check_xpath(etree, fname, path, check):
|
||||
nodes = list(etree.findall(path))
|
||||
assert nodes != [], ('did not find any node matching xpath '
|
||||
'%r in file %s' % (path, fname))
|
||||
if hasattr(check, '__call__'):
|
||||
check(nodes)
|
||||
elif not check:
|
||||
# only check for node presence
|
||||
pass
|
||||
else:
|
||||
rex = re.compile(check)
|
||||
for node in nodes:
|
||||
if node.text and rex.search(node.text):
|
||||
break
|
||||
else:
|
||||
assert False, ('%r not found in any node matching '
|
||||
'path %s in %s: %r' % (check, path, fname,
|
||||
[node.text for node in nodes]))
|
||||
|
||||
@gen_with_app(buildername='html', warning=html_warnfile, cleanenv=True,
|
||||
confoverrides={'html_context.hckey_co': 'hcval_co'},
|
||||
tags=['testtag'])
|
||||
def test_html(app):
|
||||
app.builder.build_all()
|
||||
html_warnings = html_warnfile.getvalue().replace(os.sep, '/')
|
||||
html_warnings_exp = HTML_WARNINGS % {'root': app.srcdir}
|
||||
assert html_warnings == html_warnings_exp, 'Warnings don\'t match:\n' + \
|
||||
'\n'.join(difflib.ndiff(html_warnings_exp.splitlines(),
|
||||
html_warnings.splitlines()))
|
||||
|
||||
for fname, paths in HTML_XPATH.iteritems():
|
||||
parser = NslessParser()
|
||||
parser.entity.update(htmlentitydefs.entitydefs)
|
||||
etree = ET.parse(os.path.join(app.outdir, fname), parser)
|
||||
for path, check in paths.iteritems():
|
||||
yield check_xpath, etree, fname, path, check
|
||||
|
||||
|
||||
@with_app(buildername='latex', warning=latex_warnfile, cleanenv=True)
|
||||
def test_latex(app):
|
||||
|
252
tests/test_build_html.py
Normal file
252
tests/test_build_html.py
Normal file
@ -0,0 +1,252 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
test_build_html
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Test the HTML builder and check output against XPath.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import difflib
|
||||
import htmlentitydefs
|
||||
from StringIO import StringIO
|
||||
|
||||
try:
|
||||
import pygments
|
||||
except ImportError:
|
||||
pygments = None
|
||||
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
|
||||
from util import *
|
||||
from test_build import ENV_WARNINGS
|
||||
from etree13 import ElementTree as ET
|
||||
|
||||
|
||||
def teardown_module():
|
||||
(test_root / '_build').rmtree(True)
|
||||
|
||||
|
||||
html_warnfile = StringIO()
|
||||
|
||||
HTML_WARNINGS = ENV_WARNINGS + """\
|
||||
%(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.*'
|
||||
%(root)s/markup.txt:: WARNING: invalid index entry u''
|
||||
%(root)s/markup.txt:: WARNING: invalid pair index entry u''
|
||||
%(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; '
|
||||
"""
|
||||
|
||||
HTML_XPATH = {
|
||||
'images.html': {
|
||||
".//img[@src='_images/img.png']": '',
|
||||
".//img[@src='_images/img1.png']": '',
|
||||
".//img[@src='_images/simg.png']": '',
|
||||
".//object[@data='_images/svgimg.svg']": '',
|
||||
".//embed[@src='_images/svgimg.svg']": '',
|
||||
},
|
||||
'subdir/images.html': {
|
||||
".//img[@src='../_images/img1.png']": '',
|
||||
".//img[@src='../_images/rimg.png']": '',
|
||||
},
|
||||
'subdir/includes.html': {
|
||||
".//a[@href='../_downloads/img.png']": '',
|
||||
},
|
||||
'includes.html': {
|
||||
".//pre": u'Max Strauß',
|
||||
".//a[@href='_downloads/img.png']": '',
|
||||
".//a[@href='_downloads/img1.png']": '',
|
||||
".//pre": u'"quotes"',
|
||||
".//pre": u"'included'",
|
||||
},
|
||||
'autodoc.html': {
|
||||
".//dt[@id='test_autodoc.Class']": '',
|
||||
".//dt[@id='test_autodoc.function']/em": r'\*\*kwds',
|
||||
".//dd": r'Return spam\.',
|
||||
},
|
||||
'extapi.html': {
|
||||
".//strong": 'from function: Foo',
|
||||
".//strong": 'from class: Bar',
|
||||
},
|
||||
'markup.html': {
|
||||
".//title": 'set by title directive',
|
||||
".//p/em": 'Section author: Georg Brandl',
|
||||
".//p/em": 'Module author: Georg Brandl',
|
||||
# created by the meta directive
|
||||
".//meta[@name='author'][@content='Me']": '',
|
||||
".//meta[@name='keywords'][@content='docs, sphinx']": '',
|
||||
# a label created by ``.. _label:``
|
||||
".//div[@id='label']": '',
|
||||
# code with standard code blocks
|
||||
".//pre": '^some code$',
|
||||
# an option list
|
||||
".//span[@class='option']": '--help',
|
||||
# admonitions
|
||||
".//p[@class='first admonition-title']": 'My Admonition',
|
||||
".//p[@class='last']": 'Note text.',
|
||||
".//p[@class='last']": 'Warning text.',
|
||||
# inline markup
|
||||
".//li/strong": '^command$',
|
||||
".//li/strong": '^program$',
|
||||
".//li/em": '^dfn$',
|
||||
".//li/tt/span[@class='pre']": '^kbd$',
|
||||
".//li/em": u'File \N{TRIANGULAR BULLET} Close',
|
||||
".//li/tt/span[@class='pre']": '^a/$',
|
||||
".//li/tt/em/span[@class='pre']": '^varpart$',
|
||||
".//li/tt/em/span[@class='pre']": '^i$',
|
||||
".//a[@href='http://www.python.org/dev/peps/pep-0008']/strong": 'PEP 8',
|
||||
".//a[@href='http://tools.ietf.org/html/rfc1.html']/strong": 'RFC 1',
|
||||
".//a[@href='objects.html#envvar-HOME']/tt/span[@class='pre']": 'HOME',
|
||||
".//a[@href='#with']/tt/span[@class='pre']": '^with$',
|
||||
".//a[@href='#grammar-token-try_stmt']/tt/span": '^statement$',
|
||||
".//a[@href='subdir/includes.html']/em": 'Including in subdir',
|
||||
".//a[@href='objects.html#cmdoption-python-c']/em": 'Python -c option',
|
||||
# abbreviations
|
||||
".//abbr[@title='abbreviation']": '^abbr$',
|
||||
# version stuff
|
||||
".//span[@class='versionmodified']": 'New in version 0.6',
|
||||
# footnote reference
|
||||
".//a[@class='footnote-reference']": r'\[1\]',
|
||||
# created by reference lookup
|
||||
".//a[@href='contents.html#ref1']": '',
|
||||
# ``seealso`` directive
|
||||
".//div/p[@class='first admonition-title']": 'See also',
|
||||
# a ``hlist`` directive
|
||||
".//table[@class='hlist']/tr/td/ul/li": '^This$',
|
||||
# a ``centered`` directive
|
||||
".//p[@class='centered']/strong": 'LICENSE',
|
||||
# a glossary
|
||||
".//dl/dt[@id='term-boson']": 'boson',
|
||||
# a production list
|
||||
".//pre/strong": 'try_stmt',
|
||||
".//pre/a[@href='#grammar-token-try1_stmt']/tt/span": 'try1_stmt',
|
||||
# tests for ``only`` directive
|
||||
".//p": 'A global substitution.',
|
||||
".//p": 'In HTML.',
|
||||
".//p": 'In both.',
|
||||
".//p": 'Always present',
|
||||
},
|
||||
'objects.html': {
|
||||
".//dt[@id='mod.Cls.meth1']": '',
|
||||
".//dt[@id='errmod.Error']": '',
|
||||
".//a[@href='#mod.Cls']": '',
|
||||
".//dl[@class='userdesc']": '',
|
||||
".//dt[@id='userdesc-myobj']": '',
|
||||
".//a[@href='#userdesc-myobj']": '',
|
||||
# C references
|
||||
".//span[@class='pre']": 'CFunction()',
|
||||
".//a[@href='#Sphinx_DoSomething']": '',
|
||||
".//a[@href='#SphinxStruct.member']": '',
|
||||
".//a[@href='#SPHINX_USE_PYTHON']": '',
|
||||
".//a[@href='#SphinxType']": '',
|
||||
".//a[@href='#sphinx_global']": '',
|
||||
# test global TOC created by toctree()
|
||||
".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']":
|
||||
'Testing object descriptions',
|
||||
".//li[@class='toctree-l1']/a[@href='markup.html']":
|
||||
'Testing various markup',
|
||||
},
|
||||
'contents.html': {
|
||||
".//meta[@name='hc'][@content='hcval']": '',
|
||||
".//meta[@name='hc_co'][@content='hcval_co']": '',
|
||||
".//meta[@name='testopt'][@content='testoverride']": '',
|
||||
#".//td[@class='label']": r'\[Ref1\]', # docutils 0.5 only
|
||||
".//td[@class='label']": '',
|
||||
".//li[@class='toctree-l1']/a": 'Testing various markup',
|
||||
".//li[@class='toctree-l2']/a": 'Inline markup',
|
||||
".//title": 'Sphinx <Tests>',
|
||||
".//div[@class='footer']": 'Georg Brandl & Team',
|
||||
".//a[@href='http://python.org/']": '',
|
||||
".//li/a[@href='genindex.html']/em": 'Index',
|
||||
".//li/a[@href='modindex.html']/em": 'Module Index',
|
||||
".//li/a[@href='search.html']/em": 'Search Page',
|
||||
},
|
||||
'bom.html': {
|
||||
".//title": " File with UTF-8 BOM",
|
||||
},
|
||||
'extensions.html': {
|
||||
".//a[@href='http://python.org/dev/']": "http://python.org/dev/",
|
||||
".//a[@href='http://bugs.python.org/issue1000']": "issue 1000",
|
||||
".//a[@href='http://bugs.python.org/issue1042']": "explicit caption",
|
||||
},
|
||||
'_static/statictmpl.html': {
|
||||
".//project": 'Sphinx <Tests>',
|
||||
},
|
||||
}
|
||||
|
||||
if pygments:
|
||||
HTML_XPATH['includes.html'].update({
|
||||
".//pre/span[@class='s']": u'üöä',
|
||||
".//div[@class='inc-pyobj1 highlight-text']/div/pre":
|
||||
r'^class Foo:\n pass\n\s*$',
|
||||
".//div[@class='inc-pyobj2 highlight-text']/div/pre":
|
||||
r'^ def baz\(\):\n pass\n\s*$',
|
||||
".//div[@class='inc-lines highlight-text']/div/pre":
|
||||
r'^class Foo:\n pass\nclass Bar:\n$',
|
||||
".//div[@class='inc-startend highlight-text']/div/pre":
|
||||
ur'^foo = u"Including Unicode characters: üöä"\n$',
|
||||
".//div[@class='inc-preappend highlight-text']/div/pre":
|
||||
r'(?m)^START CODE$',
|
||||
".//div[@class='inc-pyobj-dedent highlight-python']/div/pre/span":
|
||||
r'def',
|
||||
})
|
||||
HTML_XPATH['subdir/includes.html'].update({
|
||||
".//pre/span": 'line 1',
|
||||
".//pre/span": 'line 2',
|
||||
})
|
||||
|
||||
class NslessParser(ET.XMLParser):
|
||||
"""XMLParser that throws away namespaces in tag names."""
|
||||
|
||||
def _fixname(self, key):
|
||||
try:
|
||||
return self._names[key]
|
||||
except KeyError:
|
||||
name = key
|
||||
br = name.find('}')
|
||||
if br > 0:
|
||||
name = name[br+1:]
|
||||
self._names[key] = name = self._fixtext(name)
|
||||
return name
|
||||
|
||||
|
||||
def check_xpath(etree, fname, path, check):
|
||||
nodes = list(etree.findall(path))
|
||||
assert nodes != [], ('did not find any node matching xpath '
|
||||
'%r in file %s' % (path, fname))
|
||||
if hasattr(check, '__call__'):
|
||||
check(nodes)
|
||||
elif not check:
|
||||
# only check for node presence
|
||||
pass
|
||||
else:
|
||||
rex = re.compile(check)
|
||||
for node in nodes:
|
||||
if node.text and rex.search(node.text):
|
||||
break
|
||||
else:
|
||||
assert False, ('%r not found in any node matching '
|
||||
'path %s in %s: %r' % (check, path, fname,
|
||||
[node.text for node in nodes]))
|
||||
|
||||
@gen_with_app(buildername='html', warning=html_warnfile, cleanenv=True,
|
||||
confoverrides={'html_context.hckey_co': 'hcval_co'},
|
||||
tags=['testtag'])
|
||||
def test_html(app):
|
||||
app.builder.build_all()
|
||||
html_warnings = html_warnfile.getvalue().replace(os.sep, '/')
|
||||
html_warnings_exp = HTML_WARNINGS % {'root': app.srcdir}
|
||||
assert html_warnings == html_warnings_exp, 'Warnings don\'t match:\n' + \
|
||||
'\n'.join(difflib.ndiff(html_warnings_exp.splitlines(),
|
||||
html_warnings.splitlines()))
|
||||
|
||||
for fname, paths in HTML_XPATH.iteritems():
|
||||
parser = NslessParser()
|
||||
parser.entity.update(htmlentitydefs.entitydefs)
|
||||
etree = ET.parse(os.path.join(app.outdir, fname), parser)
|
||||
for path, check in paths.iteritems():
|
||||
yield check_xpath, etree, fname, path, check
|
@ -32,7 +32,7 @@ def test_core_config(app):
|
||||
# simple default values
|
||||
assert 'exclude_dirs' not in cfg.__dict__
|
||||
assert cfg.exclude_dirs == []
|
||||
assert cfg.show_authors == False
|
||||
assert cfg.trim_footnote_reference_space == False
|
||||
|
||||
# complex default values
|
||||
assert 'html_title' not in cfg.__dict__
|
||||
|
@ -36,6 +36,7 @@ def test_build(app):
|
||||
undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').text())
|
||||
assert len(undoc_c) == 1
|
||||
# the key is the full path to the header file, which isn't testable
|
||||
# XXX this should fail right now
|
||||
assert undoc_c.values()[0] == [('cfunction', 'Py_SphinxTest')]
|
||||
|
||||
assert 'test_autodoc' in undoc_py
|
||||
|
@ -20,8 +20,8 @@ warnings = []
|
||||
|
||||
def setup_module():
|
||||
global app, env
|
||||
app = TestApp(srcdir='(temp)')
|
||||
env = BuildEnvironment(app.srcdir, app.doctreedir, app.config)
|
||||
app = TestApp(srcdir='(temp)', freshenv=True)
|
||||
env = app.env
|
||||
env.set_warnfunc(lambda *args: warnings.append(args))
|
||||
|
||||
def teardown_module():
|
||||
@ -51,7 +51,7 @@ def test_images():
|
||||
|
||||
tree = env.get_doctree('images')
|
||||
app._warning.reset()
|
||||
htmlbuilder = StandaloneHTMLBuilder(app, env)
|
||||
htmlbuilder = StandaloneHTMLBuilder(app)
|
||||
htmlbuilder.post_process_images(tree)
|
||||
assert "no matching candidate for image URI u'foo.*'" in \
|
||||
app._warning.content[-1]
|
||||
@ -61,7 +61,7 @@ def test_images():
|
||||
set(['img.png', 'img1.png', 'simg.png', 'svgimg.svg'])
|
||||
|
||||
app._warning.reset()
|
||||
latexbuilder = LaTeXBuilder(app, env)
|
||||
latexbuilder = LaTeXBuilder(app)
|
||||
latexbuilder.post_process_images(tree)
|
||||
assert "no matching candidate for image URI u'foo.*'" in \
|
||||
app._warning.content[-1]
|
||||
@ -92,10 +92,10 @@ def test_second_update():
|
||||
assert 'autodoc' not in env.found_docs
|
||||
|
||||
def test_object_inventory():
|
||||
refs = env.descrefs
|
||||
refs = env.domaindata['py']['objects']
|
||||
|
||||
assert 'func_without_module' in refs
|
||||
assert refs['func_without_module'] == ('desc', 'function')
|
||||
assert refs['func_without_module'] == ('objects', 'function')
|
||||
assert 'func_without_module2' in refs
|
||||
assert 'mod.func_in_module' in refs
|
||||
assert 'mod.Cls' in refs
|
||||
@ -109,5 +109,8 @@ def test_object_inventory():
|
||||
assert 'func_in_module' not in refs
|
||||
assert 'func_noindex' not in refs
|
||||
|
||||
assert 'mod' in env.modules
|
||||
assert env.modules['mod'] == ('desc', 'Module synopsis.', 'UNIX', False)
|
||||
assert env.domaindata['py']['modules']['mod'] == \
|
||||
('objects', 'Module synopsis.', 'UNIX', False)
|
||||
|
||||
assert env.domains['py'].data is env.domaindata['py']
|
||||
assert env.domains['c'].data is env.domaindata['c']
|
||||
|
112
tests/test_intersphinx.py
Normal file
112
tests/test_intersphinx.py
Normal file
@ -0,0 +1,112 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
test_intersphinx
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Test the intersphinx extension.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import zlib
|
||||
import posixpath
|
||||
from cStringIO import StringIO
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.ext.intersphinx import read_inventory_v1, read_inventory_v2, \
|
||||
fetch_inventory, load_mappings, missing_reference
|
||||
|
||||
from util import *
|
||||
|
||||
|
||||
inventory_v1 = '''\
|
||||
# Sphinx inventory version 1
|
||||
# Project: foo
|
||||
# Version: 1.0
|
||||
module mod foo.html
|
||||
module.cls class foo.html
|
||||
'''
|
||||
|
||||
inventory_v2 = '''\
|
||||
# Sphinx inventory version 2
|
||||
# Project: foo
|
||||
# Version: 2.0
|
||||
# The remainder of this file is compressed with zlib.
|
||||
''' + zlib.compress('''\
|
||||
module1 py:module 0 foo.html#module-module1
|
||||
module2 py:module 0 foo.html#module-$
|
||||
module1.func py:function 1 sub/foo.html#$
|
||||
CFunc c:function 2 cfunc.html#CFunc
|
||||
''')
|
||||
|
||||
|
||||
def test_read_inventory_v1():
|
||||
f = StringIO(inventory_v1)
|
||||
f.readline()
|
||||
invdata = read_inventory_v1(f, '/util', posixpath.join)
|
||||
assert invdata['py:module']['module'] == \
|
||||
('foo', '1.0', '/util/foo.html#module-module')
|
||||
assert invdata['py:class']['module.cls'] == \
|
||||
('foo', '1.0', '/util/foo.html#module.cls')
|
||||
|
||||
|
||||
def test_read_inventory_v2():
|
||||
f = StringIO(inventory_v2)
|
||||
f.readline()
|
||||
invdata1 = read_inventory_v2(f, '/util', posixpath.join)
|
||||
|
||||
# try again with a small buffer size to test the chunking algorithm
|
||||
f = StringIO(inventory_v2)
|
||||
f.readline()
|
||||
invdata2 = read_inventory_v2(f, '/util', posixpath.join, bufsize=5)
|
||||
|
||||
assert invdata1 == invdata2
|
||||
|
||||
assert len(invdata1['py:module']) == 2
|
||||
assert invdata1['py:module']['module1'] == \
|
||||
('foo', '2.0', '/util/foo.html#module-module1')
|
||||
assert invdata1['py:module']['module2'] == \
|
||||
('foo', '2.0', '/util/foo.html#module-module2')
|
||||
assert invdata1['py:function']['module1.func'][2] == \
|
||||
'/util/sub/foo.html#module1.func'
|
||||
assert invdata1['c:function']['CFunc'][2] == '/util/cfunc.html#CFunc'
|
||||
|
||||
|
||||
@with_app(confoverrides={'extensions': 'sphinx.ext.intersphinx'})
|
||||
@with_tempdir
|
||||
def test_missing_reference(tempdir, app):
|
||||
inv_file = tempdir / 'inventory'
|
||||
write_file(inv_file, inventory_v2)
|
||||
app.config.intersphinx_mapping = {'http://docs.python.org/': inv_file}
|
||||
app.config.intersphinx_cache_limit = 0
|
||||
|
||||
# load the inventory and check if it's done correctly
|
||||
load_mappings(app)
|
||||
inv = app.env.intersphinx_inventory
|
||||
|
||||
assert inv['py:module']['module2'] == \
|
||||
('foo', '2.0', 'http://docs.python.org/foo.html#module-module2')
|
||||
|
||||
# create fake nodes and check referencing
|
||||
contnode = nodes.emphasis('foo')
|
||||
refnode = addnodes.pending_xref('')
|
||||
refnode['reftarget'] = 'module1.func'
|
||||
refnode['reftype'] = 'func'
|
||||
refnode['refdomain'] = 'py'
|
||||
|
||||
rn = missing_reference(app, app.env, refnode, contnode)
|
||||
assert isinstance(rn, nodes.reference)
|
||||
assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func'
|
||||
assert rn['reftitle'] == '(in foo v2.0)'
|
||||
assert rn[0] is contnode
|
||||
|
||||
# create unresolvable nodes and check None return value
|
||||
refnode['reftype'] = 'foo'
|
||||
assert missing_reference(app, app.env, refnode, contnode) is None
|
||||
|
||||
refnode['reftype'] = 'function'
|
||||
refnode['reftarget'] = 'foo.func'
|
||||
assert missing_reference(app, app.env, refnode, contnode) is None
|
@ -29,6 +29,7 @@ def setup_module():
|
||||
components=(rst.Parser, HTMLWriter, LaTeXWriter))
|
||||
settings = optparser.get_default_values()
|
||||
settings.env = app.builder.env
|
||||
settings.env.patch_lookup_functions()
|
||||
parser = rst.Parser()
|
||||
|
||||
def teardown_module():
|
||||
@ -60,7 +61,7 @@ def verify_re(rst, html_expected, latex_expected):
|
||||
html_translator = ForgivingHTMLTranslator(app.builder, document)
|
||||
document.walkabout(html_translator)
|
||||
html_translated = ''.join(html_translator.fragment).strip()
|
||||
assert re.match(html_expected, html_translated), 'from' + rst
|
||||
assert re.match(html_expected, html_translated), 'from ' + rst
|
||||
|
||||
if latex_expected:
|
||||
latex_translator = ForgivingLaTeXTranslator(document, app.builder)
|
||||
|
@ -184,9 +184,9 @@ def gen_with_app(*args, **kwargs):
|
||||
|
||||
|
||||
def with_tempdir(func):
|
||||
def new_func():
|
||||
def new_func(*args, **kwds):
|
||||
tempdir = path(tempfile.mkdtemp())
|
||||
func(tempdir)
|
||||
func(tempdir, *args, **kwds)
|
||||
tempdir.rmtree()
|
||||
new_func.__name__ = func.__name__
|
||||
return new_func
|
||||
|
Loading…
Reference in New Issue
Block a user