| # -*- coding: utf-8 -*- |
| """ |
| test_autodoc |
| ~~~~~~~~~~~~ |
| |
| 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-2014 by the Sphinx team, see AUTHORS. |
| :license: BSD, see LICENSE for details. |
| """ |
| |
| # "raises" imported for usage by autodoc |
| from util import TestApp, Struct, raises |
| from nose.tools import with_setup |
| |
| from six import StringIO |
| from docutils.statemachine import ViewList |
| |
| from sphinx.ext.autodoc import AutoDirective, add_documenter, \ |
| ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL |
| |
| app = None |
| |
| def setup_module(): |
| global app |
| app = TestApp() |
| app.builder.env.app = app |
| app.builder.env.temp_data['docname'] = 'dummy' |
| app.connect('autodoc-process-docstring', process_docstring) |
| app.connect('autodoc-process-signature', process_signature) |
| app.connect('autodoc-skip-member', skip_member) |
| |
| |
| def teardown_module(): |
| app.cleanup() |
| |
| |
| directive = options = None |
| |
| def setup_test(): |
| global options, directive |
| global processed_docstrings, processed_signatures, _warnings |
| |
| options = Struct( |
| inherited_members = False, |
| undoc_members = False, |
| private_members = False, |
| special_members = False, |
| imported_members = False, |
| show_inheritance = False, |
| noindex = False, |
| annotation = None, |
| synopsis = '', |
| platform = '', |
| deprecated = False, |
| members = [], |
| member_order = 'alphabetic', |
| exclude_members = set(), |
| ) |
| |
| directive = Struct( |
| env = app.builder.env, |
| genopt = options, |
| result = ViewList(), |
| warn = warnfunc, |
| filename_set = set(), |
| ) |
| |
| processed_docstrings = [] |
| processed_signatures = [] |
| _warnings = [] |
| |
| |
| _warnings = [] |
| |
| def warnfunc(msg): |
| _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 skip_member(app, what, name, obj, skip, options): |
| if name in ('__special1__', '__special2__'): |
| return skip |
| if name.startswith('_'): |
| return True |
| if name == 'skipmeth': |
| return True |
| |
| |
| @with_setup(setup_test) |
| 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 |
| 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 |
| verify('function', 'util.raises', ('util', ['raises'], None, None)) |
| verify('function', 'util.raises(exc) -> None', |
| ('util', ['raises'], 'exc', 'None')) |
| directive.env.temp_data['autodoc:module'] = 'util' |
| verify('function', 'raises', ('util', ['raises'], None, None)) |
| del directive.env.temp_data['autodoc:module'] |
| directive.env.temp_data['py:module'] = 'util' |
| verify('function', 'raises', ('util', ['raises'], None, None)) |
| verify('class', 'TestApp', ('util', ['TestApp'], None, None)) |
| |
| # for members |
| directive.env.temp_data['py:module'] = 'foo' |
| verify('method', 'util.TestApp.cleanup', |
| ('util', ['TestApp', 'cleanup'], None, None)) |
| directive.env.temp_data['py:module'] = 'util' |
| directive.env.temp_data['py:class'] = 'Foo' |
| directive.env.temp_data['autodoc:class'] = 'TestApp' |
| verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None)) |
| verify('method', 'TestApp.cleanup', |
| ('util', ['TestApp', 'cleanup'], None, None)) |
| |
| # and clean up |
| del directive.env.temp_data['py:module'] |
| del directive.env.temp_data['py:class'] |
| del directive.env.temp_data['autodoc:class'] |
| |
| |
| @with_setup(setup_test) |
| 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 formatsig('module', 'test', None, None, None) == '' |
| |
| # test for functions |
| def f(a, b, c=1, **d): |
| pass |
| def g(a='\n'): |
| pass |
| 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' |
| assert formatsig('function', 'g', g, None, None) == r"(a='\\n')" |
| |
| # test for classes |
| class D: |
| pass |
| class E(object): |
| pass |
| # no signature for classes without __init__ |
| for C in (D, E): |
| 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 formatsig('class', 'C', C, None, None) == '(a, b=None)' |
| assert formatsig('class', 'C', D, 'a, b', 'X') == '(a, b) -> X' |
| |
| #__init__ have signature at first line of docstring |
| class F2: |
| '''some docstring for F2.''' |
| def __init__(self, *args, **kw): |
| ''' |
| __init__(a1, a2, kw1=True, kw2=False) |
| |
| some docstring for __init__. |
| ''' |
| class G2(F2, object): |
| pass |
| for C in (F2, G2): |
| assert formatsig('class', 'C', C, None, None) == \ |
| '(a1, a2, kw1=True, kw2=False)' |
| |
| # test for methods |
| class H: |
| def foo1(self, b, *c): |
| pass |
| def foo2(b, *c): |
| pass |
| def foo3(self, d='\n'): |
| pass |
| 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)' |
| assert formatsig('method', 'H.foo', H.foo3, None, None) == r"(d='\\n')" |
| |
| # test exception handling (exception is caught and args is '') |
| assert formatsig('function', 'int', int, None, None) == '' |
| del _warnings[:] |
| |
| # test processing by event handler |
| assert formatsig('method', 'bar', H.foo1, None, None) == '42' |
| |
| # test functions created via functools.partial |
| from functools import partial |
| curried1 = partial(lambda a, b, c: None, 'A') |
| assert formatsig('function', 'curried1', curried1, None, None) == \ |
| '(b, c)' |
| curried2 = partial(lambda a, b, c=42: None, 'A') |
| assert formatsig('function', 'curried2', curried2, None, None) == \ |
| '(b, c=42)' |
| curried3 = partial(lambda a, b, *c: None, 'A') |
| assert formatsig('function', 'curried3', curried3, None, None) == \ |
| '(b, *c)' |
| curried4 = partial(lambda a, b, c=42, *d, **e: None, 'A') |
| assert formatsig('function', 'curried4', curried4, None, None) == \ |
| '(b, c=42, *d, **e)' |
| |
| |
| @with_setup(setup_test) |
| def test_get_doc(): |
| 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] |
| |
| # objects without docstring |
| def f(): |
| pass |
| assert getdocl('function', f) == [] |
| |
| # standard function, diverse docstring styles... |
| def f(): |
| """Docstring""" |
| def g(): |
| """ |
| Docstring |
| """ |
| for func in (f, g): |
| assert getdocl('function', func) == ['Docstring'] |
| |
| # first line vs. other lines indentation |
| def f(): |
| """First line |
| |
| Other |
| lines |
| """ |
| assert getdocl('function', f) == ['First line', '', 'Other', ' lines'] |
| |
| # charset guessing (this module is encoded in utf-8) |
| def f(): |
| """Döcstring""" |
| assert getdocl('function', f) == [u'Döcstring'] |
| |
| # already-unicode docstrings must be taken literally |
| def f(): |
| u"""Döcstring""" |
| assert getdocl('function', f) == [u'Döcstring'] |
| |
| # class docstring: depends on config value which one is taken |
| class C: |
| """Class docstring""" |
| def __init__(self): |
| """Init docstring""" |
| directive.env.config.autoclass_content = 'class' |
| assert getdocl('class', C) == ['Class docstring'] |
| directive.env.config.autoclass_content = 'init' |
| assert getdocl('class', C) == ['Init docstring'] |
| directive.env.config.autoclass_content = 'both' |
| assert getdocl('class', C) == ['Class docstring', '', 'Init docstring'] |
| |
| class D: |
| """Class docstring""" |
| def __init__(self): |
| """Init docstring |
| |
| Other |
| lines |
| """ |
| |
| # Indentation is normalized for 'both' |
| assert getdocl('class', D) == ['Class docstring', '', 'Init docstring', |
| '', 'Other', ' lines'] |
| |
| #__init__ have signature at first line of docstring |
| class E: |
| """Class docstring""" |
| def __init__(self, *args, **kw): |
| """ |
| __init__(a1, a2, kw1=True, kw2=False) |
| |
| Init docstring |
| """ |
| |
| # signature line in the docstring will be kept when |
| # autodoc_docstring_signature == False |
| directive.env.config.autodoc_docstring_signature = False |
| directive.env.config.autoclass_content = 'class' |
| assert getdocl('class', E) == ['Class docstring'] |
| directive.env.config.autoclass_content = 'init' |
| assert getdocl('class', E) == ['__init__(a1, a2, kw1=True, kw2=False)', |
| '', 'Init docstring'] |
| directive.env.config.autoclass_content = 'both' |
| assert getdocl('class', E) == ['Class docstring', '', |
| '__init__(a1, a2, kw1=True, kw2=False)', |
| '', 'Init docstring'] |
| |
| # signature line in the docstring will be removed when |
| # autodoc_docstring_signature == True |
| directive.env.config.autodoc_docstring_signature = True #default |
| directive.env.config.autoclass_content = 'class' |
| assert getdocl('class', E) == ['Class docstring'] |
| directive.env.config.autoclass_content = 'init' |
| assert getdocl('class', E) == ['Init docstring'] |
| directive.env.config.autoclass_content = 'both' |
| assert getdocl('class', E) == ['Class docstring', '', 'Init docstring'] |
| |
| # class does not have __init__ method |
| class F(object): |
| """Class docstring""" |
| |
| # docstring in the __init__ method of base class will be discard |
| for f in (False, True): |
| directive.env.config.autodoc_docstring_signature = f |
| directive.env.config.autoclass_content = 'class' |
| assert getdocl('class', F) == ['Class docstring'] |
| directive.env.config.autoclass_content = 'init' |
| assert getdocl('class', F) == ['Class docstring'] |
| directive.env.config.autoclass_content = 'both' |
| assert getdocl('class', F) == ['Class docstring'] |
| |
| # class has __init__ method with no docstring |
| class G(object): |
| """Class docstring""" |
| def __init__(self): |
| pass |
| |
| # docstring in the __init__ method of base class will not be used |
| for f in (False, True): |
| directive.env.config.autodoc_docstring_signature = f |
| directive.env.config.autoclass_content = 'class' |
| assert getdocl('class', G) == ['Class docstring'] |
| directive.env.config.autoclass_content = 'init' |
| assert getdocl('class', G) == ['Class docstring'] |
| directive.env.config.autoclass_content = 'both' |
| assert getdocl('class', G) == ['Class docstring'] |
| |
| |
| @with_setup(setup_test) |
| def test_docstring_processing(): |
| 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): |
| """Init docstring""" |
| |
| # docstring processing by event handler |
| assert process('class', 'bar', E) == ['Init docstring', '', '42', ''] |
| |
| lid = app.connect('autodoc-process-docstring', |
| cut_lines(1, 1, ['function'])) |
| def f(): |
| """ |
| first line |
| second line |
| third line |
| """ |
| assert process('function', 'f', f) == ['second line', ''] |
| app.disconnect(lid) |
| |
| lid = app.connect('autodoc-process-docstring', between('---', ['function'])) |
| def g(): |
| """ |
| first line |
| --- |
| second line |
| --- |
| third line |
| """ |
| assert process('function', 'g', g) == ['second line', ''] |
| app.disconnect(lid) |
| |
| lid = app.connect('autodoc-process-docstring', between('---', ['function'], |
| exclude=True)) |
| def h(): |
| """ |
| first line |
| --- |
| second line |
| --- |
| third line |
| """ |
| assert process('function', 'h', h) == ['first line', 'third line', ''] |
| app.disconnect(lid) |
| |
| |
| @with_setup(setup_test) |
| def test_docstring_property_processing(): |
| def genarate_docstring(objtype, name, **kw): |
| del processed_docstrings[:] |
| del processed_signatures[:] |
| inst = AutoDirective._registry[objtype](directive, name) |
| inst.generate(**kw) |
| results = list(directive.result) |
| docstrings = inst.get_doc()[0] |
| del directive.result[:] |
| return results, docstrings |
| |
| directive.env.config.autodoc_docstring_signature = False |
| results, docstrings = genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1') |
| assert '.. py:attribute:: DocstringSig.prop1' in results |
| assert 'First line of docstring' in docstrings |
| assert 'DocstringSig.prop1(self)' in docstrings |
| results, docstrings = genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2') |
| assert '.. py:attribute:: DocstringSig.prop2' in results |
| assert 'First line of docstring' in docstrings |
| assert 'Second line of docstring' in docstrings |
| |
| directive.env.config.autodoc_docstring_signature = True |
| results, docstrings = genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1') |
| assert '.. py:attribute:: DocstringSig.prop1' in results |
| assert 'First line of docstring' in docstrings |
| assert 'DocstringSig.prop1(self)' not in docstrings |
| results, docstrings = genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2') |
| assert '.. py:attribute:: DocstringSig.prop2' in results |
| assert 'First line of docstring' in docstrings |
| assert 'Second line of docstring' in docstrings |
| |
| |
| @with_setup(setup_test) |
| def test_new_documenter(): |
| class MyDocumenter(ModuleLevelDocumenter): |
| objtype = 'integer' |
| directivetype = 'data' |
| priority = 100 |
| |
| @classmethod |
| def can_document_member(cls, member, membername, isattr, parent): |
| return isinstance(member, int) |
| |
| def document_members(self, all_members=False): |
| return |
| |
| add_documenter(MyDocumenter) |
| |
| 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[:] |
| |
| options.members = ['integer'] |
| assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc') |
| |
| |
| @with_setup(setup_test, AutoDirective._special_attrgetters.clear) |
| def test_attrgetter_using(): |
| def assert_getter_works(objtype, name, obj, attrs=[], **kw): |
| getattr_spy = [] |
| def special_getattr(obj, name, *defargs): |
| if name in attrs: |
| getattr_spy.append((obj, name)) |
| return None |
| return getattr(obj, name, *defargs) |
| AutoDirective._special_attrgetters[type] = special_getattr |
| |
| del getattr_spy[:] |
| inst = AutoDirective._registry[objtype](directive, name) |
| inst.generate(**kw) |
| |
| hooked_members = [s[1] for s in getattr_spy] |
| documented_members = [s[1] for s in processed_signatures] |
| for attr in attrs: |
| fullname = '.'.join((name, attr)) |
| assert attr in hooked_members |
| assert fullname not in documented_members, \ |
| '%r was not hooked by special_attrgetter function' % fullname |
| |
| options.members = ALL |
| options.inherited_members = False |
| assert_getter_works('class', 'test_autodoc.Class', Class, |
| ['meth']) |
| |
| options.inherited_members = True |
| assert_getter_works('class', 'test_autodoc.Class', Class, |
| ['meth', 'inheritedmeth']) |
| |
| |
| @with_setup(setup_test) |
| def test_generate(): |
| 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(objtype, name, **kw): |
| inst = AutoDirective._registry[objtype](directive, name) |
| inst.generate(**kw) |
| assert directive.result |
| #print '\n'.join(directive.result) |
| assert len(_warnings) == 0, _warnings |
| del directive.result[:] |
| |
| def assert_processes(items, objtype, name, **kw): |
| del processed_docstrings[:] |
| del processed_signatures[:] |
| assert_works(objtype, name, **kw) |
| assert set(processed_docstrings) | set(processed_signatures) == \ |
| set(items) |
| |
| 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[:] |
| |
| 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? |
| assert_warns("import for autodocumenting 'foobar'", |
| 'function', 'foobar', more_content=None) |
| # importing |
| assert_warns("failed to import module 'test_foobar'", |
| 'module', 'test_foobar', more_content=None) |
| # attributes missing |
| assert_warns("failed to import function 'foobar' from module 'util'", |
| 'function', 'util.foobar', more_content=None) |
| # method missing |
| assert_warns("failed to import method 'Class.foobar' from module 'test_autodoc';", |
| 'method', 'test_autodoc.Class.foobar', more_content=None) |
| |
| # test auto and given content mixing |
| directive.env.temp_data['py:module'] = 'test_autodoc' |
| assert_result_contains(' Function.', 'method', 'Class.meth') |
| add_content = ViewList() |
| add_content.append('Content.', '', 0) |
| assert_result_contains(' Function.', 'method', |
| 'Class.meth', more_content=add_content) |
| assert_result_contains(' Content.', 'method', |
| 'Class.meth', more_content=add_content) |
| |
| # test check_module |
| 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_members=True) |
| assert_works('exception', 'test_autodoc.CustomEx') |
| |
| # test diverse inclusion settings for members |
| should = [('class', 'test_autodoc.Class')] |
| assert_processes(should, 'class', 'Class') |
| should.extend([('method', 'test_autodoc.Class.meth')]) |
| options.members = ['meth'] |
| options.exclude_members = set(['excludemeth']) |
| assert_processes(should, 'class', 'Class') |
| should.extend([('attribute', 'test_autodoc.Class.prop'), |
| ('attribute', 'test_autodoc.Class.descr'), |
| ('attribute', 'test_autodoc.Class.attr'), |
| ('attribute', 'test_autodoc.Class.docattr'), |
| ('attribute', 'test_autodoc.Class.udocattr'), |
| ('attribute', 'test_autodoc.Class.mdocattr'), |
| ('attribute', 'test_autodoc.Class.inst_attr_comment'), |
| ('attribute', 'test_autodoc.Class.inst_attr_inline'), |
| ('attribute', 'test_autodoc.Class.inst_attr_string'), |
| ('method', 'test_autodoc.Class.moore'), |
| ]) |
| options.members = ALL |
| assert_processes(should, 'class', 'Class') |
| options.undoc_members = True |
| should.extend((('attribute', 'test_autodoc.Class.skipattr'), |
| ('method', 'test_autodoc.Class.undocmeth'), |
| ('method', 'test_autodoc.Class.roger'))) |
| assert_processes(should, 'class', 'Class') |
| options.inherited_members = True |
| should.append(('method', 'test_autodoc.Class.inheritedmeth')) |
| assert_processes(should, 'class', 'Class') |
| |
| # test special members |
| options.special_members = ['__special1__'] |
| should.append(('method', 'test_autodoc.Class.__special1__')) |
| assert_processes(should, 'class', 'Class') |
| options.special_members = ALL |
| should.append(('method', 'test_autodoc.Class.__special2__')) |
| assert_processes(should, 'class', 'Class') |
| options.special_members = False |
| |
| options.members = [] |
| # test module flags |
| assert_result_contains('.. py:module:: test_autodoc', |
| 'module', 'test_autodoc') |
| options.synopsis = 'Synopsis' |
| assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc') |
| options.deprecated = True |
| assert_result_contains(' :deprecated:', 'module', 'test_autodoc') |
| options.platform = 'Platform' |
| assert_result_contains(' :platform: Platform', 'module', 'test_autodoc') |
| # test if __all__ is respected for modules |
| options.members = ALL |
| assert_result_contains('.. py:class:: Class(arg)', 'module', 'test_autodoc') |
| try: |
| assert_result_contains('.. py: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') |
| assert_result_contains(' :noindex:', 'class', 'Base') |
| |
| # okay, now let's get serious about mixing Python and C signature stuff |
| assert_result_contains('.. py:class:: CustomDict', 'class', 'CustomDict', |
| 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_members=True) |
| |
| # test descriptor docstrings |
| assert_result_contains(' Descriptor instance docstring.', |
| 'attribute', 'test_autodoc.Class.descr') |
| |
| # test generation for C modules (which have no source file) |
| directive.env.temp_data['py:module'] = 'time' |
| 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.mdocattr', |
| ' .. py:classmethod:: Class.roger(a, e=5, f=6)', |
| ' .. py:classmethod:: Class.moore(a, e, f) -> happiness', |
| ' .. py:attribute:: Class.inst_attr_comment', |
| ' .. py:attribute:: Class.inst_attr_string', |
| ' .. py:method:: Class.inheritedmeth()', |
| ], |
| 'class', 'Class', member_order='bysource', all_members=True) |
| del directive.env.temp_data['py:module'] |
| |
| # test attribute initialized to class instance from other module |
| directive.env.temp_data['autodoc:class'] = 'test_autodoc.Class' |
| assert_result_contains(u' should be documented as well - s\xfc\xdf', |
| 'attribute', 'mdocattr') |
| del directive.env.temp_data['autodoc:class'] |
| |
| # test autodoc_docstring_signature |
| assert_result_contains( |
| '.. py:method:: DocstringSig.meth(FOO, BAR=1) -> BAZ', 'method', |
| 'test_autodoc.DocstringSig.meth') |
| assert_result_contains( |
| ' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth') |
| assert_result_contains( |
| '.. py:method:: DocstringSig.meth2()', 'method', |
| 'test_autodoc.DocstringSig.meth2') |
| assert_result_contains( |
| ' indented line', 'method', |
| 'test_autodoc.DocstringSig.meth2') |
| assert_result_contains( |
| '.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method', |
| 'test_autodoc.Class.moore') |
| |
| # test new attribute documenter behavior |
| directive.env.temp_data['py:module'] = 'test_autodoc' |
| options.undoc_members = True |
| assert_processes([('class', 'test_autodoc.AttCls'), |
| ('attribute', 'test_autodoc.AttCls.a1'), |
| ('attribute', 'test_autodoc.AttCls.a2'), |
| ], 'class', 'AttCls') |
| assert_result_contains( |
| ' :annotation: = hello world', 'attribute', 'AttCls.a1') |
| assert_result_contains( |
| ' :annotation: = None', 'attribute', 'AttCls.a2') |
| |
| # test explicit members with instance attributes |
| del directive.env.temp_data['autodoc:class'] |
| del directive.env.temp_data['autodoc:module'] |
| directive.env.temp_data['py:module'] = 'test_autodoc' |
| options.inherited_members = False |
| options.undoc_members = False |
| options.members = ALL |
| assert_processes([ |
| ('class', 'test_autodoc.InstAttCls'), |
| ('attribute', 'test_autodoc.InstAttCls.ca1'), |
| ('attribute', 'test_autodoc.InstAttCls.ca2'), |
| ('attribute', 'test_autodoc.InstAttCls.ca3'), |
| ('attribute', 'test_autodoc.InstAttCls.ia1'), |
| ('attribute', 'test_autodoc.InstAttCls.ia2'), |
| ], 'class', 'InstAttCls') |
| del directive.env.temp_data['autodoc:class'] |
| del directive.env.temp_data['autodoc:module'] |
| options.members = ['ca1', 'ia1'] |
| assert_processes([ |
| ('class', 'test_autodoc.InstAttCls'), |
| ('attribute', 'test_autodoc.InstAttCls.ca1'), |
| ('attribute', 'test_autodoc.InstAttCls.ia1'), |
| ], 'class', 'InstAttCls') |
| del directive.env.temp_data['autodoc:class'] |
| del directive.env.temp_data['autodoc:module'] |
| del directive.env.temp_data['py:module'] |
| |
| # test descriptor class documentation |
| options.members = ['CustomDataDescriptor'] |
| assert_result_contains('.. py:class:: CustomDataDescriptor(doc)', |
| 'module', 'test_autodoc') |
| assert_result_contains(' .. py:method:: CustomDataDescriptor.meth()', |
| 'module', 'test_autodoc') |
| |
| # --- generate fodder ------------ |
| |
| __all__ = ['Class'] |
| |
| #: documentation for the integer |
| integer = 1 |
| |
| class CustomEx(Exception): |
| """My custom exception.""" |
| |
| def f(self): |
| """Exception method.""" |
| |
| class CustomDataDescriptor(object): |
| """Descriptor class docstring.""" |
| |
| def __init__(self, doc): |
| self.__doc__ = doc |
| |
| def __get__(self, obj, type=None): |
| if obj is None: |
| return self |
| return 42 |
| |
| def meth(self): |
| """Function.""" |
| return "The Answer" |
| |
| def _funky_classmethod(name, b, c, d, docstring=None): |
| """Generates a classmethod for a class from a template by filling out |
| some arguments.""" |
| def template(cls, a, b, c, d=4, e=5, f=6): |
| return a, b, c, d, e, f |
| from functools import partial |
| function = partial(template, b=b, c=c, d=d) |
| function.__name__ = name |
| function.__doc__ = docstring |
| return classmethod(function) |
| |
| class Base(object): |
| def inheritedmeth(self): |
| """Inherited function.""" |
| |
| class Class(Base): |
| """Class to document.""" |
| |
| descr = CustomDataDescriptor("Descriptor instance docstring.") |
| |
| def meth(self): |
| """Function.""" |
| |
| def undocmeth(self): |
| pass |
| |
| def skipmeth(self): |
| """Method that should be skipped.""" |
| |
| def excludemeth(self): |
| """Method that should be excluded.""" |
| |
| # should not be documented |
| skipattr = 'foo' |
| |
| #: should be documented -- süß |
| attr = 'bar' |
| |
| @property |
| def prop(self): |
| """Property.""" |
| |
| docattr = 'baz' |
| """should likewise be documented -- süß""" |
| |
| udocattr = 'quux' |
| u"""should be documented as well - süß""" |
| |
| # initialized to any class imported from another module |
| mdocattr = StringIO() |
| """should be documented as well - süß""" |
| |
| roger = _funky_classmethod("roger", 2, 3, 4) |
| |
| moore = _funky_classmethod("moore", 9, 8, 7, |
| docstring="moore(a, e, f) -> happiness") |
| |
| def __init__(self, arg): |
| self.inst_attr_inline = None #: an inline documented instance attr |
| #: a documented instance attribute |
| self.inst_attr_comment = None |
| self.inst_attr_string = None |
| """a documented instance attribute""" |
| |
| def __special1__(self): |
| """documented special method""" |
| |
| def __special2__(self): |
| # undocumented special method |
| pass |
| |
| |
| class CustomDict(dict): |
| """Docstring.""" |
| |
| def function(foo, *args, **kwds): |
| """ |
| Return spam. |
| """ |
| pass |
| |
| |
| class Outer(object): |
| """Foo""" |
| |
| class Inner(object): |
| """Foo""" |
| |
| def meth(self): |
| """Foo""" |
| |
| # should be documented as an alias |
| factory = dict |
| |
| |
| class DocstringSig(object): |
| def meth(self): |
| """meth(FOO, BAR=1) -> BAZ |
| First line of docstring |
| |
| rest of docstring |
| """ |
| |
| def meth2(self): |
| """First line, no signature |
| Second line followed by indentation:: |
| |
| indented line |
| """ |
| |
| @property |
| def prop1(self): |
| """DocstringSig.prop1(self) |
| First line of docstring |
| """ |
| return 123 |
| |
| @property |
| def prop2(self): |
| """First line of docstring |
| Second line of docstring |
| """ |
| return 456 |
| |
| class StrRepr(str): |
| def __repr__(self): |
| return self |
| |
| class AttCls(object): |
| a1 = StrRepr('hello\nworld') |
| a2 = None |
| |
| class InstAttCls(object): |
| """Class with documented class and instance attributes.""" |
| |
| #: Doc comment for class attribute InstAttCls.ca1. |
| #: It can have multiple lines. |
| ca1 = 'a' |
| |
| ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only. |
| |
| ca3 = 'c' |
| """Docstring for class attribute InstAttCls.ca3.""" |
| |
| def __init__(self): |
| #: Doc comment for instance attribute InstAttCls.ia1 |
| self.ia1 = 'd' |
| |
| self.ia2 = 'e' |
| """Docstring for instance attribute InstAttCls.ia2.""" |