summaryrefslogtreecommitdiff
path: root/sphinx/pycode
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2008-12-30 02:26:47 +0100
committerGeorg Brandl <georg@python.org>2008-12-30 02:26:47 +0100
commit7124a1e1760c7704a555b2eda54d1970783b1d56 (patch)
treedfc7365e42cd045bd2e8565f01310a72d0cf8af0 /sphinx/pycode
parentb16fc1a0ae62ebb0c97511da7ae04d890c7a9ad3 (diff)
downloadsphinx-7124a1e1760c7704a555b2eda54d1970783b1d56.tar.gz
Also find attribute docs in the "other" style: docstrings after the
assignment.
Diffstat (limited to 'sphinx/pycode')
-rw-r--r--sphinx/pycode/__init__.py75
1 files changed, 61 insertions, 14 deletions
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 0d4058bd..f4bd1b1d 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -14,7 +14,7 @@ import time
from os import path
from sphinx.pycode import pytree
-from sphinx.pycode.pgen2 import driver, token, parse
+from sphinx.pycode.pgen2 import driver, token, parse, literals
# load the Python grammar
@@ -46,13 +46,42 @@ def prepare_commentdoc(s):
return result
+def prepare_literaldoc(s):
+ # first, "evaluate" the string
+ s = literals.evalString(s)
+ # then, prepare (XXX copied from ext/autodoc)
+ lines = s.expandtabs().splitlines()
+ # Find minimum indentation of any non-blank lines after first line.
+ margin = sys.maxint
+ for line in lines[1:]:
+ content = len(line.lstrip())
+ if content:
+ indent = len(line) - content
+ margin = min(margin, indent)
+ # Remove indentation.
+ if lines:
+ lines[0] = lines[0].lstrip()
+ if margin < sys.maxint:
+ for i in range(1, len(lines)): lines[i] = lines[i][margin:]
+ # Remove any leading blank lines.
+ while lines and not lines[0]:
+ lines.pop(0)
+ # make sure there is an empty line at the end
+ if lines and lines[-1]:
+ lines.append('')
+ return lines
+
+
_eq = pytree.Leaf(token.EQUAL, '=')
-class ClassAttrVisitor(pytree.NodeVisitor):
+class AttrDocVisitor(pytree.NodeVisitor):
"""
- Visitor that collects comments appearing before attribute assignments
- on toplevel and in classes.
+ Visitor that collects docstrings for attribute assignments on toplevel and
+ in classes.
+
+ The docstrings can either be in special '#:' comments before the assignment
+ or in a docstring after it.
"""
def init(self, scope):
self.scope = scope
@@ -65,6 +94,7 @@ class ClassAttrVisitor(pytree.NodeVisitor):
self.namespace.pop()
def visit_expr_stmt(self, node):
+ """Visit an assignment which may have a special comment before it."""
if _eq not in node.children:
# not an assignment (we don't care for augmented assignments)
return
@@ -79,8 +109,27 @@ class ClassAttrVisitor(pytree.NodeVisitor):
break
prefix = pnode.get_prefix()
docstring = prepare_commentdoc(prefix)
- if not docstring:
+ if docstring:
+ self.add_docstring(node, docstring)
+
+ def visit_simple_stmt(self, node):
+ """Visit a docstring statement which may have an assignment before."""
+ if node[0].type != token.STRING:
+ # not a docstring; but still need to visit children
+ return self.generic_visit(node)
+ prev = node.get_prev_sibling()
+ if not prev:
return
+ if prev.type == sym.simple_stmt and \
+ prev[0].type == sym.expr_stmt and _eq in prev[0].children:
+ docstring = prepare_literaldoc(node[0].value)
+ self.add_docstring(prev[0], docstring)
+
+ def visit_funcdef(self, node):
+ # don't descend into functions -- nothing interesting there
+ return
+
+ def add_docstring(self, node, docstring):
# add an item for each assignment target
for i in range(0, len(node) - 1, 2):
target = node[i]
@@ -91,10 +140,6 @@ class ClassAttrVisitor(pytree.NodeVisitor):
if namespace.startswith(self.scope):
self.collected[namespace, target.value] = docstring
- def visit_funcdef(self, node):
- # don't descend into functions -- nothing interesting there
- return
-
class PycodeError(Exception):
def __str__(self):
@@ -164,17 +209,19 @@ class ModuleAnalyzer(object):
return obj
def find_attr_docs(self, scope=''):
- attr_visitor = ClassAttrVisitor(number2name, scope)
+ attr_visitor = AttrDocVisitor(number2name, scope)
attr_visitor.visit(self.tree)
return attr_visitor.collected
if __name__ == '__main__':
x0 = time.time()
- ma = ModuleAnalyzer.for_file('sphinx/builders/html.py', 'sphinx.builders.html')
+ #ma = ModuleAnalyzer.for_file('sphinx/builders/html.py', 'sphinx.builders.html')
+ ma = ModuleAnalyzer.for_file(__file__.rstrip('c'), 'sphinx.builders.html')
x1 = time.time()
- for name, doc in ma.find_attrs():
- print '>>', name
- print doc
+ for (ns, name), doc in ma.find_attr_docs().iteritems():
+ print '>>', ns, name
+ print '\n'.join(doc)
x2 = time.time()
+ #print pytree.nice_repr(ma.tree, number2name)
print "parsing %.4f, finding %.4f" % (x1-x0, x2-x1)