This commit is contained in:
Georg Brandl 2010-01-13 23:35:13 +00:00
commit 07f295df7c
22 changed files with 351 additions and 104 deletions

View File

@ -7,6 +7,10 @@ Release 1.0 (in development)
* Support for docutils 0.4 has been removed.
* Added the ``viewcode`` extension.
* Added ``html-collect-pages`` event.
* Added ``tab-width`` option to ``literalinclude`` directive.
* The ``html_sidebars`` config value can now contain patterns as

View File

@ -7,7 +7,7 @@ import sys, os, re
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
'sphinx.ext.autosummary']
'sphinx.ext.autosummary', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View File

@ -360,7 +360,15 @@ registered event handlers.
.. versionadded:: 0.5
.. event:: page-context (app, pagename, templatename, context, doctree)
.. event:: html-collect-pages (app)
Emitted when the HTML builder is starting to write non-document pages. You
can add pages to write by returning an iterable from this event consisting of
``(pagename, context, templatename)``.
.. versionadded:: 1.0
.. event:: html-page-context (app, pagename, templatename, context, doctree)
Emitted when the HTML builder has created a context dictionary to render a
template with -- this can be used to add custom elements to the context.

19
doc/ext/viewcode.rst Normal file
View File

@ -0,0 +1,19 @@
:mod:`sphinx.ext.viewcode` -- Add links to highlighted source code
==================================================================
.. module:: sphinx.ext.viewcode
:synopsis: Add links to a highlighted version of the source code.
.. moduleauthor:: Georg Brandl
.. versionadded:: 1.0
This extension looks at your Python object descriptions (``.. class::``,
``.. function::`` etc.) and tries to find the source files where the objects are
contained. When found, a separate HTML page will be output for each module with
a highlighted version of the source code, and a link will be added to all object
descriptions that leads to the source code of the described object. A link back
from the source to the description will also be inserted.
There are currently no configuration values for this extension; you just need to
add ``'sphinx.ext.viewcode'`` to your :confval:`extensions` value for it to work.

View File

@ -52,6 +52,7 @@ These extensions are built in and can be activated by respective entries in the
ext/coverage
ext/todo
ext/extlinks
ext/viewcode
Third-party extensions

View File

@ -47,6 +47,7 @@ events = {
'missing-reference': 'env, node, contnode',
'doctree-resolved': 'doctree, docname',
'env-updated': 'env',
'html-collect-pages': 'builder',
'html-page-context': 'pagename, context, doctree or None',
'build-finished': 'exception',
}

View File

@ -381,8 +381,12 @@ class StandaloneHTMLBuilder(Builder):
def finish(self):
self.info(bold('writing additional files...'), nonl=1)
# the global general index
# pages from extensions
for pagelist in self.app.emit('html-collect-pages'):
for pagename, context, template in pagelist:
self.handle_page(pagename, context, template)
# the global general index
if self.config.html_use_index:
# the total count of lines for each index letter, used to distribute
# the entries into two columns

View File

@ -190,7 +190,7 @@ class ObjectDescription(Directive):
return [strip_backslash_re.sub('', sig.strip())
for sig in self.arguments[0].split('\n')]
def parse_signature(self, sig, signode):
def handle_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
@ -242,8 +242,10 @@ class ObjectDescription(Directive):
signode['first'] = False
node.append(signode)
try:
# name can also be a tuple, e.g. (classname, objname)
name = self.parse_signature(sig, signode)
# name can also be a tuple, e.g. (classname, objname);
# this is strictly domain-specific (i.e. no assumptions may
# be made in this base class)
name = self.handle_signature(sig, signode)
except ValueError, err:
# signature parsing failed
signode.clear()

View File

@ -215,7 +215,8 @@ class VersionChange(Directive):
env = self.state.document.settings.env
env.versionchanges.setdefault(node['version'], []).append(
(node['type'], env.doc_read_data['docname'], self.lineno,
env.doc_read_data.get('py_module'),
# XXX: python domain specific
env.doc_read_data.get('py:module'),
env.doc_read_data.get('object'),
node.astext()))
return ret

View File

@ -66,7 +66,7 @@ class CObject(ObjectDescription):
else:
node += tnode
def parse_signature(self, sig, signode):
def handle_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)

View File

@ -53,7 +53,7 @@ class PyObject(ObjectDescription):
"""
return False
def parse_signature(self, sig, signode):
def handle_signature(self, sig, signode):
"""
Transform a Python signature into RST nodes.
Returns (fully qualified name of the thing, classname if any).
@ -65,37 +65,49 @@ class PyObject(ObjectDescription):
m = py_sig_re.match(sig)
if m is None:
raise ValueError
classname, name, arglist, retann = m.groups()
name_prefix, name, arglist, retann = m.groups()
currclass = self.env.doc_read_data.get('py_class')
if currclass:
# determine module and class name (if applicable), as well as full name
modname = self.options.get(
'module', self.env.doc_read_data.get('py:module'))
classname = self.env.doc_read_data.get('py:class')
if classname:
add_module = False
if classname and classname.startswith(currclass):
fullname = classname + name
if name_prefix and name_prefix.startswith(classname):
fullname = name_prefix + name
# class name is given again in the signature
classname = classname[len(currclass):].lstrip('.')
elif classname:
name_prefix = name_prefix[len(classname):].lstrip('.')
elif name_prefix:
# class name is given in the signature, but different
# (shouldn't happen)
fullname = currclass + '.' + classname + name
fullname = classname + '.' + name_prefix + name
else:
# class name is not given in the signature
fullname = currclass + '.' + name
fullname = classname + '.' + name
else:
add_module = True
fullname = classname and classname + name or name
if name_prefix:
classname = name_prefix.rstrip('.')
fullname = name_prefix + name
else:
classname = ''
fullname = name
prefix = self.get_signature_prefix(sig)
if prefix:
signode += addnodes.desc_annotation(prefix, prefix)
signode['module'] = modname
signode['class'] = classname
signode['fullname'] = fullname
if classname:
signode += addnodes.desc_addname(classname, classname)
sig_prefix = self.get_signature_prefix(sig)
if sig_prefix:
signode += addnodes.desc_annotation(sig_prefix, sig_prefix)
if name_prefix:
signode += addnodes.desc_addname(name_prefix, name_prefix)
# 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'))
'module', self.env.doc_read_data.get('py:module'))
if modname and modname != 'exceptions':
nodetext = modname + '.'
signode += addnodes.desc_addname(nodetext, nodetext)
@ -107,7 +119,7 @@ class PyObject(ObjectDescription):
signode += addnodes.desc_parameterlist()
if retann:
signode += addnodes.desc_returns(retann, retann)
return fullname, classname
return fullname, name_prefix
signode += addnodes.desc_parameterlist()
stack = [signode[-1]]
@ -130,7 +142,7 @@ class PyObject(ObjectDescription):
raise ValueError
if retann:
signode += addnodes.desc_returns(retann, retann)
return fullname, classname
return fullname, name_prefix
def get_index_text(self, modname, name):
"""
@ -140,7 +152,7 @@ class PyObject(ObjectDescription):
def add_target_and_index(self, name_cls, sig, signode):
modname = self.options.get(
'module', self.env.doc_read_data.get('py_module'))
'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:
@ -169,7 +181,7 @@ class PyObject(ObjectDescription):
def after_content(self):
if self.clsname_set:
self.env.doc_read_data['py_class'] = None
self.env.doc_read_data['py:class'] = None
class PyModulelevel(PyObject):
@ -214,7 +226,7 @@ class PyClasslike(PyObject):
def before_content(self):
PyObject.before_content(self)
if self.names:
self.env.doc_read_data['py_class'] = self.names[0][0]
self.env.doc_read_data['py:class'] = self.names[0][0]
self.clsname_set = True
@ -292,8 +304,8 @@ class PyClassmember(PyObject):
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('.')
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
@ -317,7 +329,7 @@ class PyModule(Directive):
env = self.state.document.settings.env
modname = self.arguments[0].strip()
noindex = 'noindex' in self.options
env.doc_read_data['py_module'] = modname
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)
@ -361,16 +373,16 @@ class PyCurrentModule(Directive):
env = self.state.document.settings.env
modname = self.arguments[0].strip()
if modname == 'None':
env.doc_read_data['py_module'] = None
env.doc_read_data['py:module'] = None
else:
env.doc_read_data['py_module'] = modname
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')
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
@ -497,8 +509,8 @@ class PythonDomain(Domain):
return make_refnode(builder, fromdocname, docname,
'module-' + target, contnode, title)
else:
modname = node.get('py_module')
clsname = node.get('py_class')
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)

View File

@ -35,7 +35,7 @@ class GenericObject(ObjectDescription):
indextemplate = ''
parse_node = None
def parse_signature(self, sig, signode):
def handle_signature(self, sig, signode):
if self.parse_node:
name = self.parse_node(self.env, sig, signode)
else:
@ -146,7 +146,7 @@ class Cmdoption(ObjectDescription):
def add_target_and_index(self, name, sig, signode):
targetname = name.replace('/', '-')
currprogram = self.env.doc_read_data.get('std_program')
currprogram = self.env.doc_read_data.get('std:program')
if currprogram:
targetname = '-' + currprogram + targetname
targetname = 'cmdoption' + targetname
@ -175,9 +175,9 @@ class Program(Directive):
env = self.state.document.settings.env
program = ws_re.sub('-', self.arguments[0].strip())
if program == 'None':
env.doc_read_data['std_program'] = None
env.doc_read_data['std:program'] = None
else:
env.doc_read_data['std_program'] = program
env.doc_read_data['std:program'] = program
return []
@ -185,7 +185,7 @@ 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')
program = env.doc_read_data.get('std:program')
if not has_explicit_title:
if ' ' in title and not (title.startswith('/') or
title.startswith('-')):

View File

@ -713,12 +713,12 @@ class BuildEnvironment:
@property
def currmodule(self):
"""Backwards compatible alias."""
return self.doc_read_data.get('py_module')
return self.doc_read_data.get('py:module')
@property
def currclass(self):
"""Backwards compatible alias."""
return self.doc_read_data.get('py_class')
return self.doc_read_data.get('py:class')
def new_serialno(self, category=''):
"""Return a serial number, e.g. for index entry targets."""

View File

@ -46,3 +46,11 @@ class ExtensionError(SphinxError):
class ThemeError(SphinxError):
category = 'Theme error'
class PycodeError(Exception):
def __str__(self):
res = self.args[0]
if len(self.args) > 1:
res += ' (exception was: %r)' % self.args[1]
return res

View File

@ -562,9 +562,9 @@ class Documenter(object):
do all members, else those given by *self.options.members*.
"""
# set current namespace for finding members
self.env.doc_read_data['autodoc_module'] = self.modname
self.env.doc_read_data['autodoc:module'] = self.modname
if self.objpath:
self.env.doc_read_data['autodoc_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
@ -605,8 +605,8 @@ class Documenter(object):
check_module=members_check_module)
# reset current objects
self.env.doc_read_data['autodoc_module'] = None
self.env.doc_read_data['autodoc_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):
@ -764,10 +764,10 @@ class ModuleLevelDocumenter(Documenter):
else:
# if documenting a toplevel object without explicit module,
# it can be contained in another auto directive ...
modname = self.env.doc_read_data.get('autodoc_module')
modname = self.env.doc_read_data.get('autodoc:module')
# ... or in the scope of a module directive
if not modname:
modname = self.env.doc_read_data.get('py_module')
modname = self.env.doc_read_data.get('py:module')
# ... else, it stays None, which means invalid
return modname, parents + [base]
@ -786,10 +786,10 @@ class ClassLevelDocumenter(Documenter):
# if documenting a class-level object without path,
# there must be a current class, either from a parent
# auto directive ...
mod_cls = self.env.doc_read_data.get('autodoc_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.doc_read_data.get('py_class')
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, []
@ -797,9 +797,9 @@ class ClassLevelDocumenter(Documenter):
parents = [cls]
# if the module name is still missing, get it like above
if not modname:
modname = self.env.doc_read_data.get('autodoc_module')
modname = self.env.doc_read_data.get('autodoc:module')
if not modname:
modname = self.env.doc_read_data.get('py_module')
modname = self.env.doc_read_data.get('py:module')
# ... else, it stays None, which means invalid
return modname, parents + [base]

View File

@ -228,7 +228,7 @@ class Autosummary(Directive):
env = self.state.document.settings.env
prefixes = ['']
currmodule = env.doc_read_data.get('py_module')
currmodule = env.doc_read_data.get('py:module')
if currmodule:
prefixes.insert(0, currmodule)

View File

@ -284,7 +284,7 @@ class InheritanceDiagram(Directive):
# Create a graph starting with the list of classes
try:
graph = InheritanceGraph(class_names,
env.doc_read_data.get('py_module'))
env.doc_read_data.get('py:module'))
except InheritanceException, err:
return [node.document.reporter.warning(err.args[0],
line=self.lineno)]

162
sphinx/ext/viewcode.py Normal file
View File

@ -0,0 +1,162 @@
# -*- coding: utf-8 -*-
"""
sphinx.ext.viewcode
~~~~~~~~~~~~~~~~~~~
Add links to module code in Python object descriptions.
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from docutils import nodes
from sphinx import addnodes
from sphinx.util import make_refnode
from sphinx.pycode import ModuleAnalyzer
def doctree_read(app, doctree):
env = app.builder.env
if not hasattr(env, '_viewcode_modules'):
env._viewcode_modules = {}
def has_tag(modname, fullname, docname):
entry = env._viewcode_modules.get(modname, None)
if entry is None:
try:
analyzer = ModuleAnalyzer.for_module(modname)
except Exception:
env._viewcode_modules[modname] = False
return
analyzer.find_tags()
entry = analyzer.code, analyzer.tags, {}
env._viewcode_modules[modname] = entry
elif entry is False:
return
code, tags, used = entry
if fullname in tags:
used[fullname] = docname
return True
for objnode in doctree.traverse(addnodes.desc):
if objnode['domain'] != 'py':
continue
names = set()
for signode in objnode.traverse(addnodes.desc_signature):
modname = signode['module']
if not modname:
continue
fullname = signode['fullname']
if not has_tag(modname, fullname, env.docname):
continue
if fullname in names:
# only one link per name, please
continue
names.add(fullname)
pagename = '_modules/' + modname.replace('.', '/')
onlynode = addnodes.only(expr='html')
onlynode += addnodes.pending_xref(
'', reftype='viewcode', refdomain='std', refexplicit=False,
reftarget=pagename, refid=fullname,
refdoc=env.docname)
onlynode[0] += nodes.inline('', _('[source]'),
classes=['viewcode-link'])
signode += onlynode
def missing_reference(app, env, node, contnode):
# resolve our "viewcode" reference nodes -- they need special treatment
if node['reftype'] == 'viewcode':
return make_refnode(app.builder, node['refdoc'], node['reftarget'],
node['refid'], contnode)
def collect_pages(app):
env = app.builder.env
if not hasattr(env, '_viewcode_modules'):
return
highlighter = app.builder.highlighter
urito = app.builder.get_relative_uri
modnames = set(env._viewcode_modules)
for modname, (code, tags, used) in env._viewcode_modules.iteritems():
# construct a page name for the highlighted source
pagename = '_modules/' + modname.replace('.', '/')
# highlight the source using the builder's highlighter
highlighted = highlighter.highlight_block(code, 'python', False)
# split the code into lines
lines = highlighted.splitlines()
# split off wrap markup from the first line of the actual code
before, after = lines[0].split('<pre>')
lines[0:1] = [before + '<pre>', after]
# nothing to do for the last line; it always starts with </pre> anyway
# now that we have code lines (starting at index 1), insert anchors for
# the collected tags (HACK: this only works if the tag boundaries are
# properly nested!)
for name, docname in used.iteritems():
type, start, end = tags[name]
backlink = urito(pagename, docname) + '#' + modname + '.' + name
lines[start] = (
'<div class="viewcode-block" id="%s"><a class="viewcode-back" '
'href="%s">%s</a>' % (name, backlink, _('[docs]')) + lines[start])
lines[end - 1] += '</div>'
# try to find parents (for submodules)
parents = []
parent = modname
while '.' in parent:
parent = parent.rsplit('.', 1)[0]
if parent in modnames:
parents.append({
'link': urito(pagename, '_modules/' +
parent.replace('.', '/')),
'title': parent})
parents.append({'link': urito(pagename, '_modules/index'),
'title': _('Module code')})
parents.reverse()
# putting it all together
context = {
'parents': parents,
'title': modname,
'body': _('<h2>Source code for %s</h2>') % modname + '\n'.join(lines)
}
app.builder.info(' '+pagename, nonl=1)
yield (pagename, context, 'page.html')
if not modnames:
return
app.builder.info(' _modules/index')
html = ['\n']
# the stack logic is needed for using nested lists for submodules
stack = ['']
for modname in sorted(modnames):
if modname.startswith(stack[-1]):
stack.append(modname + '.')
html.append('<ul>')
else:
stack.pop()
while not modname.startswith(stack[-1]):
stack.pop()
html.append('</ul>')
stack.append(modname + '.')
html.append('<li><a href="%s">%s</a></li>\n' % (
urito('_modules/index', '_modules/' + modname.replace('.', '/')),
modname))
html.append('</ul>' * (len(stack) - 1))
context = {
'title': _('Overview: module code'),
'body': _('<h2>All modules for which code is available</h2>') + \
''.join(html),
}
yield ('_modules/index', context, 'page.html')
def setup(app):
app.connect('doctree-read', doctree_read)
app.connect('html-collect-pages', collect_pages)
app.connect('missing-reference', missing_reference)
#app.add_config_value('viewcode_include_modules', [], 'env')
#app.add_config_value('viewcode_exclude_modules', [], 'env')

View File

@ -14,8 +14,10 @@ import sys
from os import path
from cStringIO import StringIO
from sphinx.errors import PycodeError
from sphinx.pycode import nodes
from sphinx.pycode.pgen2 import driver, token, tokenize, parse, literals
from sphinx.util import get_module_source
from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc
@ -136,14 +138,6 @@ class AttrDocVisitor(nodes.NodeVisitor):
self.collected[namespace, name] = docstring
class PycodeError(Exception):
def __str__(self):
res = self.args[0]
if len(self.args) > 1:
res += ' (exception was: %r)' % self.args[1]
return res
class ModuleAnalyzer(object):
# cache for analyzer objects -- caches both by module and file name
cache = {}
@ -173,33 +167,11 @@ class ModuleAnalyzer(object):
return entry
try:
if modname not in sys.modules:
try:
__import__(modname)
except ImportError, err:
raise PycodeError('error importing %r' % modname, err)
mod = sys.modules[modname]
if hasattr(mod, '__loader__'):
try:
source = mod.__loader__.get_source(modname)
except Exception, err:
raise PycodeError('error getting source for %r' % modname,
err)
type, source = get_module_source(modname)
if type == 'string':
obj = cls.for_string(source, modname)
cls.cache['module', modname] = obj
return obj
filename = getattr(mod, '__file__', None)
if filename is None:
raise PycodeError('no source found for module %r' % modname)
filename = path.normpath(path.abspath(filename))
lfilename = filename.lower()
if lfilename.endswith('.pyo') or lfilename.endswith('.pyc'):
filename = filename[:-1]
elif not lfilename.endswith('.py'):
raise PycodeError('source is not a .py file: %r' % filename)
if not path.isfile(filename):
raise PycodeError('source file is not present: %r' % filename)
obj = cls.for_file(filename, modname)
else:
obj = cls.for_file(source, modname)
except PycodeError, err:
cls.cache['module', modname] = err
raise
@ -214,6 +186,11 @@ class ModuleAnalyzer(object):
# file-like object yielding source lines
self.source = source
# cache the source code as well
pos = self.source.tell()
self.code = self.source.read()
self.source.seek(pos)
# will be filled by tokenize()
self.tokens = None
# will be filled by parse()

View File

@ -368,6 +368,22 @@ dl.glossary dt {
margin-left: 1.5em;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border: 1px solid #D5BB73;
margin: -1px -10px;
padding: 0 10px;
}
/* -- code displays --------------------------------------------------------- */
pre {

View File

@ -508,6 +508,38 @@ def make_refnode(builder, fromdocname, todocname, targetid, child, title=None):
return node
def get_module_source(modname):
"""Try to find the source code for a module.
Can return ('file', 'filename') in which case the source is in the given
file, or ('string', 'source') which which case the source is the string.
"""
if modname not in sys.modules:
try:
__import__(modname)
except Exception, err:
raise PycodeError('error importing %r' % modname, err)
mod = sys.modules[modname]
if hasattr(mod, '__loader__'):
try:
source = mod.__loader__.get_source(modname)
except Exception, err:
raise PycodeError('error getting source for %r' % modname, err)
return 'string', source
filename = getattr(mod, '__file__', None)
if filename is None:
raise PycodeError('no source found for module %r' % modname)
filename = path.normpath(path.abspath(filename))
lfilename = filename.lower()
if lfilename.endswith('.pyo') or lfilename.endswith('.pyc'):
filename = filename[:-1]
elif not lfilename.endswith('.py'):
raise PycodeError('source is not a .py file: %r' % filename)
if not path.isfile(filename):
raise PycodeError('source file is not present: %r' % filename)
return 'file', filename
try:
any = any
except NameError:

View File

@ -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.doc_read_data['autodoc_module'] = 'util'
directive.env.doc_read_data['autodoc:module'] = 'util'
verify('function', 'raises', ('util', ['raises'], None, None))
del directive.env.doc_read_data['autodoc_module']
directive.env.doc_read_data['py_module'] = '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.doc_read_data['py_module'] = 'foo'
directive.env.doc_read_data['py:module'] = 'foo'
verify('method', 'util.TestApp.cleanup',
('util', ['TestApp', 'cleanup'], None, None))
directive.env.doc_read_data['py_module'] = 'util'
directive.env.doc_read_data['py_class'] = 'Foo'
directive.env.doc_read_data['autodoc_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
del directive.env.doc_read_data['py_module']
del directive.env.doc_read_data['py_class']
del directive.env.doc_read_data['autodoc_class']
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():
@ -353,7 +353,7 @@ def test_generate():
'function', 'util.foobar', more_content=None)
# test auto and given content mixing
directive.env.doc_read_data['py_module'] = '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)
@ -437,7 +437,7 @@ def test_generate():
'attribute', 'test_autodoc.Class.descr')
# test generation for C modules (which have no source file)
directive.env.doc_read_data['py_module'] = 'time'
directive.env.doc_read_data['py:module'] = 'time'
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
assert_processes([('function', 'time.asctime')], 'function', 'asctime')