Merge pull request #6268 from tk0miya/refactor_py_domain

Refactoring python domain: Add new description classes for methods and attributes
This commit is contained in:
Takeshi KOMIYA 2019-04-13 19:46:34 +09:00 committed by GitHub
commit a337cb793c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 194 additions and 5 deletions

View File

@ -33,6 +33,7 @@ Deprecated
* ``sphinx.directives.TabularColumns`` * ``sphinx.directives.TabularColumns``
* ``sphinx.directives.TocTree`` * ``sphinx.directives.TocTree``
* ``sphinx.directives.VersionChange`` * ``sphinx.directives.VersionChange``
* ``sphinx.domains.python.PyClassmember``
* ``sphinx.domains.std.StandardDomain._resolve_citation_xref()`` * ``sphinx.domains.std.StandardDomain._resolve_citation_xref()``
* ``sphinx.domains.std.StandardDomain.note_citations()`` * ``sphinx.domains.std.StandardDomain.note_citations()``
* ``sphinx.domains.std.StandardDomain.note_citation_refs()`` * ``sphinx.domains.std.StandardDomain.note_citation_refs()``

View File

@ -116,6 +116,14 @@ The following is a list of deprecated interfaces.
- 4.0 - 4.0
- ``sphinx.directives.other.VersionChange`` - ``sphinx.directives.other.VersionChange``
* - ``sphinx.domains.python.PyClassmember``
- 2.1
- 4.0
- ``sphinx.domains.python.PyAttribute``,
``sphinx.domains.python.PyMethod``,
``sphinx.domains.python.PyClassMethod`` and
``sphinx.domains.python.PyStaticMethod``
* - ``sphinx.domains.std.StandardDomain._resolve_citation_xref()`` * - ``sphinx.domains.std.StandardDomain._resolve_citation_xref()``
- 2.1 - 2.1
- 4.0 - 4.0

View File

@ -9,13 +9,16 @@
""" """
import re import re
import warnings
from typing import cast from typing import cast
from docutils import nodes from docutils import nodes
from docutils.parsers.rst import directives from docutils.parsers.rst import directives
from sphinx import addnodes, locale from sphinx import addnodes, locale
from sphinx.deprecation import DeprecatedDict, RemovedInSphinx30Warning from sphinx.deprecation import (
DeprecatedDict, RemovedInSphinx30Warning, RemovedInSphinx40Warning
)
from sphinx.directives import ObjectDescription from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType, Index, IndexEntry from sphinx.domains import Domain, ObjType, Index, IndexEntry
from sphinx.locale import _, __ from sphinx.locale import _, __
@ -453,6 +456,13 @@ class PyClassmember(PyObject):
Description of a class member (methods, attributes). Description of a class member (methods, attributes).
""" """
def run(self):
# type: () -> List[nodes.Node]
warnings.warn('PyClassmember is deprecated.',
RemovedInSphinx40Warning)
return super().run()
def needs_arglist(self): def needs_arglist(self):
# type: () -> bool # type: () -> bool
return self.objtype.endswith('method') return self.objtype.endswith('method')
@ -523,6 +533,94 @@ class PyClassmember(PyObject):
return '' return ''
class PyMethod(PyObject):
"""Description of a method."""
def needs_arglist(self):
# type: () -> bool
return True
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
name, cls = name_cls
try:
clsname, methname = name.rsplit('.', 1)
if modname and self.env.config.add_module_names:
clsname = '.'.join([modname, clsname])
except ValueError:
if modname:
return _('%s() (in module %s)') % (name, modname)
else:
return '%s()' % name
return _('%s() (%s method)') % (methname, clsname)
class PyClassMethod(PyMethod):
"""Description of a classmethod."""
def get_signature_prefix(self, sig):
# type: (str) -> str
return 'classmethod '
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
name, cls = name_cls
try:
clsname, methname = name.rsplit('.', 1)
if modname and self.env.config.add_module_names:
clsname = '.'.join([modname, clsname])
except ValueError:
if modname:
return _('%s() (in module %s)') % (name, modname)
else:
return '%s()' % name
return _('%s() (%s class method)') % (methname, clsname)
class PyStaticMethod(PyMethod):
"""Description of a staticmethod."""
def get_signature_prefix(self, sig):
# type: (str) -> str
return 'static '
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
name, cls = name_cls
try:
clsname, methname = name.rsplit('.', 1)
if modname and self.env.config.add_module_names:
clsname = '.'.join([modname, clsname])
except ValueError:
if modname:
return _('%s() (in module %s)') % (name, modname)
else:
return '%s()' % name
return _('%s() (%s static method)') % (methname, clsname)
class PyAttribute(PyObject):
"""Description of an attribute."""
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
name, cls = name_cls
try:
clsname, attrname = name.rsplit('.', 1)
if modname and self.env.config.add_module_names:
clsname = '.'.join([modname, clsname])
except ValueError:
if modname:
return _('%s (in module %s)') % (name, modname)
else:
return name
return _('%s (%s attribute)') % (attrname, clsname)
class PyDecoratorMixin: class PyDecoratorMixin:
""" """
Mixin for decorator directives. Mixin for decorator directives.
@ -745,10 +843,10 @@ class PythonDomain(Domain):
'data': PyModulelevel, 'data': PyModulelevel,
'class': PyClasslike, 'class': PyClasslike,
'exception': PyClasslike, 'exception': PyClasslike,
'method': PyClassmember, 'method': PyMethod,
'classmethod': PyClassmember, 'classmethod': PyClassMethod,
'staticmethod': PyClassmember, 'staticmethod': PyStaticMethod,
'attribute': PyClassmember, 'attribute': PyAttribute,
'module': PyModule, 'module': PyModule,
'currentmodule': PyCurrentModule, 'currentmodule': PyCurrentModule,
'decorator': PyDecoratorFunction, 'decorator': PyDecoratorFunction,

View File

@ -290,3 +290,85 @@ def test_pyobject_prefix(app):
desc)])])) desc)])]))
assert doctree[1][1][1].astext().strip() == 'say' # prefix is stripped assert doctree[1][1][1].astext().strip() == 'say' # prefix is stripped
assert doctree[1][1][3].astext().strip() == 'FooBar.say' # not stripped assert doctree[1][1][3].astext().strip() == 'FooBar.say' # not stripped
def test_pymethod(app):
text = (".. py:class:: Class\n"
"\n"
" .. py:method:: 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 method)', 'Class.meth', '', None)])
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "meth"],
[desc_parameterlist, ()])],
[desc_content, ()]))
assert 'Class.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', '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', 'classmethod')
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', 'staticmethod')
def test_pyattribute(app):
text = (".. py:class:: Class\n"
"\n"
" .. py:attribute:: attr\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_content, ()]))
assert 'Class.attr' in domain.objects
assert domain.objects['Class.attr'] == ('index', 'attribute')