mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
This generates `:canonical:` option for `:py:class:` directive if the target class is imported from other module. It allows users to refer it using both the new name (imported name) and the original name (canonical name). It helps a library that implements some class in private module (like `_io.StringIO`), and publish it as public module (like `io.StringIO`).
2508 lines
76 KiB
Python
2508 lines
76 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(),
|
|
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
|
|
|
|
|
|
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.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)'
|
|
]
|
|
|
|
# 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: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: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: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: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: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: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: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_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()'
|
|
]
|
|
|
|
# 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 = {"noindex": None}
|
|
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'] = None
|
|
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": 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.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": 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',
|
|
'',
|
|
]
|
|
|
|
|
|
@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',
|
|
'',
|
|
' 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: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_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.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 :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)
|
|
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`',
|
|
'',
|
|
'',
|
|
'.. py:data:: T7',
|
|
' :module: target.typevar',
|
|
'',
|
|
' T7',
|
|
'',
|
|
" alias of TypeVar('T7', bound=\\ :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.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)
|
|
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 = 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 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, 7), reason='python 3.7+ is required.')
|
|
@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.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': 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',
|
|
'',
|
|
]
|