mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
In development of 3.0, Sphinx starts to obey to the rule of "Identifier Normalization" of docutils. This extends it to allow dots(".") and underscores("_") for node identifier. It allows Sphinx to generate node identifier from source string as possible as it is (bacause dots and underscores are usually used in many programming langauges). This change will keep not to break hyperlinks as possible.
705 lines
33 KiB
Python
705 lines
33 KiB
Python
"""
|
|
test_domain_py
|
|
~~~~~~~~~~~~~~
|
|
|
|
Tests the Python Domain
|
|
|
|
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
|
|
:license: BSD, see LICENSE for details.
|
|
"""
|
|
|
|
import sys
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
from docutils import nodes
|
|
|
|
from sphinx import addnodes
|
|
from sphinx.addnodes import (
|
|
desc, desc_addname, desc_annotation, desc_content, desc_name, desc_optional,
|
|
desc_parameter, desc_parameterlist, desc_returns, desc_signature,
|
|
desc_sig_name, desc_sig_operator, desc_sig_punctuation,
|
|
)
|
|
from sphinx.domains import IndexEntry
|
|
from sphinx.domains.python import (
|
|
py_sig_re, _pseudo_parse_arglist, PythonDomain, PythonModuleIndex
|
|
)
|
|
from sphinx.testing import restructuredtext
|
|
from sphinx.testing.util import assert_node
|
|
|
|
|
|
def parse(sig):
|
|
m = py_sig_re.match(sig)
|
|
if m is None:
|
|
raise ValueError
|
|
name_prefix, name, arglist, retann = m.groups()
|
|
signode = addnodes.desc_signature(sig, '')
|
|
_pseudo_parse_arglist(signode, arglist)
|
|
return signode.astext()
|
|
|
|
|
|
def test_function_signatures():
|
|
rv = parse('func(a=1) -> int object')
|
|
assert rv == 'a=1'
|
|
|
|
rv = parse('func(a=1, [b=None])')
|
|
assert rv == 'a=1, [b=None]'
|
|
|
|
rv = parse('func(a=1[, b=None])')
|
|
assert rv == 'a=1, [b=None]'
|
|
|
|
rv = parse("compile(source : string, filename, symbol='file')")
|
|
assert rv == "source : string, filename, symbol='file'"
|
|
|
|
rv = parse('func(a=[], [b=None])')
|
|
assert rv == 'a=[], [b=None]'
|
|
|
|
rv = parse('func(a=[][, b=None])')
|
|
assert rv == 'a=[], [b=None]'
|
|
|
|
|
|
@pytest.mark.sphinx('dummy', testroot='domain-py')
|
|
def test_domain_py_xrefs(app, status, warning):
|
|
"""Domain objects have correct prefixes when looking up xrefs"""
|
|
app.builder.build_all()
|
|
|
|
def assert_refnode(node, module_name, class_name, target, reftype=None,
|
|
domain='py'):
|
|
attributes = {
|
|
'refdomain': domain,
|
|
'reftarget': target,
|
|
}
|
|
if reftype is not None:
|
|
attributes['reftype'] = reftype
|
|
if module_name is not False:
|
|
attributes['py:module'] = module_name
|
|
if class_name is not False:
|
|
attributes['py:class'] = class_name
|
|
assert_node(node, **attributes)
|
|
|
|
doctree = app.env.get_doctree('roles')
|
|
refnodes = list(doctree.traverse(addnodes.pending_xref))
|
|
assert_refnode(refnodes[0], None, None, 'TopLevel', 'class')
|
|
assert_refnode(refnodes[1], None, None, 'top_level', 'meth')
|
|
assert_refnode(refnodes[2], None, 'NestedParentA', 'child_1', 'meth')
|
|
assert_refnode(refnodes[3], None, 'NestedParentA', 'NestedChildA.subchild_2', 'meth')
|
|
assert_refnode(refnodes[4], None, 'NestedParentA', 'child_2', 'meth')
|
|
assert_refnode(refnodes[5], False, 'NestedParentA', 'any_child', domain='')
|
|
assert_refnode(refnodes[6], None, 'NestedParentA', 'NestedChildA', 'class')
|
|
assert_refnode(refnodes[7], None, 'NestedParentA.NestedChildA', 'subchild_2', 'meth')
|
|
assert_refnode(refnodes[8], None, 'NestedParentA.NestedChildA',
|
|
'NestedParentA.child_1', 'meth')
|
|
assert_refnode(refnodes[9], None, 'NestedParentA', 'NestedChildA.subchild_1', 'meth')
|
|
assert_refnode(refnodes[10], None, 'NestedParentB', 'child_1', 'meth')
|
|
assert_refnode(refnodes[11], None, 'NestedParentB', 'NestedParentB', 'class')
|
|
assert_refnode(refnodes[12], None, None, 'NestedParentA.NestedChildA', 'class')
|
|
assert len(refnodes) == 13
|
|
|
|
doctree = app.env.get_doctree('module')
|
|
refnodes = list(doctree.traverse(addnodes.pending_xref))
|
|
assert_refnode(refnodes[0], 'module_a.submodule', None,
|
|
'ModTopLevel', 'class')
|
|
assert_refnode(refnodes[1], 'module_a.submodule', 'ModTopLevel',
|
|
'mod_child_1', 'meth')
|
|
assert_refnode(refnodes[2], 'module_a.submodule', 'ModTopLevel',
|
|
'ModTopLevel.mod_child_1', 'meth')
|
|
assert_refnode(refnodes[3], 'module_a.submodule', 'ModTopLevel',
|
|
'mod_child_2', 'meth')
|
|
assert_refnode(refnodes[4], 'module_a.submodule', 'ModTopLevel',
|
|
'module_a.submodule.ModTopLevel.mod_child_1', 'meth')
|
|
assert_refnode(refnodes[5], 'module_a.submodule', 'ModTopLevel',
|
|
'prop', 'attr')
|
|
assert_refnode(refnodes[6], 'module_a.submodule', 'ModTopLevel',
|
|
'prop', 'meth')
|
|
assert_refnode(refnodes[7], 'module_b.submodule', None,
|
|
'ModTopLevel', 'class')
|
|
assert_refnode(refnodes[8], 'module_b.submodule', 'ModTopLevel',
|
|
'ModNoModule', 'class')
|
|
assert_refnode(refnodes[9], False, False, 'int', 'class')
|
|
assert_refnode(refnodes[10], False, False, 'tuple', 'class')
|
|
assert_refnode(refnodes[11], False, False, 'str', 'class')
|
|
assert_refnode(refnodes[12], False, False, 'float', 'class')
|
|
assert_refnode(refnodes[13], False, False, 'list', 'class')
|
|
assert_refnode(refnodes[14], False, False, 'ModTopLevel', 'class')
|
|
assert_refnode(refnodes[15], False, False, 'index', 'doc', domain='std')
|
|
assert len(refnodes) == 16
|
|
|
|
doctree = app.env.get_doctree('module_option')
|
|
refnodes = list(doctree.traverse(addnodes.pending_xref))
|
|
print(refnodes)
|
|
print(refnodes[0])
|
|
print(refnodes[1])
|
|
assert_refnode(refnodes[0], 'test.extra', 'B', 'foo', 'meth')
|
|
assert_refnode(refnodes[1], 'test.extra', 'B', 'foo', 'meth')
|
|
assert len(refnodes) == 2
|
|
|
|
|
|
@pytest.mark.sphinx('dummy', testroot='domain-py')
|
|
def test_domain_py_objects(app, status, warning):
|
|
app.builder.build_all()
|
|
|
|
modules = app.env.domains['py'].data['modules']
|
|
objects = app.env.domains['py'].data['objects']
|
|
|
|
assert 'module_a.submodule' in modules
|
|
assert 'module_a.submodule' in objects
|
|
assert 'module_b.submodule' in modules
|
|
assert 'module_b.submodule' in objects
|
|
|
|
assert objects['module_a.submodule.ModTopLevel'][2] == 'class'
|
|
assert objects['module_a.submodule.ModTopLevel.mod_child_1'][2] == 'method'
|
|
assert objects['module_a.submodule.ModTopLevel.mod_child_2'][2] == 'method'
|
|
assert 'ModTopLevel.ModNoModule' not in objects
|
|
assert objects['ModNoModule'][2] == 'class'
|
|
assert objects['module_b.submodule.ModTopLevel'][2] == 'class'
|
|
|
|
assert objects['TopLevel'][2] == 'class'
|
|
assert objects['top_level'][2] == 'method'
|
|
assert objects['NestedParentA'][2] == 'class'
|
|
assert objects['NestedParentA.child_1'][2] == 'method'
|
|
assert objects['NestedParentA.any_child'][2] == 'method'
|
|
assert objects['NestedParentA.NestedChildA'][2] == 'class'
|
|
assert objects['NestedParentA.NestedChildA.subchild_1'][2] == 'method'
|
|
assert objects['NestedParentA.NestedChildA.subchild_2'][2] == 'method'
|
|
assert objects['NestedParentA.child_2'][2] == 'method'
|
|
assert objects['NestedParentB'][2] == 'class'
|
|
assert objects['NestedParentB.child_1'][2] == 'method'
|
|
|
|
|
|
@pytest.mark.sphinx('html', testroot='domain-py')
|
|
def test_resolve_xref_for_properties(app, status, warning):
|
|
app.builder.build_all()
|
|
|
|
content = (app.outdir / 'module.html').read_text()
|
|
assert ('Link to <a class="reference internal" href="#module_a.submodule.modtoplevel.prop"'
|
|
' title="module_a.submodule.ModTopLevel.prop">'
|
|
'<code class="xref py py-attr docutils literal notranslate"><span class="pre">'
|
|
'prop</span> <span class="pre">attribute</span></code></a>' in content)
|
|
assert ('Link to <a class="reference internal" href="#module_a.submodule.modtoplevel.prop"'
|
|
' title="module_a.submodule.ModTopLevel.prop">'
|
|
'<code class="xref py py-meth docutils literal notranslate"><span class="pre">'
|
|
'prop</span> <span class="pre">method</span></code></a>' in content)
|
|
|
|
|
|
@pytest.mark.sphinx('dummy', testroot='domain-py')
|
|
def test_domain_py_find_obj(app, status, warning):
|
|
|
|
def find_obj(modname, prefix, obj_name, obj_type, searchmode=0):
|
|
return app.env.domains['py'].find_obj(
|
|
app.env, modname, prefix, obj_name, obj_type, searchmode)
|
|
|
|
app.builder.build_all()
|
|
|
|
assert (find_obj(None, None, 'NONEXISTANT', 'class') == [])
|
|
assert (find_obj(None, None, 'NestedParentA', 'class') ==
|
|
[('NestedParentA', ('roles', 'nestedparenta', 'class'))])
|
|
assert (find_obj(None, None, 'NestedParentA.NestedChildA', 'class') ==
|
|
[('NestedParentA.NestedChildA', ('roles', 'nestedparenta.nestedchilda', 'class'))])
|
|
assert (find_obj(None, 'NestedParentA', 'NestedChildA', 'class') ==
|
|
[('NestedParentA.NestedChildA', ('roles', 'nestedparenta.nestedchilda', 'class'))])
|
|
assert (find_obj(None, None, 'NestedParentA.NestedChildA.subchild_1', 'meth') ==
|
|
[('NestedParentA.NestedChildA.subchild_1',
|
|
('roles', 'nestedparenta.nestedchilda.subchild_1', 'method'))])
|
|
assert (find_obj(None, 'NestedParentA', 'NestedChildA.subchild_1', 'meth') ==
|
|
[('NestedParentA.NestedChildA.subchild_1',
|
|
('roles', 'nestedparenta.nestedchilda.subchild_1', 'method'))])
|
|
assert (find_obj(None, 'NestedParentA.NestedChildA', 'subchild_1', 'meth') ==
|
|
[('NestedParentA.NestedChildA.subchild_1',
|
|
('roles', 'nestedparenta.nestedchilda.subchild_1', 'method'))])
|
|
|
|
|
|
def test_get_full_qualified_name():
|
|
env = Mock(domaindata={})
|
|
domain = PythonDomain(env)
|
|
|
|
# non-python references
|
|
node = nodes.reference()
|
|
assert domain.get_full_qualified_name(node) is None
|
|
|
|
# simple reference
|
|
node = nodes.reference(reftarget='func')
|
|
assert domain.get_full_qualified_name(node) == 'func'
|
|
|
|
# with py:module context
|
|
kwargs = {'py:module': 'module1'}
|
|
node = nodes.reference(reftarget='func', **kwargs)
|
|
assert domain.get_full_qualified_name(node) == 'module1.func'
|
|
|
|
# with py:class context
|
|
kwargs = {'py:class': 'Class'}
|
|
node = nodes.reference(reftarget='func', **kwargs)
|
|
assert domain.get_full_qualified_name(node) == 'Class.func'
|
|
|
|
# with both py:module and py:class context
|
|
kwargs = {'py:module': 'module1', 'py:class': 'Class'}
|
|
node = nodes.reference(reftarget='func', **kwargs)
|
|
assert domain.get_full_qualified_name(node) == 'module1.Class.func'
|
|
|
|
|
|
def test_pyfunction_signature(app):
|
|
text = ".. py:function:: hello(name: str) -> str"
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_name, "hello"],
|
|
desc_parameterlist,
|
|
[desc_returns, "str"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], addnodes.desc, desctype="function",
|
|
domain="py", objtype="function", noindex=False)
|
|
assert_node(doctree[1][0][1],
|
|
[desc_parameterlist, desc_parameter, ([desc_sig_name, "name"],
|
|
[desc_sig_punctuation, ":"],
|
|
" ",
|
|
[nodes.inline, "str"])])
|
|
|
|
|
|
def test_pyfunction_signature_full(app):
|
|
text = (".. py:function:: hello(a: str, b = 1, *args: str, "
|
|
"c: bool = True, **kwargs: str) -> str")
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_name, "hello"],
|
|
desc_parameterlist,
|
|
[desc_returns, "str"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], addnodes.desc, desctype="function",
|
|
domain="py", objtype="function", noindex=False)
|
|
assert_node(doctree[1][0][1],
|
|
[desc_parameterlist, ([desc_parameter, ([desc_sig_name, "a"],
|
|
[desc_sig_punctuation, ":"],
|
|
" ",
|
|
[desc_sig_name, "str"])],
|
|
[desc_parameter, ([desc_sig_name, "b"],
|
|
[desc_sig_operator, "="],
|
|
[nodes.inline, "1"])],
|
|
[desc_parameter, ([desc_sig_operator, "*"],
|
|
[desc_sig_name, "args"],
|
|
[desc_sig_punctuation, ":"],
|
|
" ",
|
|
[desc_sig_name, "str"])],
|
|
[desc_parameter, ([desc_sig_name, "c"],
|
|
[desc_sig_punctuation, ":"],
|
|
" ",
|
|
[desc_sig_name, "bool"],
|
|
" ",
|
|
[desc_sig_operator, "="],
|
|
" ",
|
|
[nodes.inline, "True"])],
|
|
[desc_parameter, ([desc_sig_operator, "**"],
|
|
[desc_sig_name, "kwargs"],
|
|
[desc_sig_punctuation, ":"],
|
|
" ",
|
|
[desc_sig_name, "str"])])])
|
|
|
|
|
|
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
|
def test_pyfunction_signature_full_py38(app):
|
|
# case: separator at head
|
|
text = ".. py:function:: hello(*, a)"
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree[1][0][1],
|
|
[desc_parameterlist, ([desc_parameter, nodes.inline, "*"],
|
|
[desc_parameter, ([desc_sig_name, "a"],
|
|
[desc_sig_operator, "="],
|
|
[nodes.inline, "None"])])])
|
|
|
|
# case: separator in the middle
|
|
text = ".. py:function:: hello(a, /, b, *, c)"
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree[1][0][1],
|
|
[desc_parameterlist, ([desc_parameter, desc_sig_name, "a"],
|
|
[desc_parameter, desc_sig_operator, "/"],
|
|
[desc_parameter, desc_sig_name, "b"],
|
|
[desc_parameter, desc_sig_operator, "*"],
|
|
[desc_parameter, ([desc_sig_name, "c"],
|
|
[desc_sig_operator, "="],
|
|
[nodes.inline, "None"])])])
|
|
|
|
# case: separator in the middle (2)
|
|
text = ".. py:function:: hello(a, /, *, b)"
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree[1][0][1],
|
|
[desc_parameterlist, ([desc_parameter, desc_sig_name, "a"],
|
|
[desc_parameter, desc_sig_operator, "/"],
|
|
[desc_parameter, desc_sig_operator, "*"],
|
|
[desc_parameter, ([desc_sig_name, "b"],
|
|
[desc_sig_operator, "="],
|
|
[nodes.inline, "None"])])])
|
|
|
|
# case: separator at tail
|
|
text = ".. py:function:: hello(a, /)"
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree[1][0][1],
|
|
[desc_parameterlist, ([desc_parameter, desc_sig_name, "a"],
|
|
[desc_parameter, desc_sig_operator, "/"])])
|
|
|
|
|
|
def test_optional_pyfunction_signature(app):
|
|
text = ".. py:function:: compile(source [, filename [, symbol]]) -> ast object"
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_name, "compile"],
|
|
desc_parameterlist,
|
|
[desc_returns, "ast object"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], addnodes.desc, desctype="function",
|
|
domain="py", objtype="function", noindex=False)
|
|
assert_node(doctree[1][0][1],
|
|
([desc_parameter, "source"],
|
|
[desc_optional, ([desc_parameter, "filename"],
|
|
[desc_optional, desc_parameter, "symbol"])]))
|
|
|
|
|
|
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")
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_annotation, "exception "],
|
|
[desc_name, "IOError"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], desc, desctype="exception",
|
|
domain="py", objtype="exception", noindex=False)
|
|
|
|
|
|
def test_pydata_signature(app):
|
|
text = (".. py:data:: version\n"
|
|
" :type: int\n"
|
|
" :value: 1\n")
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_name, "version"],
|
|
[desc_annotation, ": int"],
|
|
[desc_annotation, " = 1"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], addnodes.desc, desctype="data",
|
|
domain="py", objtype="data", noindex=False)
|
|
|
|
|
|
def test_pydata_signature_old(app):
|
|
text = (".. py:data:: version\n"
|
|
" :annotation: = 1\n")
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_name, "version"],
|
|
[desc_annotation, " = 1"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], addnodes.desc, desctype="data",
|
|
domain="py", objtype="data", noindex=False)
|
|
|
|
|
|
def test_pyobject_prefix(app):
|
|
text = (".. py:class:: Foo\n"
|
|
"\n"
|
|
" .. py:method:: Foo.say\n"
|
|
" .. py:method:: FooBar.say")
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_annotation, "class "],
|
|
[desc_name, "Foo"])],
|
|
[desc_content, (addnodes.index,
|
|
desc,
|
|
addnodes.index,
|
|
desc)])]))
|
|
assert doctree[1][1][1].astext().strip() == 'say' # prefix is stripped
|
|
assert doctree[1][1][3].astext().strip() == 'FooBar.say' # not stripped
|
|
|
|
|
|
def test_pydata(app):
|
|
text = ".. py:data:: var\n"
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, desc_name, "var"],
|
|
[desc_content, ()])]))
|
|
assert 'var' in domain.objects
|
|
assert domain.objects['var'] == ('index', 'var', 'data')
|
|
|
|
|
|
def test_pyfunction(app):
|
|
text = (".. py:function:: func1\n"
|
|
".. py:function:: func2\n"
|
|
" :async:\n")
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_name, "func1"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()])],
|
|
addnodes.index,
|
|
[desc, ([desc_signature, ([desc_annotation, "async "],
|
|
[desc_name, "func2"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()])]))
|
|
assert 'func1' in domain.objects
|
|
assert domain.objects['func1'] == ('index', 'func1', 'function')
|
|
assert 'func2' in domain.objects
|
|
assert domain.objects['func2'] == ('index', 'func2', 'function')
|
|
|
|
|
|
def test_pymethod_options(app):
|
|
text = (".. py:class:: Class\n"
|
|
"\n"
|
|
" .. py:method:: meth1\n"
|
|
" .. py:method:: meth2\n"
|
|
" :classmethod:\n"
|
|
" .. py:method:: meth3\n"
|
|
" :staticmethod:\n"
|
|
" .. py:method:: meth4\n"
|
|
" :async:\n"
|
|
" .. py:method:: meth5\n"
|
|
" :property:\n"
|
|
" .. py:method:: meth6\n"
|
|
" :abstractmethod:\n")
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_annotation, "class "],
|
|
[desc_name, "Class"])],
|
|
[desc_content, (addnodes.index,
|
|
desc,
|
|
addnodes.index,
|
|
desc,
|
|
addnodes.index,
|
|
desc,
|
|
addnodes.index,
|
|
desc,
|
|
addnodes.index,
|
|
desc,
|
|
addnodes.index,
|
|
desc)])]))
|
|
|
|
# method
|
|
assert_node(doctree[1][1][0], addnodes.index,
|
|
entries=[('single', 'meth1() (Class method)', 'class.meth1', '', None)])
|
|
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "meth1"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth1' in domain.objects
|
|
assert domain.objects['Class.meth1'] == ('index', 'class.meth1', 'method')
|
|
|
|
# :classmethod:
|
|
assert_node(doctree[1][1][2], addnodes.index,
|
|
entries=[('single', 'meth2() (Class class method)', 'class.meth2', '', None)])
|
|
assert_node(doctree[1][1][3], ([desc_signature, ([desc_annotation, "classmethod "],
|
|
[desc_name, "meth2"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth2' in domain.objects
|
|
assert domain.objects['Class.meth2'] == ('index', 'class.meth2', 'method')
|
|
|
|
# :staticmethod:
|
|
assert_node(doctree[1][1][4], addnodes.index,
|
|
entries=[('single', 'meth3() (Class static method)', 'class.meth3', '', None)])
|
|
assert_node(doctree[1][1][5], ([desc_signature, ([desc_annotation, "static "],
|
|
[desc_name, "meth3"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth3' in domain.objects
|
|
assert domain.objects['Class.meth3'] == ('index', 'class.meth3', 'method')
|
|
|
|
# :async:
|
|
assert_node(doctree[1][1][6], addnodes.index,
|
|
entries=[('single', 'meth4() (Class method)', 'class.meth4', '', None)])
|
|
assert_node(doctree[1][1][7], ([desc_signature, ([desc_annotation, "async "],
|
|
[desc_name, "meth4"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth4' in domain.objects
|
|
assert domain.objects['Class.meth4'] == ('index', 'class.meth4', 'method')
|
|
|
|
# :property:
|
|
assert_node(doctree[1][1][8], addnodes.index,
|
|
entries=[('single', 'meth5() (Class property)', 'class.meth5', '', None)])
|
|
assert_node(doctree[1][1][9], ([desc_signature, ([desc_annotation, "property "],
|
|
[desc_name, "meth5"])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth5' in domain.objects
|
|
assert domain.objects['Class.meth5'] == ('index', 'class.meth5', 'method')
|
|
|
|
# :abstractmethod:
|
|
assert_node(doctree[1][1][10], addnodes.index,
|
|
entries=[('single', 'meth6() (Class method)', 'class.meth6', '', None)])
|
|
assert_node(doctree[1][1][11], ([desc_signature, ([desc_annotation, "abstract "],
|
|
[desc_name, "meth6"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth6' in domain.objects
|
|
assert domain.objects['Class.meth6'] == ('index', 'class.meth6', 'method')
|
|
|
|
|
|
def test_pyclassmethod(app):
|
|
text = (".. py:class:: Class\n"
|
|
"\n"
|
|
" .. py:classmethod:: meth\n")
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_annotation, "class "],
|
|
[desc_name, "Class"])],
|
|
[desc_content, (addnodes.index,
|
|
desc)])]))
|
|
assert_node(doctree[1][1][0], addnodes.index,
|
|
entries=[('single', 'meth() (Class class method)', 'class.meth', '', None)])
|
|
assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "classmethod "],
|
|
[desc_name, "meth"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth' in domain.objects
|
|
assert domain.objects['Class.meth'] == ('index', 'class.meth', 'method')
|
|
|
|
|
|
def test_pystaticmethod(app):
|
|
text = (".. py:class:: Class\n"
|
|
"\n"
|
|
" .. py:staticmethod:: meth\n")
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_annotation, "class "],
|
|
[desc_name, "Class"])],
|
|
[desc_content, (addnodes.index,
|
|
desc)])]))
|
|
assert_node(doctree[1][1][0], addnodes.index,
|
|
entries=[('single', 'meth() (Class static method)', 'class.meth', '', None)])
|
|
assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "static "],
|
|
[desc_name, "meth"],
|
|
[desc_parameterlist, ()])],
|
|
[desc_content, ()]))
|
|
assert 'Class.meth' in domain.objects
|
|
assert domain.objects['Class.meth'] == ('index', 'class.meth', 'method')
|
|
|
|
|
|
def test_pyattribute(app):
|
|
text = (".. py:class:: Class\n"
|
|
"\n"
|
|
" .. py:attribute:: attr\n"
|
|
" :type: str\n"
|
|
" :value: ''\n")
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_annotation, "class "],
|
|
[desc_name, "Class"])],
|
|
[desc_content, (addnodes.index,
|
|
desc)])]))
|
|
assert_node(doctree[1][1][0], addnodes.index,
|
|
entries=[('single', 'attr (Class attribute)', 'class.attr', '', None)])
|
|
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "attr"],
|
|
[desc_annotation, ": str"],
|
|
[desc_annotation, " = ''"])],
|
|
[desc_content, ()]))
|
|
assert 'Class.attr' in domain.objects
|
|
assert domain.objects['Class.attr'] == ('index', 'class.attr', 'attribute')
|
|
|
|
|
|
def test_pydecorator_signature(app):
|
|
text = ".. py:decorator:: deco"
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_addname, "@"],
|
|
[desc_name, "deco"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], addnodes.desc, desctype="function",
|
|
domain="py", objtype="function", noindex=False)
|
|
|
|
assert 'deco' in domain.objects
|
|
assert domain.objects['deco'] == ('index', 'deco', 'function')
|
|
|
|
|
|
def test_pydecoratormethod_signature(app):
|
|
text = ".. py:decoratormethod:: deco"
|
|
domain = app.env.get_domain('py')
|
|
doctree = restructuredtext.parse(app, text)
|
|
assert_node(doctree, (addnodes.index,
|
|
[desc, ([desc_signature, ([desc_addname, "@"],
|
|
[desc_name, "deco"])],
|
|
desc_content)]))
|
|
assert_node(doctree[1], addnodes.desc, desctype="method",
|
|
domain="py", objtype="method", noindex=False)
|
|
|
|
assert 'deco' in domain.objects
|
|
assert domain.objects['deco'] == ('index', 'deco', 'method')
|
|
|
|
|
|
@pytest.mark.sphinx(freshenv=True)
|
|
def test_module_index(app):
|
|
text = (".. py:module:: docutils\n"
|
|
".. py:module:: sphinx\n"
|
|
".. py:module:: sphinx.config\n"
|
|
".. py:module:: sphinx.builders\n"
|
|
".. py:module:: sphinx.builders.html\n"
|
|
".. py:module:: sphinx_intl\n")
|
|
restructuredtext.parse(app, text)
|
|
index = PythonModuleIndex(app.env.get_domain('py'))
|
|
assert index.generate() == (
|
|
[('d', [IndexEntry('docutils', 0, 'index', 'module-docutils', '', '', '')]),
|
|
('s', [IndexEntry('sphinx', 1, 'index', 'module-sphinx', '', '', ''),
|
|
IndexEntry('sphinx.builders', 2, 'index', 'module-sphinx.builders', '', '', ''), # NOQA
|
|
IndexEntry('sphinx.builders.html', 2, 'index', 'module-sphinx.builders.html', '', '', ''), # NOQA
|
|
IndexEntry('sphinx.config', 2, 'index', 'module-sphinx.config', '', '', ''),
|
|
IndexEntry('sphinx_intl', 0, 'index', 'module-sphinx_intl', '', '', '')])],
|
|
False
|
|
)
|
|
|
|
|
|
@pytest.mark.sphinx(freshenv=True)
|
|
def test_module_index_submodule(app):
|
|
text = ".. py:module:: sphinx.config\n"
|
|
restructuredtext.parse(app, text)
|
|
index = PythonModuleIndex(app.env.get_domain('py'))
|
|
assert index.generate() == (
|
|
[('s', [IndexEntry('sphinx', 1, '', '', '', '', ''),
|
|
IndexEntry('sphinx.config', 2, 'index', 'module-sphinx.config', '', '', '')])],
|
|
False
|
|
)
|
|
|
|
|
|
@pytest.mark.sphinx(freshenv=True)
|
|
def test_module_index_not_collapsed(app):
|
|
text = (".. py:module:: docutils\n"
|
|
".. py:module:: sphinx\n")
|
|
restructuredtext.parse(app, text)
|
|
index = PythonModuleIndex(app.env.get_domain('py'))
|
|
assert index.generate() == (
|
|
[('d', [IndexEntry('docutils', 0, 'index', 'module-docutils', '', '', '')]),
|
|
('s', [IndexEntry('sphinx', 0, 'index', 'module-sphinx', '', '', '')])],
|
|
True
|
|
)
|
|
|
|
|
|
@pytest.mark.sphinx(freshenv=True, confoverrides={'modindex_common_prefix': ['sphinx.']})
|
|
def test_modindex_common_prefix(app):
|
|
text = (".. py:module:: docutils\n"
|
|
".. py:module:: sphinx\n"
|
|
".. py:module:: sphinx.config\n"
|
|
".. py:module:: sphinx.builders\n"
|
|
".. py:module:: sphinx.builders.html\n"
|
|
".. py:module:: sphinx_intl\n")
|
|
restructuredtext.parse(app, text)
|
|
index = PythonModuleIndex(app.env.get_domain('py'))
|
|
assert index.generate() == (
|
|
[('b', [IndexEntry('sphinx.builders', 1, 'index', 'module-sphinx.builders', '', '', ''), # NOQA
|
|
IndexEntry('sphinx.builders.html', 2, 'index', 'module-sphinx.builders.html', '', '', '')]), # NOQA
|
|
('c', [IndexEntry('sphinx.config', 0, 'index', 'module-sphinx.config', '', '', '')]),
|
|
('d', [IndexEntry('docutils', 0, 'index', 'module-docutils', '', '', '')]),
|
|
('s', [IndexEntry('sphinx', 0, 'index', 'module-sphinx', '', '', ''),
|
|
IndexEntry('sphinx_intl', 0, 'index', 'module-sphinx_intl', '', '', '')])],
|
|
True
|
|
)
|
|
|
|
|