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
* #6212 autosummary: Add :confval:`autosummary_imported_members` to display
imported members on autosummary
* Add ``:classmethod:`` and ``:staticmethod:`` options to :rst:dir:`py:method`
directive
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
: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)
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):
"""Description of a method."""
option_spec = PyObject.option_spec.copy()
option_spec.update({
'classmethod': directives.flag,
'staticmethod': directives.flag,
})
def needs_arglist(self):
# type: () -> bool
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):
# type: (str, Tuple[str, str]) -> str
name, cls = name_cls
@ -588,53 +603,38 @@ class PyMethod(PyObject):
else:
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):
"""Description of a classmethod."""
def get_signature_prefix(self, sig):
# type: (str) -> str
return 'classmethod '
option_spec = PyObject.option_spec.copy()
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
def run(self):
# type: () -> List[nodes.Node]
self.name = 'py:method'
self.options['classmethod'] = True
return _('%s() (%s class method)') % (methname, clsname)
return super().run()
class PyStaticMethod(PyMethod):
"""Description of a staticmethod."""
def get_signature_prefix(self, sig):
# type: (str) -> str
return 'static '
option_spec = PyObject.option_spec.copy()
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
def run(self):
# type: () -> List[nodes.Node]
self.name = 'py:method'
self.options['staticmethod'] = True
return _('%s() (%s static method)') % (methname, clsname)
return super().run()
class PyAttribute(PyObject):

View File

@ -315,25 +315,54 @@ def test_pyfunction(app):
assert domain.objects['func'] == ('index', 'function')
def test_pymethod(app):
def test_pymethod_options(app):
text = (".. py:class:: Class\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')
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)])]))
# method
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"],
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.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'method')
assert 'Class.meth1' in domain.objects
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):
@ -354,7 +383,7 @@ def test_pyclassmethod(app):
[desc_parameterlist, ()])],
[desc_content, ()]))
assert 'Class.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'classmethod')
assert domain.objects['Class.meth'] == ('index', 'method')
def test_pystaticmethod(app):
@ -375,7 +404,7 @@ def test_pystaticmethod(app):
[desc_parameterlist, ()])],
[desc_content, ()]))
assert 'Class.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'staticmethod')
assert domain.objects['Class.meth'] == ('index', 'method')
def test_pyattribute(app):