mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '4.x' into 4.0.x
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
|
||||
module_attr
|
||||
C.class_attr
|
||||
C.instance_attr
|
||||
C.prop_attr1
|
||||
C.prop_attr2
|
||||
C.C2
|
||||
@@ -51,6 +52,12 @@ class C:
|
||||
#: value is integer.
|
||||
class_attr = 42
|
||||
|
||||
def __init__(self):
|
||||
#: This is an instance attribute
|
||||
#:
|
||||
#: value is a string
|
||||
self.instance_attr = "42"
|
||||
|
||||
def _prop_attr_get(self):
|
||||
"""
|
||||
This is a function docstring
|
||||
|
||||
4
tests/roots/test-domain-c/field-role.rst
Normal file
4
tests/roots/test-domain-c/field-role.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
.. c:function:: void f(int a, int *b)
|
||||
|
||||
:param int a:
|
||||
:param int* b:
|
||||
5
tests/roots/test-domain-cpp/field-role.rst
Normal file
5
tests/roots/test-domain-cpp/field-role.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
.. cpp:function:: void f()
|
||||
|
||||
:throws int:
|
||||
:throws int*:
|
||||
|
||||
@@ -4,5 +4,9 @@ domain-py-smart_reference
|
||||
.. py:class:: Name
|
||||
:module: foo
|
||||
|
||||
:param name: blah blah
|
||||
:type name: foo.Name
|
||||
:param age: blah blah
|
||||
:type age: foo.Age
|
||||
|
||||
.. py:function:: hello(name: foo.Name, age: foo.Age)
|
||||
|
||||
@@ -10,4 +10,6 @@
|
||||
|
||||
.. autofunction:: target.typehints.incr
|
||||
|
||||
.. autofunction:: target.overload.sum
|
||||
|
||||
.. autofunction:: target.typehints.tuple_args
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
from typing import overload
|
||||
|
||||
myint = int
|
||||
@@ -11,6 +12,10 @@ variable: myint
|
||||
variable2 = None # type: myint
|
||||
|
||||
|
||||
def read(r: io.BytesIO) -> io.StringIO:
|
||||
"""docstring"""
|
||||
|
||||
|
||||
def sum(x: myint, y: myint) -> myint:
|
||||
"""docstring"""
|
||||
return x + y
|
||||
@@ -30,3 +30,6 @@ class Quux(List[Union[int, float]]):
|
||||
|
||||
|
||||
Alias = Foo
|
||||
|
||||
#: docstring
|
||||
OtherAlias = Bar
|
||||
|
||||
@@ -8,3 +8,4 @@ class Bar(Foo):
|
||||
def __init__(self):
|
||||
self.attr2 = None #: docstring bar
|
||||
self.attr3 = None #: docstring bar
|
||||
self.attr4 = None
|
||||
|
||||
2
tests/roots/test-ext-autodoc/target/metadata.py
Normal file
2
tests/roots/test-ext-autodoc/target/metadata.py
Normal file
@@ -0,0 +1,2 @@
|
||||
def foo():
|
||||
""":meta metadata-only-docstring:"""
|
||||
14
tests/roots/test-ext-autodoc/target/module.py
Normal file
14
tests/roots/test-ext-autodoc/target/module.py
Normal file
@@ -0,0 +1,14 @@
|
||||
undocumented = 1
|
||||
|
||||
#: docstring
|
||||
documented = 1
|
||||
|
||||
undoc_annotated: int
|
||||
|
||||
#: docstring
|
||||
annotated: int
|
||||
|
||||
__special__ = 1
|
||||
|
||||
#: docstring
|
||||
__documented_special__ = 1
|
||||
@@ -15,6 +15,7 @@ def func(arg, kwarg=None):
|
||||
|
||||
|
||||
@func.register(int)
|
||||
@func.register(float)
|
||||
def _func_int(arg, kwarg=None):
|
||||
"""A function for int."""
|
||||
pass
|
||||
|
||||
@@ -10,6 +10,7 @@ class Foo:
|
||||
pass
|
||||
|
||||
@meth.register(int)
|
||||
@meth.register(float)
|
||||
def _meth_int(self, arg, kwarg=None):
|
||||
"""A method for int."""
|
||||
pass
|
||||
|
||||
@@ -5,7 +5,7 @@ Translation Tips
|
||||
-----------------
|
||||
|
||||
.. _download Sphinx: https://pypi.org/project/Sphinx/
|
||||
.. _Docutils site: http://docutils.sourceforge.net/
|
||||
.. _Docutils site: https://docutils.sourceforge.io/
|
||||
.. _Sphinx site: http://sphinx-doc.org/
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ Some additional anchors to exercise ignore code
|
||||
* `Complete nonsense <https://localhost:7777/doesnotexist>`_
|
||||
* `Example valid local file <conf.py>`_
|
||||
* `Example invalid local file <path/to/notfound>`_
|
||||
* https://github.com/sphinx-doc/sphinx#documentation
|
||||
* https://github.com/sphinx-doc/sphinx#user-content-testing
|
||||
|
||||
.. image:: https://www.google.com/image.png
|
||||
.. figure:: https://www.google.com/image2.png
|
||||
|
||||
1
tests/roots/test-nitpicky-warnings/conf.py
Normal file
1
tests/roots/test-nitpicky-warnings/conf.py
Normal file
@@ -0,0 +1 @@
|
||||
nitpicky = True
|
||||
7
tests/roots/test-nitpicky-warnings/index.rst
Normal file
7
tests/roots/test-nitpicky-warnings/index.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
test-nitpicky-warnings
|
||||
======================
|
||||
|
||||
:py:const:`prefix.anything.postfix`
|
||||
:py:class:`prefix.anything`
|
||||
:py:class:`anything.postfix`
|
||||
:js:class:`prefix.anything.postfix`
|
||||
@@ -65,8 +65,8 @@ def test_defaults_json(app):
|
||||
"info"]:
|
||||
assert attr in row
|
||||
|
||||
assert len(content.splitlines()) == 10
|
||||
assert len(rows) == 10
|
||||
assert len(content.splitlines()) == 12
|
||||
assert len(rows) == 12
|
||||
# the output order of the rows is not stable
|
||||
# due to possible variance in network latency
|
||||
rowsby = {row["uri"]: row for row in rows}
|
||||
@@ -87,7 +87,7 @@ def test_defaults_json(app):
|
||||
assert dnerow['uri'] == 'https://localhost:7777/doesnotexist'
|
||||
assert rowsby['https://www.google.com/image2.png'] == {
|
||||
'filename': 'links.txt',
|
||||
'lineno': 18,
|
||||
'lineno': 20,
|
||||
'status': 'broken',
|
||||
'code': 0,
|
||||
'uri': 'https://www.google.com/image2.png',
|
||||
@@ -101,6 +101,10 @@ def test_defaults_json(app):
|
||||
# images should fail
|
||||
assert "Not Found for url: https://www.google.com/image.png" in \
|
||||
rowsby["https://www.google.com/image.png"]["info"]
|
||||
# The anchor of the URI for github.com is automatically modified
|
||||
assert 'https://github.com/sphinx-doc/sphinx#documentation' not in rowsby
|
||||
assert 'https://github.com/sphinx-doc/sphinx#user-content-documentation' in rowsby
|
||||
assert 'https://github.com/sphinx-doc/sphinx#user-content-testing' in rowsby
|
||||
|
||||
|
||||
@pytest.mark.sphinx(
|
||||
|
||||
@@ -34,7 +34,7 @@ def test_all(app, status, warning):
|
||||
confoverrides={'man_make_section_directory': True})
|
||||
def test_man_make_section_directory(app, status, warning):
|
||||
app.build()
|
||||
assert (app.outdir / '1' / 'python.1').exists()
|
||||
assert (app.outdir / 'man1' / 'python.1').exists()
|
||||
|
||||
|
||||
@pytest.mark.sphinx('man', testroot='directive-code')
|
||||
|
||||
@@ -74,6 +74,11 @@ def test_core_config(app, status, warning):
|
||||
assert cfg['project'] == cfg.project == 'Sphinx Tests'
|
||||
|
||||
|
||||
def test_config_not_found(tempdir):
|
||||
with pytest.raises(ConfigError):
|
||||
Config.read(tempdir)
|
||||
|
||||
|
||||
def test_extension_values():
|
||||
config = Config()
|
||||
|
||||
@@ -311,3 +316,77 @@ def test_check_enum_for_list_failed(logger):
|
||||
config.init_values()
|
||||
check_confval_types(None, config)
|
||||
assert logger.warning.called
|
||||
|
||||
|
||||
nitpick_warnings = [
|
||||
"WARNING: py:const reference target not found: prefix.anything.postfix",
|
||||
"WARNING: py:class reference target not found: prefix.anything",
|
||||
"WARNING: py:class reference target not found: anything.postfix",
|
||||
"WARNING: js:class reference target not found: prefix.anything.postfix",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='nitpicky-warnings')
|
||||
def test_nitpick_base(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
warning = warning.getvalue().strip().split('\n')
|
||||
assert len(warning) == len(nitpick_warnings)
|
||||
for actual, expected in zip(warning, nitpick_warnings):
|
||||
assert expected in actual
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
|
||||
'nitpick_ignore': [
|
||||
('py:const', 'prefix.anything.postfix'),
|
||||
('py:class', 'prefix.anything'),
|
||||
('py:class', 'anything.postfix'),
|
||||
('js:class', 'prefix.anything.postfix'),
|
||||
],
|
||||
})
|
||||
def test_nitpick_ignore(app, status, warning):
|
||||
app.builder.build_all()
|
||||
assert not len(warning.getvalue().strip())
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
|
||||
'nitpick_ignore_regex': [
|
||||
(r'py:.*', r'.*postfix'),
|
||||
(r'.*:class', r'prefix.*'),
|
||||
]
|
||||
})
|
||||
def test_nitpick_ignore_regex1(app, status, warning):
|
||||
app.builder.build_all()
|
||||
assert not len(warning.getvalue().strip())
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
|
||||
'nitpick_ignore_regex': [
|
||||
(r'py:.*', r'prefix.*'),
|
||||
(r'.*:class', r'.*postfix'),
|
||||
]
|
||||
})
|
||||
def test_nitpick_ignore_regex2(app, status, warning):
|
||||
app.builder.build_all()
|
||||
assert not len(warning.getvalue().strip())
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
|
||||
'nitpick_ignore_regex': [
|
||||
# None of these should match
|
||||
(r'py:', r'.*'),
|
||||
(r':class', r'.*'),
|
||||
(r'', r'.*'),
|
||||
(r'.*', r'anything'),
|
||||
(r'.*', r'prefix'),
|
||||
(r'.*', r'postfix'),
|
||||
(r'.*', r''),
|
||||
]
|
||||
})
|
||||
def test_nitpick_ignore_regex_fullmatch(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
warning = warning.getvalue().strip().split('\n')
|
||||
assert len(warning) == len(nitpick_warnings)
|
||||
for actual, expected in zip(warning, nitpick_warnings):
|
||||
assert expected in actual
|
||||
|
||||
@@ -112,7 +112,7 @@ def check(name, input, idDict, output=None, key=None, asTextOutput=None):
|
||||
asTextOutput + ';' if asTextOutput is not None else None)
|
||||
|
||||
|
||||
def test_expressions():
|
||||
def test_domain_c_ast_expressions():
|
||||
def exprCheck(expr, output=None):
|
||||
class Config:
|
||||
c_id_attributes = ["id_attr"]
|
||||
@@ -269,7 +269,7 @@ def test_expressions():
|
||||
exprCheck('a or_eq 5')
|
||||
|
||||
|
||||
def test_type_definitions():
|
||||
def test_domain_c_ast_type_definitions():
|
||||
check('type', "{key}T", {1: "T"})
|
||||
|
||||
check('type', "{key}bool *b", {1: 'b'}, key='typedef')
|
||||
@@ -290,7 +290,7 @@ def test_type_definitions():
|
||||
{1: 'gpio_callback_t'}, key='typedef')
|
||||
|
||||
|
||||
def test_macro_definitions():
|
||||
def test_domain_c_ast_macro_definitions():
|
||||
check('macro', 'M', {1: 'M'})
|
||||
check('macro', 'M()', {1: 'M'})
|
||||
check('macro', 'M(arg)', {1: 'M'})
|
||||
@@ -306,7 +306,7 @@ def test_macro_definitions():
|
||||
check('macro', 'M(arg1, arg2..., arg3)', {1: 'M'})
|
||||
|
||||
|
||||
def test_member_definitions():
|
||||
def test_domain_c_ast_member_definitions():
|
||||
check('member', 'void a', {1: 'a'})
|
||||
check('member', '_Bool a', {1: 'a'})
|
||||
check('member', 'bool a', {1: 'a'})
|
||||
@@ -364,7 +364,7 @@ def test_member_definitions():
|
||||
check('member', 'int b : 3', {1: 'b'})
|
||||
|
||||
|
||||
def test_function_definitions():
|
||||
def test_domain_c_ast_function_definitions():
|
||||
check('function', 'void f()', {1: 'f'})
|
||||
check('function', 'void f(int)', {1: 'f'})
|
||||
check('function', 'void f(int i)', {1: 'f'})
|
||||
@@ -424,29 +424,29 @@ def test_function_definitions():
|
||||
check('function', 'void f(void (*p)(int, double), int i)', {1: 'f'})
|
||||
|
||||
|
||||
def test_nested_name():
|
||||
def test_domain_c_ast_nested_name():
|
||||
check('struct', '{key}.A', {1: "A"})
|
||||
check('struct', '{key}.A.B', {1: "A.B"})
|
||||
check('function', 'void f(.A a)', {1: "f"})
|
||||
check('function', 'void f(.A.B a)', {1: "f"})
|
||||
|
||||
|
||||
def test_struct_definitions():
|
||||
def test_domain_c_ast_struct_definitions():
|
||||
check('struct', '{key}A', {1: 'A'})
|
||||
|
||||
|
||||
def test_union_definitions():
|
||||
def test_domain_c_ast_union_definitions():
|
||||
check('union', '{key}A', {1: 'A'})
|
||||
|
||||
|
||||
def test_enum_definitions():
|
||||
def test_domain_c_ast_enum_definitions():
|
||||
check('enum', '{key}A', {1: 'A'})
|
||||
|
||||
check('enumerator', '{key}A', {1: 'A'})
|
||||
check('enumerator', '{key}A = 42', {1: 'A'})
|
||||
|
||||
|
||||
def test_anon_definitions():
|
||||
def test_domain_c_ast_anon_definitions():
|
||||
check('struct', '@a', {1: "@a"}, asTextOutput='struct [anonymous]')
|
||||
check('union', '@a', {1: "@a"}, asTextOutput='union [anonymous]')
|
||||
check('enum', '@a', {1: "@a"}, asTextOutput='enum [anonymous]')
|
||||
@@ -454,7 +454,7 @@ def test_anon_definitions():
|
||||
check('struct', '@a.A', {1: "@a.A"}, asTextOutput='struct [anonymous].A')
|
||||
|
||||
|
||||
def test_initializers():
|
||||
def test_domain_c_ast_initializers():
|
||||
idsMember = {1: 'v'}
|
||||
idsFunction = {1: 'f'}
|
||||
# no init
|
||||
@@ -473,7 +473,7 @@ def test_initializers():
|
||||
# TODO: designator-list
|
||||
|
||||
|
||||
def test_attributes():
|
||||
def test_domain_c_ast_attributes():
|
||||
# style: C++
|
||||
check('member', '[[]] int f', {1: 'f'})
|
||||
check('member', '[ [ ] ] int f', {1: 'f'},
|
||||
@@ -566,14 +566,14 @@ def extract_role_links(app, filename):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_c(app, status, warning):
|
||||
def test_domain_c_build(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "index")
|
||||
assert len(ws) == 0
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_c_namespace(app, status, warning):
|
||||
def test_domain_c_build_namespace(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "namespace")
|
||||
assert len(ws) == 0
|
||||
@@ -583,7 +583,7 @@ def test_build_domain_c_namespace(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_c_anon_dup_decl(app, status, warning):
|
||||
def test_domain_c_build_anon_dup_decl(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "anon-dup-decl")
|
||||
assert len(ws) == 2
|
||||
@@ -592,7 +592,7 @@ def test_build_domain_c_anon_dup_decl(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(confoverrides={'nitpicky': True})
|
||||
def test_build_domain_c_semicolon(app, warning):
|
||||
def test_domain_c_build_semicolon(app, warning):
|
||||
text = """
|
||||
.. c:member:: int member;
|
||||
.. c:var:: int var;
|
||||
@@ -611,7 +611,7 @@ def test_build_domain_c_semicolon(app, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||
def test_build_function_param_target(app, warning):
|
||||
def test_domain_c_build_function_param_target(app, warning):
|
||||
# the anchor for function parameters should be the function
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "function_param_target")
|
||||
@@ -624,12 +624,19 @@ def test_build_function_param_target(app, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||
def test_build_ns_lookup(app, warning):
|
||||
def test_domain_c_build_ns_lookup(app, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "ns_lookup")
|
||||
assert len(ws) == 0
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||
def test_domain_c_build_field_role(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "field-role")
|
||||
assert len(ws) == 0
|
||||
|
||||
|
||||
def _get_obj(app, queryName):
|
||||
domain = app.env.get_domain('c')
|
||||
for name, dispname, objectType, docname, anchor, prio in domain.get_objects():
|
||||
@@ -638,49 +645,8 @@ def _get_obj(app, queryName):
|
||||
return (queryName, "not", "found")
|
||||
|
||||
|
||||
def test_cfunction(app):
|
||||
text = (".. c:function:: PyObject* "
|
||||
"PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree[1], addnodes.desc, desctype="function",
|
||||
domain="c", objtype="function", noindex=False)
|
||||
|
||||
entry = _get_obj(app, 'PyType_GenericAlloc')
|
||||
assert entry == ('index', 'c.PyType_GenericAlloc', 'function')
|
||||
|
||||
|
||||
def test_cmember(app):
|
||||
text = ".. c:member:: PyObject* PyTypeObject.tp_bases"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree[1], addnodes.desc, desctype="member",
|
||||
domain="c", objtype="member", noindex=False)
|
||||
|
||||
entry = _get_obj(app, 'PyTypeObject.tp_bases')
|
||||
assert entry == ('index', 'c.PyTypeObject.tp_bases', 'member')
|
||||
|
||||
|
||||
def test_cvar(app):
|
||||
text = ".. c:var:: PyObject* PyClass_Type"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree[1], addnodes.desc, desctype="var",
|
||||
domain="c", objtype="var", noindex=False)
|
||||
|
||||
entry = _get_obj(app, 'PyClass_Type')
|
||||
assert entry == ('index', 'c.PyClass_Type', 'member')
|
||||
|
||||
|
||||
def test_noindexentry(app):
|
||||
text = (".. c:function:: void f()\n"
|
||||
".. c:function:: void g()\n"
|
||||
" :noindexentry:\n")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree, (addnodes.index, desc, addnodes.index, desc))
|
||||
assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C function)', 'c.f', '', None)])
|
||||
assert_node(doctree[2], addnodes.index, entries=[])
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-c-intersphinx', confoverrides={'nitpicky': True})
|
||||
def test_intersphinx(tempdir, app, status, warning):
|
||||
def test_domain_c_build_intersphinx(tempdir, app, status, warning):
|
||||
# a splitting of test_ids_vs_tags0 into the primary directives in a remote project,
|
||||
# and then the references in the test project
|
||||
origSource = """\
|
||||
@@ -728,3 +694,44 @@ _var c:member 1 index.html#c.$ -
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "index")
|
||||
assert len(ws) == 0
|
||||
|
||||
|
||||
def test_domain_c_parse_cfunction(app):
|
||||
text = (".. c:function:: PyObject* "
|
||||
"PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree[1], addnodes.desc, desctype="function",
|
||||
domain="c", objtype="function", noindex=False)
|
||||
|
||||
entry = _get_obj(app, 'PyType_GenericAlloc')
|
||||
assert entry == ('index', 'c.PyType_GenericAlloc', 'function')
|
||||
|
||||
|
||||
def test_domain_c_parse_cmember(app):
|
||||
text = ".. c:member:: PyObject* PyTypeObject.tp_bases"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree[1], addnodes.desc, desctype="member",
|
||||
domain="c", objtype="member", noindex=False)
|
||||
|
||||
entry = _get_obj(app, 'PyTypeObject.tp_bases')
|
||||
assert entry == ('index', 'c.PyTypeObject.tp_bases', 'member')
|
||||
|
||||
|
||||
def test_domain_c_parse_cvar(app):
|
||||
text = ".. c:var:: PyObject* PyClass_Type"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree[1], addnodes.desc, desctype="var",
|
||||
domain="c", objtype="var", noindex=False)
|
||||
|
||||
entry = _get_obj(app, 'PyClass_Type')
|
||||
assert entry == ('index', 'c.PyClass_Type', 'member')
|
||||
|
||||
|
||||
def test_domain_c_parse_noindexentry(app):
|
||||
text = (".. c:function:: void f()\n"
|
||||
".. c:function:: void g()\n"
|
||||
" :noindexentry:\n")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree, (addnodes.index, desc, addnodes.index, desc))
|
||||
assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C function)', 'c.f', '', None)])
|
||||
assert_node(doctree[2], addnodes.index, entries=[])
|
||||
|
||||
@@ -117,7 +117,7 @@ def check(name, input, idDict, output=None, key=None, asTextOutput=None):
|
||||
asTextOutput + ';' if asTextOutput is not None else None)
|
||||
|
||||
|
||||
def test_fundamental_types():
|
||||
def test_domain_cpp_ast_fundamental_types():
|
||||
# see https://en.cppreference.com/w/cpp/language/types
|
||||
for t, id_v2 in cppDomain._id_fundamental_v2.items():
|
||||
def makeIdV1():
|
||||
@@ -137,7 +137,7 @@ def test_fundamental_types():
|
||||
check("function", "void f(%s arg)" % t, {1: makeIdV1(), 2: makeIdV2()})
|
||||
|
||||
|
||||
def test_expressions():
|
||||
def test_domain_cpp_ast_expressions():
|
||||
def exprCheck(expr, id, id4=None):
|
||||
ids = 'IE1CIA%s_1aE'
|
||||
# call .format() on the expr to unescape double curly braces
|
||||
@@ -351,7 +351,7 @@ def test_expressions():
|
||||
exprCheck('a(b(c, 1 + d...)..., e(f..., g))', 'cl1aspcl1b1cspplL1E1dEcl1esp1f1gEE')
|
||||
|
||||
|
||||
def test_type_definitions():
|
||||
def test_domain_cpp_ast_type_definitions():
|
||||
check("type", "public bool b", {1: "b", 2: "1b"}, "{key}bool b", key='typedef')
|
||||
check("type", "{key}bool A::b", {1: "A::b", 2: "N1A1bE"}, key='typedef')
|
||||
check("type", "{key}bool *b", {1: "b", 2: "1b"}, key='typedef')
|
||||
@@ -396,7 +396,7 @@ def test_type_definitions():
|
||||
check('type', '{key}T = Q<A::operator bool>', {2: '1T'}, key='using')
|
||||
|
||||
|
||||
def test_concept_definitions():
|
||||
def test_domain_cpp_ast_concept_definitions():
|
||||
check('concept', 'template<typename Param> {key}A::B::Concept',
|
||||
{2: 'I0EN1A1B7ConceptE'})
|
||||
check('concept', 'template<typename A, typename B, typename ...C> {key}Foo',
|
||||
@@ -407,7 +407,7 @@ def test_concept_definitions():
|
||||
parse('concept', 'template<typename T> template<typename U> {key}Foo')
|
||||
|
||||
|
||||
def test_member_definitions():
|
||||
def test_domain_cpp_ast_member_definitions():
|
||||
check('member', ' const std::string & name = 42',
|
||||
{1: "name__ssCR", 2: "4name"}, output='const std::string &name = 42')
|
||||
check('member', ' const std::string & name', {1: "name__ssCR", 2: "4name"},
|
||||
@@ -436,7 +436,7 @@ def test_member_definitions():
|
||||
check('member', 'int b : 1 || new int{0}', {1: 'b__i', 2: '1b'})
|
||||
|
||||
|
||||
def test_function_definitions():
|
||||
def test_domain_cpp_ast_function_definitions():
|
||||
check('function', 'void f(volatile int)', {1: "f__iV", 2: "1fVi"})
|
||||
check('function', 'void f(std::size_t)', {1: "f__std::s", 2: "1fNSt6size_tE"})
|
||||
check('function', 'operator bool() const', {1: "castto-b-operatorC", 2: "NKcvbEv"})
|
||||
@@ -624,7 +624,7 @@ def test_function_definitions():
|
||||
check('function', 'void f(void (*p)(int, double), int i)', {2: '1fPFvidEi'})
|
||||
|
||||
|
||||
def test_operators():
|
||||
def test_domain_cpp_ast_operators():
|
||||
check('function', 'void operator new()', {1: "new-operator", 2: "nwv"})
|
||||
check('function', 'void operator new[]()', {1: "new-array-operator", 2: "nav"})
|
||||
check('function', 'void operator delete()', {1: "delete-operator", 2: "dlv"})
|
||||
@@ -684,14 +684,14 @@ def test_operators():
|
||||
check('function', 'void operator[]()', {1: "subscript-operator", 2: "ixv"})
|
||||
|
||||
|
||||
def test_nested_name():
|
||||
def test_domain_cpp_ast_nested_name():
|
||||
check('class', '{key}::A', {1: "A", 2: "1A"})
|
||||
check('class', '{key}::A::B', {1: "A::B", 2: "N1A1BE"})
|
||||
check('function', 'void f(::A a)', {1: "f__A", 2: "1f1A"})
|
||||
check('function', 'void f(::A::B a)', {1: "f__A::B", 2: "1fN1A1BE"})
|
||||
|
||||
|
||||
def test_class_definitions():
|
||||
def test_domain_cpp_ast_class_definitions():
|
||||
check('class', 'public A', {1: "A", 2: "1A"}, output='{key}A')
|
||||
check('class', 'private {key}A', {1: "A", 2: "1A"})
|
||||
check('class', '{key}A final', {1: 'A', 2: '1A'})
|
||||
@@ -722,11 +722,11 @@ def test_class_definitions():
|
||||
{2: 'I_DpiE1TIJX(Is)EEE', 3: 'I_DpiE1TIJX2IsEEE'})
|
||||
|
||||
|
||||
def test_union_definitions():
|
||||
def test_domain_cpp_ast_union_definitions():
|
||||
check('union', '{key}A', {2: "1A"})
|
||||
|
||||
|
||||
def test_enum_definitions():
|
||||
def test_domain_cpp_ast_enum_definitions():
|
||||
check('enum', '{key}A', {2: "1A"})
|
||||
check('enum', '{key}A : std::underlying_type<B>::type', {2: "1A"})
|
||||
check('enum', '{key}A : unsigned int', {2: "1A"})
|
||||
@@ -737,7 +737,7 @@ def test_enum_definitions():
|
||||
check('enumerator', '{key}A = std::numeric_limits<unsigned long>::max()', {2: "1A"})
|
||||
|
||||
|
||||
def test_anon_definitions():
|
||||
def test_domain_cpp_ast_anon_definitions():
|
||||
check('class', '@a', {3: "Ut1_a"}, asTextOutput='class [anonymous]')
|
||||
check('union', '@a', {3: "Ut1_a"}, asTextOutput='union [anonymous]')
|
||||
check('enum', '@a', {3: "Ut1_a"}, asTextOutput='enum [anonymous]')
|
||||
@@ -748,7 +748,7 @@ def test_anon_definitions():
|
||||
asTextOutput='int f(int [anonymous])')
|
||||
|
||||
|
||||
def test_templates():
|
||||
def test_domain_cpp_ast_templates():
|
||||
check('class', "A<T>", {2: "IE1AI1TE"}, output="template<> {key}A<T>")
|
||||
# first just check which objects support templating
|
||||
check('class', "template<> {key}A", {2: "IE1A"})
|
||||
@@ -854,7 +854,7 @@ def test_templates():
|
||||
check('type', 'template<C T = int&> {key}A', {2: 'I_1CE1A'}, key='using')
|
||||
|
||||
|
||||
def test_requires_clauses():
|
||||
def test_domain_cpp_ast_requires_clauses():
|
||||
check('function', 'template<typename T> requires A auto f() -> void requires B',
|
||||
{4: 'I0EIQaa1A1BE1fvv'})
|
||||
check('function', 'template<typename T> requires A || B or C void f()',
|
||||
@@ -863,7 +863,7 @@ def test_requires_clauses():
|
||||
{4: 'I0EIQooaa1A1Baa1C1DE1fvv'})
|
||||
|
||||
|
||||
def test_template_args():
|
||||
def test_domain_cpp_ast_template_args():
|
||||
# from breathe#218
|
||||
check('function',
|
||||
"template<typename F> "
|
||||
@@ -878,7 +878,7 @@ def test_template_args():
|
||||
key='using')
|
||||
|
||||
|
||||
def test_initializers():
|
||||
def test_domain_cpp_ast_initializers():
|
||||
idsMember = {1: 'v__T', 2: '1v'}
|
||||
idsFunction = {1: 'f__T', 2: '1f1T'}
|
||||
idsTemplate = {2: 'I_1TE1fv', 4: 'I_1TE1fvv'}
|
||||
@@ -912,7 +912,7 @@ def test_initializers():
|
||||
check('member', 'T v = T{}', idsMember)
|
||||
|
||||
|
||||
def test_attributes():
|
||||
def test_domain_cpp_ast_attributes():
|
||||
# style: C++
|
||||
check('member', '[[]] int f', {1: 'f__i', 2: '1f'})
|
||||
check('member', '[ [ ] ] int f', {1: 'f__i', 2: '1f'},
|
||||
@@ -960,7 +960,7 @@ def test_attributes():
|
||||
check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f', 2: '1fv'})
|
||||
|
||||
|
||||
def test_xref_parsing():
|
||||
def test_domain_cpp_ast_xref_parsing():
|
||||
def check(target):
|
||||
class Config:
|
||||
cpp_id_attributes = ["id_attr"]
|
||||
@@ -993,7 +993,7 @@ def filter_warnings(warning, file):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_cpp_multi_decl_lookup(app, status, warning):
|
||||
def test_domain_cpp_build_multi_decl_lookup(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "lookup-key-overload")
|
||||
assert len(ws) == 0
|
||||
@@ -1003,7 +1003,7 @@ def test_build_domain_cpp_multi_decl_lookup(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_cpp_warn_template_param_qualified_name(app, status, warning):
|
||||
def test_domain_cpp_build_warn_template_param_qualified_name(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "warn-template-param-qualified-name")
|
||||
assert len(ws) == 2
|
||||
@@ -1012,14 +1012,14 @@ def test_build_domain_cpp_warn_template_param_qualified_name(app, status, warnin
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_cpp_backslash_ok_true(app, status, warning):
|
||||
def test_domain_cpp_build_backslash_ok_true(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "backslash")
|
||||
assert len(ws) == 0
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_cpp_semicolon(app, status, warning):
|
||||
def test_domain_cpp_build_semicolon(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "semicolon")
|
||||
assert len(ws) == 0
|
||||
@@ -1027,7 +1027,7 @@ def test_build_domain_cpp_semicolon(app, status, warning):
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp',
|
||||
confoverrides={'nitpicky': True, 'strip_signature_backslash': True})
|
||||
def test_build_domain_cpp_backslash_ok_false(app, status, warning):
|
||||
def test_domain_cpp_build_backslash_ok_false(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "backslash")
|
||||
assert len(ws) == 1
|
||||
@@ -1035,7 +1035,7 @@ def test_build_domain_cpp_backslash_ok_false(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
||||
def test_build_domain_cpp_anon_dup_decl(app, status, warning):
|
||||
def test_domain_cpp_build_anon_dup_decl(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "anon-dup-decl")
|
||||
assert len(ws) == 2
|
||||
@@ -1044,7 +1044,7 @@ def test_build_domain_cpp_anon_dup_decl(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp')
|
||||
def test_build_domain_cpp_misuse_of_roles(app, status, warning):
|
||||
def test_domain_cpp_build_misuse_of_roles(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "roles-targets-ok")
|
||||
assert len(ws) == 0
|
||||
@@ -1092,7 +1092,7 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': True})
|
||||
def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, warning):
|
||||
def test_domain_cpp_build_with_add_function_parentheses_is_True(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
def check(spec, text, file):
|
||||
@@ -1133,7 +1133,7 @@ def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, war
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': False})
|
||||
def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, warning):
|
||||
def test_domain_cpp_build_with_add_function_parentheses_is_False(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
def check(spec, text, file):
|
||||
@@ -1174,7 +1174,7 @@ def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, wa
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp')
|
||||
def test_xref_consistency(app, status, warning):
|
||||
def test_domain_cpp_build_xref_consistency(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
test = 'xref_consistency.html'
|
||||
@@ -1237,33 +1237,15 @@ not found in `{test}`
|
||||
assert any_role.classes == texpr_role.content_classes['a'], expect
|
||||
|
||||
|
||||
def test_noindexentry(app):
|
||||
text = (".. cpp:function:: void f()\n"
|
||||
".. cpp:function:: void g()\n"
|
||||
" :noindexentry:\n")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree, (addnodes.index, desc, addnodes.index, desc))
|
||||
assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C++ function)', '_CPPv41fv', '', None)])
|
||||
assert_node(doctree[2], addnodes.index, entries=[])
|
||||
|
||||
|
||||
def test_mix_decl_duplicate(app, warning):
|
||||
# Issue 8270
|
||||
text = (".. cpp:struct:: A\n"
|
||||
".. cpp:function:: void A()\n"
|
||||
".. cpp:struct:: A\n")
|
||||
restructuredtext.parse(app, text)
|
||||
ws = warning.getvalue().split("\n")
|
||||
assert len(ws) == 5
|
||||
assert "index.rst:2: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[0]
|
||||
assert "Declaration is '.. cpp:function:: void A()'." in ws[1]
|
||||
assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[2]
|
||||
assert "Declaration is '.. cpp:struct:: A'." in ws[3]
|
||||
assert ws[4] == ""
|
||||
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
||||
def test_domain_cpp_build_field_role(app, status, warning):
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "field-role")
|
||||
assert len(ws) == 0
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp-intersphinx', confoverrides={'nitpicky': True})
|
||||
def test_intersphinx(tempdir, app, status, warning):
|
||||
def test_domain_cpp_build_intersphinx(tempdir, app, status, warning):
|
||||
origSource = """\
|
||||
.. cpp:class:: _class
|
||||
.. cpp:struct:: _struct
|
||||
@@ -1323,3 +1305,28 @@ _var cpp:member 1 index.html#_CPPv44$ -
|
||||
app.builder.build_all()
|
||||
ws = filter_warnings(warning, "index")
|
||||
assert len(ws) == 0
|
||||
|
||||
|
||||
def test_domain_cpp_parse_noindexentry(app):
|
||||
text = (".. cpp:function:: void f()\n"
|
||||
".. cpp:function:: void g()\n"
|
||||
" :noindexentry:\n")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree, (addnodes.index, desc, addnodes.index, desc))
|
||||
assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C++ function)', '_CPPv41fv', '', None)])
|
||||
assert_node(doctree[2], addnodes.index, entries=[])
|
||||
|
||||
|
||||
def test_domain_cpp_parse_mix_decl_duplicate(app, warning):
|
||||
# Issue 8270
|
||||
text = (".. cpp:struct:: A\n"
|
||||
".. cpp:function:: void A()\n"
|
||||
".. cpp:struct:: A\n")
|
||||
restructuredtext.parse(app, text)
|
||||
ws = warning.getvalue().split("\n")
|
||||
assert len(ws) == 5
|
||||
assert "index.rst:2: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[0]
|
||||
assert "Declaration is '.. cpp:function:: void A()'." in ws[1]
|
||||
assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[2]
|
||||
assert "Declaration is '.. cpp:struct:: A'." in ws[3]
|
||||
assert ws[4] == ""
|
||||
|
||||
@@ -477,23 +477,11 @@ def test_optional_pyfunction_signature(app):
|
||||
|
||||
|
||||
def test_pyexception_signature(app):
|
||||
text = ".. py:exception:: exceptions.IOError"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree, (addnodes.index,
|
||||
[desc, ([desc_signature, ([desc_annotation, "exception "],
|
||||
[desc_addname, "exceptions."],
|
||||
[desc_name, "IOError"])],
|
||||
desc_content)]))
|
||||
assert_node(doctree[1], desc, desctype="exception",
|
||||
domain="py", objtype="exception", noindex=False)
|
||||
|
||||
|
||||
def test_exceptions_module_is_ignored(app):
|
||||
text = (".. py:exception:: IOError\n"
|
||||
" :module: exceptions\n")
|
||||
text = ".. py:exception:: builtins.IOError"
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree, (addnodes.index,
|
||||
[desc, ([desc_signature, ([desc_annotation, "exception "],
|
||||
[desc_addname, "builtins."],
|
||||
[desc_name, "IOError"])],
|
||||
desc_content)]))
|
||||
assert_node(doctree[1], desc, desctype="exception",
|
||||
@@ -922,7 +910,8 @@ def test_info_field_list(app):
|
||||
" :param age: blah blah\n"
|
||||
" :type age: int\n"
|
||||
" :param items: blah blah\n"
|
||||
" :type items: Tuple[str, ...]\n")
|
||||
" :type items: Tuple[str, ...]\n"
|
||||
" :param Dict[str, str] params: blah blah\n")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
print(doctree)
|
||||
|
||||
@@ -936,6 +925,7 @@ def test_info_field_list(app):
|
||||
assert_node(doctree[3][1][0][0],
|
||||
([nodes.field_name, "Parameters"],
|
||||
[nodes.field_body, nodes.bullet_list, ([nodes.list_item, nodes.paragraph],
|
||||
[nodes.list_item, nodes.paragraph],
|
||||
[nodes.list_item, nodes.paragraph],
|
||||
[nodes.list_item, nodes.paragraph])]))
|
||||
|
||||
@@ -983,6 +973,63 @@ def test_info_field_list(app):
|
||||
refdomain="py", reftype="class", reftarget="str",
|
||||
**{"py:module": "example", "py:class": "Class"})
|
||||
|
||||
# :param Dict[str, str] params:
|
||||
assert_node(doctree[3][1][0][0][1][0][3][0],
|
||||
([addnodes.literal_strong, "params"],
|
||||
" (",
|
||||
[pending_xref, addnodes.literal_emphasis, "Dict"],
|
||||
[addnodes.literal_emphasis, "["],
|
||||
[pending_xref, addnodes.literal_emphasis, "str"],
|
||||
[addnodes.literal_emphasis, ", "],
|
||||
[pending_xref, addnodes.literal_emphasis, "str"],
|
||||
[addnodes.literal_emphasis, "]"],
|
||||
")",
|
||||
" -- ",
|
||||
"blah blah"))
|
||||
assert_node(doctree[3][1][0][0][1][0][3][0][2], pending_xref,
|
||||
refdomain="py", reftype="class", reftarget="Dict",
|
||||
**{"py:module": "example", "py:class": "Class"})
|
||||
assert_node(doctree[3][1][0][0][1][0][3][0][4], pending_xref,
|
||||
refdomain="py", reftype="class", reftarget="str",
|
||||
**{"py:module": "example", "py:class": "Class"})
|
||||
assert_node(doctree[3][1][0][0][1][0][3][0][6], pending_xref,
|
||||
refdomain="py", reftype="class", reftarget="str",
|
||||
**{"py:module": "example", "py:class": "Class"})
|
||||
|
||||
|
||||
def test_info_field_list_piped_type(app):
|
||||
text = (".. py:module:: example\n"
|
||||
".. py:class:: Class\n"
|
||||
"\n"
|
||||
" :param age: blah blah\n"
|
||||
" :type age: int | str\n")
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
|
||||
assert_node(doctree,
|
||||
(nodes.target,
|
||||
addnodes.index,
|
||||
addnodes.index,
|
||||
[desc, ([desc_signature, ([desc_annotation, "class "],
|
||||
[desc_addname, "example."],
|
||||
[desc_name, "Class"])],
|
||||
[desc_content, nodes.field_list, nodes.field, (nodes.field_name,
|
||||
nodes.field_body)])]))
|
||||
assert_node(doctree[3][1][0][0][1],
|
||||
([nodes.paragraph, ([addnodes.literal_strong, "age"],
|
||||
" (",
|
||||
[pending_xref, addnodes.literal_emphasis, "int"],
|
||||
[addnodes.literal_emphasis, " | "],
|
||||
[pending_xref, addnodes.literal_emphasis, "str"],
|
||||
")",
|
||||
" -- ",
|
||||
"blah blah")],))
|
||||
assert_node(doctree[3][1][0][0][1][0][2], pending_xref,
|
||||
refdomain="py", reftype="class", reftarget="int",
|
||||
**{"py:module": "example", "py:class": "Class"})
|
||||
assert_node(doctree[3][1][0][0][1][0][4], pending_xref,
|
||||
refdomain="py", reftype="class", reftarget="str",
|
||||
**{"py:module": "example", "py:class": "Class"})
|
||||
|
||||
|
||||
def test_info_field_list_var(app):
|
||||
text = (".. py:class:: Class\n"
|
||||
@@ -1100,6 +1147,9 @@ def test_python_python_use_unqualified_type_names(app, status, warning):
|
||||
assert ('<span class="n"><a class="reference internal" href="#foo.Name" title="foo.Name">'
|
||||
'<span class="pre">Name</span></a></span>' in content)
|
||||
assert '<span class="n"><span class="pre">foo.Age</span></span>' in content
|
||||
assert ('<p><strong>name</strong> (<a class="reference internal" href="#foo.Name" '
|
||||
'title="foo.Name"><em>Name</em></a>) – blah blah</p>' in content)
|
||||
assert '<p><strong>age</strong> (<em>foo.Age</em>) – blah blah</p>' in content
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='domain-py-python_use_unqualified_type_names',
|
||||
@@ -1110,6 +1160,9 @@ def test_python_python_use_unqualified_type_names_disabled(app, status, warning)
|
||||
assert ('<span class="n"><a class="reference internal" href="#foo.Name" title="foo.Name">'
|
||||
'<span class="pre">foo.Name</span></a></span>' in content)
|
||||
assert '<span class="n"><span class="pre">foo.Age</span></span>' in content
|
||||
assert ('<p><strong>name</strong> (<a class="reference internal" href="#foo.Name" '
|
||||
'title="foo.Name"><em>foo.Name</em></a>) – blah blah</p>' in content)
|
||||
assert '<p><strong>age</strong> (<em>foo.Age</em>) – blah blah</p>' in content
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='domain-py-xref-warning')
|
||||
|
||||
@@ -324,6 +324,23 @@ def test_cmdoption(app):
|
||||
assert domain.progoptions[('ls', '-l')] == ('index', 'cmdoption-ls-l')
|
||||
|
||||
|
||||
def test_cmdoption_for_None(app):
|
||||
text = (".. program:: ls\n"
|
||||
".. program:: None\n"
|
||||
"\n"
|
||||
".. option:: -l\n")
|
||||
domain = app.env.get_domain('std')
|
||||
doctree = restructuredtext.parse(app, text)
|
||||
assert_node(doctree, (addnodes.index,
|
||||
[desc, ([desc_signature, ([desc_name, "-l"],
|
||||
[desc_addname, ()])],
|
||||
[desc_content, ()])]))
|
||||
assert_node(doctree[0], addnodes.index,
|
||||
entries=[('pair', 'command line option; -l', 'cmdoption-l', '', None)])
|
||||
assert (None, '-l') in domain.progoptions
|
||||
assert domain.progoptions[(None, '-l')] == ('index', 'cmdoption-l')
|
||||
|
||||
|
||||
def test_multiple_cmdoptions(app):
|
||||
text = (".. program:: cmd\n"
|
||||
"\n"
|
||||
|
||||
@@ -735,6 +735,34 @@ def test_autodoc_undoc_members(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_undoc_members_for_metadata_only(app):
|
||||
# metadata only member is not displayed
|
||||
options = {"members": None}
|
||||
actual = do_autodoc(app, 'module', 'target.metadata', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.metadata',
|
||||
'',
|
||||
]
|
||||
|
||||
# metadata only member is displayed when undoc-member given
|
||||
options = {"members": None,
|
||||
"undoc-members": None}
|
||||
actual = do_autodoc(app, 'module', 'target.metadata', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.metadata',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: foo()',
|
||||
' :module: target.metadata',
|
||||
'',
|
||||
' :meta metadata-only-docstring:',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_inherited_members(app):
|
||||
options = {"members": None,
|
||||
@@ -2080,6 +2108,7 @@ def test_singledispatch(app):
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
@@ -2107,6 +2136,7 @@ def test_singledispatchmethod(app):
|
||||
'',
|
||||
'',
|
||||
' .. py:method:: Foo.meth(arg, kwarg=None)',
|
||||
' Foo.meth(arg: float, kwarg=None)',
|
||||
' Foo.meth(arg: int, kwarg=None)',
|
||||
' Foo.meth(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatchmethod',
|
||||
@@ -2125,6 +2155,7 @@ def test_singledispatchmethod_automethod(app):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:method:: Foo.meth(arg, kwarg=None)',
|
||||
' Foo.meth(arg: float, kwarg=None)',
|
||||
' Foo.meth(arg: int, kwarg=None)',
|
||||
' Foo.meth(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatchmethod',
|
||||
|
||||
@@ -100,6 +100,17 @@ def test_autoattribute_instance_variable_in_alias(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_instance_variable_without_comment(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.instance_variable.Bar.attr4')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Bar.attr4',
|
||||
' :module: target.instance_variable',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_slots_variable_list(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.slots.Foo.attr')
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"""
|
||||
|
||||
import sys
|
||||
from typing import List, Union
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -264,6 +265,94 @@ def test_show_inheritance_for_subclass_of_generic_type(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_process_bases(app):
|
||||
def autodoc_process_bases(app, name, obj, options, bases):
|
||||
assert name == 'target.classes.Quux'
|
||||
assert obj.__module__ == 'target.classes'
|
||||
assert obj.__name__ == 'Quux'
|
||||
assert options == {'show-inheritance': True,
|
||||
'members': []}
|
||||
assert bases == [List[Union[int, float]]]
|
||||
|
||||
bases.pop()
|
||||
bases.extend([int, str])
|
||||
|
||||
app.connect('autodoc-process-bases', autodoc_process_bases)
|
||||
|
||||
options = {'show-inheritance': None}
|
||||
actual = do_autodoc(app, 'class', 'target.classes.Quux', options)
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Quux(*args, **kwds)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
' Bases: :class:`int`, :class:`str`',
|
||||
'',
|
||||
' A subclass of List[Union[int, float]]',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Quux(iterable=(), /)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
' Bases: :class:`int`, :class:`str`',
|
||||
'',
|
||||
' A subclass of List[Union[int, float]]',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_class_doc_from_class(app):
|
||||
options = {"members": None,
|
||||
"class-doc-from": "class"}
|
||||
actual = do_autodoc(app, 'class', 'target.autoclass_content.C', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: C()',
|
||||
' :module: target.autoclass_content',
|
||||
'',
|
||||
' A class having __init__, no __new__',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_class_doc_from_init(app):
|
||||
options = {"members": None,
|
||||
"class-doc-from": "init"}
|
||||
actual = do_autodoc(app, 'class', 'target.autoclass_content.C', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: C()',
|
||||
' :module: target.autoclass_content',
|
||||
'',
|
||||
' __init__ docstring',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_class_doc_from_both(app):
|
||||
options = {"members": None,
|
||||
"class-doc-from": "both"}
|
||||
actual = do_autodoc(app, 'class', 'target.autoclass_content.C', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: C()',
|
||||
' :module: target.autoclass_content',
|
||||
'',
|
||||
' A class having __init__, no __new__',
|
||||
'',
|
||||
' __init__ docstring',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
def test_class_alias(app):
|
||||
def autodoc_process_docstring(*args):
|
||||
"""A handler always raises an error.
|
||||
@@ -280,3 +369,15 @@ def test_class_alias(app):
|
||||
'',
|
||||
' alias of :class:`target.classes.Foo`',
|
||||
]
|
||||
|
||||
|
||||
def test_class_alias_having_doccomment(app):
|
||||
actual = do_autodoc(app, 'class', 'target.classes.OtherAlias')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: OtherAlias',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
]
|
||||
|
||||
@@ -119,6 +119,7 @@ def test_singledispatch(app):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
|
||||
@@ -29,6 +29,95 @@ def test_empty_all(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_automodule(app):
|
||||
options = {'members': None}
|
||||
actual = do_autodoc(app, 'module', 'target.module', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.module',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: annotated',
|
||||
' :module: target.module',
|
||||
' :type: int',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: documented',
|
||||
' :module: target.module',
|
||||
' :value: 1',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_automodule_undoc_members(app):
|
||||
options = {'members': None,
|
||||
'undoc-members': None}
|
||||
actual = do_autodoc(app, 'module', 'target.module', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.module',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: annotated',
|
||||
' :module: target.module',
|
||||
' :type: int',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: documented',
|
||||
' :module: target.module',
|
||||
' :value: 1',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: undoc_annotated',
|
||||
' :module: target.module',
|
||||
' :type: int',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_automodule_special_members(app):
|
||||
options = {'members': None,
|
||||
'special-members': None}
|
||||
actual = do_autodoc(app, 'module', 'target.module', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.module',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: __documented_special__',
|
||||
' :module: target.module',
|
||||
' :value: 1',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: annotated',
|
||||
' :module: target.module',
|
||||
' :type: int',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: documented',
|
||||
' :module: target.module',
|
||||
' :value: 1',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc',
|
||||
confoverrides={'autodoc_mock_imports': ['missing_module',
|
||||
'missing_package1',
|
||||
|
||||
@@ -140,6 +140,57 @@ def test_autoclass_content_init(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_class_signature_mixed(app):
|
||||
app.config.autodoc_class_signature = 'mixed'
|
||||
options = {"members": None,
|
||||
"undoc-members": None}
|
||||
actual = do_autodoc(app, 'class', 'target.classes.Bar', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Bar(x, y)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_class_signature_separated_init(app):
|
||||
app.config.autodoc_class_signature = 'separated'
|
||||
options = {"members": None,
|
||||
"undoc-members": None}
|
||||
actual = do_autodoc(app, 'class', 'target.classes.Bar', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Bar',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
'',
|
||||
' .. py:method:: Bar.__init__(x, y)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_class_signature_separated_new(app):
|
||||
app.config.autodoc_class_signature = 'separated'
|
||||
options = {"members": None,
|
||||
"undoc-members": None}
|
||||
actual = do_autodoc(app, 'class', 'target.classes.Baz', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Baz',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
'',
|
||||
' .. py:method:: Baz.__new__(cls, x, y)',
|
||||
' :module: target.classes',
|
||||
' :staticmethod:',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoclass_content_both(app):
|
||||
app.config.autoclass_content = 'both'
|
||||
@@ -695,6 +746,14 @@ def test_autodoc_typehints_description(app):
|
||||
' Tuple[int, int]\n'
|
||||
in context)
|
||||
|
||||
# Overloads still get displyed in the signature
|
||||
assert ('target.overload.sum(x: int, y: int = 0) -> int\n'
|
||||
'target.overload.sum(x: float, y: float = 0.0) -> float\n'
|
||||
'target.overload.sum(x: str, y: str = None) -> str\n'
|
||||
'\n'
|
||||
' docstring\n'
|
||||
in context)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('text', testroot='ext-autodoc',
|
||||
confoverrides={'autodoc_typehints': "description",
|
||||
@@ -787,32 +846,72 @@ def test_autodoc_typehints_description_for_invalid_node(app):
|
||||
restructuredtext.parse(app, text) # raises no error
|
||||
|
||||
|
||||
@pytest.mark.sphinx('text', testroot='ext-autodoc',
|
||||
confoverrides={'autodoc_typehints': "both"})
|
||||
def test_autodoc_typehints_both(app):
|
||||
(app.srcdir / 'index.rst').write_text(
|
||||
'.. autofunction:: target.typehints.incr\n'
|
||||
'\n'
|
||||
'.. autofunction:: target.typehints.tuple_args\n'
|
||||
'\n'
|
||||
'.. autofunction:: target.overload.sum\n'
|
||||
)
|
||||
app.build()
|
||||
context = (app.outdir / 'index.txt').read_text()
|
||||
assert ('target.typehints.incr(a: int, b: int = 1) -> int\n'
|
||||
'\n'
|
||||
' Parameters:\n'
|
||||
' * **a** (*int*) --\n'
|
||||
'\n'
|
||||
' * **b** (*int*) --\n'
|
||||
'\n'
|
||||
' Return type:\n'
|
||||
' int\n'
|
||||
in context)
|
||||
assert ('target.typehints.tuple_args(x: Tuple[int, Union[int, str]]) -> Tuple[int, int]\n'
|
||||
'\n'
|
||||
' Parameters:\n'
|
||||
' **x** (*Tuple**[**int**, **Union**[**int**, **str**]**]*) --\n'
|
||||
'\n'
|
||||
' Return type:\n'
|
||||
' Tuple[int, int]\n'
|
||||
in context)
|
||||
|
||||
# Overloads still get displyed in the signature
|
||||
assert ('target.overload.sum(x: int, y: int = 0) -> int\n'
|
||||
'target.overload.sum(x: float, y: float = 0.0) -> float\n'
|
||||
'target.overload.sum(x: str, y: str = None) -> str\n'
|
||||
'\n'
|
||||
' docstring\n'
|
||||
in context)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx('text', testroot='ext-autodoc')
|
||||
def test_autodoc_type_aliases(app):
|
||||
# default
|
||||
options = {"members": None}
|
||||
actual = do_autodoc(app, 'module', 'target.annotations', options)
|
||||
actual = do_autodoc(app, 'module', 'target.autodoc_type_aliases', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.annotations',
|
||||
'.. py:module:: target.autodoc_type_aliases',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: Foo()',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr1',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: int',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr2',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: int',
|
||||
'',
|
||||
' docstring',
|
||||
@@ -820,26 +919,32 @@ def test_autodoc_type_aliases(app):
|
||||
'',
|
||||
'.. py:function:: mult(x: int, y: int) -> int',
|
||||
' mult(x: float, y: float) -> float',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: read(r: _io.BytesIO) -> _io.StringIO',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: sum(x: int, y: int) -> int',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: variable',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: int',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: variable2',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: int',
|
||||
' :value: None',
|
||||
'',
|
||||
@@ -848,28 +953,29 @@ def test_autodoc_type_aliases(app):
|
||||
]
|
||||
|
||||
# define aliases
|
||||
app.config.autodoc_type_aliases = {'myint': 'myint'}
|
||||
actual = do_autodoc(app, 'module', 'target.annotations', options)
|
||||
app.config.autodoc_type_aliases = {'myint': 'myint',
|
||||
'io.StringIO': 'my.module.StringIO'}
|
||||
actual = do_autodoc(app, 'module', 'target.autodoc_type_aliases', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.annotations',
|
||||
'.. py:module:: target.autodoc_type_aliases',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: Foo()',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr1',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: myint',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Foo.attr2',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: myint',
|
||||
'',
|
||||
' docstring',
|
||||
@@ -877,26 +983,32 @@ def test_autodoc_type_aliases(app):
|
||||
'',
|
||||
'.. py:function:: mult(x: myint, y: myint) -> myint',
|
||||
' mult(x: float, y: float) -> float',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: read(r: _io.BytesIO) -> my.module.StringIO',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: sum(x: myint, y: myint) -> myint',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: variable',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: myint',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: variable2',
|
||||
' :module: target.annotations',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: myint',
|
||||
' :value: None',
|
||||
'',
|
||||
@@ -911,10 +1023,10 @@ def test_autodoc_type_aliases(app):
|
||||
confoverrides={'autodoc_typehints': "description",
|
||||
'autodoc_type_aliases': {'myint': 'myint'}})
|
||||
def test_autodoc_typehints_description_and_type_aliases(app):
|
||||
(app.srcdir / 'annotations.rst').write_text('.. autofunction:: target.annotations.sum')
|
||||
(app.srcdir / 'autodoc_type_aliases.rst').write_text('.. autofunction:: target.autodoc_type_aliases.sum')
|
||||
app.build()
|
||||
context = (app.outdir / 'annotations.txt').read_text()
|
||||
assert ('target.annotations.sum(x, y)\n'
|
||||
context = (app.outdir / 'autodoc_type_aliases.txt').read_text()
|
||||
assert ('target.autodoc_type_aliases.sum(x, y)\n'
|
||||
'\n'
|
||||
' docstring\n'
|
||||
'\n'
|
||||
|
||||
@@ -161,6 +161,7 @@ def test_get_items_summary(make_app, app_params):
|
||||
'emptyLine': "This is the real summary",
|
||||
'module_attr': 'This is a module attribute',
|
||||
'C.class_attr': 'This is a class attribute',
|
||||
'C.instance_attr': 'This is an instance attribute',
|
||||
'C.prop_attr1': 'This is a function docstring',
|
||||
'C.prop_attr2': 'This is a attribute docstring',
|
||||
'C.C2': 'This is a nested inner class docstring',
|
||||
@@ -329,6 +330,7 @@ def test_autosummary_generate(app, status, warning):
|
||||
' ~Foo.CONSTANT3\n'
|
||||
' ~Foo.CONSTANT4\n'
|
||||
' ~Foo.baz\n'
|
||||
' ~Foo.value\n'
|
||||
' \n' in Foo)
|
||||
|
||||
FooBar = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.Bar.rst').read_text()
|
||||
|
||||
@@ -196,14 +196,6 @@ def test_missing_reference_pydomain(tempdir, app, status, warning):
|
||||
rn = missing_reference(app, app.env, node, contnode)
|
||||
assert rn.astext() == 'Foo.bar'
|
||||
|
||||
# pending_xref_condition="resolved"
|
||||
node = addnodes.pending_xref('', reftarget='Foo.bar', refdomain='py', reftype='attr')
|
||||
node['py:module'] = 'module1'
|
||||
node += addnodes.pending_xref_condition('', 'Foo.bar', condition='resolved')
|
||||
node += addnodes.pending_xref_condition('', 'module1.Foo.bar', condition='*')
|
||||
rn = missing_reference(app, app.env, node, nodes.Text('dummy-cont-node'))
|
||||
assert rn.astext() == 'Foo.bar'
|
||||
|
||||
|
||||
def test_missing_reference_stddomain(tempdir, app, status, warning):
|
||||
inv_file = tempdir / 'inventory'
|
||||
|
||||
@@ -410,7 +410,7 @@ def test_text_admonitions(app):
|
||||
app.build()
|
||||
# --- admonitions
|
||||
# #1206: gettext did not translate admonition directive's title
|
||||
# seealso: http://docutils.sourceforge.net/docs/ref/rst/directives.html#admonitions
|
||||
# seealso: https://docutils.sourceforge.io/docs/ref/rst/directives.html#admonitions
|
||||
result = (app.outdir / 'admonitions.txt').read_text()
|
||||
directives = (
|
||||
"attention", "caution", "danger", "error", "hint",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"""
|
||||
|
||||
# adapted from an example of bibliographic metadata at
|
||||
# http://docutils.sourceforge.net/docs/user/rst/demo.txt
|
||||
# https://docutils.sourceforge.io/docs/user/rst/demo.txt
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -8,31 +8,48 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.util.docstrings import extract_metadata, prepare_commentdoc, prepare_docstring
|
||||
from sphinx.util.docstrings import prepare_commentdoc, prepare_docstring, separate_metadata
|
||||
|
||||
|
||||
def test_extract_metadata():
|
||||
metadata = extract_metadata(":meta foo: bar\n"
|
||||
":meta baz:\n")
|
||||
def test_separate_metadata():
|
||||
# metadata only
|
||||
text = (":meta foo: bar\n"
|
||||
":meta baz:\n")
|
||||
docstring, metadata = separate_metadata(text)
|
||||
assert docstring == ''
|
||||
assert metadata == {'foo': 'bar', 'baz': ''}
|
||||
|
||||
# non metadata field list item
|
||||
text = (":meta foo: bar\n"
|
||||
":param baz:\n")
|
||||
docstring, metadata = separate_metadata(text)
|
||||
assert docstring == ':param baz:\n'
|
||||
assert metadata == {'foo': 'bar'}
|
||||
|
||||
# field_list like text following just after paragaph is not a field_list
|
||||
metadata = extract_metadata("blah blah blah\n"
|
||||
":meta foo: bar\n"
|
||||
":meta baz:\n")
|
||||
text = ("blah blah blah\n"
|
||||
":meta foo: bar\n"
|
||||
":meta baz:\n")
|
||||
docstring, metadata = separate_metadata(text)
|
||||
assert docstring == text
|
||||
assert metadata == {}
|
||||
|
||||
# field_list like text following after blank line is a field_list
|
||||
metadata = extract_metadata("blah blah blah\n"
|
||||
"\n"
|
||||
":meta foo: bar\n"
|
||||
":meta baz:\n")
|
||||
text = ("blah blah blah\n"
|
||||
"\n"
|
||||
":meta foo: bar\n"
|
||||
":meta baz:\n")
|
||||
docstring, metadata = separate_metadata(text)
|
||||
assert docstring == "blah blah blah\n\n"
|
||||
assert metadata == {'foo': 'bar', 'baz': ''}
|
||||
|
||||
# non field_list item breaks field_list
|
||||
metadata = extract_metadata(":meta foo: bar\n"
|
||||
"blah blah blah\n"
|
||||
":meta baz:\n")
|
||||
text = (":meta foo: bar\n"
|
||||
"blah blah blah\n"
|
||||
":meta baz:\n")
|
||||
docstring, metadata = separate_metadata(text)
|
||||
assert docstring == ("blah blah blah\n"
|
||||
":meta baz:\n")
|
||||
assert metadata == {'foo': 'bar'}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
import ast
|
||||
import datetime
|
||||
import enum
|
||||
import functools
|
||||
import sys
|
||||
import types
|
||||
@@ -19,7 +20,26 @@ import _testcapi
|
||||
import pytest
|
||||
|
||||
from sphinx.util import inspect
|
||||
from sphinx.util.inspect import stringify_signature
|
||||
from sphinx.util.inspect import TypeAliasNamespace, stringify_signature
|
||||
|
||||
|
||||
def test_TypeAliasNamespace():
|
||||
import logging.config
|
||||
type_alias = TypeAliasNamespace({'logging.Filter': 'MyFilter',
|
||||
'logging.Handler': 'MyHandler',
|
||||
'logging.handlers.SyslogHandler': 'MySyslogHandler'})
|
||||
|
||||
assert type_alias['logging'].Filter == 'MyFilter'
|
||||
assert type_alias['logging'].Handler == 'MyHandler'
|
||||
assert type_alias['logging'].handlers.SyslogHandler == 'MySyslogHandler'
|
||||
assert type_alias['logging'].Logger == logging.Logger
|
||||
assert type_alias['logging'].config == logging.config
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
assert type_alias['log']
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
assert type_alias['unknown']
|
||||
|
||||
|
||||
def test_signature():
|
||||
@@ -183,10 +203,7 @@ def test_signature_annotations():
|
||||
|
||||
# Instance annotations
|
||||
sig = inspect.signature(f11)
|
||||
if sys.version_info < (3, 10):
|
||||
assert stringify_signature(sig) == '(x: CustomAnnotation, y: 123) -> None'
|
||||
else:
|
||||
assert stringify_signature(sig) == '(x: CustomAnnotation(), y: 123) -> None'
|
||||
assert stringify_signature(sig) == '(x: CustomAnnotation, y: 123) -> None'
|
||||
|
||||
# tuple with more than two items
|
||||
sig = inspect.signature(f12)
|
||||
@@ -500,6 +517,14 @@ def test_dict_customtype():
|
||||
assert "<CustomType(2)>: 2" in description
|
||||
|
||||
|
||||
def test_object_description_enum():
|
||||
class MyEnum(enum.Enum):
|
||||
FOO = 1
|
||||
BAR = 2
|
||||
|
||||
assert inspect.object_description(MyEnum.FOO) == "MyEnum.FOO"
|
||||
|
||||
|
||||
def test_getslots():
|
||||
class Foo:
|
||||
pass
|
||||
@@ -658,7 +683,10 @@ def test_unpartial():
|
||||
def test_getdoc_inherited_decorated_method():
|
||||
class Foo:
|
||||
def meth(self):
|
||||
"""docstring."""
|
||||
"""
|
||||
docstring
|
||||
indented text
|
||||
"""
|
||||
|
||||
class Bar(Foo):
|
||||
@functools.lru_cache()
|
||||
@@ -667,7 +695,7 @@ def test_getdoc_inherited_decorated_method():
|
||||
pass
|
||||
|
||||
assert inspect.getdoc(Bar.meth, getattr, False, Bar, "meth") is None
|
||||
assert inspect.getdoc(Bar.meth, getattr, True, Bar, "meth") == "docstring."
|
||||
assert inspect.getdoc(Bar.meth, getattr, True, Bar, "meth") == Foo.meth.__doc__
|
||||
|
||||
|
||||
def test_is_builtin_class_method():
|
||||
|
||||
@@ -133,6 +133,12 @@ def test_restify_type_ForwardRef():
|
||||
assert restify(ForwardRef("myint")) == ":class:`myint`"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||
def test_restify_type_Literal():
|
||||
from typing import Literal # type: ignore
|
||||
assert restify(Literal[1, "2", "\r"]) == ":obj:`~typing.Literal`\\ [1, '2', '\\r']"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 10), reason='python 3.10+ is required.')
|
||||
def test_restify_type_union_operator():
|
||||
assert restify(int | None) == "Optional[:class:`int`]" # type: ignore
|
||||
@@ -237,6 +243,12 @@ def test_stringify_type_hints_alias():
|
||||
assert stringify(MyTuple) == "Tuple[str, str]" # type: ignore
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||
def test_stringify_type_Literal():
|
||||
from typing import Literal # type: ignore
|
||||
assert stringify(Literal[1, "2", "\r"]) == "Literal[1, '2', '\\r']"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 10), reason='python 3.10+ is required.')
|
||||
def test_stringify_type_union_operator():
|
||||
assert stringify(int | None) == "Optional[int]" # type: ignore
|
||||
|
||||
@@ -15,7 +15,7 @@ from sphinx.writers.latex import rstdim_to_latexdim
|
||||
|
||||
def test_rstdim_to_latexdim():
|
||||
# Length units docutils supported
|
||||
# http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#length-units
|
||||
# https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units
|
||||
assert rstdim_to_latexdim('160em') == '160em'
|
||||
assert rstdim_to_latexdim('160px') == '160\\sphinxpxdimen'
|
||||
assert rstdim_to_latexdim('160in') == '160in'
|
||||
|
||||
Reference in New Issue
Block a user