From 120525563c4ed38ca2d05dc4757e81cf5415c473 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 17 Jul 2021 14:24:31 +0900 Subject: [PATCH] Cloase #9445: :py:property: directive now supports :classmethod: option Since python 3.9, `classmethod` starts to support creating a "class property". This allows to describe it. --- CHANGES | 3 +++ doc/usage/restructuredtext/domains.rst | 7 +++++++ sphinx/domains/python.py | 8 ++++++-- tests/test_domain_py.py | 24 +++++++++++++++++++----- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index 5658cc43f1..d4fc4d2115 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,9 @@ Deprecated Features added -------------- +* #9445: py domain: ``:py:property:`` directive supports ``:classmethod:`` + option to describe the class property + Bugs fixed ---------- diff --git a/doc/usage/restructuredtext/domains.rst b/doc/usage/restructuredtext/domains.rst index 23844886e1..abece42131 100644 --- a/doc/usage/restructuredtext/domains.rst +++ b/doc/usage/restructuredtext/domains.rst @@ -329,6 +329,13 @@ The following directives are provided for module and class contents: Indicate the property is abstract. + .. rst:directive:option:: classmethod + :type: no value + + Indicate the property is a classmethod. + + .. versionaddedd: 4.2 + .. rst:directive:option:: type: type of the property :type: text diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index d79de154ec..e8330e81cf 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -852,6 +852,7 @@ class PyProperty(PyObject): option_spec = PyObject.option_spec.copy() option_spec.update({ 'abstractmethod': directives.flag, + 'classmethod': directives.flag, 'type': directives.unchanged, }) @@ -865,10 +866,13 @@ def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str] return fullname, prefix def get_signature_prefix(self, sig: str) -> str: - prefix = ['property'] + prefix = [] if 'abstractmethod' in self.options: - prefix.insert(0, 'abstract') + prefix.append('abstract') + if 'classmethod' in self.options: + prefix.append('class') + prefix.append('property') return ' '.join(prefix) + ' ' def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index e4fb08155b..8b72f8b7a2 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -813,8 +813,12 @@ def test_pyattribute(app): def test_pyproperty(app): text = (".. py:class:: Class\n" "\n" - " .. py:property:: prop\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) @@ -822,15 +826,25 @@ def test_pyproperty(app): [desc, ([desc_signature, ([desc_annotation, "class "], [desc_name, "Class"])], [desc_content, (addnodes.index, + desc, + addnodes.index, desc)])])) assert_node(doctree[1][1][0], addnodes.index, - entries=[('single', 'prop (Class property)', 'Class.prop', '', None)]) + entries=[('single', 'prop1 (Class property)', 'Class.prop1', '', None)]) assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "abstract property "], - [desc_name, "prop"], + [desc_name, "prop1"], + [desc_annotation, ": 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 property "], + [desc_name, "prop2"], [desc_annotation, ": str"])], [desc_content, ()])) - assert 'Class.prop' in domain.objects - assert domain.objects['Class.prop'] == ('index', 'Class.prop', 'property', False) + 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):