diff options
Diffstat (limited to 'tests/test_ext_autodoc.py')
-rw-r--r-- | tests/test_ext_autodoc.py | 2537 |
1 files changed, 0 insertions, 2537 deletions
diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py deleted file mode 100644 index 7062763..0000000 --- a/tests/test_ext_autodoc.py +++ /dev/null @@ -1,2537 +0,0 @@ -"""Test the autodoc extension. - -This tests mainly the Documenters; the auto directives are tested in a test -source file translated by test_build. -""" - -import sys -from types import SimpleNamespace -from unittest.mock import Mock -from warnings import catch_warnings - -import pytest -from docutils.statemachine import ViewList - -from sphinx import addnodes -from sphinx.ext.autodoc import ALL, ModuleLevelDocumenter, Options -from sphinx.ext.autodoc.directive import DocumenterBridge, process_documenter_options -from sphinx.util.docutils import LoggingReporter - -try: - # Enable pyximport to test cython module - import pyximport - pyximport.install() -except ImportError: - pyximport = None - - -def do_autodoc(app, objtype, name, options=None): - if options is None: - options = {} - app.env.temp_data.setdefault('docname', 'index') # set dummy docname - doccls = app.registry.documenters[objtype] - docoptions = process_documenter_options(doccls, app.config, options) - state = Mock() - state.document.settings.tab_width = 8 - bridge = DocumenterBridge(app.env, LoggingReporter(''), docoptions, 1, state) - documenter = doccls(bridge, name) - documenter.generate() - - return bridge.result - - -def make_directive_bridge(env): - options = Options( - inherited_members = False, - undoc_members = False, - private_members = False, - special_members = False, - imported_members = False, - show_inheritance = False, - no_index = False, - annotation = None, - synopsis = '', - platform = '', - deprecated = False, - members = [], - member_order = 'alphabetical', - exclude_members = set(), - ignore_module_all = False, - ) - - directive = SimpleNamespace( - env = env, - genopt = options, - result = ViewList(), - record_dependencies = set(), - state = Mock(), - ) - directive.state.document.settings.tab_width = 8 - - return directive - - -processed_signatures = [] - - -def process_signature(app, what, name, obj, options, args, retann): - processed_signatures.append((what, name)) - if name == 'bar': - return '42', None - return 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 - return None - - -def test_parse_name(app): - def verify(objtype, name, result): - inst = app.registry.documenters[objtype](directive, name) - assert inst.parse_name() - assert (inst.modname, inst.objpath, inst.args, inst.retann) == result - - directive = make_directive_bridge(app.env) - - # for modules - verify('module', 'test_ext_autodoc', ('test_ext_autodoc', [], None, None)) - verify('module', 'test.test_ext_autodoc', ('test.test_ext_autodoc', [], None, None)) - verify('module', 'test(arg)', ('test', [], 'arg', None)) - assert 'signature arguments' in app._warning.getvalue() - - # for functions/classes - verify('function', 'test_ext_autodoc.raises', - ('test_ext_autodoc', ['raises'], None, None)) - verify('function', 'test_ext_autodoc.raises(exc) -> None', - ('test_ext_autodoc', ['raises'], 'exc', 'None')) - directive.env.temp_data['autodoc:module'] = 'test_ext_autodoc' - verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None)) - del directive.env.temp_data['autodoc:module'] - directive.env.ref_context['py:module'] = 'test_ext_autodoc' - verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None)) - verify('class', 'Base', ('test_ext_autodoc', ['Base'], None, None)) - - # for members - directive.env.ref_context['py:module'] = 'sphinx.testing.util' - verify('method', 'SphinxTestApp.cleanup', - ('sphinx.testing.util', ['SphinxTestApp', 'cleanup'], None, None)) - directive.env.ref_context['py:module'] = 'sphinx.testing.util' - directive.env.ref_context['py:class'] = 'Foo' - directive.env.temp_data['autodoc:class'] = 'SphinxTestApp' - verify('method', 'cleanup', - ('sphinx.testing.util', ['SphinxTestApp', 'cleanup'], None, None)) - verify('method', 'SphinxTestApp.cleanup', - ('sphinx.testing.util', ['SphinxTestApp', 'cleanup'], None, None)) - - -def test_format_signature(app): - app.connect('autodoc-process-signature', process_signature) - app.connect('autodoc-skip-member', skip_member) - - directive = make_directive_bridge(app.env) - - def formatsig(objtype, name, obj, args, retann): - inst = app.registry.documenters[objtype](directive, name) - inst.fullname = name - inst.doc_as_attr = False # for class objtype - inst.parent = object # dummy - inst.object = obj - inst.objpath = [name] - inst.args = args - inst.retann = retann - res = inst.format_signature() - print(res) - return res - - # 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', 'g', g, None, None) == r"(a='\n')" - - # test for classes - class D: - pass - - class E: - def __init__(self): - pass - - # an empty init and no init are the same - for C in (D, E): - assert formatsig('class', 'D', C, None, None) == '()' - - class SomeMeta(type): - def __call__(cls, a, b=None): - return type.__call__(cls, a, b) - - # these three are all equivalent - class F: - def __init__(self, a, b=None): - pass - - class FNew: - def __new__(cls, a, b=None): - return super().__new__(cls) - - class FMeta(metaclass=SomeMeta): - pass - - # and subclasses should always inherit - class G(F): - pass - - class GNew(FNew): - pass - - class GMeta(FMeta): - pass - - # subclasses inherit - for C in (F, FNew, FMeta, G, GNew, GMeta): - assert formatsig('class', 'C', C, None, None) == '(a, b=None)' - assert formatsig('class', 'C', D, 'a, b', 'X') == '(a, b) -> X' - - class ListSubclass(list): - pass - - # only supported if the python implementation decides to document it - if getattr(list, '__text_signature__', None) is not None: - assert formatsig('class', 'C', ListSubclass, None, None) == '(iterable=(), /)' - else: - assert formatsig('class', 'C', ListSubclass, None, None) == '' - - class ExceptionSubclass(Exception): - pass - - # Exception has no __text_signature__ at least in Python 3.11 - if getattr(Exception, '__text_signature__', None) is None: - assert formatsig('class', 'C', ExceptionSubclass, None, None) == '' - - # __init__ have signature at first line of docstring - directive.env.config.autoclass_content = 'both' - - 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): - pass - - assert formatsig('class', 'F2', F2, None, None) == \ - '(a1, a2, kw1=True, kw2=False)' - assert formatsig('class', 'G2', G2, 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) == '(*c)' - assert formatsig('method', 'H.foo', H.foo3, None, None) == r"(d='\n')" - - # test bound methods interpreted as functions - assert formatsig('function', 'foo', H().foo1, None, None) == '(b, *c)' - assert formatsig('function', 'foo', H().foo2, None, None) == '(*c)' - assert formatsig('function', 'foo', H().foo3, None, None) == r"(d='\n')" - - # test exception handling (exception is caught and args is '') - directive.env.config.autodoc_docstring_signature = False - assert formatsig('function', 'int', int, None, None) == '' - - # 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)' - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_process_signature_typing_generic(app): - actual = do_autodoc(app, 'class', 'target.generic_class.A', {}) - - assert list(actual) == [ - '', - '.. py:class:: A(a, b=None)', - ' :module: target.generic_class', - '', - ' docstring for A', - '', - ] - - -def test_autodoc_process_signature_typehints(app): - captured = [] - - def process_signature(*args): - captured.append(args) - - app.connect('autodoc-process-signature', process_signature) - - def func(x: int, y: int) -> int: - pass - - directive = make_directive_bridge(app.env) - inst = app.registry.documenters['function'](directive, 'func') - inst.fullname = 'func' - inst.object = func - inst.objpath = ['func'] - inst.format_signature() - assert captured == [(app, 'function', 'func', func, - directive.genopt, '(x: int, y: int)', 'int')] - - -def test_get_doc(app): - directive = make_directive_bridge(app.env) - - def getdocl(objtype, obj): - inst = app.registry.documenters[objtype](directive, 'tmp') - inst.parent = object # dummy - inst.object = obj - inst.objpath = [obj.__name__] - inst.doc_as_attr = False - inst.format_signature() # handle docstring signatures! - ds = inst.get_doc() - # for testing purposes, concat them and strip the empty line at the end - res = sum(ds, [])[:-1] - print(res) - return res - - # 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) == ['Döcstring'] - - # verify that method docstrings get extracted in both normal case - # and in case of bound method posing as a function - class J: - def foo(self): - """Method docstring""" - assert getdocl('method', J.foo) == ['Method docstring'] - assert getdocl('function', J().foo) == ['Method docstring'] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_new_documenter(app): - class MyDocumenter(ModuleLevelDocumenter): - objtype = 'integer' - directivetype = 'integer' - priority = 100 - - @classmethod - def can_document_member(cls, member, membername, isattr, parent): - return isinstance(member, int) - - def document_members(self, all_members=False): - return - - app.add_autodocumenter(MyDocumenter) - - options = {"members": 'integer'} - actual = do_autodoc(app, 'module', 'target', options) - assert list(actual) == [ - '', - '.. py:module:: target', - '', - '', - '.. py:integer:: integer', - ' :module: target', - '', - ' documentation for the integer', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_attrgetter_using(app): - directive = make_directive_bridge(app.env) - directive.genopt['members'] = ALL - - directive.genopt['inherited_members'] = False - with catch_warnings(record=True): - _assert_getter_works(app, directive, 'class', 'target.Class', ['meth']) - - directive.genopt['inherited_members'] = True - with catch_warnings(record=True): - _assert_getter_works(app, directive, 'class', 'target.inheritance.Derived', ['inheritedmeth']) - - -def _assert_getter_works(app, directive, objtype, name, attrs=(), **kw): - getattr_spy = [] - - def _special_getattr(obj, attr_name, *defargs): - if attr_name in attrs: - getattr_spy.append((obj, attr_name)) - return None - return getattr(obj, attr_name, *defargs) - - app.add_autodoc_attrgetter(type, _special_getattr) - - getattr_spy.clear() - app.registry.documenters[objtype](directive, name).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, f'{fullname!r} not intercepted' - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_py_module(app, warning): - # without py:module - actual = do_autodoc(app, 'method', 'Class.meth') - assert list(actual) == [] - assert ("don't know which module to import for autodocumenting 'Class.meth'" - in warning.getvalue()) - - # with py:module - app.env.ref_context['py:module'] = 'target' - warning.truncate(0) - - actual = do_autodoc(app, 'method', 'Class.meth') - assert list(actual) == [ - '', - '.. py:method:: Class.meth()', - ' :module: target', - '', - ' Function.', - '', - ] - assert ("don't know which module to import for autodocumenting 'Class.meth'" - not in warning.getvalue()) - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_decorator(app): - actual = do_autodoc(app, 'decorator', 'target.decorator.deco1') - assert list(actual) == [ - '', - '.. py:decorator:: deco1', - ' :module: target.decorator', - '', - ' docstring for deco1', - '', - ] - - actual = do_autodoc(app, 'decorator', 'target.decorator.deco2') - assert list(actual) == [ - '', - '.. py:decorator:: deco2(condition, message)', - ' :module: target.decorator', - '', - ' docstring for deco2', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_exception(app): - actual = do_autodoc(app, 'exception', 'target.CustomEx') - assert list(actual) == [ - '', - '.. py:exception:: CustomEx', - ' :module: target', - '', - ' My custom exception.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_warnings(app, warning): - app.env.temp_data['docname'] = 'dummy' - - # can't import module - do_autodoc(app, 'module', 'unknown') - assert "failed to import module 'unknown'" in warning.getvalue() - - # missing function - do_autodoc(app, 'function', 'unknown') - assert "import for autodocumenting 'unknown'" in warning.getvalue() - - do_autodoc(app, 'function', 'target.unknown') - assert "failed to import function 'unknown' from module 'target'" in warning.getvalue() - - # missing method - do_autodoc(app, 'method', 'target.Class.unknown') - assert "failed to import method 'Class.unknown' from module 'target'" in warning.getvalue() - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_attributes(app): - options = {"synopsis": 'Synopsis', - "platform": "Platform", - "deprecated": None} - actual = do_autodoc(app, 'module', 'target', options) - assert list(actual) == [ - '', - '.. py:module:: target', - ' :synopsis: Synopsis', - ' :platform: Platform', - ' :deprecated:', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_members(app): - # default (no-members) - actual = do_autodoc(app, 'class', 'target.inheritance.Base') - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ] - - # default ALL-members - options = {"members": None} - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ' .. py:method:: Base.inheritedmeth()', - ' .. py:method:: Base.inheritedstaticmeth(cls)', - ] - - # default specific-members - options = {"members": "inheritedmeth,inheritedstaticmeth"} - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:method:: Base.inheritedmeth()', - ' .. py:method:: Base.inheritedstaticmeth(cls)', - ] - - # ALL-members override autodoc_default_options - options = {"members": None} - app.config.autodoc_default_options["members"] = "inheritedstaticmeth" - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ' .. py:method:: Base.inheritedmeth()', - ' .. py:method:: Base.inheritedstaticmeth(cls)', - ] - - # members override autodoc_default_options - options = {"members": "inheritedmeth"} - app.config.autodoc_default_options["members"] = "inheritedstaticmeth" - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:method:: Base.inheritedmeth()', - ] - - # members extends autodoc_default_options - options = {"members": "+inheritedmeth"} - app.config.autodoc_default_options["members"] = "inheritedstaticmeth" - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:method:: Base.inheritedmeth()', - ' .. py:method:: Base.inheritedstaticmeth(cls)', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_exclude_members(app): - options = {"members": None, - "exclude-members": "inheritedmeth,inheritedstaticmeth"} - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ] - - # members vs exclude-members - options = {"members": "inheritedmeth", - "exclude-members": "inheritedmeth"} - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ] - - # + has no effect when autodoc_default_options are not present - options = {"members": None, - "exclude-members": "+inheritedmeth,inheritedstaticmeth"} - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ] - - # exclude-members overrides autodoc_default_options - options = {"members": None, - "exclude-members": "inheritedmeth"} - app.config.autodoc_default_options["exclude-members"] = "inheritedstaticmeth" - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ' .. py:method:: Base.inheritedstaticmeth(cls)', - ] - - # exclude-members extends autodoc_default_options - options = {"members": None, - "exclude-members": "+inheritedmeth"} - app.config.autodoc_default_options["exclude-members"] = "inheritedstaticmeth" - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ] - - # no exclude-members causes use autodoc_default_options - options = {"members": None} - app.config.autodoc_default_options["exclude-members"] = "inheritedstaticmeth,inheritedmeth" - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ] - - # empty exclude-members cancels autodoc_default_options - options = {"members": None, - "exclude-members": None} - app.config.autodoc_default_options["exclude-members"] = "inheritedstaticmeth,inheritedmeth" - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Base()', - ' .. py:attribute:: Base.inheritedattr', - ' .. py:method:: Base.inheritedclassmeth()', - ' .. py:method:: Base.inheritedmeth()', - ' .. py:method:: Base.inheritedstaticmeth(cls)', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_undoc_members(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ' .. py:method:: Class.excludemeth()', - ' .. py:attribute:: Class.inst_attr_comment', - ' .. py:attribute:: Class.inst_attr_inline', - ' .. py:attribute:: Class.inst_attr_string', - ' .. py:attribute:: Class.mdocattr', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:method:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)', - ' .. py:attribute:: Class.skipattr', - ' .. py:method:: Class.skipmeth()', - ' .. py:attribute:: Class.udocattr', - ' .. py:method:: Class.undocmeth()', - ] - - # use autodoc_default_options - options = {"members": None} - app.config.autodoc_default_options["undoc-members"] = None - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ' .. py:method:: Class.excludemeth()', - ' .. py:attribute:: Class.inst_attr_comment', - ' .. py:attribute:: Class.inst_attr_inline', - ' .. py:attribute:: Class.inst_attr_string', - ' .. py:attribute:: Class.mdocattr', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:method:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)', - ' .. py:attribute:: Class.skipattr', - ' .. py:method:: Class.skipmeth()', - ' .. py:attribute:: Class.udocattr', - ' .. py:method:: Class.undocmeth()', - ] - - # options negation work check - options = {"members": None, - "no-undoc-members": None} - app.config.autodoc_default_options["undoc-members"] = None - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ' .. py:method:: Class.excludemeth()', - ' .. py:attribute:: Class.inst_attr_comment', - ' .. py:attribute:: Class.inst_attr_inline', - ' .. py:attribute:: Class.inst_attr_string', - ' .. py:attribute:: Class.mdocattr', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:method:: Class.skipmeth()', - ' .. py:attribute:: Class.udocattr', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_undoc_members_for_metadata_only(app): - # metadata only member is not displayed - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.metadata', options) - assert list(actual) == [ - '', - '.. py:module:: target.metadata', - '', - ] - - # metadata only member is displayed when undoc-member given - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.metadata', options) - assert list(actual) == [ - '', - '.. py:module:: target.metadata', - '', - '', - '.. py:function:: foo()', - ' :module: target.metadata', - '', - ' :meta metadata-only-docstring:', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_inherited_members(app): - options = {"members": None, - "inherited-members": None} - actual = do_autodoc(app, 'class', 'target.inheritance.Derived', options) - assert list(filter(lambda l: 'method::' in l, actual)) == [ - ' .. py:method:: Derived.inheritedclassmeth()', - ' .. py:method:: Derived.inheritedmeth()', - ' .. py:method:: Derived.inheritedstaticmeth(cls)', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_inherited_members_Base(app): - options = {"members": None, - "inherited-members": "Base", - "special-members": None} - - # check methods for object class are shown - actual = do_autodoc(app, 'class', 'target.inheritance.Derived', options) - assert ' .. py:method:: Derived.inheritedmeth()' in actual - assert ' .. py:method:: Derived.inheritedclassmeth' not in actual - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_inherited_members_None(app): - options = {"members": None, - "inherited-members": "None", - "special-members": None} - - # check methods for object class are shown - actual = do_autodoc(app, 'class', 'target.inheritance.Derived', options) - assert ' .. py:method:: Derived.__init__()' in actual - assert ' .. py:method:: Derived.__str__()' in actual - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_imported_members(app): - options = {"members": None, - "imported-members": None, - "ignore-module-all": None} - actual = do_autodoc(app, 'module', 'target', options) - assert '.. py:function:: function_to_be_imported(app: ~sphinx.application.Sphinx | None) -> str' in actual - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_special_members(app): - # specific special methods - options = {"undoc-members": None, - "special-members": "__init__,__special1__"} - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:method:: Class.__init__(arg)', - ' .. py:method:: Class.__special1__()', - ] - - # combination with specific members - options = {"members": "attr,docattr", - "undoc-members": None, - "special-members": "__init__,__special1__"} - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:method:: Class.__init__(arg)', - ' .. py:method:: Class.__special1__()', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ] - - # all special methods - options = {"members": None, - "undoc-members": None, - "special-members": None} - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:attribute:: Class.__annotations__', - ' .. py:attribute:: Class.__dict__', - ' .. py:method:: Class.__init__(arg)', - ' .. py:attribute:: Class.__module__', - ' .. py:method:: Class.__special1__()', - ' .. py:method:: Class.__special2__()', - ' .. py:attribute:: Class.__weakref__', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ' .. py:method:: Class.excludemeth()', - ' .. py:attribute:: Class.inst_attr_comment', - ' .. py:attribute:: Class.inst_attr_inline', - ' .. py:attribute:: Class.inst_attr_string', - ' .. py:attribute:: Class.mdocattr', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:method:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)', - ' .. py:attribute:: Class.skipattr', - ' .. py:method:: Class.skipmeth()', - ' .. py:attribute:: Class.udocattr', - ' .. py:method:: Class.undocmeth()', - ] - - # specific special methods from autodoc_default_options - options = {"undoc-members": None} - app.config.autodoc_default_options["special-members"] = "__special2__" - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:method:: Class.__special2__()', - ] - - # specific special methods option with autodoc_default_options - options = {"undoc-members": None, - "special-members": "__init__,__special1__"} - app.config.autodoc_default_options["special-members"] = "__special2__" - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:method:: Class.__init__(arg)', - ' .. py:method:: Class.__special1__()', - ] - - # specific special methods merge with autodoc_default_options - options = {"undoc-members": None, - "special-members": "+__init__,__special1__"} - app.config.autodoc_default_options["special-members"] = "__special2__" - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:method:: Class.__init__(arg)', - ' .. py:method:: Class.__special1__()', - ' .. py:method:: Class.__special2__()', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_ignore_module_all(app): - # default (no-ignore-module-all) - options = {"members": None} - actual = do_autodoc(app, 'module', 'target', options) - assert list(filter(lambda l: 'class::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ] - - # ignore-module-all - options = {"members": None, - "ignore-module-all": None} - actual = do_autodoc(app, 'module', 'target', options) - assert list(filter(lambda l: 'class::' in l, actual)) == [ - '.. py:class:: Class(arg)', - '.. py:class:: CustomDict', - '.. py:class:: InnerChild()', - '.. py:class:: InstAttCls()', - '.. py:class:: Outer()', - ' .. py:class:: Outer.Inner()', - '.. py:class:: StrRepr', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_noindex(app): - options = {"no-index": None} - actual = do_autodoc(app, 'module', 'target', options) - assert list(actual) == [ - '', - '.. py:module:: target', - ' :no-index:', - '', - ] - - # TODO: :no-index: should be propagated to children of target item. - - actual = do_autodoc(app, 'class', 'target.inheritance.Base', options) - assert list(actual) == [ - '', - '.. py:class:: Base()', - ' :no-index:', - ' :module: target.inheritance', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_subclass_of_builtin_class(app): - options = {"members": None} - actual = do_autodoc(app, 'class', 'target.CustomDict', options) - assert list(actual) == [ - '', - '.. py:class:: CustomDict', - ' :module: target', - '', - ' Docstring.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_inner_class(app): - options = {"members": None} - actual = do_autodoc(app, 'class', 'target.Outer', options) - assert list(actual) == [ - '', - '.. py:class:: Outer()', - ' :module: target', - '', - ' Foo', - '', - '', - ' .. py:class:: Outer.Inner()', - ' :module: target', - '', - ' Foo', - '', - '', - ' .. py:method:: Outer.Inner.meth()', - ' :module: target', - '', - ' Foo', - '', - '', - ' .. py:attribute:: Outer.factory', - ' :module: target', - '', - ' alias of :py:class:`dict`', - ] - - actual = do_autodoc(app, 'class', 'target.Outer.Inner', options) - assert list(actual) == [ - '', - '.. py:class:: Inner()', - ' :module: target.Outer', - '', - ' Foo', - '', - '', - ' .. py:method:: Inner.meth()', - ' :module: target.Outer', - '', - ' Foo', - '', - ] - - options['show-inheritance'] = None - actual = do_autodoc(app, 'class', 'target.InnerChild', options) - assert list(actual) == [ - '', - '.. py:class:: InnerChild()', - ' :module: target', '', - ' Bases: :py:class:`~target.Outer.Inner`', - '', - ' InnerChild docstring', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_classmethod(app): - actual = do_autodoc(app, 'method', 'target.inheritance.Base.inheritedclassmeth') - assert list(actual) == [ - '', - '.. py:method:: Base.inheritedclassmeth()', - ' :module: target.inheritance', - ' :classmethod:', - '', - ' Inherited class method.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_staticmethod(app): - actual = do_autodoc(app, 'method', 'target.inheritance.Base.inheritedstaticmeth') - assert list(actual) == [ - '', - '.. py:method:: Base.inheritedstaticmeth(cls)', - ' :module: target.inheritance', - ' :staticmethod:', - '', - ' Inherited static method.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_descriptor(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'class', 'target.descriptor.Class', options) - assert list(actual) == [ - '', - '.. py:class:: Class()', - ' :module: target.descriptor', - '', - '', - ' .. py:attribute:: Class.descr', - ' :module: target.descriptor', - '', - ' Descriptor instance docstring.', - '', - '', - ' .. py:property:: Class.prop', - ' :module: target.descriptor', - '', - ' Property.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_cached_property(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'class', 'target.cached_property.Foo', options) - assert list(actual) == [ - '', - '.. py:class:: Foo()', - ' :module: target.cached_property', - '', - '', - ' .. py:property:: Foo.prop', - ' :module: target.cached_property', - ' :type: int', - '', - '', - ' .. py:property:: Foo.prop_with_type_comment', - ' :module: target.cached_property', - ' :type: int', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_member_order(app): - # case member-order='bysource' - options = {"members": None, - 'member-order': 'bysource', - "undoc-members": None, - 'private-members': None} - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.undocmeth()', - ' .. py:method:: Class.skipmeth()', - ' .. py:method:: Class.excludemeth()', - ' .. py:attribute:: Class.skipattr', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ' .. py:attribute:: Class.udocattr', - ' .. py:attribute:: Class.mdocattr', - ' .. py:method:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:attribute:: Class.inst_attr_inline', - ' .. py:attribute:: Class.inst_attr_comment', - ' .. py:attribute:: Class.inst_attr_string', - ' .. py:attribute:: Class._private_inst_attr', - ] - - # case member-order='groupwise' - options = {"members": None, - 'member-order': 'groupwise', - "undoc-members": None, - 'private-members': None} - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:method:: Class.excludemeth()', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:method:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)', - ' .. py:method:: Class.skipmeth()', - ' .. py:method:: Class.undocmeth()', - ' .. py:attribute:: Class._private_inst_attr', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ' .. py:attribute:: Class.inst_attr_comment', - ' .. py:attribute:: Class.inst_attr_inline', - ' .. py:attribute:: Class.inst_attr_string', - ' .. py:attribute:: Class.mdocattr', - ' .. py:attribute:: Class.skipattr', - ' .. py:attribute:: Class.udocattr', - ] - - # case member-order=None - options = {"members": None, - "undoc-members": None, - 'private-members': None} - actual = do_autodoc(app, 'class', 'target.Class', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:class:: Class(arg)', - ' .. py:attribute:: Class._private_inst_attr', - ' .. py:attribute:: Class.attr', - ' .. py:attribute:: Class.docattr', - ' .. py:method:: Class.excludemeth()', - ' .. py:attribute:: Class.inst_attr_comment', - ' .. py:attribute:: Class.inst_attr_inline', - ' .. py:attribute:: Class.inst_attr_string', - ' .. py:attribute:: Class.mdocattr', - ' .. py:method:: Class.meth()', - ' .. py:method:: Class.moore(a, e, f) -> happiness', - ' .. py:method:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)', - ' .. py:attribute:: Class.skipattr', - ' .. py:method:: Class.skipmeth()', - ' .. py:attribute:: Class.udocattr', - ' .. py:method:: Class.undocmeth()', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_module_member_order(app): - # case member-order='bysource' - options = {"members": 'foo, Bar, baz, qux, Quux, foobar', - 'member-order': 'bysource', - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.sort_by_all', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:module:: target.sort_by_all', - '.. py:function:: baz()', - '.. py:function:: foo()', - '.. py:class:: Bar()', - '.. py:class:: Quux()', - '.. py:function:: foobar()', - '.. py:function:: qux()', - ] - - # case member-order='bysource' and ignore-module-all - options = {"members": 'foo, Bar, baz, qux, Quux, foobar', - 'member-order': 'bysource', - "undoc-members": None, - "ignore-module-all": None} - actual = do_autodoc(app, 'module', 'target.sort_by_all', options) - assert list(filter(lambda l: '::' in l, actual)) == [ - '.. py:module:: target.sort_by_all', - '.. py:function:: foo()', - '.. py:class:: Bar()', - '.. py:function:: baz()', - '.. py:function:: qux()', - '.. py:class:: Quux()', - '.. py:function:: foobar()', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_module_scope(app): - app.env.temp_data['autodoc:module'] = 'target' - actual = do_autodoc(app, 'attribute', 'Class.mdocattr') - assert list(actual) == [ - '', - '.. py:attribute:: Class.mdocattr', - ' :module: target', - ' :value: <_io.StringIO object>', - '', - ' should be documented as well - süß', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_class_scope(app): - app.env.temp_data['autodoc:module'] = 'target' - app.env.temp_data['autodoc:class'] = 'Class' - actual = do_autodoc(app, 'attribute', 'mdocattr') - assert list(actual) == [ - '', - '.. py:attribute:: Class.mdocattr', - ' :module: target', - ' :value: <_io.StringIO object>', - '', - ' should be documented as well - süß', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_class_attributes(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'class', 'target.AttCls', options) - assert list(actual) == [ - '', - '.. py:class:: AttCls()', - ' :module: target', - '', - '', - ' .. py:attribute:: AttCls.a1', - ' :module: target', - ' :value: hello world', - '', - '', - ' .. py:attribute:: AttCls.a2', - ' :module: target', - ' :value: None', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autoclass_instance_attributes(app): - options = {"members": None} - actual = do_autodoc(app, 'class', 'target.InstAttCls', options) - assert list(actual) == [ - '', - '.. py:class:: InstAttCls()', - ' :module: target', - '', - ' Class with documented class and instance attributes.', - '', - '', - ' .. py:attribute:: InstAttCls.ca1', - ' :module: target', - " :value: 'a'", - '', - ' Doc comment for class attribute InstAttCls.ca1.', - ' It can have multiple lines.', - '', - '', - ' .. py:attribute:: InstAttCls.ca2', - ' :module: target', - " :value: 'b'", - '', - ' Doc comment for InstAttCls.ca2. One line only.', - '', - '', - ' .. py:attribute:: InstAttCls.ca3', - ' :module: target', - " :value: 'c'", - '', - ' Docstring for class attribute InstAttCls.ca3.', - '', - '', - ' .. py:attribute:: InstAttCls.ia1', - ' :module: target', - '', - ' Doc comment for instance attribute InstAttCls.ia1', - '', - '', - ' .. py:attribute:: InstAttCls.ia2', - ' :module: target', - '', - ' Docstring for instance attribute InstAttCls.ia2.', - '', - ] - - # pick up arbitrary attributes - options = {"members": 'ca1,ia1'} - actual = do_autodoc(app, 'class', 'target.InstAttCls', options) - assert list(actual) == [ - '', - '.. py:class:: InstAttCls()', - ' :module: target', - '', - ' Class with documented class and instance attributes.', - '', - '', - ' .. py:attribute:: InstAttCls.ca1', - ' :module: target', - " :value: 'a'", - '', - ' Doc comment for class attribute InstAttCls.ca1.', - ' It can have multiple lines.', - '', - '', - ' .. py:attribute:: InstAttCls.ia1', - ' :module: target', - '', - ' Doc comment for instance attribute InstAttCls.ia1', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autoattribute_instance_attributes(app): - actual = do_autodoc(app, 'attribute', 'target.InstAttCls.ia1') - assert list(actual) == [ - '', - '.. py:attribute:: InstAttCls.ia1', - ' :module: target', - '', - ' Doc comment for instance attribute InstAttCls.ia1', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_slots(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.slots', options) - assert list(actual) == [ - '', - '.. py:module:: target.slots', - '', - '', - '.. py:class:: Bar()', - ' :module: target.slots', - '', - ' docstring', - '', - '', - ' .. py:attribute:: Bar.attr1', - ' :module: target.slots', - ' :type: int', - '', - ' docstring of attr1', - '', - '', - ' .. py:attribute:: Bar.attr2', - ' :module: target.slots', - '', - ' docstring of instance attr2', - '', - '', - ' .. py:attribute:: Bar.attr3', - ' :module: target.slots', - '', - '', - '.. py:class:: Baz()', - ' :module: target.slots', - '', - ' docstring', - '', - '', - ' .. py:attribute:: Baz.attr', - ' :module: target.slots', - '', - '', - '.. py:class:: Foo()', - ' :module: target.slots', - '', - ' docstring', - '', - '', - ' .. py:attribute:: Foo.attr', - ' :module: target.slots', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_enum_class(app): - options = {"members": None} - actual = do_autodoc(app, 'class', 'target.enums.EnumCls', options) - - if sys.version_info[:2] >= (3, 12): - args = ('(value, names=None, *values, module=None, ' - 'qualname=None, type=None, start=1, boundary=None)') - elif sys.version_info[:2] >= (3, 11): - args = ('(value, names=None, *, module=None, qualname=None, ' - 'type=None, start=1, boundary=None)') - else: - args = '(value)' - - assert list(actual) == [ - '', - '.. py:class:: EnumCls' + args, - ' :module: target.enums', - '', - ' this is enum class', - '', - '', - ' .. py:method:: EnumCls.say_goodbye()', - ' :module: target.enums', - ' :classmethod:', - '', - ' a classmethod says good-bye to you.', - '', - '', - ' .. py:method:: EnumCls.say_hello()', - ' :module: target.enums', - '', - ' a method says hello to you.', - '', - '', - ' .. py:attribute:: EnumCls.val1', - ' :module: target.enums', - ' :value: 12', - '', - ' doc for val1', - '', - '', - ' .. py:attribute:: EnumCls.val2', - ' :module: target.enums', - ' :value: 23', - '', - ' doc for val2', - '', - '', - ' .. py:attribute:: EnumCls.val3', - ' :module: target.enums', - ' :value: 34', - '', - ' doc for val3', - '', - ] - - # checks for an attribute of EnumClass - actual = do_autodoc(app, 'attribute', 'target.enums.EnumCls.val1') - assert list(actual) == [ - '', - '.. py:attribute:: EnumCls.val1', - ' :module: target.enums', - ' :value: 12', - '', - ' doc for val1', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_descriptor_class(app): - options = {"members": 'CustomDataDescriptor,CustomDataDescriptor2'} - actual = do_autodoc(app, 'module', 'target.descriptor', options) - assert list(actual) == [ - '', - '.. py:module:: target.descriptor', - '', - '', - '.. py:class:: CustomDataDescriptor(doc)', - ' :module: target.descriptor', - '', - ' Descriptor class docstring.', - '', - '', - ' .. py:method:: CustomDataDescriptor.meth()', - ' :module: target.descriptor', - '', - ' Function.', - '', - '', - '.. py:class:: CustomDataDescriptor2(doc)', - ' :module: target.descriptor', - '', - ' Descriptor class with custom metaclass docstring.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_automethod_for_builtin(app): - actual = do_autodoc(app, 'method', 'builtins.int.__add__') - assert list(actual) == [ - '', - '.. py:method:: int.__add__(value, /)', - ' :module: builtins', - '', - ' Return self+value.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_automethod_for_decorated(app): - actual = do_autodoc(app, 'method', 'target.decorator.Bar.meth') - assert list(actual) == [ - '', - '.. py:method:: Bar.meth(name=None, age=None)', - ' :module: target.decorator', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_abstractmethods(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.abstractmethods', options) - assert list(actual) == [ - '', - '.. py:module:: target.abstractmethods', - '', - '', - '.. py:class:: Base()', - ' :module: target.abstractmethods', - '', - '', - ' .. py:method:: Base.abstractmeth()', - ' :module: target.abstractmethods', - ' :abstractmethod:', - '', - '', - ' .. py:method:: Base.classmeth()', - ' :module: target.abstractmethods', - ' :abstractmethod:', - ' :classmethod:', - '', - '', - ' .. py:method:: Base.coroutinemeth()', - ' :module: target.abstractmethods', - ' :abstractmethod:', - ' :async:', - '', - '', - ' .. py:method:: Base.meth()', - ' :module: target.abstractmethods', - '', - '', - ' .. py:property:: Base.prop', - ' :module: target.abstractmethods', - ' :abstractmethod:', - '', - '', - ' .. py:method:: Base.staticmeth()', - ' :module: target.abstractmethods', - ' :abstractmethod:', - ' :staticmethod:', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_partialfunction(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.partialfunction', options) - assert list(actual) == [ - '', - '.. py:module:: target.partialfunction', - '', - '', - '.. py:function:: func1(a, b, c)', - ' :module: target.partialfunction', - '', - ' docstring of func1', - '', - '', - '.. py:function:: func2(b, c)', - ' :module: target.partialfunction', - '', - ' docstring of func1', - '', - '', - '.. py:function:: func3(c)', - ' :module: target.partialfunction', - '', - ' docstring of func3', - '', - '', - '.. py:function:: func4()', - ' :module: target.partialfunction', - '', - ' docstring of func3', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_imported_partialfunction_should_not_shown_without_imported_members(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.imported_members', options) - assert list(actual) == [ - '', - '.. py:module:: target.imported_members', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_bound_method(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.bound_method', options) - assert list(actual) == [ - '', - '.. py:module:: target.bound_method', - '', - '', - '.. py:function:: bound_method()', - ' :module: target.bound_method', - '', - ' Method docstring', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_partialmethod(app): - expected = [ - '', - '.. py:class:: Cell()', - ' :module: target.partialmethod', - '', - ' An example for partialmethod.', - '', - ' refs: https://docs.python.jp/3/library/functools.html#functools.partialmethod', - '', - '', - ' .. py:method:: Cell.set_alive()', - ' :module: target.partialmethod', - '', - ' Make a cell alive.', - '', - '', - ' .. py:method:: Cell.set_state(state)', - ' :module: target.partialmethod', - '', - ' Update state of cell to *state*.', - '', - ] - - options = {"members": None} - actual = do_autodoc(app, 'class', 'target.partialmethod.Cell', options) - assert list(actual) == expected - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_partialmethod_undoc_members(app): - expected = [ - '', - '.. py:class:: Cell()', - ' :module: target.partialmethod', - '', - ' An example for partialmethod.', - '', - ' refs: https://docs.python.jp/3/library/functools.html#functools.partialmethod', - '', - '', - ' .. py:method:: Cell.set_alive()', - ' :module: target.partialmethod', - '', - ' Make a cell alive.', - '', - '', - ' .. py:method:: Cell.set_dead()', - ' :module: target.partialmethod', - '', - '', - ' .. py:method:: Cell.set_state(state)', - ' :module: target.partialmethod', - '', - ' Update state of cell to *state*.', - '', - ] - - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'class', 'target.partialmethod.Cell', options) - assert list(actual) == expected - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_typed_instance_variables(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.typed_vars', options) - assert list(actual) == [ - '', - '.. py:module:: target.typed_vars', - '', - '', - '.. py:attribute:: Alias', - ' :module: target.typed_vars', - '', - ' alias of :py:class:`~target.typed_vars.Derived`', - '', - '.. py:class:: Class()', - ' :module: target.typed_vars', - '', - '', - ' .. py:attribute:: Class.attr1', - ' :module: target.typed_vars', - ' :type: int', - ' :value: 0', - '', - '', - ' .. py:attribute:: Class.attr2', - ' :module: target.typed_vars', - ' :type: int', - '', - '', - ' .. py:attribute:: Class.attr3', - ' :module: target.typed_vars', - ' :type: int', - ' :value: 0', - '', - '', - ' .. py:attribute:: Class.attr4', - ' :module: target.typed_vars', - ' :type: int', - '', - ' attr4', - '', - '', - ' .. py:attribute:: Class.attr5', - ' :module: target.typed_vars', - ' :type: int', - '', - ' attr5', - '', - '', - ' .. py:attribute:: Class.attr6', - ' :module: target.typed_vars', - ' :type: int', - '', - ' attr6', - '', - '', - ' .. py:attribute:: Class.descr4', - ' :module: target.typed_vars', - ' :type: int', - '', - ' This is descr4', - '', - '', - '.. py:class:: Derived()', - ' :module: target.typed_vars', - '', - '', - ' .. py:attribute:: Derived.attr7', - ' :module: target.typed_vars', - ' :type: int', - '', - '', - '.. py:data:: attr1', - ' :module: target.typed_vars', - ' :type: str', - " :value: ''", - '', - ' attr1', - '', - '', - '.. py:data:: attr2', - ' :module: target.typed_vars', - ' :type: str', - '', - ' attr2', - '', - '', - '.. py:data:: attr3', - ' :module: target.typed_vars', - ' :type: str', - " :value: ''", - '', - ' attr3', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_typed_inherited_instance_variables(app): - options = {"members": None, - "undoc-members": None, - "inherited-members": None} - actual = do_autodoc(app, 'class', 'target.typed_vars.Derived', options) - assert list(actual) == [ - '', - '.. py:class:: Derived()', - ' :module: target.typed_vars', - '', - '', - ' .. py:attribute:: Derived.attr1', - ' :module: target.typed_vars', - ' :type: int', - ' :value: 0', - '', - '', - ' .. py:attribute:: Derived.attr2', - ' :module: target.typed_vars', - ' :type: int', - '', - '', - ' .. py:attribute:: Derived.attr3', - ' :module: target.typed_vars', - ' :type: int', - ' :value: 0', - '', - '', - ' .. py:attribute:: Derived.attr4', - ' :module: target.typed_vars', - ' :type: int', - '', - ' attr4', - '', - '', - ' .. py:attribute:: Derived.attr5', - ' :module: target.typed_vars', - ' :type: int', - '', - ' attr5', - '', - '', - ' .. py:attribute:: Derived.attr6', - ' :module: target.typed_vars', - ' :type: int', - '', - ' attr6', - '', - '', - ' .. py:attribute:: Derived.attr7', - ' :module: target.typed_vars', - ' :type: int', - '', - '', - ' .. py:attribute:: Derived.descr4', - ' :module: target.typed_vars', - ' :type: int', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_GenericAlias(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.genericalias', options) - assert list(actual) == [ - '', - '.. py:module:: target.genericalias', - '', - '', - '.. py:class:: Class()', - ' :module: target.genericalias', - '', - '', - ' .. py:attribute:: Class.T', - ' :module: target.genericalias', - '', - ' A list of int', - '', - ' alias of :py:class:`~typing.List`\\ [:py:class:`int`]', - '', - '', - '.. py:data:: L', - ' :module: target.genericalias', - '', - ' A list of Class', - '', - ' alias of :py:class:`~typing.List`\\ ' - '[:py:class:`~target.genericalias.Class`]', - '', - '', - '.. py:data:: T', - ' :module: target.genericalias', - '', - ' A list of int', - '', - ' alias of :py:class:`~typing.List`\\ [:py:class:`int`]', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_TypeVar(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.typevar', options) - assert list(actual) == [ - '', - '.. py:module:: target.typevar', - '', - '', - '.. py:class:: Class()', - ' :module: target.typevar', - '', - '', - ' .. py:class:: Class.T1', - ' :module: target.typevar', - '', - ' T1', - '', - " alias of TypeVar('T1')", - '', - '', - ' .. py:class:: Class.T6', - ' :module: target.typevar', - '', - ' T6', - '', - ' alias of :py:class:`~datetime.date`', - '', - '', - '.. py:class:: T1', - ' :module: target.typevar', - '', - ' T1', - '', - " alias of TypeVar('T1')", - '', - '', - '.. py:class:: T3', - ' :module: target.typevar', - '', - ' T3', - '', - " alias of TypeVar('T3', int, str)", - '', - '', - '.. py:class:: T4', - ' :module: target.typevar', - '', - ' T4', - '', - " alias of TypeVar('T4', covariant=True)", - '', - '', - '.. py:class:: T5', - ' :module: target.typevar', - '', - ' T5', - '', - " alias of TypeVar('T5', contravariant=True)", - '', - '', - '.. py:class:: T6', - ' :module: target.typevar', - '', - ' T6', - '', - ' alias of :py:class:`~datetime.date`', - '', - '', - '.. py:class:: T7', - ' :module: target.typevar', - '', - ' T7', - '', - " alias of TypeVar('T7', bound=\\ :py:class:`int`)", - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_Annotated(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.annotated', options) - assert list(actual) == [ - '', - '.. py:module:: target.annotated', - '', - '', - '.. py:function:: hello(name: str) -> None', - ' :module: target.annotated', - '', - ' docstring', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_TYPE_CHECKING(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.TYPE_CHECKING', options) - assert list(actual) == [ - '', - '.. py:module:: target.TYPE_CHECKING', - '', - '', - '.. py:class:: Foo()', - ' :module: target.TYPE_CHECKING', - '', - '', - ' .. py:attribute:: Foo.attr1', - ' :module: target.TYPE_CHECKING', - ' :type: ~_io.StringIO', - '', - '', - '.. py:function:: spam(ham: ~collections.abc.Iterable[str]) -> tuple[~gettext.NullTranslations, bool]', - ' :module: target.TYPE_CHECKING', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_autodoc_TYPE_CHECKING_circular_import(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'circular_import', options) - assert list(actual) == [ - '', - '.. py:module:: circular_import', - '', - ] - assert sys.modules["circular_import"].a is sys.modules["circular_import.a"] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_singledispatch(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.singledispatch', options) - assert list(actual) == [ - '', - '.. py:module:: target.singledispatch', - '', - '', - '.. py:function:: func(arg, kwarg=None)', - ' func(arg: float, kwarg=None)', - ' func(arg: int, kwarg=None)', - ' func(arg: str, kwarg=None)', - ' func(arg: dict, kwarg=None)', - ' :module: target.singledispatch', - '', - ' A function for general use.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_singledispatchmethod(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.singledispatchmethod', options) - assert list(actual) == [ - '', - '.. py:module:: target.singledispatchmethod', - '', - '', - '.. py:class:: Foo()', - ' :module: target.singledispatchmethod', - '', - ' docstring', - '', - '', - ' .. py:method:: Foo.meth(arg, kwarg=None)', - ' Foo.meth(arg: float, kwarg=None)', - ' Foo.meth(arg: int, kwarg=None)', - ' Foo.meth(arg: str, kwarg=None)', - ' Foo.meth(arg: dict, kwarg=None)', - ' :module: target.singledispatchmethod', - '', - ' A method for general use.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_singledispatchmethod_automethod(app): - options = {} - actual = do_autodoc(app, 'method', 'target.singledispatchmethod.Foo.meth', options) - assert list(actual) == [ - '', - '.. py:method:: Foo.meth(arg, kwarg=None)', - ' Foo.meth(arg: float, kwarg=None)', - ' Foo.meth(arg: int, kwarg=None)', - ' Foo.meth(arg: str, kwarg=None)', - ' Foo.meth(arg: dict, kwarg=None)', - ' :module: target.singledispatchmethod', - '', - ' A method for general use.', - '', - ] - - -@pytest.mark.skipif(sys.version_info[:2] >= (3, 13), - reason='Cython does not support Python 3.13 yet.') -@pytest.mark.skipif(pyximport is None, reason='cython is not installed') -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_cython(app): - options = {"members": None, - "undoc-members": None} - actual = do_autodoc(app, 'module', 'target.cython', options) - assert list(actual) == [ - '', - '.. py:module:: target.cython', - '', - '', - '.. py:class:: Class()', - ' :module: target.cython', - '', - ' Docstring.', - '', - '', - ' .. py:method:: Class.meth(name: str, age: int = 0) -> None', - ' :module: target.cython', - '', - ' Docstring.', - '', - '', - '.. py:function:: foo(x: int, *args, y: str, **kwargs)', - ' :module: target.cython', - '', - ' Docstring.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_final(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.final', options) - assert list(actual) == [ - '', - '.. py:module:: target.final', - '', - '', - '.. py:class:: Class()', - ' :module: target.final', - ' :final:', - '', - ' docstring', - '', - '', - ' .. py:method:: Class.meth1()', - ' :module: target.final', - ' :final:', - '', - ' docstring', - '', - '', - ' .. py:method:: Class.meth2()', - ' :module: target.final', - '', - ' docstring', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_overload(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.overload', options) - assert list(actual) == [ - '', - '.. py:module:: target.overload', - '', - '', - '.. py:class:: Bar(x: int, y: int)', - ' Bar(x: str, y: str)', - ' :module: target.overload', - '', - ' docstring', - '', - '', - '.. py:class:: Baz(x: int, y: int)', - ' Baz(x: str, y: str)', - ' :module: target.overload', - '', - ' docstring', - '', - '', - '.. py:class:: Foo(x: int, y: int)', - ' Foo(x: str, y: str)', - ' :module: target.overload', - '', - ' docstring', - '', - '', - '.. py:class:: Math()', - ' :module: target.overload', - '', - ' docstring', - '', - '', - ' .. py:method:: Math.sum(x: int, y: int = 0) -> int', - ' Math.sum(x: float, y: float = 0.0) -> float', - ' Math.sum(x: str, y: str = None) -> str', - ' :module: target.overload', - '', - ' docstring', - '', - '', - '.. py:function:: sum(x: int, y: int = 0) -> int', - ' sum(x: float, y: float = 0.0) -> float', - ' sum(x: str, y: str = None) -> str', - ' :module: target.overload', - '', - ' docstring', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_overload2(app): - options = {"members": None} - actual = do_autodoc(app, 'module', 'target.overload2', options) - assert list(actual) == [ - '', - '.. py:module:: target.overload2', - '', - '', - '.. py:class:: Baz(x: int, y: int)', - ' Baz(x: str, y: str)', - ' :module: target.overload2', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_pymodule_for_ModuleLevelDocumenter(app): - app.env.ref_context['py:module'] = 'target.classes' - actual = do_autodoc(app, 'class', 'Foo') - assert list(actual) == [ - '', - '.. py:class:: Foo()', - ' :module: target.classes', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_pymodule_for_ClassLevelDocumenter(app): - app.env.ref_context['py:module'] = 'target.methods' - actual = do_autodoc(app, 'method', 'Base.meth') - assert list(actual) == [ - '', - '.. py:method:: Base.meth()', - ' :module: target.methods', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_pyclass_for_ClassLevelDocumenter(app): - app.env.ref_context['py:module'] = 'target.methods' - app.env.ref_context['py:class'] = 'Base' - actual = do_autodoc(app, 'method', 'meth') - assert list(actual) == [ - '', - '.. py:method:: Base.meth()', - ' :module: target.methods', - '', - ] - - -@pytest.mark.sphinx('dummy', testroot='ext-autodoc') -def test_autodoc(app, status, warning): - app.builder.build_all() - - content = app.env.get_doctree('index') - assert isinstance(content[3], addnodes.desc) - assert content[3][0].astext() == 'autodoc_dummy_module.test()' - assert content[3][1].astext() == 'Dummy function using dummy.*' - - # issue sphinx-doc/sphinx#2437 - assert content[11][-1].astext() == """Dummy class Bar with alias. - - - -my_name - -alias of Foo""" - assert warning.getvalue() == '' - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_name_conflict(app): - actual = do_autodoc(app, 'class', 'target.name_conflict.foo') - assert list(actual) == [ - '', - '.. py:class:: foo()', - ' :module: target.name_conflict', - '', - ' docstring of target.name_conflict::foo.', - '', - ] - - actual = do_autodoc(app, 'class', 'target.name_conflict.foo.bar') - assert list(actual) == [ - '', - '.. py:class:: bar()', - ' :module: target.name_conflict.foo', - '', - ' docstring of target.name_conflict.foo::bar.', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_name_mangling(app): - options = {"members": None, - "undoc-members": None, - "private-members": None} - actual = do_autodoc(app, 'module', 'target.name_mangling', options) - assert list(actual) == [ - '', - '.. py:module:: target.name_mangling', - '', - '', - '.. py:class:: Bar()', - ' :module: target.name_mangling', - '', - '', - ' .. py:attribute:: Bar._Baz__email', - ' :module: target.name_mangling', - ' :value: None', - '', - ' a member having mangled-like name', - '', - '', - ' .. py:attribute:: Bar.__address', - ' :module: target.name_mangling', - ' :value: None', - '', - '', - '.. py:class:: Foo()', - ' :module: target.name_mangling', - '', - '', - ' .. py:attribute:: Foo.__age', - ' :module: target.name_mangling', - ' :value: None', - '', - '', - ' .. py:attribute:: Foo.__name', - ' :module: target.name_mangling', - ' :value: None', - '', - ' name of Foo', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_type_union_operator(app): - options = {'members': None} - actual = do_autodoc(app, 'module', 'target.pep604', options) - assert list(actual) == [ - '', - '.. py:module:: target.pep604', - '', - '', - '.. py:class:: Foo()', - ' :module: target.pep604', - '', - ' docstring', - '', - '', - ' .. py:attribute:: Foo.attr', - ' :module: target.pep604', - ' :type: int | str', - '', - ' docstring', - '', - '', - ' .. py:method:: Foo.meth(x: int | str, y: int | str) -> int | str', - ' :module: target.pep604', - '', - ' docstring', - '', - '', - '.. py:data:: attr', - ' :module: target.pep604', - ' :type: int | str', - '', - ' docstring', - '', - '', - '.. py:function:: sum(x: int | str, y: int | str) -> int | str', - ' :module: target.pep604', - '', - ' docstring', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_hide_value(app): - options = {'members': None} - actual = do_autodoc(app, 'module', 'target.hide_value', options) - assert list(actual) == [ - '', - '.. py:module:: target.hide_value', - '', - '', - '.. py:class:: Foo()', - ' :module: target.hide_value', - '', - ' docstring', - '', - '', - ' .. py:attribute:: Foo.SENTINEL1', - ' :module: target.hide_value', - '', - ' docstring', - '', - ' :meta hide-value:', - '', - '', - ' .. py:attribute:: Foo.SENTINEL2', - ' :module: target.hide_value', - '', - ' :meta hide-value:', - '', - '', - '.. py:data:: SENTINEL1', - ' :module: target.hide_value', - '', - ' docstring', - '', - ' :meta hide-value:', - '', - '', - '.. py:data:: SENTINEL2', - ' :module: target.hide_value', - '', - ' :meta hide-value:', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_canonical(app): - options = {'members': None, - 'imported-members': None} - actual = do_autodoc(app, 'module', 'target.canonical', options) - assert list(actual) == [ - '', - '.. py:module:: target.canonical', - '', - '', - '.. py:class:: Bar()', - ' :module: target.canonical', - '', - ' docstring', - '', - '', - '.. py:class:: Foo()', - ' :module: target.canonical', - ' :canonical: target.canonical.original.Foo', - '', - ' docstring', - '', - '', - ' .. py:method:: Foo.meth()', - ' :module: target.canonical', - '', - ' docstring', - '', - ] - - -@pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_literal_render(app): - def bounded_typevar_rst(name, bound): - return [ - '', - f'.. py:class:: {name}', - ' :module: target.literal', - '', - ' docstring', - '', - f' alias of TypeVar({name!r}, bound={bound})', - '', - ] - - def function_rst(name, sig): - return [ - '', - f'.. py:function:: {name}({sig})', - ' :module: target.literal', - '', - ' docstring', - '', - ] - - # autodoc_typehints_format can take 'short' or 'fully-qualified' values - # and this will be interpreted as 'smart' or 'fully-qualified-except-typing' by restify() - # and 'smart' or 'fully-qualified' by stringify_annotation(). - - options = {'members': None, 'exclude-members': 'MyEnum'} - app.config.autodoc_typehints_format = 'short' - actual = do_autodoc(app, 'module', 'target.literal', options) - assert list(actual) == [ - '', - '.. py:module:: target.literal', - '', - *bounded_typevar_rst('T', r'\ :py:obj:`~typing.Literal`\ [1234]'), - *bounded_typevar_rst('U', r'\ :py:obj:`~typing.Literal`\ [:py:attr:`~target.literal.MyEnum.a`]'), - *function_rst('bar', 'x: ~typing.Literal[1234]'), - *function_rst('foo', 'x: ~typing.Literal[MyEnum.a]'), - ] - - # restify() assumes that 'fully-qualified' is 'fully-qualified-except-typing' - # because it is more likely that a user wants to suppress 'typing.*' - app.config.autodoc_typehints_format = 'fully-qualified' - actual = do_autodoc(app, 'module', 'target.literal', options) - assert list(actual) == [ - '', - '.. py:module:: target.literal', - '', - *bounded_typevar_rst('T', r'\ :py:obj:`~typing.Literal`\ [1234]'), - *bounded_typevar_rst('U', r'\ :py:obj:`~typing.Literal`\ [:py:attr:`target.literal.MyEnum.a`]'), - *function_rst('bar', 'x: typing.Literal[1234]'), - *function_rst('foo', 'x: typing.Literal[target.literal.MyEnum.a]'), - ] |