summaryrefslogtreecommitdiff
path: root/sphinx/ext
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2008-12-30 02:09:29 +0100
committerGeorg Brandl <georg@python.org>2008-12-30 02:09:29 +0100
commitb16fc1a0ae62ebb0c97511da7ae04d890c7a9ad3 (patch)
tree8bdd9694c882bbb79144d8b30a1c6d6aaf4f9145 /sphinx/ext
parentbc4c6b9214603c8a04b965eae7ddebaa61727530 (diff)
downloadsphinx-b16fc1a0ae62ebb0c97511da7ae04d890c7a9ad3.tar.gz
First iteration of an autodoc that handles attribute documentation.
Diffstat (limited to 'sphinx/ext')
-rw-r--r--sphinx/ext/autodoc.py55
1 files changed, 41 insertions, 14 deletions
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index f94afc75..ddea1e44 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -22,6 +22,7 @@ from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
from sphinx.util import rpartition, nested_parse_with_titles
+from sphinx.pycode import ModuleAnalyzer, PycodeError
clstypes = (type, ClassType)
try:
@@ -313,7 +314,7 @@ class RstGenerator(object):
'for automodule %s' % name)
return (path or '') + base, [], None, None
- elif what in ('exception', 'function', 'class'):
+ elif what in ('exception', 'function', 'class', 'data'):
if mod is None:
if path:
mod = path.rstrip('.')
@@ -434,7 +435,9 @@ class RstGenerator(object):
modfile = None # e.g. for builtin and C modules
for part in objpath:
todoc = getattr(todoc, part)
- except (ImportError, AttributeError), err:
+ # also get a source code analyzer for attribute docs
+ analyzer = ModuleAnalyzer.for_module(mod)
+ except (ImportError, AttributeError, PycodeError), err:
self.warn('autodoc can\'t import/find %s %r, it reported error: "%s", '
'please check your spelling and sys.path' %
(what, str(fullname), err))
@@ -503,6 +506,15 @@ class RstGenerator(object):
else:
sourcename = 'docstring of %s' % fullname
+ # add content from attribute documentation
+ attr_docs = analyzer.find_attr_docs()
+ if what in ('data', 'attribute'):
+ key = ('.'.join(objpath[:-1]), objpath[-1])
+ if key in attr_docs:
+ no_docstring = True
+ for i, line in enumerate(attr_docs[key]):
+ self.result.append(indent + line, sourcename, i)
+
# add content from docstrings
if not no_docstring:
for i, line in enumerate(self.get_doc(what, fullname, todoc)):
@@ -524,9 +536,9 @@ class RstGenerator(object):
self.env.autodoc_current_class = objpath[0]
# add members, if possible
- _all = members == ['__all__']
+ all_members = members == ['__all__']
members_check_module = False
- if _all:
+ if all_members:
# unqualified :members: given
if what == 'module':
if hasattr(todoc, '__all__'):
@@ -555,14 +567,28 @@ class RstGenerator(object):
else:
all_members = [(mname, getattr(todoc, mname)) for mname in members]
+ # search for members in source code too
+ namespace = '.'.join(objpath) # will be empty for modules
+
for (membername, member) in all_members:
- if _all and membername.startswith('_'):
+ # if isattr is True, the member is documented as an attribute
+ isattr = False
+ # if content is not None, no extra content from docstrings will be added
+ content = None
+
+ if all_members and membername.startswith('_'):
# ignore members whose name starts with _ by default
skip = True
else:
- # ignore undocumented members if :undoc-members: is not given
- doc = getattr(member, '__doc__', None)
- skip = not self.options.undoc_members and not doc
+ if (namespace, membername) in attr_docs:
+ # keep documented attributes
+ skip = False
+ isattr = True
+ else:
+ # ignore undocumented members if :undoc-members: is not given
+ doc = getattr(member, '__doc__', None)
+ skip = not self.options.undoc_members and not doc
+
# give the user a chance to decide whether this member should be skipped
if self.env.app:
# let extensions preprocess docstrings
@@ -573,10 +599,11 @@ class RstGenerator(object):
if skip:
continue
- content = None
if what == 'module':
if isinstance(member, (FunctionType, BuiltinFunctionType)):
memberwhat = 'function'
+ elif isattr:
+ memberwhat = 'attribute'
elif isinstance(member, clstypes):
if member.__name__ != membername:
# assume it's aliased
@@ -588,10 +615,13 @@ class RstGenerator(object):
else:
memberwhat = 'class'
else:
- # XXX: todo -- attribute docs
continue
else:
- if isinstance(member, clstypes):
+ if inspect.isroutine(member):
+ memberwhat = 'method'
+ elif isattr:
+ memberwhat = 'attribute'
+ elif isinstance(member, clstypes):
if member.__name__ != membername:
# assume it's aliased
memberwhat = 'attribute'
@@ -599,12 +629,9 @@ class RstGenerator(object):
source='')
else:
memberwhat = 'class'
- elif inspect.isroutine(member):
- memberwhat = 'method'
elif isdescriptor(member):
memberwhat = 'attribute'
else:
- # XXX: todo -- attribute docs
continue
# give explicitly separated module name, so that members of inner classes
# can be documented