summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in1
-rw-r--r--doc/ext/autodoc.rst18
-rw-r--r--sphinx/config.py2
-rw-r--r--sphinx/environment.py2
-rw-r--r--sphinx/ext/autodoc.py4
-rw-r--r--sphinx/pycode/__init__.py5
-rw-r--r--sphinx/pycode/pgen2/tokenize.py9
-rw-r--r--sphinx/util/compat.py2
-rw-r--r--tests/test_build.py2
9 files changed, 37 insertions, 8 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index a22d6a8e..e1f0b575 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -16,6 +16,7 @@ recursive-include sphinx/themes *
recursive-include sphinx/locale *
recursive-include tests *
recursive-include utils *
+include sphinx/pycode/Grammar.txt
recursive-include doc *
prune doc/_build
diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst
index 993f971a..e0766938 100644
--- a/doc/ext/autodoc.rst
+++ b/doc/ext/autodoc.rst
@@ -135,12 +135,30 @@ directive.
.. directive:: autofunction
+ autodata
automethod
autoattribute
These work exactly like :dir:`autoclass` etc., but do not offer the options
used for automatic member documentation.
+ For module data members and class attributes, documentation can either be put
+ into a special-formatted comment *before* the attribute definition, or in a
+ docstring *after* the definition. This means that in the following class
+ definition, both attributes can be autodocumented::
+
+ class Foo:
+ """Docstring for class Foo."""
+
+ #: Doc comment for attribute Foo.bar.
+ bar = 1
+
+ baz = 2
+ """Docstring for attribute Foo.baz."""
+
+ .. versionchanged:: 0.6
+ :dir:`autodata` and :dir:`autoattribute` can now extract docstrings.
+
.. note::
If you document decorated functions or methods, keep in mind that autodoc
diff --git a/sphinx/config.py b/sphinx/config.py
index 60f85375..5942fcf8 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -139,7 +139,7 @@ class Config(object):
if name not in self.values:
raise AttributeError('No such config value: %s' % name)
default = self.values[name][0]
- if callable(default):
+ if hasattr(default, '__call__'):
return default(self)
return default
diff --git a/sphinx/environment.py b/sphinx/environment.py
index b70bd250..fe4cba6b 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -541,7 +541,7 @@ class BuildEnvironment:
doctree = pub.document
except UnicodeError, err:
from sphinx.application import SphinxError
- raise SphinxError(err.message)
+ raise SphinxError(str(err))
self.filter_messages(doctree)
self.process_dependencies(docname, doctree)
self.process_images(docname, doctree)
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index be3e3f0f..d0512f2b 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -166,7 +166,7 @@ def between(marker, what=None, keepempty=False):
def isdescriptor(x):
"""Check if the object is some kind of descriptor."""
for item in '__get__', '__set__', '__delete__':
- if callable(getattr(x, item, None)):
+ if hasattr(getattr(x, item, None), '__call__'):
return True
return False
@@ -380,6 +380,8 @@ class RstGenerator(object):
# try to also get a source code analyzer for attribute docs
try:
analyzer = ModuleAnalyzer.for_module(mod)
+ # parse right now, to get PycodeErrors on parsing
+ analyzer.parse()
except PycodeError, err:
# no source file -- e.g. for builtin and C modules
analyzer = None
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 17dc6afb..c2086da5 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -210,7 +210,10 @@ class ModuleAnalyzer(object):
if self.parsetree is not None:
return
self.tokenize()
- self.parsetree = pydriver.parse_tokens(self.tokens)
+ try:
+ self.parsetree = pydriver.parse_tokens(self.tokens)
+ except parse.ParseError, err:
+ raise PycodeError('parsing failed', err)
# find the source code encoding
encoding = sys.getdefaultencoding()
comments = self.parsetree.get_prefix()
diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py
index 46ee7842..4489db89 100644
--- a/sphinx/pycode/pgen2/tokenize.py
+++ b/sphinx/pycode/pgen2/tokenize.py
@@ -274,12 +274,17 @@ def generate_tokens(readline):
line = readline()
except StopIteration:
line = ''
+ # if we are not at the end of the file make sure the
+ # line ends with a newline because the parser depends
+ # on that.
+ if line:
+ line = line.rstrip() + '\n'
lnum = lnum + 1
pos, max = 0, len(line)
if contstr: # continued string
if not line:
- raise TokenError, ("EOF in multi-line string", strstart)
+ raise TokenError("EOF in multi-line string", strstart)
endmatch = endprog.match(line)
if endmatch:
pos = end = endmatch.end(0)
@@ -335,7 +340,7 @@ def generate_tokens(readline):
else: # continued statement
if not line:
- raise TokenError, ("EOF in multi-line statement", (lnum, 0))
+ raise TokenError("EOF in multi-line statement", (lnum, 0))
continued = 0
while pos < max:
diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py
index 4d5e1996..56ac9e80 100644
--- a/sphinx/util/compat.py
+++ b/sphinx/util/compat.py
@@ -27,7 +27,7 @@ def make_admonition(node_class, name, arguments, options, content, lineno,
textnodes, messages = state.inline_text(title_text, lineno)
admonition_node += nodes.title(title_text, '', *textnodes)
admonition_node += messages
- if options.has_key('class'):
+ if 'class' in options:
classes = options['class']
else:
classes = ['admonition-' + nodes.make_id(title_text)]
diff --git a/tests/test_build.py b/tests/test_build.py
index 5e815e88..9999abd0 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -129,7 +129,7 @@ def test_html(app):
for path, check in paths.iteritems():
nodes = list(etree.findall(path))
assert nodes != []
- if callable(check):
+ if hasattr(check, '__call__'):
check(nodes)
elif not check:
# only check for node presence