"""Tests the Python Domain""" from __future__ import annotations from docutils import nodes from sphinx import addnodes from sphinx.addnodes import ( desc, desc_addname, desc_annotation, desc_content, desc_name, desc_parameterlist, desc_sig_punctuation, desc_sig_space, desc_signature, pending_xref, ) from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node def test_pyexception_signature(app): text = ".. py:exception:: builtins.IOError" doctree = restructuredtext.parse(app, text) assert_node(doctree, (addnodes.index, [desc, ([desc_signature, ([desc_annotation, ('exception', desc_sig_space)], [desc_addname, "builtins."], [desc_name, "IOError"])], desc_content)])) assert_node(doctree[1], desc, desctype="exception", domain="py", objtype="exception", no_index=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, ([desc_sig_punctuation, ':'], desc_sig_space, [pending_xref, "int"])], [desc_annotation, ( desc_sig_space, [desc_sig_punctuation, '='], desc_sig_space, "1")], )], desc_content)])) assert_node(doctree[1], addnodes.desc, desctype="data", domain="py", objtype="data", no_index=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, (desc_sig_space, "= 1")])], desc_content)])) assert_node(doctree[1], addnodes.desc, desctype="data", domain="py", objtype="data", no_index=False) def test_pydata_with_union_type_operator(app): text = (".. py:data:: version\n" " :type: int | str") doctree = restructuredtext.parse(app, text) assert_node(doctree[1][0], ([desc_name, "version"], [desc_annotation, ([desc_sig_punctuation, ':'], desc_sig_space, [pending_xref, "int"], desc_sig_space, [desc_sig_punctuation, "|"], desc_sig_space, [pending_xref, "str"])])) 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_sig_space)], [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:module:: example\n" ".. py:data:: var\n" " :type: int\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) assert_node(doctree, (addnodes.index, addnodes.index, nodes.target, [desc, ([desc_signature, ([desc_addname, "example."], [desc_name, "var"], [desc_annotation, ([desc_sig_punctuation, ':'], desc_sig_space, [pending_xref, "int"])])], [desc_content, ()])])) assert_node(doctree[3][0][2][2], pending_xref, **{"py:module": "example"}) assert 'example.var' in domain.objects assert domain.objects['example.var'] == ('index', 'example.var', 'data', False) def test_pyclass_options(app): text = (".. py:class:: Class1\n" ".. py:class:: Class2\n" " :final:\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) assert_node(doctree, (addnodes.index, [desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)], [desc_name, "Class1"])], [desc_content, ()])], addnodes.index, [desc, ([desc_signature, ([desc_annotation, ("final", desc_sig_space, "class", desc_sig_space)], [desc_name, "Class2"])], [desc_content, ()])])) # class assert_node(doctree[0], addnodes.index, entries=[('single', 'Class1 (built-in class)', 'Class1', '', None)]) assert 'Class1' in domain.objects assert domain.objects['Class1'] == ('index', 'Class1', 'class', False) # :final: assert_node(doctree[2], addnodes.index, entries=[('single', 'Class2 (built-in class)', 'Class2', '', None)]) assert 'Class2' in domain.objects assert domain.objects['Class2'] == ('index', 'Class2', 'class', False) 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" " :abstractmethod:\n" " .. py:method:: meth6\n" " :final:\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) assert_node(doctree, (addnodes.index, [desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)], [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', False) # :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_sig_space)], [desc_name, "meth2"], [desc_parameterlist, ()])], [desc_content, ()])) assert 'Class.meth2' in domain.objects assert domain.objects['Class.meth2'] == ('index', 'Class.meth2', 'method', False) # :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_sig_space)], [desc_name, "meth3"], [desc_parameterlist, ()])], [desc_content, ()])) assert 'Class.meth3' in domain.objects assert domain.objects['Class.meth3'] == ('index', 'Class.meth3', 'method', False) # :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_sig_space)], [desc_name, "meth4"], [desc_parameterlist, ()])], [desc_content, ()])) assert 'Class.meth4' in domain.objects assert domain.objects['Class.meth4'] == ('index', 'Class.meth4', 'method', False) # :abstractmethod: assert_node(doctree[1][1][8], addnodes.index, entries=[('single', 'meth5() (Class method)', 'Class.meth5', '', None)]) assert_node(doctree[1][1][9], ([desc_signature, ([desc_annotation, ("abstract", desc_sig_space)], [desc_name, "meth5"], [desc_parameterlist, ()])], [desc_content, ()])) assert 'Class.meth5' in domain.objects assert domain.objects['Class.meth5'] == ('index', 'Class.meth5', 'method', False) # :final: 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, ("final", desc_sig_space)], [desc_name, "meth6"], [desc_parameterlist, ()])], [desc_content, ()])) assert 'Class.meth6' in domain.objects assert domain.objects['Class.meth6'] == ('index', 'Class.meth6', 'method', False) 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_sig_space)], [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_sig_space)], [desc_name, "meth"], [desc_parameterlist, ()])], [desc_content, ()])) assert 'Class.meth' in domain.objects assert domain.objects['Class.meth'] == ('index', 'Class.meth', 'method', False) 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_sig_space)], [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_sig_space)], [desc_name, "meth"], [desc_parameterlist, ()])], [desc_content, ()])) assert 'Class.meth' in domain.objects assert domain.objects['Class.meth'] == ('index', 'Class.meth', 'method', False) def test_pyattribute(app): text = (".. py:class:: Class\n" "\n" " .. py:attribute:: attr\n" " :type: Optional[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_sig_space)], [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, ([desc_sig_punctuation, ':'], desc_sig_space, [pending_xref, "str"], desc_sig_space, [desc_sig_punctuation, "|"], desc_sig_space, [pending_xref, "None"])], [desc_annotation, (desc_sig_space, [desc_sig_punctuation, '='], desc_sig_space, "''")], )], [desc_content, ()])) assert_node(doctree[1][1][1][0][1][2], pending_xref, **{"py:class": "Class"}) assert_node(doctree[1][1][1][0][1][6], pending_xref, **{"py:class": "Class"}) assert 'Class.attr' in domain.objects assert domain.objects['Class.attr'] == ('index', 'Class.attr', 'attribute', False) def test_pyproperty(app): text = (".. py:class:: Class\n" "\n" " .. py:property:: prop1\n" " :abstractmethod:\n" " :type: str\n" "\n" " .. py:property:: prop2\n" " :classmethod:\n" " :type: str\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) assert_node(doctree, (addnodes.index, [desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)], [desc_name, "Class"])], [desc_content, (addnodes.index, desc, addnodes.index, desc)])])) assert_node(doctree[1][1][0], addnodes.index, entries=[('single', 'prop1 (Class property)', 'Class.prop1', '', None)]) assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, ("abstract", desc_sig_space, "property", desc_sig_space)], [desc_name, "prop1"], [desc_annotation, ([desc_sig_punctuation, ':'], desc_sig_space, [pending_xref, "str"])])], [desc_content, ()])) assert_node(doctree[1][1][2], addnodes.index, entries=[('single', 'prop2 (Class property)', 'Class.prop2', '', None)]) assert_node(doctree[1][1][3], ([desc_signature, ([desc_annotation, ("class", desc_sig_space, "property", desc_sig_space)], [desc_name, "prop2"], [desc_annotation, ([desc_sig_punctuation, ':'], desc_sig_space, [pending_xref, "str"])])], [desc_content, ()])) assert 'Class.prop1' in domain.objects assert domain.objects['Class.prop1'] == ('index', 'Class.prop1', 'property', False) assert 'Class.prop2' in domain.objects assert domain.objects['Class.prop2'] == ('index', 'Class.prop2', 'property', False) 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", no_index=False) assert 'deco' in domain.objects assert domain.objects['deco'] == ('index', 'deco', 'function', False) 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", no_index=False) assert 'deco' in domain.objects assert domain.objects['deco'] == ('index', 'deco', 'method', False) def test_pycurrentmodule(app): text = (".. py:module:: Other\n" "\n" ".. py:module:: Module\n" ".. py:class:: A\n" "\n" " .. py:method:: m1\n" " .. py:method:: m2\n" "\n" ".. py:currentmodule:: Other\n" "\n" ".. py:class:: B\n" "\n" " .. py:method:: m3\n" " .. py:method:: m4\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) print(doctree) assert_node( doctree, ( addnodes.index, addnodes.index, addnodes.index, nodes.target, nodes.target, [desc, ( [desc_signature, ( [desc_annotation, ("class", desc_sig_space)], [desc_addname, "Module."], [desc_name, "A"], )], [desc_content, ( addnodes.index, [desc, ( [desc_signature, ( [desc_name, "m1"], [desc_parameterlist, ()], )], [desc_content, ()], )], addnodes.index, [desc, ( [desc_signature, ( [desc_name, "m2"], [desc_parameterlist, ()], )], [desc_content, ()], )], )], )], addnodes.index, [desc, ( [desc_signature, ( [desc_annotation, ("class", desc_sig_space)], [desc_addname, "Other."], [desc_name, "B"], )], [desc_content, ( addnodes.index, [desc, ( [desc_signature, ( [desc_name, "m3"], [desc_parameterlist, ()], )], [desc_content, ()], )], addnodes.index, [desc, ( [desc_signature, ( [desc_name, "m4"], [desc_parameterlist, ()], )], [desc_content, ()], )], )], )], )) assert 'Module' in domain.objects assert domain.objects['Module'] == ('index', 'module-Module', 'module', False) assert 'Other' in domain.objects assert domain.objects['Other'] == ('index', 'module-Other', 'module', False) assert 'Module.A' in domain.objects assert domain.objects['Module.A'] == ('index', 'Module.A', 'class', False) assert 'Other.B' in domain.objects assert domain.objects['Other.B'] == ('index', 'Other.B', 'class', False) assert 'Module.A.m1' in domain.objects assert domain.objects['Module.A.m1'] == ('index', 'Module.A.m1', 'method', False) assert 'Module.A.m2' in domain.objects assert domain.objects['Module.A.m2'] == ('index', 'Module.A.m2', 'method', False) assert 'Other.B.m3' in domain.objects assert domain.objects['Other.B.m3'] == ('index', 'Other.B.m3', 'method', False) assert 'Other.B.m4' in domain.objects assert domain.objects['Other.B.m4'] == ('index', 'Other.B.m4', 'method', False)