[Python-checkins] r65503 - in doctools/trunk: sphinx/ext/autodoc.py tests/root/conf.py tests/test_autodoc.py tests/test_quickstart.py tests/util.py
georg.brandl
python-checkins at python.org
Mon Aug 4 21:39:06 CEST 2008
Author: georg.brandl
Date: Mon Aug 4 21:39:05 2008
New Revision: 65503
Log:
Add a test suite for autodoc.
Added:
doctools/trunk/tests/test_autodoc.py (contents, props changed)
Modified:
doctools/trunk/sphinx/ext/autodoc.py
doctools/trunk/tests/root/conf.py
doctools/trunk/tests/test_quickstart.py
doctools/trunk/tests/util.py
Modified: doctools/trunk/sphinx/ext/autodoc.py
==============================================================================
--- doctools/trunk/sphinx/ext/autodoc.py (original)
+++ doctools/trunk/sphinx/ext/autodoc.py Mon Aug 4 21:39:05 2008
@@ -284,7 +284,7 @@
if what == 'module':
if args or retann:
self.warn('ignoring signature arguments and return annotation '
- 'for automodule %s' % mod)
+ 'for automodule %s' % fullname)
return fullname, fullname, [], None, None
elif what in ('class', 'exception', 'function'):
@@ -335,18 +335,21 @@
else:
# try to introspect the signature
try:
+ args = None
+ getargs = True
if what == 'class':
# for classes, the relevant signature is the __init__ method's
obj = getattr(obj, '__init__', None)
# classes without __init__ method?
if obj is None or obj is object.__init__ or not \
(inspect.ismethod(obj) or inspect.isfunction(obj)):
- return ''
- argspec = inspect.getargspec(obj)
- if what in ('class', 'method') and argspec[0] and \
- argspec[0][0] in ('cls', 'self'):
- del argspec[0][0]
- args = inspect.formatargspec(*argspec)
+ getargs = False
+ if getargs:
+ argspec = inspect.getargspec(obj)
+ if what in ('class', 'method') and argspec[0] and \
+ argspec[0][0] in ('cls', 'self'):
+ del argspec[0][0]
+ args = inspect.formatargspec(*argspec)
except Exception, e:
args = None
err = e
@@ -392,7 +395,7 @@
for part in objpath:
todoc = getattr(todoc, part)
except (ImportError, AttributeError), err:
- self.warn('autodoc can\'t import/find %s %r, it reported error: "%s",'
+ self.warn('autodoc can\'t import/find %s %r, it reported error: "%s", '
'please check your spelling and sys.path' %
(what, str(fullname), err))
return
Modified: doctools/trunk/tests/root/conf.py
==============================================================================
--- doctools/trunk/tests/root/conf.py (original)
+++ doctools/trunk/tests/root/conf.py Mon Aug 4 21:39:05 2008
@@ -23,7 +23,7 @@
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['ext']
+extensions = ['ext', 'sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Added: doctools/trunk/tests/test_autodoc.py
==============================================================================
--- (empty file)
+++ doctools/trunk/tests/test_autodoc.py Mon Aug 4 21:39:05 2008
@@ -0,0 +1,331 @@
+# -*- coding: utf-8 -*-
+"""
+ test_autodoc
+ ~~~~~~~~~~~~
+
+ Test the autodoc extension. This tests mainly the RstGenerator; the auto
+ directives are tested in a test source file translated by test_build.
+
+ :copyright: 2008 by Georg Brandl.
+ :license: BSD.
+"""
+
+from util import *
+
+from docutils.statemachine import ViewList
+
+from sphinx.ext.autodoc import RstGenerator
+
+
+def setup_module():
+ global app, lid, options, gen
+
+ app = TestApp()
+ app.builder.env.app = app
+ app.connect('autodoc-process-docstring', process_docstring)
+ app.connect('autodoc-process-signature', process_signature)
+
+ options = Struct(
+ inherited_members = False,
+ undoc_members = False,
+ show_inheritance = False,
+ noindex = False,
+ synopsis = '',
+ platform = '',
+ deprecated = False,
+ )
+
+ gen = TestGenerator(options, app)
+
+def teardown_module():
+ app.cleanup()
+
+
+class TestGenerator(RstGenerator):
+ """Generator that handles warnings without a reporter."""
+
+ def __init__(self, options, app):
+ self.options = options
+ self.env = app.builder.env
+ self.lineno = 42
+ self.filename_set = set()
+ self.warnings = []
+ self.result = ViewList()
+
+ def warn(self, msg):
+ self.warnings.append(msg)
+
+
+processed_docstrings = []
+
+def process_docstring(app, what, name, obj, options, lines):
+ processed_docstrings.append((what, name))
+ if name == 'bar':
+ lines.extend(['42', ''])
+
+processed_signatures = []
+
+def process_signature(app, what, name, obj, options, args, retann):
+ processed_signatures.append((what, name))
+ if name == 'bar':
+ return '42', None
+
+
+def test_resolve_name():
+ # for modules
+ assert gen.resolve_name('module', 'test_autodoc') == \
+ ('test_autodoc', 'test_autodoc', [], None, None)
+ assert gen.resolve_name('module', 'test.test_autodoc') == \
+ ('test.test_autodoc', 'test.test_autodoc', [], None, None)
+
+ assert gen.resolve_name('module', 'test(arg)') == \
+ ('test', 'test', [], None, None)
+ assert 'ignoring signature arguments' in gen.warnings[0]
+ del gen.warnings[:]
+
+ # for functions/classes
+ assert gen.resolve_name('function', 'util.raises') == \
+ ('util.raises', 'util', ['raises'], None, None)
+ assert gen.resolve_name('function', 'util.raises(exc) -> None') == \
+ ('util.raises', 'util', ['raises'], 'exc', ' -> None')
+ gen.env.autodoc_current_module = 'util'
+ assert gen.resolve_name('function', 'raises') == \
+ ('raises', 'util', ['raises'], None, None)
+ gen.env.autodoc_current_module = None
+ gen.env.currmodule = 'util'
+ assert gen.resolve_name('function', 'raises') == \
+ ('raises', 'util', ['raises'], None, None)
+ assert gen.resolve_name('class', 'TestApp') == \
+ ('TestApp', 'util', ['TestApp'], None, None)
+
+ # for members
+ gen.env.currmodule = 'foo'
+ assert gen.resolve_name('method', 'util.TestApp.cleanup') == \
+ ('util.TestApp.cleanup', 'util', ['TestApp', 'cleanup'], None, None)
+ gen.env.currmodule = 'util'
+ gen.env.currclass = 'Foo'
+ gen.env.autodoc_current_class = 'TestApp'
+ assert gen.resolve_name('method', 'cleanup') == \
+ ('cleanup', 'util', ['TestApp', 'cleanup'], None, None)
+ assert gen.resolve_name('method', 'TestApp.cleanup') == \
+ ('TestApp.cleanup', 'util', ['TestApp', 'cleanup'], None, None)
+
+ # and clean up
+ gen.env.currmodule = None
+ gen.env.currclass = None
+ gen.env.autodoc_current_class = None
+
+
+def test_format_signature():
+ # no signatures for modules
+ assert gen.format_signature('module', 'test', None, None, None) == ''
+
+ # test for functions
+ def f(a, b, c=1, **d):
+ pass
+ assert gen.format_signature('function', 'f', f, None, None) == '(a, b, c=1, **d)'
+ assert gen.format_signature('function', 'f', f, 'a, b, c, d', None) == \
+ '(a, b, c, d)'
+ assert gen.format_signature('function', 'f', f, None, ' -> None') == \
+ '(a, b, c=1, **d) -> None'
+
+ # test for classes
+ class D:
+ pass
+ class E(object):
+ pass
+ # no signature for classes without __init__
+ for C in (D, E):
+ assert gen.format_signature('class', 'D', C, None, None) == ''
+ class F:
+ def __init__(self, a, b=None):
+ pass
+ class G(F, object):
+ pass
+ for C in (F, G):
+ assert gen.format_signature('class', 'C', C, None, None) == '(a, b=None)'
+ assert gen.format_signature('class', 'C', D, 'a, b', ' -> X') == '(a, b) -> X'
+
+ # test for methods
+ class H:
+ def foo1(self, b, *c):
+ pass
+ def foo2(b, *c):
+ pass
+ assert gen.format_signature('method', 'H.foo', H.foo1, None, None) == '(b, *c)'
+ assert gen.format_signature('method', 'H.foo', H.foo1, 'a', None) == '(a)'
+ assert gen.format_signature('method', 'H.foo', H.foo2, None, None) == '(b, *c)'
+
+ # test exception handling
+ raises(RuntimeError, gen.format_signature, 'function', 'int', int, None, None)
+
+ # test processing by event handler
+ assert gen.format_signature('method', 'bar', H.foo1, None, None) == '42'
+
+
+def test_get_doc():
+ def getdocl(*args):
+ # strip the empty line at the end
+ return list(gen.get_doc(*args))[:-1]
+
+ # objects without docstring
+ def f():
+ pass
+ assert getdocl('function', 'f', f) == []
+
+ # standard function, diverse docstring styles...
+ def f():
+ """Docstring"""
+ def g():
+ """
+ Docstring
+ """
+ for func in (f, g):
+ assert getdocl('function', 'f', func) == ['Docstring']
+
+ # first line vs. other lines indentation
+ def f():
+ """First line
+
+ Other
+ lines
+ """
+ assert getdocl('function', 'f', f) == ['First line', '', 'Other', ' lines']
+
+ # charset guessing (this module is encoded in utf-8)
+ def f():
+ """Döcstring"""
+ assert getdocl('function', 'f', f) == [u'Döcstring']
+
+ # already-unicode docstrings must be taken literally
+ def f():
+ u"""Döcstring"""
+ assert getdocl('function', 'f', f) == [u'Döcstring']
+
+ # class docstring: depends on config value which one is taken
+ class C:
+ """Class docstring"""
+ def __init__(self):
+ """Init docstring"""
+ gen.env.config.autoclass_content = 'class'
+ assert getdocl('class', 'C', C) == ['Class docstring']
+ gen.env.config.autoclass_content = 'init'
+ assert getdocl('class', 'C', C) == ['Init docstring']
+ gen.env.config.autoclass_content = 'both'
+ assert getdocl('class', 'C', C) == ['Class docstring', '', 'Init docstring']
+
+ class D:
+ def __init__(self):
+ """Init docstring"""
+
+ # docstring processing by event handler
+ assert getdocl('class', 'bar', D) == ['Init docstring', '', '42']
+
+
+def test_generate():
+ def assert_warns(warn_str, *args):
+ gen.generate(*args)
+ assert len(gen.result) == 0, gen.result
+ assert len(gen.warnings) == 1, gen.warnings
+ assert warn_str in gen.warnings[0], gen.warnings
+ del gen.warnings[:]
+
+ def assert_works(*args):
+ gen.generate(*args)
+ assert gen.result
+ assert len(gen.warnings) == 0, gen.warnings
+ del gen.result[:]
+
+ def assert_processes(items, *args):
+ del processed_docstrings[:]
+ del processed_signatures[:]
+ assert_works(*args)
+ assert set(processed_docstrings) | set(processed_signatures) == set(items)
+
+ def assert_result_contains(item, *args):
+ gen.generate(*args)
+ assert len(gen.warnings) == 0, gen.warnings
+ assert item in gen.result
+ del gen.result[:]
+
+ # no module found?
+ assert_warns("import for autodocumenting 'foobar'",
+ 'function', 'foobar', None, None)
+ # importing
+ assert_warns("import/find module 'test_foobar'",
+ 'module', 'test_foobar', None, None)
+ # attributes missing
+ assert_warns("import/find function 'util.foobar'",
+ 'function', 'util.foobar', None, None)
+
+ # test auto and given content mixing
+ gen.env.currmodule = 'test_autodoc'
+ assert_result_contains(' Function.', 'method', 'Class.meth', [], None)
+ add_content = ViewList()
+ add_content.append('Content.', '', 0)
+ assert_result_contains(' Function.', 'method', 'Class.meth', [], add_content)
+ assert_result_contains(' Content.', 'method', 'Class.meth', [], add_content)
+
+ # test check_module
+ gen.generate('function', 'raises', None, None, check_module=True)
+ assert len(gen.result) == 0
+
+ # assert that exceptions can be documented
+ assert_works('exception', 'test_autodoc.CustomEx', ['__all__'], None)
+ assert_works('exception', 'test_autodoc.CustomEx', [], None)
+
+ # test diverse inclusion settings for members
+ should = [('class', 'Class')]
+ assert_processes(should, 'class', 'Class', [], None)
+ should.extend([('method', 'Class.meth')])
+ assert_processes(should, 'class', 'Class', ['meth'], None)
+ should.extend([('attribute', 'Class.prop')])
+ assert_processes(should, 'class', 'Class', ['__all__'], None)
+ options.undoc_members = True
+ should.append(('method', 'Class.undocmeth'))
+ assert_processes(should, 'class', 'Class', ['__all__'], None)
+ options.inherited_members = True
+ should.append(('method', 'Class.inheritedmeth'))
+ assert_processes(should, 'class', 'Class', ['__all__'], None)
+
+ # test module flags
+ assert_result_contains('.. module:: test_autodoc', 'module',
+ 'test_autodoc', [], None)
+ options.synopsis = 'Synopsis'
+ assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc', [], None)
+ options.deprecated = True
+ assert_result_contains(' :deprecated:', 'module', 'test_autodoc', [], None)
+ options.platform = 'Platform'
+ assert_result_contains(' :platform: Platform', 'module', 'test_autodoc', [], None)
+
+ # test noindex flag
+ options.noindex = True
+ assert_result_contains(' :noindex:', 'module', 'test_autodoc', [], None)
+ assert_result_contains(' :noindex:', 'class', 'Base', [], None)
+
+
+# --- generate fodder ------------
+
+class CustomEx(Exception):
+ """My custom exception."""
+
+ def f(self):
+ """Exception method."""
+
+
+class Base(object):
+ def inheritedmeth(self):
+ """Inherited function."""
+
+class Class(Base):
+ """Class to document."""
+
+ def meth(self):
+ """Function."""
+
+ def undocmeth(self):
+ pass
+
+ @property
+ def prop(self):
+ """Property."""
Modified: doctools/trunk/tests/test_quickstart.py
==============================================================================
--- doctools/trunk/tests/test_quickstart.py (original)
+++ doctools/trunk/tests/test_quickstart.py Mon Aug 4 21:39:05 2008
@@ -117,6 +117,7 @@
'Name of your master document': 'contents',
'autodoc': 'y',
'doctest': 'yes',
+ 'intersphinx': 'no',
'Create Makefile': 'no',
}
qs.raw_input = mock_raw_input(answers, needanswer=True)
Modified: doctools/trunk/tests/util.py
==============================================================================
--- doctools/trunk/tests/util.py (original)
+++ doctools/trunk/tests/util.py Mon Aug 4 21:39:05 2008
@@ -24,7 +24,7 @@
__all__ = [
'test_root',
- 'raises', 'raises_msg',
+ 'raises', 'raises_msg', 'Struct',
'ListOutput', 'TestApp', 'with_testapp',
'path', 'with_tempdir', 'write_file',
'sprint',
@@ -66,6 +66,11 @@
(func.__name__, _excstr(exc)))
+class Struct(object):
+ def __init__(self, **kwds):
+ self.__dict__.update(kwds)
+
+
class ListOutput(object):
"""
File-like object that collects written text in a list.
More information about the Python-checkins
mailing list