From ec201c21c2259fc57e59aa38a1cf8fb02b2f8b0f Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:22:49 +0100 Subject: [PATCH 1/4] Move signature option handling into get_items() get_items() already formats the signature. Handling :nosignatures: option in the saves the signature computation cost if the signature is not wanted. Also, this prepares for more complex signature options. --- sphinx/ext/autosummary/__init__.py | 38 +++++++++++++++++------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index ffae20af0ee..7714813ef9f 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -307,13 +307,15 @@ def create_documenter(self, app: Sphinx, obj: Any, doccls = get_documenter(app, obj, parent) return doccls(self.bridge, full_name) - def get_items(self, names: list[str]) -> list[tuple[str, str, str, str]]: + def get_items(self, names: list[str]) -> list[tuple[str, str | None, str, str]]: """Try to import the given names, and return a list of ``[(name, signature, summary_string, real_name), ...]``. + + signature is already formatted and is None if :nosignatures: option was given. """ prefixes = get_import_prefixes_from_env(self.env) - items: list[tuple[str, str, str, str]] = [] + items: list[tuple[str, str | None, str, str]] = [] max_item_chars = 50 @@ -365,17 +367,20 @@ def get_items(self, names: list[str]) -> list[tuple[str, str, str, str]]: # -- Grab the signature - try: - sig = documenter.format_signature(show_annotation=False) - except TypeError: - # the documenter does not support ``show_annotation`` option - sig = documenter.format_signature() - - if not sig: - sig = '' + if 'nosignatures' in self.options: + sig = None else: - max_chars = max(10, max_item_chars - len(display_name)) - sig = mangle_signature(sig, max_chars=max_chars) + try: + sig = documenter.format_signature(show_annotation=False) + except TypeError: + # the documenter does not support ``show_annotation`` option + sig = documenter.format_signature() + + if not sig: + sig = '' + else: + max_chars = max(10, max_item_chars - len(display_name)) + sig = mangle_signature(sig, max_chars=max_chars) # -- Grab the summary @@ -389,7 +394,7 @@ def get_items(self, names: list[str]) -> list[tuple[str, str, str, str]]: return items - def get_table(self, items: list[tuple[str, str, str, str]]) -> list[Node]: + def get_table(self, items: list[tuple[str, str | None, str, str]]) -> list[Node]: """Generate a proper list of table nodes for autosummary:: directive. *items* is a list produced by :meth:`get_items`. @@ -424,10 +429,11 @@ def append_row(*column_texts: str) -> None: for name, sig, summary, real_name in items: qualifier = 'obj' - if 'nosignatures' not in self.options: - col1 = f':py:{qualifier}:`{name} <{real_name}>`\\ {rst.escape(sig)}' - else: + if sig is None: col1 = f':py:{qualifier}:`{name} <{real_name}>`' + else: + col1 = f':py:{qualifier}:`{name} <{real_name}>`\\ {rst.escape(sig)}' + col2 = summary append_row(col1, col2) From 73bb50dcad9c4971d230e6ff21ba66e97e27b9f8 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:53:03 +0100 Subject: [PATCH 2/4] Add :signatures: option to autosummary directive This is in preparation of extending singature formating. --- doc/usage/extensions/autosummary.rst | 12 ++++++++++++ sphinx/ext/autosummary/__init__.py | 11 ++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/usage/extensions/autosummary.rst b/doc/usage/extensions/autosummary.rst index 0b2b0c69cf8..265864c4bc2 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -89,10 +89,22 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts: .. versionadded:: 3.1 + .. rst:directive:option:: signatures: format + + How to display signatures. Valid values are + + - ``long`` (*default*): use a long signature. This is still cut off so that name + plus signature do not exceeed a certain length. + - ``none``: do not show signatures. + + .. versionadded:: 9.0 + .. rst:directive:option:: nosignatures Do not show function signatures in the summary. + This is equivalent to ``:signatures: none``. + .. versionadded:: 0.6 .. rst:directive:option:: template: filename diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 7714813ef9f..351437ee1bc 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -228,6 +228,7 @@ class Autosummary(SphinxDirective): 'toctree': directives.unchanged, 'nosignatures': directives.flag, 'recursive': directives.flag, + 'signatures': directives.unchanged, 'template': directives.unchanged, } @@ -317,6 +318,14 @@ def get_items(self, names: list[str]) -> list[tuple[str, str | None, str, str]]: items: list[tuple[str, str | None, str, str]] = [] + signatures_option = self.options.get('signatures') + if signatures_option is None: + signatures_option = 'none' if self.options.get('nosignatures') else 'long' + if signatures_option not in ['none', 'long']: + raise ValueError(f"Invalid value for autosummary :signatures: option: " + f"{signatures_option!r}. " + f"Valid values are 'none', 'long'") + max_item_chars = 50 for name in names: @@ -367,7 +376,7 @@ def get_items(self, names: list[str]) -> list[tuple[str, str | None, str, str]]: # -- Grab the signature - if 'nosignatures' in self.options: + if signatures_option == 'none': sig = None else: try: From df273d62e3caffd345192ca995f8e5741d67ff43 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Fri, 6 Dec 2024 23:19:23 +0100 Subject: [PATCH 3/4] Add ":signatures: short" to autosummary directive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This formats functions and classes with (…) if they have arguments and () if they don't have arguments. This makes it easier to distinguish callables from attributes and properties. --- doc/usage/extensions/autosummary.rst | 4 +++- sphinx/ext/autosummary/__init__.py | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/doc/usage/extensions/autosummary.rst b/doc/usage/extensions/autosummary.rst index 265864c4bc2..2817732b5eb 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -95,9 +95,11 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts: - ``long`` (*default*): use a long signature. This is still cut off so that name plus signature do not exceeed a certain length. + - ``short``: Function and class signatures are displayed as ``(…)`` if they have + arguments and as ``()`` if they don't have arguments. - ``none``: do not show signatures. - .. versionadded:: 9.0 + .. versionadded:: 8.2 .. rst:directive:option:: nosignatures diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 351437ee1bc..7b93a551fb4 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -320,11 +320,11 @@ def get_items(self, names: list[str]) -> list[tuple[str, str | None, str, str]]: signatures_option = self.options.get('signatures') if signatures_option is None: - signatures_option = 'none' if self.options.get('nosignatures') else 'long' - if signatures_option not in ['none', 'long']: - raise ValueError(f"Invalid value for autosummary :signatures: option: " - f"{signatures_option!r}. " - f"Valid values are 'none', 'long'") + signatures_option = 'none' if 'nosignatures' in self.options else 'long' + if signatures_option not in {'none', 'short', 'long'}: + msg = ("Invalid value for autosummary :signatures: option: " + f"{signatures_option!r}. Valid values are 'none', 'short', 'long'") + raise ValueError(msg) max_item_chars = 50 @@ -384,10 +384,12 @@ def get_items(self, names: list[str]) -> list[tuple[str, str | None, str, str]]: except TypeError: # the documenter does not support ``show_annotation`` option sig = documenter.format_signature() - if not sig: sig = '' - else: + elif signatures_option == 'short': + if sig != '()': + sig = '(…)' + else: # signatures_option == 'long' max_chars = max(10, max_item_chars - len(display_name)) sig = mangle_signature(sig, max_chars=max_chars) From bf018908d7225447bf5e5e0ca5bf18e186271e68 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:09:14 +0100 Subject: [PATCH 4/4] Fix ruff --- sphinx/ext/autosummary/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index fe5ee064daf..2e3b972c90f 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -344,8 +344,10 @@ def get_items(self, names: list[str]) -> list[tuple[str, str | None, str, str]]: if signatures_option is None: signatures_option = 'none' if 'nosignatures' in self.options else 'long' if signatures_option not in {'none', 'short', 'long'}: - msg = ("Invalid value for autosummary :signatures: option: " - f"{signatures_option!r}. Valid values are 'none', 'short', 'long'") + msg = ( + 'Invalid value for autosummary :signatures: option: ' + f"{signatures_option!r}. Valid values are 'none', 'short', 'long'" + ) raise ValueError(msg) max_item_chars = 50