Commits

Georg Brandl committed 77cd4b7

Update the test_autodoc for the autodoc refactorings and fix a few remaining bugs.

Comments (0)

Files changed (4)

sphinx/ext/autodoc.py

         self.modname, self.objpath = \
                       self.resolve_name(modname, parents, path, base)
 
+        if not self.modname:
+            return False
+
         self.args = args
         self.retann = retann
-        self.fullname = self.modname + (self.objpath and
-                                        '.' + '.'.join(self.objpath) or '')
+        self.fullname = (self.modname or '') + (self.objpath and
+                                                '.' + '.'.join(self.objpath) or '')
         return True
 
     def import_object(self):
         return None
 
     def format_signature(self):
-        err = None
         if self.args is not None:
             # signature given explicitly
             args = "(%s)" % self.args
         else:
             # try to introspect the signature
-            try:
-                args = self.format_args()
-            except Exception, e:
-                args = None
-                err = e
+            args = self.format_args()
         if args is None:
             return ''
         retann = self.retann
 
         if args is not None:
             return args + (retann and (' -> %s' % retann) or '')
-        elif err:
-            # re-raise the error for perusal of the handler in generate()
-            raise RuntimeError(err)
         else:
             return ''
 
 
 
 class ModuleDocumenter(Documenter):
+    objtype = 'module'
+    content_indent = u''
+
     option_spec = {
         'members': members_option, 'undoc-members': bool_option,
         'noindex': bool_option, 'inherited-members': bool_option,
         if self.options.deprecated:
             self.add_line(u'   :deprecated:', '<autodoc>')
 
-    def get_object_members(self, members=None):
-        if members is ALL or not hasattr(self.object, '__all__'):
-            # for implicit module members, check __module__ to avoid
-            # documenting imported objects
-            return True, inspect.getmembers(self.object)
+    def get_object_members(self, want_all):
+        if want_all:
+            if not hasattr(self.object, '__all__'):
+                # for implicit module members, check __module__ to avoid
+                # documenting imported objects
+                return True, inspect.getmembers(self.object)
+            else:
+                memberlist = self.object.__all__
+        else:
+            memberlist = self.options.members
         ret = []
-        for mname in (members or self.object.__all__):
+        for mname in memberlist:
             try:
                 ret.append((mname, getattr(self.object, mname)))
             except AttributeError:
         else:
             ModuleLevelDocumenter.add_content(self, more_content)
 
+    def document_members(self, all_members=False):
+        if self.doc_as_attr:
+            return
+        ModuleLevelDocumenter.document_members(self, all_members)
+
 
 class ExceptionDocumenter(ClassDocumenter):
     objtype = 'exception'

sphinx/util/__init__.py

     """Return a relative URL from ``base`` to ``to``."""
     b2 = base.split(SEP)
     t2 = to.split(SEP)
+    if len(t2) > 1 and t2[0] == '':
+        # "to" is absolute, return it
+        return to
     # remove common segments
     for x, y in zip(b2, t2):
         if x != y:

tests/test_autodoc.py

     test_autodoc
     ~~~~~~~~~~~~
 
-    Test the autodoc extension.  This tests mainly the RstGenerator; the auto
+    Test the autodoc extension.  This tests mainly the Documenters; the auto
     directives are tested in a test source file translated by test_build.
 
     :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
 
 from docutils.statemachine import ViewList
 
-from sphinx.ext.autodoc import RstGenerator, cut_lines, between
+from sphinx.ext.autodoc import AutoDirective, Documenter, ModuleDocumenter, \
+     ClassDocumenter, FunctionDocumenter, DataDocumenter, MethodDocumenter, \
+     AttributeDocumenter, cut_lines, between, ALL
 
 
 def setup_module():
-    global app, lid, options, gen
+    global app, lid, options, directive
 
     app = TestApp()
     app.builder.env.app = app
         synopsis = '',
         platform = '',
         deprecated = False,
+        members = [],
     )
 
-    gen = TestGenerator(options, app)
+    directive = Struct(
+        env = app.builder.env,
+        genopt = options,
+        result = ViewList(),
+        warn = warnfunc,
+        filename_set = set(),
+    )
 
 def teardown_module():
     app.cleanup()
 
 
-class TestGenerator(RstGenerator):
-    """Generator that handles warnings without a reporter."""
+_warnings = []
 
-    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)
+def warnfunc(msg):
+    _warnings.append(msg)
 
 
 processed_docstrings = []
         return True
 
 
-def test_resolve_name():
+def test_parse_name():
+    def verify(objtype, name, result):
+        inst = AutoDirective._registry[objtype](directive, name)
+        assert inst.parse_name()
+        assert (inst.modname, inst.objpath, inst.args, inst.retann) == result
+
     # for modules
-    assert gen.resolve_name('module', 'test_autodoc') == \
-           ('test_autodoc', [], None, None)
-    assert gen.resolve_name('module', 'test.test_autodoc') == \
-           ('test.test_autodoc', [], None, None)
-
-    assert gen.resolve_name('module', 'test(arg)') == \
-           ('test', [], None, None)
-    assert 'ignoring signature arguments' in gen.warnings[0]
-    del gen.warnings[:]
+    verify('module', 'test_autodoc', ('test_autodoc', [], None, None))
+    verify('module', 'test.test_autodoc', ('test.test_autodoc', [], None, None))
+    verify('module', 'test(arg)', ('test', [], 'arg', None))
+    assert 'signature arguments' in _warnings[0]
+    del _warnings[:]
 
     # for functions/classes
-    assert gen.resolve_name('function', 'util.raises') == \
-           ('util', ['raises'], None, None)
-    assert gen.resolve_name('function', 'util.raises(exc) -> None') == \
-           ('util', ['raises'], 'exc', 'None')
-    gen.env.autodoc_current_module = 'util'
-    assert gen.resolve_name('function', 'raises') == \
-           ('util', ['raises'], None, None)
-    gen.env.autodoc_current_module = None
-    gen.env.currmodule = 'util'
-    assert gen.resolve_name('function', 'raises') == \
-           ('util', ['raises'], None, None)
-    assert gen.resolve_name('class', 'TestApp') == \
-           ('util', ['TestApp'], None, None)
+    verify('function', 'util.raises', ('util', ['raises'], None, None))
+    verify('function', 'util.raises(exc) -> None',
+           ('util', ['raises'], 'exc', 'None'))
+    directive.env.autodoc_current_module = 'util'
+    verify('function', 'raises', ('util', ['raises'], None, None))
+    directive.env.autodoc_current_module = None
+    directive.env.currmodule = 'util'
+    verify('function', 'raises', ('util', ['raises'], None, None))
+    verify('class', 'TestApp', ('util', ['TestApp'], None, None))
 
     # for members
-    gen.env.currmodule = 'foo'
-    assert gen.resolve_name('method', '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') == \
-           ('util', ['TestApp', 'cleanup'], None, None)
-    assert gen.resolve_name('method', 'TestApp.cleanup') == \
-           ('util', ['TestApp', 'cleanup'], None, None)
+    directive.env.currmodule = 'foo'
+    verify('method', 'util.TestApp.cleanup',
+           ('util', ['TestApp', 'cleanup'], None, None))
+    directive.env.currmodule = 'util'
+    directive.env.currclass = 'Foo'
+    directive.env.autodoc_current_class = 'TestApp'
+    verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None))
+    verify('method', 'TestApp.cleanup',
+           ('util', ['TestApp', 'cleanup'], None, None))
 
     # and clean up
-    gen.env.currmodule = None
-    gen.env.currclass = None
-    gen.env.autodoc_current_class = None
+    directive.env.currmodule = None
+    directive.env.currclass = None
+    directive.env.autodoc_current_class = None
 
 
 def test_format_signature():
+    def formatsig(objtype, name, obj, args, retann):
+        inst = AutoDirective._registry[objtype](directive, name)
+        inst.fullname = name
+        inst.doc_as_attr = False  # for class objtype
+        inst.object = obj
+        inst.args = args
+        inst.retann = retann
+        return inst.format_signature()
+
     # no signatures for modules
-    assert gen.format_signature('module', 'test', None, None, None) == ''
+    assert formatsig('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') == \
+    assert formatsig('function', 'f', f, None, None) == '(a, b, c=1, **d)'
+    assert formatsig('function', 'f', f, 'a, b, c, d', None) == '(a, b, c, d)'
+    assert formatsig('function', 'f', f, None, 'None') == \
            '(a, b, c=1, **d) -> None'
 
     # test for classes
         pass
     # no signature for classes without __init__
     for C in (D, E):
-        assert gen.format_signature('class', 'D', C, None, None) == ''
+        assert formatsig('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'
+        assert formatsig('class', 'C', C, None, None) == '(a, b=None)'
+    assert formatsig('class', 'C', D, 'a, b', 'X') == '(a, b) -> X'
 
     # test for methods
     class H:
             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)'
+    assert formatsig('method', 'H.foo', H.foo1, None, None) == '(b, *c)'
+    assert formatsig('method', 'H.foo', H.foo1, 'a', None) == '(a)'
+    assert formatsig('method', 'H.foo', H.foo2, None, None) == '(b, *c)'
 
     # test exception handling
-    raises(RuntimeError, gen.format_signature,
-           'function', 'int', int, None, None)
+    raises(TypeError, formatsig, 'function', 'int', int, None, None)
 
     # test processing by event handler
-    assert gen.format_signature('method', 'bar', H.foo1, None, None) == '42'
+    assert formatsig('method', 'bar', H.foo1, None, None) == '42'
 
 
 def test_get_doc():
-    def getdocl(*args):
-        ds = gen.get_doc(*args)
+    def getdocl(objtype, obj, encoding=None):
+        inst = AutoDirective._registry[objtype](directive, 'tmp')
+        inst.object = obj
+        ds = inst.get_doc(encoding)
         # for testing purposes, concat them and strip the empty line at the end
         return sum(ds, [])[:-1]
 
         """Class docstring"""
         def __init__(self):
             """Init docstring"""
-    gen.env.config.autoclass_content = 'class'
+    directive.env.config.autoclass_content = 'class'
     assert getdocl('class', C) == ['Class docstring']
-    gen.env.config.autoclass_content = 'init'
+    directive.env.config.autoclass_content = 'init'
     assert getdocl('class', C) == ['Init docstring']
-    gen.env.config.autoclass_content = 'both'
+    directive.env.config.autoclass_content = 'both'
     assert getdocl('class', C) == ['Class docstring', '', 'Init docstring']
 
     class D:
 
 
 def test_docstring_processing():
-    def process(what, name, obj):
-        return list(gen.process_doc(gen.get_doc(what, obj), what, name, obj))
+    def process(objtype, name, obj):
+        inst = AutoDirective._registry[objtype](directive, name)
+        inst.object = obj
+        inst.fullname = name
+        return list(inst.process_doc(inst.get_doc()))
 
     class E:
         def __init__(self):
 
 
 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_warns(warn_str, objtype, name, **kw):
+        inst = AutoDirective._registry[objtype](directive, name)
+        inst.generate(**kw)
+        assert len(directive.result) == 0, directive.result
+        assert len(_warnings) == 1, _warnings
+        assert warn_str in _warnings[0], _warnings
+        del _warnings[:]
 
-    def assert_works(*args):
-        gen.generate(*args)
-        assert gen.result
-        assert len(gen.warnings) == 0, gen.warnings
-        del gen.result[:]
+    def assert_works(objtype, name, **kw):
+        inst = AutoDirective._registry[objtype](directive, name)
+        inst.generate(**kw)
+        assert directive.result
+        assert len(_warnings) == 0, _warnings
+        del directive.result[:]
 
-    def assert_processes(items, *args):
+    def assert_processes(items, objtype, name, **kw):
         del processed_docstrings[:]
         del processed_signatures[:]
-        assert_works(*args)
+        assert_works(objtype, name, **kw)
         assert set(processed_docstrings) | set(processed_signatures) == \
                set(items)
 
-    def assert_result_contains(item, *args):
-        gen.generate(*args)
-        #print '\n'.join(gen.result)
-        assert len(gen.warnings) == 0, gen.warnings
-        assert item in gen.result
-        del gen.result[:]
+    def assert_result_contains(item, objtype, name, **kw):
+        inst = AutoDirective._registry[objtype](directive, name)
+        inst.generate(**kw)
+        #print '\n'.join(directive.result)
+        assert len(_warnings) == 0, _warnings
+        assert item in directive.result
+        del directive.result[:]
 
     # no module found?
     assert_warns("import for autodocumenting 'foobar'",
-                 'function', 'foobar', None, None)
+                 'function', 'foobar', more_content=None)
     # importing
     assert_warns("import/find module 'test_foobar'",
-                 'module', 'test_foobar', None, None)
+                 'module', 'test_foobar', more_content=None)
     # attributes missing
     assert_warns("import/find function 'util.foobar'",
-                 'function', 'util.foobar', None, None)
+                 'function', 'util.foobar', more_content=None)
 
     # test auto and given content mixing
-    gen.env.currmodule = 'test_autodoc'
-    assert_result_contains('   Function.', 'method', 'Class.meth', [], None)
+    directive.env.currmodule = 'test_autodoc'
+    assert_result_contains('   Function.', 'method', 'Class.meth')
     add_content = ViewList()
     add_content.append('Content.', '', 0)
     assert_result_contains('   Function.', 'method',
-                           'Class.meth', [], add_content)
+                           'Class.meth', more_content=add_content)
     assert_result_contains('   Content.', 'method',
-                           'Class.meth', [], add_content)
+                           'Class.meth', more_content=add_content)
 
     # test check_module
-    gen.generate('function', 'raises', None, None, check_module=True)
-    assert len(gen.result) == 0
+    inst = FunctionDocumenter(directive, 'raises')
+    inst.generate(check_module=True)
+    assert len(directive.result) == 0
 
     # assert that exceptions can be documented
-    assert_works('exception', 'test_autodoc.CustomEx', ['__all__'], None)
-    assert_works('exception', 'test_autodoc.CustomEx', [], None)
+    assert_works('exception', 'test_autodoc.CustomEx', all_members=True)
+    assert_works('exception', 'test_autodoc.CustomEx')
 
     # test diverse inclusion settings for members
     should = [('class', 'test_autodoc.Class')]
-    assert_processes(should, 'class', 'Class', [], None)
+    assert_processes(should, 'class', 'Class')
     should.extend([('method', 'test_autodoc.Class.meth')])
-    assert_processes(should, 'class', 'Class', ['meth'], None)
+    options.members = ['meth']
+    assert_processes(should, 'class', 'Class')
     should.extend([('attribute', 'test_autodoc.Class.prop'),
                    ('attribute', 'test_autodoc.Class.attr'),
                    ('attribute', 'test_autodoc.Class.docattr'),
                    ('attribute', 'test_autodoc.Class.udocattr')])
-    assert_processes(should, 'class', 'Class', ['__all__'], None)
+    options.members = ALL
+    assert_processes(should, 'class', 'Class')
     options.undoc_members = True
     should.append(('method', 'test_autodoc.Class.undocmeth'))
-    assert_processes(should, 'class', 'Class', ['__all__'], None)
+    assert_processes(should, 'class', 'Class')
     options.inherited_members = True
     should.append(('method', 'test_autodoc.Class.inheritedmeth'))
-    assert_processes(should, 'class', 'Class', ['__all__'], None)
+    assert_processes(should, 'class', 'Class')
 
+    options.members = []
     # test module flags
-    assert_result_contains('.. module:: test_autodoc',
-                           'module', 'test_autodoc', [], None)
+    assert_result_contains('.. module:: test_autodoc', 'module', 'test_autodoc')
     options.synopsis = 'Synopsis'
-    assert_result_contains('   :synopsis: Synopsis',
-                           'module', 'test_autodoc', [], None)
+    assert_result_contains('   :synopsis: Synopsis', 'module', 'test_autodoc')
     options.deprecated = True
-    assert_result_contains('   :deprecated:',
-                           'module', 'test_autodoc', [], None)
+    assert_result_contains('   :deprecated:', 'module', 'test_autodoc')
     options.platform = 'Platform'
-    assert_result_contains('   :platform: Platform',
-                           'module', 'test_autodoc', [], None)
+    assert_result_contains('   :platform: Platform', 'module', 'test_autodoc')
     # test if __all__ is respected for modules
-    assert_result_contains('.. class:: Class',
-                           'module', 'test_autodoc', ['__all__'], None)
+    options.members = ALL
+    assert_result_contains('.. class:: Class', 'module', 'test_autodoc')
     try:
-        assert_result_contains('.. exception:: CustomEx',
-                               'module', 'test_autodoc', ['__all__'], None)
+        assert_result_contains('.. exception:: CustomEx', 'module', 'test_autodoc')
     except AssertionError:
         pass
     else:
         assert False, 'documented CustomEx which is not in __all__'
 
     # test noindex flag
+    options.members = []
     options.noindex = True
-    assert_result_contains('   :noindex:', 'module', 'test_autodoc', [], None)
-    assert_result_contains('   :noindex:', 'class', 'Base', [], None)
+    assert_result_contains('   :noindex:', 'module', 'test_autodoc')
+    assert_result_contains('   :noindex:', 'class', 'Base')
 
     # okay, now let's get serious about mixing Python and C signature stuff
     assert_result_contains('.. class:: CustomDict', 'class', 'CustomDict',
-                           ['__all__'], None)
+                           all_members=True)
 
     # test inner class handling
     assert_processes([('class', 'test_autodoc.Outer'),
                       ('class', 'test_autodoc.Outer.Inner'),
                       ('method', 'test_autodoc.Outer.Inner.meth')],
-                     'class', 'Outer', ['__all__'], None)
+                     'class', 'Outer', all_members=True)
 
     # test generation for C modules (which have no source file)
-    gen.env.currmodule = 'time'
-    assert_processes([('function', 'time.asctime')],
-                     'function', 'asctime', [], None)
-    assert_processes([('function', 'time.asctime')],
-                     'function', 'asctime', [], None)
+    directive.env.currmodule = 'time'
+    assert_processes([('function', 'time.asctime')], 'function', 'asctime')
+    assert_processes([('function', 'time.asctime')], 'function', 'asctime')
 
 
 # --- generate fodder ------------
     wraps = lambda f: (lambda w: w)
 
 from sphinx import application
+from sphinx.ext.autodoc import AutoDirective
 
 from path import path
 
                                     freshenv)
 
     def cleanup(self, doctrees=False):
+        AutoDirective._registry.clear()
         for tree in self.cleanup_trees:
             shutil.rmtree(tree, True)