[Python-checkins] r64297 - in doctools/trunk: CHANGES sphinx/ext/autodoc.py

georg.brandl python-checkins at python.org
Sun Jun 15 19:09:23 CEST 2008


Author: georg.brandl
Date: Sun Jun 15 19:09:23 2008
New Revision: 64297
Log:
Correctly report source location for docstrings included
with autodoc.
Modified:
 doctools/trunk/CHANGES
 doctools/trunk/sphinx/ext/autodoc.py
Modified: doctools/trunk/CHANGES
==============================================================================
--- doctools/trunk/CHANGES	(original)
+++ doctools/trunk/CHANGES	Sun Jun 15 19:09:23 2008
@@ -42,7 +42,8 @@
 which makes the builder select the one that matches best.
 
 * The new config value `exclude_trees` can be used to exclude whole
- subtrees from the search for source files.
+ subtrees from the search for source files. Thanks to Sebastian
+ Wiesner.
 
 * Defaults for configuration values can now be callables, which allows
 dynamic defaults.
@@ -58,6 +59,9 @@
 Bugs fixed
 ----------
 
+* Correctly report the source location for docstrings included with
+ autodoc.
+
 * Fix the LaTeX output of description units with multiple signatures.
 
 * Handle the figure directive in LaTeX output.
Modified: doctools/trunk/sphinx/ext/autodoc.py
==============================================================================
--- doctools/trunk/sphinx/ext/autodoc.py	(original)
+++ doctools/trunk/sphinx/ext/autodoc.py	Sun Jun 15 19:09:23 2008
@@ -33,6 +33,47 @@
 _module_charsets = {}
 
 
+class AutodocReporter(object):
+ """
+ A reporter replacement that assigns the correct source name
+ and line number to a system message, as recorded in a ViewList.
+ """
+ def __init__(self, viewlist, reporter):
+ self.viewlist = viewlist
+ self.reporter = reporter
+
+ def __getattr__(self, name):
+ return getattr(self.reporter, name)
+
+ def system_message(self, level, message, *children, **kwargs):
+ if 'line' in kwargs:
+ try:
+ source, line = self.viewlist.items[kwargs['line']]
+ except IndexError:
+ pass
+ else:
+ kwargs['source'] = source
+ kwargs['line'] = line
+ return self.reporter.system_message(level, message,
+ *children, **kwargs)
+
+ def debug(self, *args, **kwargs):
+ if self.reporter.debug_flag:
+ return self.system_message(0, *args, **kwargs)
+
+ def info(self, *args, **kwargs):
+ return self.system_message(1, *args, **kwargs)
+
+ def warning(self, *args, **kwargs):
+ return self.system_message(2, *args, **kwargs)
+
+ def error(self, *args, **kwargs):
+ return self.system_message(3, *args, **kwargs)
+
+ def severe(self, *args, **kwargs):
+ return self.system_message(4, *args, **kwargs)
+
+
 def isdescriptor(x):
 """Check if the object is some kind of descriptor."""
 for item in '__get__', '__set__', '__delete__':
@@ -65,8 +106,11 @@
 """Return the charset of the given module (cached in _module_charsets)."""
 if module in _module_charsets:
 return _module_charsets[module]
- filename = __import__(module, None, None, ['']).__file__
- if filename[-4:] in ('.pyc', '.pyo'):
+ try:
+ filename = __import__(module, None, None, ['']).__file__
+ except (ImportError, AttributeError):
+ return None
+ if filename[-4:].lower() in ('.pyc', '.pyo'):
 filename = filename[:-1]
 for line in [linecache.getline(filename, x) for x in (1, 2)]:
 match = _charset_re.search(line)
@@ -137,6 +181,8 @@
 lineno, indent='', filename_set=None, check_module=False):
 env = document.settings.env
 
+ result = None
+
 # first, parse the definition -- auto directives for classes and functions
 # can contain a signature which is then used instead of an autogenerated one
 try:
@@ -144,7 +190,7 @@
 except:
 warning = document.reporter.warning(
 'invalid signature for auto%s (%r)' % (what, name), line=lineno)
- return [warning], ViewList()
+ return [warning], result
 # fullname is the fully qualified name, base the name after the last dot
 fullname = (path or '') + base
 # path is the name up to the last dot
@@ -203,20 +249,17 @@
 # the name to put into the generated directive -- doesn't contain the module
 name_in_directive = '.'.join(objpath) or mod
 
- # make sure that the view list starts with an empty line. This is
- # necessary for some situations where another directive preprocesses
- # reST and no starting newline is present
- result = ViewList()
- result.append('', '')
-
 # now, import the module and get docstring(s) of object to document
 try:
 todoc = module = __import__(mod, None, None, ['foo'])
- if filename_set is not None and hasattr(module, '__file__') and module.__file__:
+ if hasattr(module, '__file__') and module.__file__:
 modfile = module.__file__
- if modfile.lower().endswith('.pyc') or modfile.lower().endswith('.pyo'):
+ if modfile[-4:].lower() in ('.pyc', '.pyo'):
 modfile = modfile[:-1]
- filename_set.add(modfile)
+ if filename_set is not None:
+ filename_set.add(modfile)
+ else:
+ modfile = None # e.g. for builtin and C modules
 for part in objpath:
 todoc = getattr(todoc, part)
 except (ImportError, AttributeError):
@@ -244,6 +287,12 @@
 (fullname, err), line=lineno))
 args = ''
 
+ # make sure that the view list starts with an empty line. This is
+ # necessary for some situations where another directive preprocesses
+ # reST and no starting newline is present
+ result = ViewList()
+ result.append('', '')
+
 # now, create the directive header
 result.append(indent + '.. %s:: %s%s' % (what, name_in_directive, args),
 '<autodoc>')
@@ -257,9 +306,14 @@
 if what != 'module':
 indent += ' '
 
+ if modfile:
+ sourcename = '%s:docstring of %s' % (modfile, fullname)
+ else:
+ sourcename = 'docstring of %s' % fullname
+
 # add content from docstrings
 for i, line in enumerate(get_doc(what, todoc, env)):
- result.append(indent + line, '<docstring of %s>' % fullname, i)
+ result.append(indent + line, sourcename, i)
 
 # add source content, if present
 if add_content:
@@ -349,12 +403,17 @@
 filename_set = set()
 warnings, result = generate_rst(what, name, members, inherited, undoc, content,
 state.document, lineno, filename_set=filename_set)
+ if result is None:
+ return warnings
 
 # record all filenames as dependencies -- this will at least partially make
 # automatic invalidation possible
 for fn in filename_set:
 state.document.settings.env.note_dependency(fn)
 
+ # use a custom reporter that correctly assigns lines to source and lineno
+ old_reporter = state.memo.reporter
+ state.memo.reporter = AutodocReporter(result, state.memo.reporter)
 if dirname == 'automodule':
 node = nodes.section()
 # hack around title style bookkeeping
@@ -362,12 +421,13 @@
 surrounding_section_level = state.memo.section_level
 state.memo.title_styles = []
 state.memo.section_level = 0
- state.nested_parse(result, content_offset, node, match_titles=1)
+ state.nested_parse(result, 0, node, match_titles=1)
 state.memo.title_styles = surrounding_title_styles
 state.memo.section_level = surrounding_section_level
 else:
 node = nodes.paragraph()
- state.nested_parse(result, content_offset, node)
+ state.nested_parse(result, 0, node)
+ state.memo.reporter = old_reporter
 return warnings + node.children
 
 def auto_directive(*args, **kwds):


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /