From fd498d49c83332759a31a6a57ee825b9143c790e Mon Sep 17 00:00:00 2001 From: unknown <55wokqe9@anonaddy.me> Date: Sat, 4 Jan 2025 12:06:54 +0100 Subject: [PATCH 1/4] ENH: implement typehints for parameters --- numpydoc/docscrape.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index bfc2840e..618e7cba 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -237,7 +237,8 @@ def _parse_param_list(self, content, single_element_is_type=False): if single_element_is_type: arg_name, arg_type = "", header else: - arg_name, arg_type = header, "" + arg_name = header + arg_type = self._get_type_from_signature(header) desc = r.read_to_next_unindented_line() desc = dedent_lines(desc) @@ -247,6 +248,9 @@ def _parse_param_list(self, content, single_element_is_type=False): return params + def _get_type_from_signature(self, arg_name: str) -> str: + return "" + # See also supports the following formats. # # @@ -577,6 +581,7 @@ def dedent_lines(lines): class FunctionDoc(NumpyDocString): def __init__(self, func, role="func", doc=None, config=None): self._f = func + self._signature = inspect.signature(func) self._role = role # e.g. "func" or "meth" if doc is None: @@ -610,6 +615,13 @@ def __str__(self): out += super().__str__(func_role=self._role) return out + def _get_type_from_signature(self, arg_name: str) -> str: + parameter = self._signature.parameters[arg_name.replace("*", "")] + if parameter.annotation == parameter.empty: + return "" + else: + return str(parameter.annotation) + class ObjDoc(NumpyDocString): def __init__(self, obj, doc=None, config=None): @@ -645,6 +657,9 @@ def __init__(self, cls, doc=None, modulename="", func_doc=FunctionDoc, config=No raise ValueError("No class or documentation string given") doc = pydoc.getdoc(cls) + if cls is not None: + self._signature = inspect.signature(cls.__init__) + NumpyDocString.__init__(self, doc) _members = config.get("members", []) @@ -728,6 +743,16 @@ def _is_show_member(self, name): or name in self._cls.__dict__ ) + def _get_type_from_signature(self, arg_name: str) -> str: + try: + parameter = self._signature.parameters[arg_name.replace("*", "")] + if parameter.annotation == parameter.empty: + return "" + else: + return str(parameter.annotation) + except AttributeError: + return "" + def get_doc_object( obj, From b6a41c48e80a5d8ffd5d42a9086e29547a47c47a Mon Sep 17 00:00:00 2001 From: Rastislav Turanyi Date: Wed, 8 Jan 2025 14:36:03 +0000 Subject: [PATCH 2/4] ENH: fix error when no signature for function For some functions, the signature cannot be obtained and so inspect.signature raises a ValueError, which can crash the sphinx build. This has been fixed by catching the exception --- numpydoc/docscrape.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 618e7cba..b374eb62 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -581,7 +581,11 @@ def dedent_lines(lines): class FunctionDoc(NumpyDocString): def __init__(self, func, role="func", doc=None, config=None): self._f = func - self._signature = inspect.signature(func) + try: + self._signature = inspect.signature(func) + except ValueError: + self._signature = None + self._role = role # e.g. "func" or "meth" if doc is None: @@ -616,7 +620,11 @@ def __str__(self): return out def _get_type_from_signature(self, arg_name: str) -> str: + if self._signature is None: + return "" + parameter = self._signature.parameters[arg_name.replace("*", "")] + if parameter.annotation == parameter.empty: return "" else: From 577d9a9dcf1964f49b053846c09c255f8ed25922 Mon Sep 17 00:00:00 2001 From: Rastislav Turanyi Date: Wed, 8 Jan 2025 15:40:29 +0000 Subject: [PATCH 3/4] ENH: increase ClassDoc._get_type_from_signature robustness For ClassDoc, the _get_type_from_signature method handles not only the docs for __init__, but also for the Attribute and Method etc. sections, whose typehints cannot be obtained from signature(__init__). Therefore, further code has been added that attempts to find the type hint from different sources and should work for functions, methods, properties, and attributes. --- numpydoc/docscrape.py | 52 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index b374eb62..35cd59d0 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -9,6 +9,7 @@ from collections import namedtuple from collections.abc import Callable, Mapping from functools import cached_property +from typing import ForwardRef, get_type_hints from warnings import warn @@ -666,7 +667,12 @@ def __init__(self, cls, doc=None, modulename="", func_doc=FunctionDoc, config=No doc = pydoc.getdoc(cls) if cls is not None: - self._signature = inspect.signature(cls.__init__) + try: + self._signature = inspect.signature(cls.__init__) + except ValueError: + self._signature = None + else: + self._signature = None NumpyDocString.__init__(self, doc) @@ -752,14 +758,50 @@ def _is_show_member(self, name): ) def _get_type_from_signature(self, arg_name: str) -> str: + if self._signature is None: + return "" + + arg_name = arg_name.replace("*", "") + try: + parameter = self._signature.parameters[arg_name] + except KeyError: + return self._find_type_hint(self._cls, arg_name) + + if parameter.annotation == parameter.empty: + return "" + else: + return str(parameter.annotation) + + @staticmethod + def _find_type_hint(cls: type, arg_name: str) -> str: + type_hints = get_type_hints(cls) try: - parameter = self._signature.parameters[arg_name.replace("*", "")] - if parameter.annotation == parameter.empty: + annotation = type_hints[arg_name] + except KeyError: + try: + attr = getattr(cls, arg_name) + except AttributeError: return "" + + attr = attr.fget if isinstance(attr, property) else attr + + if callable(attr): + try: + signature = inspect.signature(attr) + except ValueError: + return "" + + if signature.return_annotation == signature.empty: + return "" + else: + return str(signature.return_annotation) else: - return str(parameter.annotation) + return type(attr).__name__ + + try: + return str(annotation.__name__) except AttributeError: - return "" + return str(annotation) def get_doc_object( From dd8c5d823b0e2bf212b34c8696c8fe0d136b9e83 Mon Sep 17 00:00:00 2001 From: Rastislav Turanyi Date: Wed, 15 Jan 2025 10:07:19 +0000 Subject: [PATCH 4/4] ENH: Remove unused import ForwardRef is no longer necessary since the functionality is handled via typing.get_type_hints --- numpydoc/docscrape.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 35cd59d0..2695f7fa 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -9,7 +9,7 @@ from collections import namedtuple from collections.abc import Callable, Mapping from functools import cached_property -from typing import ForwardRef, get_type_hints +from typing import get_type_hints from warnings import warn