sphinx/tests/test_ext_autodoc.py
Takeshi KOMIYA 425cd1af02 Fix #8693: autodoc: Default values for overloads are rendered as string
The default values for overloaded functions are rendered as string
literal unexpectedly because autodoc extracts code snippets from
the source code, not actual value (ex. int, ellipsis, and so on).

This introduces a simple wrapper class; `DefaultValue` to render these
code snippets like actual values, not string literals.
2021-01-17 02:30:20 +09:00

2284 lines
68 KiB
Python

"""
test_ext_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-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import sys
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.testing.util import SphinxTestApp, Struct # NOQA
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,
noindex = False,
annotation = None,
synopsis = '',
platform = '',
deprecated = False,
members = [],
member_order = 'alphabetical',
exclude_members = set(),
ignore_module_all = False,
)
directive = Struct(
env = env,
genopt = options,
result = ViewList(),
filename_set = 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
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
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.8
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.skipif(sys.version_info < (3, 5), reason='typing is available since python3.5.')
@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: # NOQA
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',
'',
]
def test_attrgetter_using(app):
from target import Class
from target.inheritance import Derived
directive = make_directive_bridge(app.env)
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)
app.add_autodoc_attrgetter(type, special_getattr)
del getattr_spy[:]
inst = app.registry.documenters[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
with catch_warnings(record=True):
directive.genopt['members'] = ALL
directive.genopt['inherited_members'] = False
print(directive.genopt)
assert_getter_works('class', 'target.Class', Class, ['meth'])
directive.genopt['inherited_members'] = True
assert_getter_works('class', 'target.inheritance.Derived', Derived, ['inheritedmeth'])
@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: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)'
]
@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: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()',
]
@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()'
]
@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:: save_traceback(app: Sphinx) -> 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()'
]
@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 = {"noindex": True}
actual = do_autodoc(app, 'module', 'target', options)
assert list(actual) == [
'',
'.. py:module:: target',
' :noindex:',
''
]
# TODO: :noindex: should be propagated to children of target item.
actual = do_autodoc(app, 'class', 'target.inheritance.Base', options)
assert list(actual) == [
'',
'.. py:class:: Base()',
' :noindex:',
' :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 :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'] = True
actual = do_autodoc(app, 'class', 'target.InnerChild', options)
assert list(actual) == [
'',
'.. py:class:: InnerChild()',
' :module: target', '',
' Bases: :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": True}
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:method:: Class.prop',
' :module: target.descriptor',
' :property:',
'',
' Property.',
''
]
@pytest.mark.skipif(sys.version_info < (3, 8),
reason='cached_property is available since python3.8.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_cached_property(app):
options = {"members": None,
"undoc-members": True}
actual = do_autodoc(app, 'class', 'target.cached_property.Foo', options)
assert list(actual) == [
'',
'.. py:class:: Foo()',
' :module: target.cached_property',
'',
'',
' .. py:method:: Foo.prop',
' :module: target.cached_property',
' :property:',
'',
]
@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": True,
'private-members': True}
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": True,
'private-members': True}
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": True,
'private-members': True}
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": True}
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": True,
"ignore-module-all": True}
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": True}
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": True}
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',
'',
' 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)
assert list(actual) == [
'',
'.. py:class:: EnumCls(value)',
' :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:method:: Base.prop',
' :module: target.abstractmethods',
' :abstractmethod:',
' :property:',
'',
'',
' .. 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_coroutine(app):
actual = do_autodoc(app, 'function', 'target.functions.coroutinefunc')
assert list(actual) == [
'',
'.. py:function:: coroutinefunc()',
' :module: target.functions',
' :async:',
'',
]
options = {"members": None}
actual = do_autodoc(app, 'class', 'target.coroutine.AsyncClass', options)
assert list(actual) == [
'',
'.. py:class:: AsyncClass()',
' :module: target.coroutine',
'',
'',
' .. py:method:: AsyncClass.do_coroutine()',
' :module: target.coroutine',
' :async:',
'',
' A documented coroutine function',
'',
'',
' .. py:method:: AsyncClass.do_coroutine2()',
' :module: target.coroutine',
' :async:',
' :classmethod:',
'',
' A documented coroutine classmethod',
'',
'',
' .. py:method:: AsyncClass.do_coroutine3()',
' :module: target.coroutine',
' :async:',
' :staticmethod:',
'',
' A documented coroutine staticmethod',
'',
]
# force-synchronized wrapper
actual = do_autodoc(app, 'function', 'target.coroutine.sync_func')
assert list(actual) == [
'',
'.. py:function:: sync_func()',
' :module: target.coroutine',
'',
]
@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.skipif(sys.version_info < (3, 6), reason='py36+ is available since python3.6.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_typed_instance_variables(app):
options = {"members": None,
"undoc-members": True}
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 :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.skipif(sys.version_info < (3, 6), reason='py36+ is available since python3.6.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_typed_inherited_instance_variables(app):
options = {"members": None,
"undoc-members": True,
"inherited-members": True}
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)
if sys.version_info < (3, 7):
assert list(actual) == [
'',
'.. py:module:: target.genericalias',
'',
'',
'.. py:class:: Class()',
' :module: target.genericalias',
'',
'',
' .. py:attribute:: Class.T',
' :module: target.genericalias',
'',
' alias of :class:`List`\\ [:class:`int`]',
'',
'.. py:attribute:: T',
' :module: target.genericalias',
'',
' alias of :class:`List`\\ [:class:`int`]',
]
else:
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 List[int]',
'',
'',
'.. py:data:: T',
' :module: target.genericalias',
'',
' A list of int',
'',
' alias of List[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:attribute:: Class.T1',
' :module: target.typevar',
'',
' T1',
'',
" alias of TypeVar('T1')",
'',
'',
' .. py:attribute:: Class.T6',
' :module: target.typevar',
'',
' T6',
'',
' alias of :class:`int`',
'',
'',
'.. py:data:: T1',
' :module: target.typevar',
'',
' T1',
'',
" alias of TypeVar('T1')",
'',
'',
'.. py:data:: T3',
' :module: target.typevar',
'',
' T3',
'',
" alias of TypeVar('T3', int, str)",
'',
'',
'.. py:data:: T4',
' :module: target.typevar',
'',
' T4',
'',
" alias of TypeVar('T4', covariant=True)",
'',
'',
'.. py:data:: T5',
' :module: target.typevar',
'',
' T5',
'',
" alias of TypeVar('T5', contravariant=True)",
'',
'',
'.. py:data:: T6',
' :module: target.typevar',
'',
' T6',
'',
' alias of :class:`int`',
'',
]
@pytest.mark.skipif(sys.version_info < (3, 9), reason='py39+ is required.')
@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.skipif(sys.version_info < (3, 6), reason='py36+ is required.')
@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: StringIO',
'',
]
@pytest.mark.sphinx('html', testroot='pycode-egg')
def test_autodoc_for_egged_code(app):
options = {"members": None,
"undoc-members": None}
actual = do_autodoc(app, 'module', 'sample', options)
assert list(actual) == [
'',
'.. py:module:: sample',
'',
'',
'.. py:data:: CONSTANT',
' :module: sample',
' :value: 1',
'',
' constant on sample.py',
'',
'',
'.. py:function:: hello(s)',
' :module: sample',
''
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_singledispatch(app):
options = {"members": None}
actual = do_autodoc(app, 'module', 'target.singledispatch', options)
if sys.version_info < (3, 6):
# check the result via "in" because the order of singledispatch signatures is
# usually changed (because dict is not OrderedDict yet!)
assert '.. py:function:: func(arg, kwarg=None)' in actual
assert ' func(arg: int, kwarg=None)' in actual
assert ' func(arg: str, kwarg=None)' in actual
else:
assert list(actual) == [
'',
'.. py:module:: target.singledispatch',
'',
'',
'.. py:function:: func(arg, kwarg=None)',
' func(arg: int, kwarg=None)',
' func(arg: str, kwarg=None)',
' :module: target.singledispatch',
'',
' A function for general use.',
'',
]
@pytest.mark.skipif(sys.version_info < (3, 8),
reason='singledispatchmethod is available since python3.8')
@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: int, kwarg=None)',
' Foo.meth(arg: str, kwarg=None)',
' :module: target.singledispatchmethod',
'',
' A method for general use.',
'',
]
@pytest.mark.skipif(sys.version_info < (3, 8),
reason='singledispatchmethod is available since python3.8')
@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: int, kwarg=None)',
' Foo.meth(arg: str, kwarg=None)',
' :module: target.singledispatchmethod',
'',
' A method for general use.',
'',
]
@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.skipif(sys.version_info < (3, 8),
reason='typing.final is available since python3.8')
@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 = ...) -> 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 = ...) -> 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 bug2437.autodoc_dummy_foo.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.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_hide_value(app):
options = {'members': True}
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:',
'',
]