merge with 1.0

This commit is contained in:
Georg Brandl 2010-08-05 16:20:12 +02:00
commit 861941e5f1
31 changed files with 298 additions and 155 deletions

29
CHANGES
View File

@ -7,6 +7,35 @@ Release 1.1 (in development)
Release 1.0.2 (in development) Release 1.0.2 (in development)
============================== ==============================
* Allow breaking long signatures, continuing with backlash-escaped
newlines.
* Fix unwanted styling of C domain references (because of a namespace
clash with Pygments styles).
* Allow references to PEPs and RFCs with explicit anchors.
* #471: Fix LaTeX references to figures.
* #482: When doing a non-exact search, match only the given type
of object.
* #481: Apply non-exact search for Python reference targets with
``.name`` for modules too.
* #484: Fix crash when duplicating a parameter in an info field list.
* #487: Fix setting the default role to one provided by the
``oldcmarkup`` extension.
* #488: Fix crash when json-py is installed, which provides a
``json`` module but is incompatible to simplejson.
* #480: Fix handling of target naming in intersphinx.
* #486: Fix removal of ``!`` for all cross-reference roles.
Release 1.0.1 (Jul 27, 2010) Release 1.0.1 (Jul 27, 2010)
============================ ============================

View File

@ -97,6 +97,7 @@ Documentation using the sphinxdoc theme
* Satchmo: http://www.satchmoproject.com/docs/svn/ * Satchmo: http://www.satchmoproject.com/docs/svn/
* Sphinx: http://sphinx.pocoo.org/ * Sphinx: http://sphinx.pocoo.org/
* Sqlkit: http://sqlkit.argolinux.org/ * Sqlkit: http://sqlkit.argolinux.org/
* Tau: http://www.tango-controls.org/static/tau/latest/doc/html/index.html
* Total Open Station: http://tops.berlios.de/ * Total Open Station: http://tops.berlios.de/
* WebFaction: http://docs.webfaction.com/ * WebFaction: http://docs.webfaction.com/

View File

@ -255,11 +255,11 @@ All serialization builders outputs one file per source file and a few special
files. They also copy the reST source files in the directory ``_sources`` files. They also copy the reST source files in the directory ``_sources``
under the output directory. under the output directory.
The :class:`PickleHTMLBuilder` is a builtin subclass that implements the pickle The :class:`.PickleHTMLBuilder` is a builtin subclass that implements the pickle
serialization interface. serialization interface.
The files per source file have the extensions of The files per source file have the extensions of
:attr:`~SerializingHTMLBuilder.out_suffix`, and are arranged in directories :attr:`~.SerializingHTMLBuilder.out_suffix`, and are arranged in directories
just as the source files are. They unserialize to a dictionary (or dictionary just as the source files are. They unserialize to a dictionary (or dictionary
like structure) with these keys: like structure) with these keys:
@ -290,7 +290,7 @@ like structure) with these keys:
The special files are located in the root output directory. They are: The special files are located in the root output directory. They are:
:attr:`SerializingHTMLBuilder.globalcontext_filename` :attr:`.SerializingHTMLBuilder.globalcontext_filename`
A pickled dict with these keys: A pickled dict with these keys:
``project``, ``copyright``, ``release``, ``version`` ``project``, ``copyright``, ``release``, ``version``
@ -309,7 +309,7 @@ The special files are located in the root output directory. They are:
``titles`` ``titles``
A dictionary of all documents' titles, as HTML strings. A dictionary of all documents' titles, as HTML strings.
:attr:`SerializingHTMLBuilder.searchindex_filename` :attr:`.SerializingHTMLBuilder.searchindex_filename`
An index that can be used for searching the documentation. It is a pickled An index that can be used for searching the documentation. It is a pickled
list with these entries: list with these entries:

View File

@ -64,6 +64,10 @@ man_pages = [
'template generator', '', 1), 'template generator', '', 1),
] ]
# We're not using intersphinx right now, but if we did, this would be part of
# the mapping:
intersphinx_mapping = {'python': ('http://docs.python.org/dev', None)}
# -- Extension interface ------------------------------------------------------- # -- Extension interface -------------------------------------------------------

View File

@ -346,12 +346,12 @@ Project information
A boolean that decides whether module names are prepended to all A boolean that decides whether module names are prepended to all
:term:`object` names (for object types where a "module" of some kind is :term:`object` names (for object types where a "module" of some kind is
defined), e.g. for :rst:dir:`function` directives. Default is ``True``. defined), e.g. for :rst:dir:`py:function` directives. Default is ``True``.
.. confval:: show_authors .. confval:: show_authors
A boolean that decides whether :rst:dir:`moduleauthor` and :rst:dir:`sectionauthor` A boolean that decides whether :rst:dir:`codeauthor` and
directives produce any output in the built files. :rst:dir:`sectionauthor` directives produce any output in the built files.
.. confval:: modindex_common_prefix .. confval:: modindex_common_prefix
@ -388,6 +388,8 @@ Options for HTML output
These options influence HTML as well as HTML Help output, and other builders These options influence HTML as well as HTML Help output, and other builders
that use Sphinx' HTMLWriter class. that use Sphinx' HTMLWriter class.
.. XXX document html_context
.. confval:: html_theme .. confval:: html_theme
The "theme" that the HTML output should use. See the :doc:`section about The "theme" that the HTML output should use. See the :doc:`section about
@ -553,19 +555,6 @@ that use Sphinx' HTMLWriter class.
This will render the template ``customdownload.html`` as the page This will render the template ``customdownload.html`` as the page
``download.html``. ``download.html``.
.. note::
Earlier versions of Sphinx had a value called :confval:`html_index` which
was a clumsy way of controlling the content of the "index" document. If
you used this feature, migrate it by adding an ``'index'`` key to this
setting, with your custom template as the value, and in your custom
template, use ::
{% extend "defindex.html" %}
{% block tables %}
... old template content ...
{% endblock %}
.. confval:: html_domain_indices .. confval:: html_domain_indices
If true, generate domain-specific indices in addition to the general index. If true, generate domain-specific indices in addition to the general index.

View File

@ -52,10 +52,19 @@ flag ``:noindex:``. An example using a Python domain directive::
.. py:function:: spam(eggs) .. py:function:: spam(eggs)
ham(eggs) ham(eggs)
:noindex:
Spam or ham the foo. Spam or ham the foo.
This describes the two Python functions ``spam`` and ``ham``. (Note that when
signatures become too long, you can break them if you add a backslash to lines
that are continued in the next line. Example::
.. py:function:: filterwarnings(action, message='', category=Warning, \
module='', lineno=0, append=False)
:noindex:
(This example also shows how to use the ``:noindex:`` flag.)
The domains also provide roles that link back to these object descriptions. For The domains also provide roles that link back to these object descriptions. For
example, to link to one of the functions described in the example above, you example, to link to one of the functions described in the example above, you
could say :: could say ::
@ -138,11 +147,12 @@ declarations:
.. rst:directive:: .. py:currentmodule:: name .. rst:directive:: .. py:currentmodule:: name
This directive tells Sphinx that the classes, functions etc. documented from This directive tells Sphinx that the classes, functions etc. documented from
here are in the given module (like :rst:dir:`py:module`), but it will not create here are in the given module (like :rst:dir:`py:module`), but it will not
index entries, an entry in the Global Module Index, or a link target for create index entries, an entry in the Global Module Index, or a link target
:rst:role:`mod`. This is helpful in situations where documentation for things in for :rst:role:`py:mod`. This is helpful in situations where documentation
a module is spread over multiple files or sections -- one location has the for things in a module is spread over multiple files or sections -- one
:rst:dir:`py:module` directive, the others only :rst:dir:`py:currentmodule`. location has the :rst:dir:`py:module` directive, the others only
:rst:dir:`py:currentmodule`.
The following directives are provided for module and class contents: The following directives are provided for module and class contents:
@ -363,6 +373,9 @@ dot, this order is reversed. For example, in the documentation of Python's
:mod:`codecs` module, ``:py:func:`open``` always refers to the built-in :mod:`codecs` module, ``:py:func:`open``` always refers to the built-in
function, while ``:py:func:`.open``` refers to :func:`codecs.open`. function, while ``:py:func:`.open``` refers to :func:`codecs.open`.
A similar heuristic is used to determine whether the name is an attribute of the
currently documented class.
Also, if the name is prefixed with a dot, and no exact match is found, the Also, if the name is prefixed with a dot, and no exact match is found, the
target is taken as a suffix and all object names with that suffix are target is taken as a suffix and all object names with that suffix are
searched. For example, ``:py:meth:`.TarFile.close``` references the searched. For example, ``:py:meth:`.TarFile.close``` references the
@ -370,8 +383,9 @@ searched. For example, ``:py:meth:`.TarFile.close``` references the
``tarfile``. Since this can get ambiguous, if there is more than one possible ``tarfile``. Since this can get ambiguous, if there is more than one possible
match, you will get a warning from Sphinx. match, you will get a warning from Sphinx.
A similar heuristic is used to determine whether the name is an attribute of the Note that you can combine the ``~`` and ``.`` prefixes:
currently documented class. ``:py:meth:`~.TarFile.close``` will reference the ``tarfile.TarFile.close()``
method, but the visible link caption will only be ``close()``.
.. _c-domain: .. _c-domain:

View File

@ -210,7 +210,7 @@ the following public API:
standard Sphinx roles (see :ref:`xref-syntax`). standard Sphinx roles (see :ref:`xref-syntax`).
This method is also available under the deprecated alias This method is also available under the deprecated alias
:meth:`add_description_unit`. ``add_description_unit``.
.. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='') .. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='')
@ -272,6 +272,8 @@ the following public API:
This allows to auto-document new types of objects. See the source of the This allows to auto-document new types of objects. See the source of the
autodoc module for examples on how to subclass :class:`Documenter`. autodoc module for examples on how to subclass :class:`Documenter`.
.. XXX add real docs for Documenter and subclassing
.. versionadded:: 0.6 .. versionadded:: 0.6
.. method:: Sphinx.add_autodoc_attrgetter(type, getter) .. method:: Sphinx.add_autodoc_attrgetter(type, getter)

View File

@ -27,20 +27,21 @@ two locations for documentation, while at the same time avoiding
auto-generated-looking pure API documentation. auto-generated-looking pure API documentation.
:mod:`autodoc` provides several directives that are versions of the usual :mod:`autodoc` provides several directives that are versions of the usual
:rst:dir:`module`, :rst:dir:`class` and so forth. On parsing time, they import the :rst:dir:`py:module`, :rst:dir:`py:class` and so forth. On parsing time, they
corresponding module and extract the docstring of the given objects, inserting import the corresponding module and extract the docstring of the given objects,
them into the page source under a suitable :rst:dir:`module`, :rst:dir:`class` etc. inserting them into the page source under a suitable :rst:dir:`py:module`,
directive. :rst:dir:`py:class` etc. directive.
.. note:: .. note::
Just as :rst:dir:`class` respects the current :rst:dir:`module`, :rst:dir:`autoclass` Just as :rst:dir:`py:class` respects the current :rst:dir:`py:module`,
will also do so, and likewise with :rst:dir:`method` and :rst:dir:`class`. :rst:dir:`autoclass` will also do so. Likewise, :rst:dir:`automethod` will
respect the current :rst:dir:`py:class`.
.. rst:directive:: automodule .. rst:directive:: automodule
autoclass autoclass
autoexception autoexception
Document a module, class or exception. All three directives will by default Document a module, class or exception. All three directives will by default
only insert the docstring of the object itself:: only insert the docstring of the object itself::
@ -127,23 +128,24 @@ directive.
.. versionadded:: 0.4 .. versionadded:: 0.4
* The :rst:dir:`automodule`, :rst:dir:`autoclass` and :rst:dir:`autoexception` directives * The :rst:dir:`automodule`, :rst:dir:`autoclass` and
also support a flag option called ``show-inheritance``. When given, a list :rst:dir:`autoexception` directives also support a flag option called
of base classes will be inserted just below the class signature (when used ``show-inheritance``. When given, a list of base classes will be inserted
with :rst:dir:`automodule`, this will be inserted for every class that is just below the class signature (when used with :rst:dir:`automodule`, this
documented in the module). will be inserted for every class that is documented in the module).
.. versionadded:: 0.4 .. versionadded:: 0.4
* All autodoc directives support the ``noindex`` flag option that has the * All autodoc directives support the ``noindex`` flag option that has the
same effect as for standard :rst:dir:`function` etc. directives: no index same effect as for standard :rst:dir:`py:function` etc. directives: no
entries are generated for the documented object (and all autodocumented index entries are generated for the documented object (and all
members). autodocumented members).
.. versionadded:: 0.4 .. versionadded:: 0.4
* :rst:dir:`automodule` also recognizes the ``synopsis``, ``platform`` and * :rst:dir:`automodule` also recognizes the ``synopsis``, ``platform`` and
``deprecated`` options that the standard :rst:dir:`module` directive supports. ``deprecated`` options that the standard :rst:dir:`py:module` directive
supports.
.. versionadded:: 0.5 .. versionadded:: 0.5
@ -213,8 +215,8 @@ There are also new config values that you can set:
``"class"`` ``"class"``
Only the class' docstring is inserted. This is the default. You can Only the class' docstring is inserted. This is the default. You can
still document ``__init__`` as a separate method using :rst:dir:`automethod` still document ``__init__`` as a separate method using
or the ``members`` option to :rst:dir:`autoclass`. :rst:dir:`automethod` or the ``members`` option to :rst:dir:`autoclass`.
``"both"`` ``"both"``
Both the class' and the ``__init__`` method's docstring are concatenated Both the class' and the ``__init__`` method's docstring are concatenated
and inserted. and inserted.

View File

@ -17,7 +17,7 @@ It adds this directive:
This directive has one or more arguments, each giving a module or class This directive has one or more arguments, each giving a module or class
name. Class names can be unqualified; in that case they are taken to exist name. Class names can be unqualified; in that case they are taken to exist
in the currently described module (see :rst:dir:`module`). in the currently described module (see :rst:dir:`py:module`).
For each given class, and each class in each given module, the base classes For each given class, and each class in each given module, the base classes
are determined. Then, from all classes and their base classes, a graph is are determined. Then, from all classes and their base classes, a graph is

View File

@ -84,7 +84,7 @@ linking:
To add links to modules and objects in the Python standard library To add links to modules and objects in the Python standard library
documentation, use:: documentation, use::
intersphinx_mapping = {'python': ('http://docs.python.org/', None)} intersphinx_mapping = {'python': ('http://docs.python.org/3.2', None)}
This will download the corresponding :file:`objects.inv` file from the This will download the corresponding :file:`objects.inv` file from the
Internet and generate links to the pages under the given URI. The downloaded Internet and generate links to the pages under the given URI. The downloaded
@ -94,12 +94,12 @@ linking:
A second example, showing the meaning of a non-``None`` value of the second A second example, showing the meaning of a non-``None`` value of the second
tuple item:: tuple item::
intersphinx_mapping = {'python': ('http://docs.python.org/', intersphinx_mapping = {'python': ('http://docs.python.org/3.2',
'python-inv.txt')} 'python-inv.txt')}
This will read the inventory from :file:`python-inv.txt` in the source This will read the inventory from :file:`python-inv.txt` in the source
directory, but still generate links to the pages under directory, but still generate links to the pages under
``http://docs.python.org/``. It is up to you to update the inventory file as ``http://docs.python.org/3.2``. It is up to you to update the inventory file as
new objects are added to the Python documentation. new objects are added to the Python documentation.
.. confval:: intersphinx_cache_limit .. confval:: intersphinx_cache_limit

View File

@ -17,15 +17,15 @@ if possible, reuse that support too.
.. note:: .. note::
:mod:`sphinx.ext.mathbase` is not meant to be added to the :mod:`.mathbase` is not meant to be added to the :confval:`extensions` config
:confval:`extensions` config value, instead, use either value, instead, use either :mod:`sphinx.ext.pngmath` or
:mod:`sphinx.ext.pngmath` or :mod:`sphinx.ext.jsmath` as described below. :mod:`sphinx.ext.jsmath` as described below.
The input language for mathematics is LaTeX markup. This is the de-facto The input language for mathematics is LaTeX markup. This is the de-facto
standard for plain-text math notation and has the added advantage that no standard for plain-text math notation and has the added advantage that no
further translation is necessary when building LaTeX output. further translation is necessary when building LaTeX output.
:mod:`mathbase` defines these new markup elements: :mod:`.mathbase` defines these new markup elements:
.. rst:role:: math .. rst:role:: math

View File

@ -260,7 +260,7 @@ in a different style:
.. rst:role:: samp .. rst:role:: samp
A piece of literal text, such as code. Within the contents, you can use A piece of literal text, such as code. Within the contents, you can use
curly braces to indicate a "variable" part, as in :rst:dir:`file`. For curly braces to indicate a "variable" part, as in :rst:role:`file`. For
example, in ``:samp:`print 1+{variable}```, the part ``variable`` would be example, in ``:samp:`print 1+{variable}```, the part ``variable`` would be
emphasized. emphasized.
@ -274,13 +274,15 @@ The following roles generate external links:
A reference to a Python Enhancement Proposal. This generates appropriate A reference to a Python Enhancement Proposal. This generates appropriate
index entries. The text "PEP *number*\ " is generated; in the HTML output, index entries. The text "PEP *number*\ " is generated; in the HTML output,
this text is a hyperlink to an online copy of the specified PEP. this text is a hyperlink to an online copy of the specified PEP. You can
link to a specific section by saying ``:pep:`number#anchor```.
.. rst:role:: rfc .. rst:role:: rfc
A reference to an Internet Request for Comments. This generates appropriate A reference to an Internet Request for Comments. This generates appropriate
index entries. The text "RFC *number*\ " is generated; in the HTML output, index entries. The text "RFC *number*\ " is generated; in the HTML output,
this text is a hyperlink to an online copy of the specified RFC. this text is a hyperlink to an online copy of the specified RFC. You can
link to a specific section by saying ``:rfc:`number#anchor```.
Note that there are no special roles for including hyperlinks as you can use Note that there are no special roles for including hyperlinks as you can use

View File

@ -42,15 +42,25 @@ units as well as normal text:
Example:: Example::
.. versionadded:: 2.5 .. versionadded:: 2.5
The `spam` parameter. The *spam* parameter.
Note that there must be no blank line between the directive head and the Note that there must be no blank line between the directive head and the
explanation; this is to make these blocks visually continuous in the markup. explanation; this is to make these blocks visually continuous in the markup.
.. rst:directive:: .. versionchanged:: version .. rst:directive:: .. versionchanged:: version
Similar to :rst:dir:`versionadded`, but describes when and what changed in the named Similar to :rst:dir:`versionadded`, but describes when and what changed in
feature in some way (new parameters, changed side effects, etc.). the named feature in some way (new parameters, changed side effects, etc.).
.. rst:directive:: .. deprecated:: vesion
Similar to :rst:dir:`versionchanged`, but describes when the feature was
deprecated. An explanation can also be given, for example to inform the
reader what should be used instead. Example::
.. deprecated:: 3.1
Use :func:`spam` instead.
-------------- --------------

View File

@ -151,7 +151,7 @@ The special document names (and pages generated for them) are:
:ref:`object descriptions <basic-domain-markup>`, and from :rst:dir:`index` :ref:`object descriptions <basic-domain-markup>`, and from :rst:dir:`index`
directives. directives.
The module index contains one entry per :rst:dir:`module` directive. The Python module index contains one entry per :rst:dir:`py:module` directive.
The search page contains a form that uses the generated JSON search index and The search page contains a form that uses the generated JSON search index and
JavaScript to full-text search the generated documents for search words; it JavaScript to full-text search the generated documents for search words; it

View File

@ -21,10 +21,10 @@ No. You have several other options:
configuration value accordingly. configuration value accordingly.
* You can :ref:`write a custom builder <writing-builders>` that derives from * You can :ref:`write a custom builder <writing-builders>` that derives from
:class:`~sphinx.builders.StandaloneHTMLBuilder` and calls your template engine :class:`~sphinx.builders.html.StandaloneHTMLBuilder` and calls your template
of choice. engine of choice.
* You can use the :class:`~sphinx.builders.PickleHTMLBuilder` that produces * You can use the :class:`~sphinx.builders.html.PickleHTMLBuilder` that produces
pickle files with the page contents, and postprocess them using a custom tool, pickle files with the page contents, and postprocess them using a custom tool,
or use them in your Web application. or use them in your Web application.
@ -261,9 +261,9 @@ in the future.
.. data:: file_suffix .. data:: file_suffix
The value of the builder's :attr:`out_suffix` attribute, i.e. the file name The value of the builder's :attr:`~.SerializingHTMLBuilder.out_suffix`
extension that the output files will get. For a standard HTML builder, this attribute, i.e. the file name extension that the output files will get. For
is usually ``.html``. a standard HTML builder, this is usually ``.html``.
.. data:: has_source .. data:: has_source

View File

@ -32,6 +32,7 @@ except AttributeError:
# RE to strip backslash escapes # RE to strip backslash escapes
nl_escape_re = re.compile(r'\\\n')
strip_backslash_re = re.compile(r'\\(?=[^\\])') strip_backslash_re = re.compile(r'\\(?=[^\\])')
@ -57,10 +58,12 @@ class ObjectDescription(Directive):
""" """
Retrieve the signatures to document from the directive arguments. By Retrieve the signatures to document from the directive arguments. By
default, signatures are given as arguments, one per line. default, signatures are given as arguments, one per line.
Backslash-escaping of newlines is supported.
""" """
lines = nl_escape_re.sub('', self.arguments[0]).split('\n')
# remove backslashes to support (dummy) escapes; helps Vim highlighting # remove backslashes to support (dummy) escapes; helps Vim highlighting
return [strip_backslash_re.sub('', sig.strip()) return [strip_backslash_re.sub('', line.strip()) for line in lines]
for sig in self.arguments[0].split('\n')]
def handle_signature(self, sig, signode): def handle_signature(self, sig, signode):
""" """

View File

@ -356,6 +356,9 @@ class PyModule(Directive):
env.domaindata['py']['modules'][modname] = \ env.domaindata['py']['modules'][modname] = \
(env.docname, self.options.get('synopsis', ''), (env.docname, self.options.get('synopsis', ''),
self.options.get('platform', ''), 'deprecated' in self.options) self.options.get('platform', ''), 'deprecated' in self.options)
# make a duplicate entry in 'objects' to facilitate searching for the
# module in PythonDomain.find_obj()
env.domaindata['py']['objects'][modname] = (env.docname, 'module')
targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True) targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
self.state.document.note_explicit_target(targetnode) self.state.document.note_explicit_target(targetnode)
ret = [targetnode] ret = [targetnode]
@ -544,7 +547,7 @@ class PythonDomain(Domain):
if fn == docname: if fn == docname:
del self.data['modules'][modname] del self.data['modules'][modname]
def find_obj(self, env, modname, classname, name, type, searchorder=0): def find_obj(self, env, modname, classname, name, type, searchmode=0):
""" """
Find a Python object for "name", perhaps using the given module and/or Find a Python object for "name", perhaps using the given module and/or
classname. Returns a list of (name, object entry) tuples. classname. Returns a list of (name, object entry) tuples.
@ -560,22 +563,31 @@ class PythonDomain(Domain):
matches = [] matches = []
newname = None newname = None
if searchorder == 1: if searchmode == 1:
if modname and classname and \ objtypes = self.objtypes_for_role(type)
modname + '.' + classname + '.' + name in objects: if modname and classname:
newname = modname + '.' + classname + '.' + name fullname = modname + '.' + classname + '.' + name
elif modname and modname + '.' + name in objects: if fullname in objects and objects[fullname][1] in objtypes:
newname = modname + '.' + name newname = fullname
elif name in objects: if not newname:
newname = name if modname and modname + '.' + name in objects and \
else: objects[modname + '.' + name][1] in objtypes:
# "fuzzy" searching mode newname = modname + '.' + name
searchname = '.' + name elif name in objects and objects[name][1] in objtypes:
matches = [(name, objects[name]) for name in objects newname = name
if name.endswith(searchname)] else:
# "fuzzy" searching mode
searchname = '.' + name
matches = [(name, objects[name]) for name in objects
if name.endswith(searchname)
and objects[name][1] in objtypes]
else: else:
# NOTE: searching for exact match, object type is not considered
if name in objects: if name in objects:
newname = name newname = name
elif type == 'mod':
# only exact matches allowed for modules
return []
elif classname and classname + '.' + name in objects: elif classname and classname + '.' + name in objects:
newname = classname + '.' + name newname = classname + '.' + name
elif modname and modname + '.' + name in objects: elif modname and modname + '.' + name in objects:
@ -597,33 +609,35 @@ class PythonDomain(Domain):
def resolve_xref(self, env, fromdocname, builder, def resolve_xref(self, env, fromdocname, builder,
type, target, node, contnode): type, target, node, contnode):
if (type == 'mod' or modname = node.get('py:module')
type == 'obj' and target in self.data['modules']): clsname = node.get('py:class')
docname, synopsis, platform, deprecated = \ searchmode = node.hasattr('refspecific') and 1 or 0
self.data['modules'].get(target, ('','','', '')) matches = self.find_obj(env, modname, clsname, target,
if not docname: type, searchmode)
return None if not matches:
else: return None
title = '%s%s%s' % ((platform and '(%s) ' % platform), elif len(matches) > 1:
synopsis, env.warn(fromdocname,
(deprecated and ' (deprecated)' or '')) 'more than one target found for cross-reference '
return make_refnode(builder, fromdocname, docname, '%r: %s' % (target,
'module-' + target, contnode, title) ', '.join(match[0] for match in matches)),
node.line)
name, obj = matches[0]
if obj[1] == 'module':
# get additional info for modules
docname, synopsis, platform, deprecated = self.data['modules'][name]
assert docname == obj[0]
title = name
if synopsis:
title += ': ' + synopsis
if deprecated:
title += _(' (deprecated)')
if platform:
title += ' (' + platform + ')'
return make_refnode(builder, fromdocname, docname,
'module-' + name, contnode, title)
else: else:
modname = node.get('py:module')
clsname = node.get('py:class')
searchorder = node.hasattr('refspecific') and 1 or 0
matches = self.find_obj(env, modname, clsname, target,
type, searchorder)
if not matches:
return None
elif len(matches) > 1:
env.warn(fromdocname,
'more than one target found for cross-reference '
'%r: %s' % (target,
', '.join(match[0] for match in matches)),
node.line)
name, obj = matches[0]
return make_refnode(builder, fromdocname, obj[0], name, return make_refnode(builder, fromdocname, obj[0], name,
contnode, name) contnode, name)

View File

@ -28,7 +28,7 @@ class ReSTMarkup(ObjectDescription):
""" """
def add_target_and_index(self, name, sig, signode): def add_target_and_index(self, name, sig, signode):
targetname = name + '-' + self.objtype targetname = self.objtype + '-' + name
if targetname not in self.state.document.ids: if targetname not in self.state.document.ids:
signode['names'].append(targetname) signode['names'].append(targetname)
signode['ids'].append(targetname) signode['ids'].append(targetname)
@ -130,8 +130,9 @@ class ReSTDomain(Domain):
if (objtype, target) in objects: if (objtype, target) in objects:
return make_refnode(builder, fromdocname, return make_refnode(builder, fromdocname,
objects[objtype, target], objects[objtype, target],
target, contnode, target) objtype + '-' + target,
contnode, target + ' ' + objtype)
def get_objects(self): def get_objects(self):
for (typ, name), docname in self.data['objects'].iteritems(): for (typ, name), docname in self.data['objects'].iteritems():
yield name, name, typ, docname, name, 1 yield name, name, typ, docname, typ + '-' + name, 1

View File

@ -65,7 +65,7 @@ default_settings = {
# This is increased every time an environment attribute is added # This is increased every time an environment attribute is added
# or changed to properly invalidate pickle files. # or changed to properly invalidate pickle files.
ENV_VERSION = 37 ENV_VERSION = 38
default_substitutions = set([ default_substitutions = set([

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" r"""
sphinx.ext.inheritance_diagram sphinx.ext.inheritance_diagram
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -213,9 +213,20 @@ def missing_reference(app, env, node, contnode):
proj, version, uri, dispname = inventory[objtype][target] proj, version, uri, dispname = inventory[objtype][target]
newnode = nodes.reference('', '', internal=False, refuri=uri, newnode = nodes.reference('', '', internal=False, refuri=uri,
reftitle='(in %s v%s)' % (proj, version)) reftitle='(in %s v%s)' % (proj, version))
if dispname == '-': if node.get('refexplicit'):
dispname = target # use whatever title was given
newnode.append(contnode.__class__(dispname, dispname)) newnode.append(contnode)
elif dispname == '-':
# use whatever title was given, but strip prefix
title = contnode.astext()
if in_set and title.startswith(in_set+':'):
newnode.append(contnode.__class__(title[len(in_set)+1:],
title[len(in_set)+1:]))
else:
newnode.append(contnode)
else:
# else use the given display name (used for :ref:)
newnode.append(contnode.__class__(dispname, dispname))
return newnode return newnode
# at least get rid of the ':' in the target if no explicit title given # at least get rid of the ':' in the target if no explicit title given
if in_set is not None and not node.get('refexplicit', True): if in_set is not None and not node.get('refexplicit', True):

View File

@ -43,6 +43,8 @@ class OldCDirective(Directive):
def old_crole(typ, rawtext, text, lineno, inliner, options={}, content=[]): def old_crole(typ, rawtext, text, lineno, inliner, options={}, content=[]):
env = inliner.document.settings.env env = inliner.document.settings.env
if not typ:
typ = env.config.default_role
if not env.app._oldcmarkup_warned: if not env.app._oldcmarkup_warned:
env.warn(env.docname, WARNING_MSG) env.warn(env.docname, WARNING_MSG)
env.app._oldcmarkup_warned = True env.app._oldcmarkup_warned = True

View File

@ -240,7 +240,7 @@ class PygmentsBridge(object):
# no HTML styles needed # no HTML styles needed
return '' return ''
if self.dest == 'html': if self.dest == 'html':
return self.fmter[0].get_style_defs() return self.fmter[0].get_style_defs('.highlight')
else: else:
styledefs = self.fmter[0].get_style_defs() styledefs = self.fmter[0].get_style_defs()
# workaround for Pygments < 0.12 # workaround for Pygments < 0.12

View File

@ -105,9 +105,9 @@ class XRefRole(object):
classes = ['xref', domain, '%s-%s' % (domain, role)] classes = ['xref', domain, '%s-%s' % (domain, role)]
# if the first character is a bang, don't cross-reference at all # if the first character is a bang, don't cross-reference at all
if text[0:1] == '!': if text[0:1] == '!':
text = utils.unescape(text) text = utils.unescape(text)[1:]
if self.fix_parens: if self.fix_parens:
text, tgt = self._fix_parens(env, False, text[1:], "") text, tgt = self._fix_parens(env, False, text, "")
innernode = self.innernodeclass(rawtext, text, classes=classes) innernode = self.innernodeclass(rawtext, text, classes=classes)
return self.result_nodes(inliner.document, env, innernode, return self.result_nodes(inliner.document, env, innernode,
is_ref=False) is_ref=False)
@ -173,6 +173,10 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
indexnode['entries'] = [ indexnode['entries'] = [
('single', _('Python Enhancement Proposals!PEP %s') % text, ('single', _('Python Enhancement Proposals!PEP %s') % text,
targetid, 'PEP %s' % text)] targetid, 'PEP %s' % text)]
anchor = ''
anchorindex = text.find('#')
if anchorindex > 0:
text, anchor = text[:anchorindex], text[anchorindex:]
try: try:
pepnum = int(text) pepnum = int(text)
except ValueError: except ValueError:
@ -182,12 +186,17 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
return [prb], [msg] return [prb], [msg]
ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum
sn = nodes.strong('PEP '+text, 'PEP '+text) sn = nodes.strong('PEP '+text, 'PEP '+text)
rn = nodes.reference('', '', internal=False, refuri=ref, classes=[typ]) rn = nodes.reference('', '', internal=False, refuri=ref+anchor,
classes=[typ])
rn += sn rn += sn
return [indexnode, targetnode, rn], [] return [indexnode, targetnode, rn], []
elif typ == 'rfc': elif typ == 'rfc':
indexnode['entries'] = [('single', 'RFC; RFC %s' % text, indexnode['entries'] = [('single', 'RFC; RFC %s' % text,
targetid, 'RFC %s' % text)] targetid, 'RFC %s' % text)]
anchor = ''
anchorindex = text.find('#')
if anchorindex > 0:
text, anchor = text[:anchorindex], text[anchorindex:]
try: try:
rfcnum = int(text) rfcnum = int(text)
except ValueError: except ValueError:
@ -197,7 +206,8 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner,
return [prb], [msg] return [prb], [msg]
ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum
sn = nodes.strong('RFC '+text, 'RFC '+text) sn = nodes.strong('RFC '+text, 'RFC '+text)
rn = nodes.reference('', '', internal=False, refuri=ref, classes=[typ]) rn = nodes.reference('', '', internal=False, refuri=ref+anchor,
classes=[typ])
rn += sn rn += sn
return [indexnode, targetnode, rn], [] return [indexnode, targetnode, rn], []

View File

@ -446,6 +446,7 @@
linkcolor=InnerLinkColor,filecolor=OuterLinkColor, linkcolor=InnerLinkColor,filecolor=OuterLinkColor,
menucolor=OuterLinkColor,urlcolor=OuterLinkColor, menucolor=OuterLinkColor,urlcolor=OuterLinkColor,
citecolor=InnerLinkColor]{hyperref} citecolor=InnerLinkColor]{hyperref}
\RequirePackage[figure,table]{hypcap}
% From docutils.writers.latex2e % From docutils.writers.latex2e
\providecommand{\DUspan}[2]{% \providecommand{\DUspan}[2]{%

View File

@ -142,9 +142,12 @@ class TypedField(GroupedField):
par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong) par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong)
if fieldarg in types: if fieldarg in types:
par += nodes.Text(' (') par += nodes.Text(' (')
fieldtype = types[fieldarg] # NOTE: using .pop() here to prevent a single type node to be
# inserted twice into the doctree, which leads to
# inconsistencies later when references are resolved
fieldtype = types.pop(fieldarg)
if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text): if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text):
typename = u''.join(n.astext() for n in types[fieldarg]) typename = u''.join(n.astext() for n in fieldtype)
par += self.make_xref(self.typerolename, domain, typename) par += self.make_xref(self.typerolename, domain, typename)
else: else:
par += fieldtype par += fieldtype

View File

@ -13,8 +13,10 @@ import UserString
try: try:
import json import json
# json-py's json module has not JSONEncoder; this will raise AttributeError
# if json-py is imported instead of the built-in json module
JSONEncoder = json.JSONEncoder JSONEncoder = json.JSONEncoder
except ImportError: except (ImportError, AttributeError):
try: try:
import simplejson as json import simplejson as json
JSONEncoder = json.JSONEncoder JSONEncoder = json.JSONEncoder

View File

@ -224,6 +224,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
else: else:
self.top_sectionlevel = 1 self.top_sectionlevel = 1
self.next_section_ids = set() self.next_section_ids = set()
self.next_figure_ids = set()
self.next_table_ids = set()
# flags # flags
self.verbatim = None self.verbatim = None
self.in_title = 0 self.in_title = 0
@ -633,7 +635,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('{|' + ('L|' * self.table.colcount) + '}\n') self.body.append('{|' + ('L|' * self.table.colcount) + '}\n')
if self.table.longtable and self.table.caption is not None: if self.table.longtable and self.table.caption is not None:
self.body.append(u'\\caption{%s} \\\\\n' % self.table.caption) self.body.append(u'\\caption{%s} \\\\\n' % self.table.caption)
if self.table.caption is not None:
for id in self.next_table_ids:
self.body.append(self.hypertarget(id, anchor=False))
self.next_table_ids.clear()
if self.table.longtable: if self.table.longtable:
self.body.append('\\hline\n') self.body.append('\\hline\n')
self.body.append('\\endfirsthead\n\n') self.body.append('\\endfirsthead\n\n')
@ -887,11 +892,15 @@ class LaTeXTranslator(nodes.NodeVisitor):
pass pass
def visit_figure(self, node): def visit_figure(self, node):
ids = ''
for id in self.next_figure_ids:
ids += self.hypertarget(id, anchor=False)
self.next_figure_ids.clear()
if 'width' in node and node.get('align', '') in ('left', 'right'): if 'width' in node and node.get('align', '') in ('left', 'right'):
self.body.append('\\begin{wrapfigure}{%s}{%s}\n\\centering' % self.body.append('\\begin{wrapfigure}{%s}{%s}\n\\centering' %
(node['align'] == 'right' and 'r' or 'l', (node['align'] == 'right' and 'r' or 'l',
node['width'])) node['width']))
self.context.append('\\end{wrapfigure}\n') self.context.append(ids + '\\end{wrapfigure}\n')
else: else:
if (not 'align' in node.attributes or if (not 'align' in node.attributes or
node.attributes['align'] == 'center'): node.attributes['align'] == 'center'):
@ -903,7 +912,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
align = '\\begin{flush%s}' % node.attributes['align'] align = '\\begin{flush%s}' % node.attributes['align']
align_end = '\\end{flush%s}' % node.attributes['align'] align_end = '\\end{flush%s}' % node.attributes['align']
self.body.append('\\begin{figure}[htbp]%s\n' % align) self.body.append('\\begin{figure}[htbp]%s\n' % align)
self.context.append('%s\\end{figure}\n' % align_end) self.context.append(ids + align_end + '\\end{figure}\n')
def depart_figure(self, node): def depart_figure(self, node):
self.body.append(self.context.pop()) self.body.append(self.context.pop())
@ -983,6 +992,20 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.next_section_ids.add(node['refid']) self.next_section_ids.add(node['refid'])
self.next_section_ids.update(node['ids']) self.next_section_ids.update(node['ids'])
return return
elif isinstance(next, nodes.figure):
# labels for figures go in the figure body, not before
if node.get('refid'):
self.next_figure_ids.add(node['refid'])
self.next_figure_ids.update(node['ids'])
return
elif isinstance(next, nodes.table):
# same for tables, but only if they have a caption
for n in node:
if isinstance(n, nodes.title):
if node.get('refid'):
self.next_table_ids.add(node['refid'])
self.next_table_ids.update(node['ids'])
return
except IndexError: except IndexError:
pass pass
if 'refuri' in node: if 'refuri' in node:

View File

@ -41,6 +41,10 @@ Testing object descriptions
.. function:: func_without_module2() -> annotation .. function:: func_without_module2() -> annotation
.. object:: long(parameter, \
list)
another one
.. class:: TimeInt .. class:: TimeInt
:param moo: |test| :param moo: |test|
@ -62,6 +66,8 @@ Testing object descriptions
:ivar int hour: like *hour* :ivar int hour: like *hour*
:ivar minute: like *minute* :ivar minute: like *minute*
:vartype minute: int :vartype minute: int
:param hour: Duplicate param. Should not lead to crashes.
:type hour: Duplicate type.
C items C items

View File

@ -39,7 +39,7 @@ http://www.python.org/logo.png
reading included file u'wrongenc.inc' seems to be wrong, try giving an \ reading included file u'wrongenc.inc' seems to be wrong, try giving an \
:encoding: option\\n? :encoding: option\\n?
%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png %(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png
%(root)s/objects.txt:84: WARNING: using old C markup; please migrate to \ %(root)s/objects.txt:\\d*: WARNING: using old C markup; please migrate to \
new-style markup \(e.g. c:function instead of cfunction\), see \ new-style markup \(e.g. c:function instead of cfunction\), see \
http://sphinx.pocoo.org/domains.html http://sphinx.pocoo.org/domains.html
""" """
@ -167,6 +167,8 @@ HTML_XPATH = {
'objects.html': [ 'objects.html': [
(".//dt[@id='mod.Cls.meth1']", ''), (".//dt[@id='mod.Cls.meth1']", ''),
(".//dt[@id='errmod.Error']", ''), (".//dt[@id='errmod.Error']", ''),
(".//dt/tt", r'long\(parameter,\s* list\)'),
(".//dt/tt", 'another one'),
(".//a[@href='#mod.Cls'][@class='reference internal']", ''), (".//a[@href='#mod.Cls'][@class='reference internal']", ''),
(".//dl[@class='userdesc']", ''), (".//dl[@class='userdesc']", ''),
(".//dt[@id='userdesc-myobj']", ''), (".//dt[@id='userdesc-myobj']", ''),

View File

@ -97,46 +97,58 @@ def test_missing_reference(tempdir, app):
('foo', '2.0', 'http://docs.python.org/foo.html#module-module2', '-') ('foo', '2.0', 'http://docs.python.org/foo.html#module-module2', '-')
# create fake nodes and check referencing # create fake nodes and check referencing
contnode = nodes.emphasis('foo', 'foo')
refnode = addnodes.pending_xref('')
refnode['reftarget'] = 'module1.func'
refnode['reftype'] = 'func'
refnode['refdomain'] = 'py'
rn = missing_reference(app, app.env, refnode, contnode) def fake_node(domain, type, target, content, **attrs):
contnode = nodes.emphasis(content, content)
node = addnodes.pending_xref('')
node['reftarget'] = target
node['reftype'] = type
node['refdomain'] = domain
node.attributes.update(attrs)
node += contnode
return node, contnode
def reference_check(*args, **kwds):
node, contnode = fake_node(*args, **kwds)
return missing_reference(app, app.env, node, contnode)
# check resolution when a target is found
rn = reference_check('py', 'func', 'module1.func', 'foo')
assert isinstance(rn, nodes.reference) assert isinstance(rn, nodes.reference)
assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func' assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func'
assert rn['reftitle'] == '(in foo v2.0)' assert rn['reftitle'] == '(in foo v2.0)'
assert rn[0].astext() == 'module1.func' assert rn[0].astext() == 'foo'
# create unresolvable nodes and check None return value # create unresolvable nodes and check None return value
refnode['reftype'] = 'foo' assert reference_check('py', 'foo', 'module1.func', 'foo') is None
assert missing_reference(app, app.env, refnode, contnode) is None assert reference_check('py', 'func', 'foo', 'foo') is None
assert reference_check('py', 'func', 'foo', 'foo') is None
refnode['reftype'] = 'function'
refnode['reftarget'] = 'foo.func'
assert missing_reference(app, app.env, refnode, contnode) is None
# check handling of prefixes # check handling of prefixes
# prefix given, target found: prefix is stripped # prefix given, target found: prefix is stripped
refnode['reftype'] = 'mod' rn = reference_check('py', 'mod', 'py3k:module2', 'py3k:module2')
refnode['reftarget'] = 'py3k:module2'
rn = missing_reference(app, app.env, refnode, contnode)
assert rn[0].astext() == 'module2' assert rn[0].astext() == 'module2'
# prefix given, but not in title: nothing stripped
rn = reference_check('py', 'mod', 'py3k:module2', 'module2')
assert rn[0].astext() == 'module2'
# prefix given, but explicit: nothing stripped
rn = reference_check('py', 'mod', 'py3k:module2', 'py3k:module2',
refexplicit=True)
assert rn[0].astext() == 'py3k:module2'
# prefix given, target not found and nonexplicit title: prefix is stripped # prefix given, target not found and nonexplicit title: prefix is stripped
refnode['reftarget'] = 'py3k:unknown' node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown',
refnode['refexplicit'] = False refexplicit=False)
contnode[0] = nodes.Text('py3k:unknown') rn = missing_reference(app, app.env, node, contnode)
rn = missing_reference(app, app.env, refnode, contnode)
assert rn is None assert rn is None
assert contnode[0].astext() == 'unknown' assert contnode[0].astext() == 'unknown'
# prefix given, target not found and explicit title: nothing is changed # prefix given, target not found and explicit title: nothing is changed
refnode['reftarget'] = 'py3k:unknown' node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown',
refnode['refexplicit'] = True refexplicit=True)
contnode[0] = nodes.Text('py3k:unknown') rn = missing_reference(app, app.env, node, contnode)
rn = missing_reference(app, app.env, refnode, contnode)
assert rn is None assert rn is None
assert contnode[0].astext() == 'py3k:unknown' assert contnode[0].astext() == 'py3k:unknown'