Add :classmethod: and :staticmethod: options to py:method directive

This commit is contained in:
Takeshi KOMIYA 2019-04-07 21:09:57 +09:00
parent dbdf9a3599
commit 331594e2ca
4 changed files with 79 additions and 41 deletions

View File

@ -70,6 +70,8 @@ Features added
* #6232: Enable CLI override of Makefile variables * #6232: Enable CLI override of Makefile variables
* #6212 autosummary: Add :confval:`autosummary_imported_members` to display * #6212 autosummary: Add :confval:`autosummary_imported_members` to display
imported members on autosummary imported members on autosummary
* Add ``:classmethod:`` and ``:staticmethod:`` options to :rst:dir:`py:method`
directive
Bugs fixed Bugs fixed
---------- ----------

View File

@ -216,6 +216,13 @@ The following directives are provided for module and class contents:
described for ``function``. See also :ref:`signatures` and described for ``function``. See also :ref:`signatures` and
:ref:`info-field-lists`. :ref:`info-field-lists`.
The ``classmethod`` option and ``staticmethod`` option can be given (with
no value) to indicate the method is a class method (or a static method).
.. versionchanged:: 2.1
``:classmethod:`` and ``:staticmethod:`` options added.
.. rst:directive:: .. py:staticmethod:: name(parameters) .. rst:directive:: .. py:staticmethod:: name(parameters)
Like :rst:dir:`py:method`, but indicates that the method is a static method. Like :rst:dir:`py:method`, but indicates that the method is a static method.

View File

@ -571,10 +571,25 @@ class PyClassmember(PyObject):
class PyMethod(PyObject): class PyMethod(PyObject):
"""Description of a method.""" """Description of a method."""
option_spec = PyObject.option_spec.copy()
option_spec.update({
'classmethod': directives.flag,
'staticmethod': directives.flag,
})
def needs_arglist(self): def needs_arglist(self):
# type: () -> bool # type: () -> bool
return True return True
def get_signature_prefix(self, sig):
# type: (str) -> str
if 'staticmethod' in self.options:
return 'static '
elif 'classmethod' in self.options:
return 'classmethod '
else:
return ''
def get_index_text(self, modname, name_cls): def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str # type: (str, Tuple[str, str]) -> str
name, cls = name_cls name, cls = name_cls
@ -588,53 +603,38 @@ class PyMethod(PyObject):
else: else:
return '%s()' % name return '%s()' % name
return _('%s() (%s method)') % (methname, clsname) if 'staticmethod' in self.options:
return _('%s() (%s static method)') % (methname, clsname)
elif 'classmethod' in self.options:
return _('%s() (%s class method)') % (methname, clsname)
else:
return _('%s() (%s method)') % (methname, clsname)
class PyClassMethod(PyMethod): class PyClassMethod(PyMethod):
"""Description of a classmethod.""" """Description of a classmethod."""
def get_signature_prefix(self, sig): option_spec = PyObject.option_spec.copy()
# type: (str) -> str
return 'classmethod '
def get_index_text(self, modname, name_cls): def run(self):
# type: (str, Tuple[str, str]) -> str # type: () -> List[nodes.Node]
name, cls = name_cls self.name = 'py:method'
try: self.options['classmethod'] = True
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) return super().run()
class PyStaticMethod(PyMethod): class PyStaticMethod(PyMethod):
"""Description of a staticmethod.""" """Description of a staticmethod."""
def get_signature_prefix(self, sig): option_spec = PyObject.option_spec.copy()
# type: (str) -> str
return 'static '
def get_index_text(self, modname, name_cls): def run(self):
# type: (str, Tuple[str, str]) -> str # type: () -> List[nodes.Node]
name, cls = name_cls self.name = 'py:method'
try: self.options['staticmethod'] = True
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) return super().run()
class PyAttribute(PyObject): class PyAttribute(PyObject):

View File

@ -315,25 +315,54 @@ def test_pyfunction(app):
assert domain.objects['func'] == ('index', 'function') assert domain.objects['func'] == ('index', 'function')
def test_pymethod(app): def test_pymethod_options(app):
text = (".. py:class:: Class\n" text = (".. py:class:: Class\n"
"\n" "\n"
" .. py:method:: meth\n") " .. py:method:: meth1\n"
" .. py:method:: meth2\n"
" :classmethod:\n"
" .. py:method:: meth3\n"
" :staticmethod:\n")
domain = app.env.get_domain('py') domain = app.env.get_domain('py')
doctree = restructuredtext.parse(app, text) doctree = restructuredtext.parse(app, text)
assert_node(doctree, (addnodes.index, assert_node(doctree, (addnodes.index,
[desc, ([desc_signature, ([desc_annotation, "class "], [desc, ([desc_signature, ([desc_annotation, "class "],
[desc_name, "Class"])], [desc_name, "Class"])],
[desc_content, (addnodes.index, [desc_content, (addnodes.index,
desc,
addnodes.index,
desc,
addnodes.index,
desc)])])) desc)])]))
# method
assert_node(doctree[1][1][0], addnodes.index, assert_node(doctree[1][1][0], addnodes.index,
entries=[('single', 'meth() (Class method)', 'Class.meth', '', None)]) entries=[('single', 'meth1() (Class method)', 'Class.meth1', '', None)])
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "meth"], assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "meth1"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth' in domain.objects assert 'Class.meth1' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'method') assert domain.objects['Class.meth1'] == ('index', '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', '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', 'method')
def test_pyclassmethod(app): def test_pyclassmethod(app):
@ -354,7 +383,7 @@ def test_pyclassmethod(app):
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth' in domain.objects assert 'Class.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'classmethod') assert domain.objects['Class.meth'] == ('index', 'method')
def test_pystaticmethod(app): def test_pystaticmethod(app):
@ -375,7 +404,7 @@ def test_pystaticmethod(app):
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth' in domain.objects assert 'Class.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'staticmethod') assert domain.objects['Class.meth'] == ('index', 'method')
def test_pyattribute(app): def test_pyattribute(app):