summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2010-02-28 11:39:13 +0100
committerGeorg Brandl <georg@python.org>2010-02-28 11:39:13 +0100
commitffe393b1b0a47d28c770668378ccff750fa82be3 (patch)
tree7338193901f847626069f9805128bb24f24bf01f
parent887ee5f5291ccf51bdddf137a4cd8df20b3482a5 (diff)
downloadsphinx-ffe393b1b0a47d28c770668378ccff750fa82be3.tar.gz
#187: Added support for source ordering of members in autodoc, with ``autodoc_member_order = 'bysource'``.
-rw-r--r--CHANGES3
-rw-r--r--doc/ext/autodoc.rst10
-rw-r--r--sphinx/ext/autodoc.py13
-rw-r--r--sphinx/pycode/__init__.py22
-rw-r--r--tests/test_autodoc.py36
5 files changed, 74 insertions, 10 deletions
diff --git a/CHANGES b/CHANGES
index 31458763..5fc36540 100644
--- a/CHANGES
+++ b/CHANGES
@@ -10,6 +10,9 @@ Release 1.0 (in development)
* Added a manual page builder.
+* Added support for source ordering of members in autodoc, with
+ ``autodoc_member_order = 'bysource'``.
+
* In HTML output, inline roles now get a CSS class with their name,
allowing styles to customize their appearance. Domain-specific
roles get two classes, ``domain`` and ``domain-rolename``.
diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst
index 4098d711..08a54082 100644
--- a/doc/ext/autodoc.rst
+++ b/doc/ext/autodoc.rst
@@ -223,10 +223,16 @@ There are also new config values that you can set:
.. confval:: autodoc_member_order
This value selects if automatically documented members are sorted
- alphabetical (value ``'alphabetical'``) or by member type (value
- ``'groupwise'``). The default is alphabetical.
+ alphabetical (value ``'alphabetical'``), by member type (value
+ ``'groupwise'``) or by source order (value ``'bysource'``). The default is
+ alphabetical.
+
+ Note that for source order, the module must be a Python module with the
+ source code available.
.. versionadded:: 0.6
+ .. versionchanged:: 1.0
+ Support for ``'bysource'``.
.. confval:: autodoc_default_flags
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index 7e42002e..2597c03b 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -599,12 +599,19 @@ class Documenter(object):
'.'.join(self.objpath + [mname])
memberdocumenters.append(
classes[-1](self.directive, full_mname, self.indent))
-
- if (self.options.member_order or self.env.config.autodoc_member_order) \
- == 'groupwise':
+ member_order = self.options.member_order or \
+ self.env.config.autodoc_member_order
+ if member_order == 'groupwise':
# sort by group; relies on stable sort to keep items in the
# same group sorted alphabetically
memberdocumenters.sort(key=lambda d: d.member_order)
+ elif member_order == 'bysource' and self.analyzer:
+ # sort by source order, by virtue of the module analyzer
+ tagorder = self.analyzer.tagorder
+ def keyfunc(documenter):
+ fullname = documenter.name.split('::')[1]
+ return tagorder.get(fullname, len(tagorder))
+ memberdocumenters.sort(key=keyfunc)
for documenter in memberdocumenters:
documenter.generate(all_members=True,
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 73c2042f..63303a85 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -58,9 +58,17 @@ class AttrDocVisitor(nodes.NodeVisitor):
self.encoding = encoding
self.namespace = []
self.collected = {}
+ self.tagnumber = 0
+ self.tagorder = {}
+
+ def add_tag(self, name):
+ name = '.'.join(self.namespace + [name])
+ self.tagorder[name] = self.tagnumber
+ self.tagnumber += 1
def visit_classdef(self, node):
"""Visit a class."""
+ self.add_tag(node[1].value)
self.namespace.append(node[1].value)
self.generic_visit(node)
self.namespace.pop()
@@ -68,6 +76,7 @@ class AttrDocVisitor(nodes.NodeVisitor):
def visit_funcdef(self, node):
"""Visit a function (or method)."""
# usually, don't descend into functions -- nothing interesting there
+ self.add_tag(node[1].value)
if node[1].value == '__init__':
# however, collect attributes set in __init__ methods
self.in_init += 1
@@ -91,8 +100,7 @@ class AttrDocVisitor(nodes.NodeVisitor):
prefix = pnode.get_prefix()
prefix = prefix.decode(self.encoding)
docstring = prepare_commentdoc(prefix)
- if docstring:
- self.add_docstring(node, docstring)
+ self.add_docstring(node, docstring)
def visit_simple_stmt(self, node):
"""Visit a docstring statement which may have an assignment before."""
@@ -133,9 +141,11 @@ class AttrDocVisitor(nodes.NodeVisitor):
continue
else:
name = target.value
- namespace = '.'.join(self.namespace)
- if namespace.startswith(self.scope):
- self.collected[namespace, name] = docstring
+ self.add_tag(name)
+ if docstring:
+ namespace = '.'.join(self.namespace)
+ if namespace.startswith(self.scope):
+ self.collected[namespace, name] = docstring
class ModuleAnalyzer(object):
@@ -197,6 +207,7 @@ class ModuleAnalyzer(object):
self.parsetree = None
# will be filled by find_attr_docs()
self.attr_docs = None
+ self.tagorder = None
# will be filled by find_tags()
self.tags = None
@@ -234,6 +245,7 @@ class ModuleAnalyzer(object):
attr_visitor = AttrDocVisitor(number2name, scope, self.encoding)
attr_visitor.visit(self.parsetree)
self.attr_docs = attr_visitor.collected
+ self.tagorder = attr_visitor.tagorder
# now that we found everything we could in the tree, throw it away
# (it takes quite a bit of memory for large modules)
self.parsetree = None
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index ea41dcaa..62768b20 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -341,6 +341,26 @@ def test_generate():
assert item in directive.result
del directive.result[:]
+ def assert_order(items, objtype, name, member_order, **kw):
+ inst = AutoDirective._registry[objtype](directive, name)
+ inst.options.member_order = member_order
+ inst.generate(**kw)
+ assert len(_warnings) == 0, _warnings
+ items = list(reversed(items))
+ lineiter = iter(directive.result)
+ #for line in directive.result:
+ # if line.strip():
+ # print repr(line)
+ while items:
+ item = items.pop()
+ for line in lineiter:
+ if line == item:
+ break
+ else: # ran out of items!
+ assert False, 'item %r not found in result or not in the ' \
+ ' correct order' % item
+ del directive.result[:]
+
options.members = []
# no module found?
@@ -442,6 +462,22 @@ def test_generate():
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
+ # test autodoc_member_order == 'source'
+ directive.env.temp_data['py:module'] = 'test_autodoc'
+ assert_order(['.. py:class:: Class(arg)',
+ ' .. py:attribute:: Class.descr',
+ ' .. py:method:: Class.meth()',
+ ' .. py:method:: Class.undocmeth()',
+ ' .. py:attribute:: Class.attr',
+ ' .. py:attribute:: Class.prop',
+ ' .. py:attribute:: Class.docattr',
+ ' .. py:attribute:: Class.udocattr',
+ ' .. py:attribute:: Class.inst_attr_comment',
+ ' .. py:attribute:: Class.inst_attr_string',
+ ' .. py:method:: Class.inheritedmeth()',
+ ],
+ 'class', 'Class', member_order='bysource', all_members=True)
+
# --- generate fodder ------------