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)
==============================
* 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)
============================

View File

@ -97,6 +97,7 @@ Documentation using the sphinxdoc theme
* Satchmo: http://www.satchmoproject.com/docs/svn/
* Sphinx: http://sphinx.pocoo.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/
* 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``
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.
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
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:
:attr:`SerializingHTMLBuilder.globalcontext_filename`
:attr:`.SerializingHTMLBuilder.globalcontext_filename`
A pickled dict with these keys:
``project``, ``copyright``, ``release``, ``version``
@ -309,7 +309,7 @@ The special files are located in the root output directory. They are:
``titles``
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
list with these entries:

View File

@ -64,6 +64,10 @@ man_pages = [
'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 -------------------------------------------------------

View File

@ -346,12 +346,12 @@ Project information
A boolean that decides whether module names are prepended to all
: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
A boolean that decides whether :rst:dir:`moduleauthor` and :rst:dir:`sectionauthor`
directives produce any output in the built files.
A boolean that decides whether :rst:dir:`codeauthor` and
:rst:dir:`sectionauthor` directives produce any output in the built files.
.. 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
that use Sphinx' HTMLWriter class.
.. XXX document html_context
.. confval:: html_theme
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
``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
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)
ham(eggs)
:noindex:
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
example, to link to one of the functions described in the example above, you
could say ::
@ -138,11 +147,12 @@ declarations:
.. rst:directive:: .. py:currentmodule:: name
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
index entries, an entry in the Global Module Index, or a link target for
:rst:role:`mod`. This is helpful in situations where documentation for things in
a module is spread over multiple files or sections -- one location has the
:rst:dir:`py:module` directive, the others only :rst:dir:`py:currentmodule`.
here are in the given module (like :rst:dir:`py:module`), but it will not
create index entries, an entry in the Global Module Index, or a link target
for :rst:role:`py:mod`. This is helpful in situations where documentation
for things in a module is spread over multiple files or sections -- one
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:
@ -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
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
target is taken as a suffix and all object names with that suffix are
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
match, you will get a warning from Sphinx.
A similar heuristic is used to determine whether the name is an attribute of the
currently documented class.
Note that you can combine the ``~`` and ``.`` prefixes:
``:py:meth:`~.TarFile.close``` will reference the ``tarfile.TarFile.close()``
method, but the visible link caption will only be ``close()``.
.. _c-domain:

View File

@ -210,7 +210,7 @@ the following public API:
standard Sphinx roles (see :ref:`xref-syntax`).
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='')
@ -272,6 +272,8 @@ the following public API:
This allows to auto-document new types of objects. See the source of the
autodoc module for examples on how to subclass :class:`Documenter`.
.. XXX add real docs for Documenter and subclassing
.. versionadded:: 0.6
.. method:: Sphinx.add_autodoc_attrgetter(type, getter)

View File

@ -27,15 +27,16 @@ two locations for documentation, while at the same time avoiding
auto-generated-looking pure API documentation.
: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
corresponding module and extract the docstring of the given objects, inserting
them into the page source under a suitable :rst:dir:`module`, :rst:dir:`class` etc.
directive.
:rst:dir:`py:module`, :rst:dir:`py:class` and so forth. On parsing time, they
import the corresponding module and extract the docstring of the given objects,
inserting them into the page source under a suitable :rst:dir:`py:module`,
:rst:dir:`py:class` etc. directive.
.. note::
Just as :rst:dir:`class` respects the current :rst:dir:`module`, :rst:dir:`autoclass`
will also do so, and likewise with :rst:dir:`method` and :rst:dir:`class`.
Just as :rst:dir:`py:class` respects the current :rst:dir:`py:module`,
:rst:dir:`autoclass` will also do so. Likewise, :rst:dir:`automethod` will
respect the current :rst:dir:`py:class`.
.. rst:directive:: automodule
@ -127,23 +128,24 @@ directive.
.. versionadded:: 0.4
* The :rst:dir:`automodule`, :rst:dir:`autoclass` and :rst:dir:`autoexception` directives
also support a flag option called ``show-inheritance``. When given, a list
of base classes will be inserted just below the class signature (when used
with :rst:dir:`automodule`, this will be inserted for every class that is
documented in the module).
* The :rst:dir:`automodule`, :rst:dir:`autoclass` and
:rst:dir:`autoexception` directives also support a flag option called
``show-inheritance``. When given, a list of base classes will be inserted
just below the class signature (when used with :rst:dir:`automodule`, this
will be inserted for every class that is documented in the module).
.. versionadded:: 0.4
* All autodoc directives support the ``noindex`` flag option that has the
same effect as for standard :rst:dir:`function` etc. directives: no index
entries are generated for the documented object (and all autodocumented
members).
same effect as for standard :rst:dir:`py:function` etc. directives: no
index entries are generated for the documented object (and all
autodocumented members).
.. versionadded:: 0.4
* :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
@ -213,8 +215,8 @@ There are also new config values that you can set:
``"class"``
Only the class' docstring is inserted. This is the default. You can
still document ``__init__`` as a separate method using :rst:dir:`automethod`
or the ``members`` option to :rst:dir:`autoclass`.
still document ``__init__`` as a separate method using
:rst:dir:`automethod` or the ``members`` option to :rst:dir:`autoclass`.
``"both"``
Both the class' and the ``__init__`` method's docstring are concatenated
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
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
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
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
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
tuple item::
intersphinx_mapping = {'python': ('http://docs.python.org/',
intersphinx_mapping = {'python': ('http://docs.python.org/3.2',
'python-inv.txt')}
This will read the inventory from :file:`python-inv.txt` in the source
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.
.. confval:: intersphinx_cache_limit

View File

@ -17,15 +17,15 @@ if possible, reuse that support too.
.. note::
:mod:`sphinx.ext.mathbase` is not meant to be added to the
:confval:`extensions` config value, instead, use either
:mod:`sphinx.ext.pngmath` or :mod:`sphinx.ext.jsmath` as described below.
:mod:`.mathbase` is not meant to be added to the :confval:`extensions` config
value, instead, use either :mod:`sphinx.ext.pngmath` or
:mod:`sphinx.ext.jsmath` as described below.
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
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

View File

@ -260,7 +260,7 @@ in a different style:
.. rst:role:: samp
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
emphasized.
@ -274,13 +274,15 @@ The following roles generate external links:
A reference to a Python Enhancement Proposal. This generates appropriate
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
A reference to an Internet Request for Comments. This generates appropriate
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

View File

@ -42,15 +42,25 @@ units as well as normal text:
Example::
.. versionadded:: 2.5
The `spam` parameter.
The *spam* parameter.
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.
.. rst:directive:: .. versionchanged:: version
Similar to :rst:dir:`versionadded`, but describes when and what changed in the named
feature in some way (new parameters, changed side effects, etc.).
Similar to :rst:dir:`versionadded`, but describes when and what changed in
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`
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
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.
* You can :ref:`write a custom builder <writing-builders>` that derives from
:class:`~sphinx.builders.StandaloneHTMLBuilder` and calls your template engine
of choice.
:class:`~sphinx.builders.html.StandaloneHTMLBuilder` and calls your template
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,
or use them in your Web application.
@ -261,9 +261,9 @@ in the future.
.. data:: file_suffix
The value of the builder's :attr:`out_suffix` attribute, i.e. the file name
extension that the output files will get. For a standard HTML builder, this
is usually ``.html``.
The value of the builder's :attr:`~.SerializingHTMLBuilder.out_suffix`
attribute, i.e. the file name extension that the output files will get. For
a standard HTML builder, this is usually ``.html``.
.. data:: has_source

View File

@ -32,6 +32,7 @@ except AttributeError:
# RE to strip backslash escapes
nl_escape_re = re.compile(r'\\\n')
strip_backslash_re = re.compile(r'\\(?=[^\\])')
@ -57,10 +58,12 @@ class ObjectDescription(Directive):
"""
Retrieve the signatures to document from the directive arguments. By
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
return [strip_backslash_re.sub('', sig.strip())
for sig in self.arguments[0].split('\n')]
return [strip_backslash_re.sub('', line.strip()) for line in lines]
def handle_signature(self, sig, signode):
"""

View File

@ -356,6 +356,9 @@ class PyModule(Directive):
env.domaindata['py']['modules'][modname] = \
(env.docname, self.options.get('synopsis', ''),
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)
self.state.document.note_explicit_target(targetnode)
ret = [targetnode]
@ -544,7 +547,7 @@ class PythonDomain(Domain):
if fn == docname:
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
classname. Returns a list of (name, object entry) tuples.
@ -560,22 +563,31 @@ class PythonDomain(Domain):
matches = []
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:
if searchmode == 1:
objtypes = self.objtypes_for_role(type)
if modname and classname:
fullname = modname + '.' + classname + '.' + name
if fullname in objects and objects[fullname][1] in objtypes:
newname = fullname
if not newname:
if modname and modname + '.' + name in objects and \
objects[modname + '.' + name][1] in objtypes:
newname = modname + '.' + name
elif name in objects:
elif name in objects and objects[name][1] in objtypes:
newname = name
else:
# "fuzzy" searching mode
searchname = '.' + name
matches = [(name, objects[name]) for name in objects
if name.endswith(searchname)]
if name.endswith(searchname)
and objects[name][1] in objtypes]
else:
# NOTE: searching for exact match, object type is not considered
if name in objects:
newname = name
elif type == 'mod':
# only exact matches allowed for modules
return []
elif classname and classname + '.' + name in objects:
newname = classname + '.' + name
elif modname and modname + '.' + name in objects:
@ -597,24 +609,11 @@ class PythonDomain(Domain):
def resolve_xref(self, env, fromdocname, builder,
type, target, node, contnode):
if (type == 'mod' or
type == '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
searchmode = node.hasattr('refspecific') and 1 or 0
matches = self.find_obj(env, modname, clsname, target,
type, searchorder)
type, searchmode)
if not matches:
return None
elif len(matches) > 1:
@ -624,6 +623,21 @@ class PythonDomain(Domain):
', '.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:
return make_refnode(builder, fromdocname, obj[0], name,
contnode, name)

View File

@ -28,7 +28,7 @@ class ReSTMarkup(ObjectDescription):
"""
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:
signode['names'].append(targetname)
signode['ids'].append(targetname)
@ -130,8 +130,9 @@ class ReSTDomain(Domain):
if (objtype, target) in objects:
return make_refnode(builder, fromdocname,
objects[objtype, target],
target, contnode, target)
objtype + '-' + target,
contnode, target + ' ' + objtype)
def get_objects(self):
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
# or changed to properly invalidate pickle files.
ENV_VERSION = 37
ENV_VERSION = 38
default_substitutions = set([

View File

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

View File

@ -213,8 +213,19 @@ def missing_reference(app, env, node, contnode):
proj, version, uri, dispname = inventory[objtype][target]
newnode = nodes.reference('', '', internal=False, refuri=uri,
reftitle='(in %s v%s)' % (proj, version))
if dispname == '-':
dispname = target
if node.get('refexplicit'):
# use whatever title was given
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
# at least get rid of the ':' in the target if no explicit title given

View File

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

View File

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

View File

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

View File

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

View File

@ -142,9 +142,12 @@ class TypedField(GroupedField):
par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong)
if fieldarg in types:
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):
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)
else:
par += fieldtype

View File

@ -13,8 +13,10 @@ import UserString
try:
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
except ImportError:
except (ImportError, AttributeError):
try:
import simplejson as json
JSONEncoder = json.JSONEncoder

View File

@ -224,6 +224,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
else:
self.top_sectionlevel = 1
self.next_section_ids = set()
self.next_figure_ids = set()
self.next_table_ids = set()
# flags
self.verbatim = None
self.in_title = 0
@ -633,7 +635,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('{|' + ('L|' * self.table.colcount) + '}\n')
if self.table.longtable and self.table.caption is not None:
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:
self.body.append('\\hline\n')
self.body.append('\\endfirsthead\n\n')
@ -887,11 +892,15 @@ class LaTeXTranslator(nodes.NodeVisitor):
pass
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'):
self.body.append('\\begin{wrapfigure}{%s}{%s}\n\\centering' %
(node['align'] == 'right' and 'r' or 'l',
node['width']))
self.context.append('\\end{wrapfigure}\n')
self.context.append(ids + '\\end{wrapfigure}\n')
else:
if (not 'align' in node.attributes or
node.attributes['align'] == 'center'):
@ -903,7 +912,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
align = '\\begin{flush%s}' % node.attributes['align']
align_end = '\\end{flush%s}' % node.attributes['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):
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.update(node['ids'])
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:
pass
if 'refuri' in node:

View File

@ -41,6 +41,10 @@ Testing object descriptions
.. function:: func_without_module2() -> annotation
.. object:: long(parameter, \
list)
another one
.. class:: TimeInt
:param moo: |test|
@ -62,6 +66,8 @@ Testing object descriptions
:ivar int hour: like *hour*
:ivar minute: like *minute*
:vartype minute: int
:param hour: Duplicate param. Should not lead to crashes.
:type hour: Duplicate type.
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 \
:encoding: option\\n?
%(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 \
http://sphinx.pocoo.org/domains.html
"""
@ -167,6 +167,8 @@ HTML_XPATH = {
'objects.html': [
(".//dt[@id='mod.Cls.meth1']", ''),
(".//dt[@id='errmod.Error']", ''),
(".//dt/tt", r'long\(parameter,\s* list\)'),
(".//dt/tt", 'another one'),
(".//a[@href='#mod.Cls'][@class='reference internal']", ''),
(".//dl[@class='userdesc']", ''),
(".//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', '-')
# 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 rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func'
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
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
assert reference_check('py', 'foo', 'module1.func', 'foo') is None
assert reference_check('py', 'func', 'foo', 'foo') is None
assert reference_check('py', 'func', 'foo', 'foo') is None
# check handling of prefixes
# prefix given, target found: prefix is stripped
refnode['reftype'] = 'mod'
refnode['reftarget'] = 'py3k:module2'
rn = missing_reference(app, app.env, refnode, contnode)
rn = reference_check('py', 'mod', 'py3k:module2', 'py3k: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
refnode['reftarget'] = 'py3k:unknown'
refnode['refexplicit'] = False
contnode[0] = nodes.Text('py3k:unknown')
rn = missing_reference(app, app.env, refnode, contnode)
node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown',
refexplicit=False)
rn = missing_reference(app, app.env, node, contnode)
assert rn is None
assert contnode[0].astext() == 'unknown'
# prefix given, target not found and explicit title: nothing is changed
refnode['reftarget'] = 'py3k:unknown'
refnode['refexplicit'] = True
contnode[0] = nodes.Text('py3k:unknown')
rn = missing_reference(app, app.env, refnode, contnode)
node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown',
refexplicit=True)
rn = missing_reference(app, app.env, node, contnode)
assert rn is None
assert contnode[0].astext() == 'py3k:unknown'