From aaeb5617ac891efa554cb49694eb011ad74e50aa Mon Sep 17 00:00:00 2001 From: Casey Brooks Date: Fri, 26 Dec 2025 21:11:27 +0000 Subject: [PATCH] fix(python): omit parens for method property --- sphinx/deprecation.py | 4 +++ sphinx/domains/python.py | 9 ++++-- .../test-domain-py-method-property/conf.py | 3 ++ .../test-domain-py-method-property/index.rst | 7 +++++ tests/test_domain_py.py | 31 ++++++++++++++++++- 5 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/roots/test-domain-py-method-property/conf.py create mode 100644 tests/roots/test-domain-py-method-property/index.rst diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index 3963e63615f..6b0bdd1588b 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -14,6 +14,10 @@ from typing import Any, Dict, Type +class RemovedInSphinx40Warning(DeprecationWarning): + pass + + class RemovedInSphinx50Warning(DeprecationWarning): pass diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index cd02eaad563..cbb78fe0a87 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -783,20 +783,23 @@ def get_signature_prefix(self, sig: str) -> List[nodes.Node]: def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: name, cls = name_cls + is_property = 'property' in self.options try: clsname, methname = name.rsplit('.', 1) if modname and self.env.config.add_module_names: clsname = '.'.join([modname, clsname]) except ValueError: if modname: + if is_property: + return _('%s (in module %s)') % (name, modname) return _('%s() (in module %s)') % (name, modname) else: - return '%s()' % name + return name if is_property else '%s()' % name if 'classmethod' in self.options: return _('%s() (%s class method)') % (methname, clsname) - elif 'property' in self.options: - return _('%s() (%s property)') % (methname, clsname) + elif is_property: + return _('%s (%s property)') % (methname, clsname) elif 'staticmethod' in self.options: return _('%s() (%s static method)') % (methname, clsname) else: diff --git a/tests/roots/test-domain-py-method-property/conf.py b/tests/roots/test-domain-py-method-property/conf.py new file mode 100644 index 00000000000..50f26f69fc3 --- /dev/null +++ b/tests/roots/test-domain-py-method-property/conf.py @@ -0,0 +1,3 @@ +project = 'domain-py-method-property' +extensions = [] +master_doc = 'index' diff --git a/tests/roots/test-domain-py-method-property/index.rst b/tests/roots/test-domain-py-method-property/index.rst new file mode 100644 index 00000000000..a80a7bb27b7 --- /dev/null +++ b/tests/roots/test-domain-py-method-property/index.rst @@ -0,0 +1,7 @@ +Method property index test +=========================== + +.. py:method:: Foo.bar + :property: + +.. py:property:: Foo.baz diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 682ea76e199..9c65085d606 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -756,7 +756,7 @@ def test_pymethod_options(app): # :property: assert_node(doctree[1][1][8], addnodes.index, - entries=[('single', 'meth5() (Class property)', 'Class.meth5', '', None)]) + entries=[('single', 'meth5 (Class property)', 'Class.meth5', '', None)]) assert_node(doctree[1][1][9], ([desc_signature, ([desc_annotation, ("property", desc_sig_space)], [desc_name, "meth5"])], [desc_content, ()])) @@ -784,6 +784,35 @@ def test_pymethod_options(app): assert domain.objects['Class.meth7'] == ('index', 'Class.meth7', 'method', False) +def test_pymethod_property_without_class(app): + text = (".. py:module:: example\n" + "\n" + ".. py:method:: module_property\n" + " :property:\n") + domain = app.env.get_domain('py') + doctree = restructuredtext.parse(app, text) + + indexes = list(doctree.traverse(addnodes.index)) + entries = [entry for node in indexes for entry in node['entries']] + assert ('single', 'module_property (in module example)', 'example.module_property', '', None) in entries + for _, text, *_ in entries: + if text.startswith('module_property'): + assert '()' not in text + assert 'example.module_property' in domain.objects + assert domain.objects['example.module_property'] == ('index', 'example.module_property', 'method', False) + + +@pytest.mark.sphinx('html', testroot='domain-py-method-property') +def test_pymethod_property_genindex(app): + app.build() + result = (app.outdir / 'genindex.html').read_text() + + assert 'bar() (Foo property)' not in result + assert 'bar (Foo property)' in result + assert 'baz() (Foo property)' not in result + assert 'baz (Foo property)' in result + + def test_pyclassmethod(app): text = (".. py:class:: Class\n" "\n"