From 7f2a3258f17be6107e45ef1aa04c4512a50ca333 Mon Sep 17 00:00:00 2001 From: Numerlor Date: Mon, 19 Sep 2022 00:25:08 +0200 Subject: [PATCH 1/6] Add support for paramspec the type accesses have to use the type builtin to get the correct type in case __class__ is patched --- src/sphinx_autodoc_typehints/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sphinx_autodoc_typehints/__init__.py b/src/sphinx_autodoc_typehints/__init__.py index 753921be..653957ea 100644 --- a/src/sphinx_autodoc_typehints/__init__.py +++ b/src/sphinx_autodoc_typehints/__init__.py @@ -26,7 +26,7 @@ def get_annotation_module(annotation: Any) -> str: if annotation is None: return "builtins" is_new_type = sys.version_info >= (3, 10) and isinstance(annotation, NewType) - if is_new_type or isinstance(annotation, TypeVar): + if is_new_type or isinstance(annotation, TypeVar) or type(annotation).__name__ == "ParamSpec": return "typing" if hasattr(annotation, "__module__"): return annotation.__module__ # type: ignore # deduced Any @@ -63,7 +63,7 @@ def get_annotation_class_name(annotation: Any, module: str) -> str: elif getattr(origin, "_name", None): # Required for Union on Python 3.7+ return origin._name # type: ignore # deduced Any - annotation_cls = annotation if inspect.isclass(annotation) else annotation.__class__ + annotation_cls = annotation if inspect.isclass(annotation) else type(annotation) return annotation_cls.__qualname__.lstrip("_") # type: ignore # deduced Any @@ -153,7 +153,7 @@ def format_annotation(annotation: Any, config: Config) -> str: # noqa: C901 # t if full_name == "typing.NewType": args_format = f"\\(``{annotation.__name__}``, {{}})" role = "class" if sys.version_info >= (3, 10) else "func" - elif full_name == "typing.TypeVar": + elif full_name in {"typing.TypeVar", "typing.ParamSpec"}: params = {k: getattr(annotation, f"__{k}__") for k in ("bound", "covariant", "contravariant")} params = {k: v for k, v in params.items() if v} if "bound" in params: From 19f7937299b4e8a8f3d825f7e54d8a7e9ec089c0 Mon Sep 17 00:00:00 2001 From: Numerlor Date: Mon, 19 Sep 2022 13:45:00 +0200 Subject: [PATCH 2/6] add paramspec tests --- tests/test_sphinx_autodoc_typehints.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_sphinx_autodoc_typehints.py b/tests/test_sphinx_autodoc_typehints.py index dda77fa6..9d818eb0 100644 --- a/tests/test_sphinx_autodoc_typehints.py +++ b/tests/test_sphinx_autodoc_typehints.py @@ -56,6 +56,10 @@ Z = TypeVar("Z", bound="A") S = TypeVar("S", bound="miss") # type: ignore # miss not defined on purpose # noqa: F821 W = NewType("W", str) +P = typing_extensions.ParamSpec("P") +P_co = typing_extensions.ParamSpec("P_co", covariant=True) +P_contra = typing_extensions.ParamSpec("P_contra", contravariant=True) +P_bound = typing_extensions.ParamSpec("P_bound", bound=str) # Mypy does not support recursive type aliases, but # other type checkers do. @@ -239,6 +243,11 @@ def test_parse_annotation(annotation: Any, module: str, class_name: str, args: t (Y, ":py:class:`~typing.TypeVar`\\(``Y``, bound= :py:class:`str`)"), (Z, ":py:class:`~typing.TypeVar`\\(``Z``, bound= A)"), (S, ":py:class:`~typing.TypeVar`\\(``S``, bound= miss)"), + # ParamSpec should behave like TypeVar, except for missing constraints + (P, ":py:class:`~typing.ParamSpec`\\(``P``)"), + (P_co, ":py:class:`~typing.ParamSpec`\\(``P_co``, covariant=True)"), + (P_contra, ":py:class:`~typing.ParamSpec`\\(``P_contra``, contravariant=True)"), + (P_bound, ":py:class:`~typing.ParamSpec`\\(``P_bound``, bound= :py:class:`str`)"), # ## These test for correct internal tuple rendering, even if not all are valid Tuple types # Zero-length tuple remains (Tuple[()], ":py:data:`~typing.Tuple`"), From cd58a57f037d8db136bce3a01093e7fdfdbcae96 Mon Sep 17 00:00:00 2001 From: Numerlor Date: Mon, 19 Sep 2022 13:47:19 +0200 Subject: [PATCH 3/6] add paramspec to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 907e1e1a..2f6ea3aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 1.20 - Use hatchling instead of setuptools +- Add support for typing.ParamSpec ## 1.19.2 From dc8f06af05135c6e9d0351d2018a348e575d1af8 Mon Sep 17 00:00:00 2001 From: Numerlor Date: Mon, 19 Sep 2022 18:41:16 +0200 Subject: [PATCH 4/6] remove unused type ignore --- src/sphinx_autodoc_typehints/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphinx_autodoc_typehints/__init__.py b/src/sphinx_autodoc_typehints/__init__.py index 653957ea..32e81240 100644 --- a/src/sphinx_autodoc_typehints/__init__.py +++ b/src/sphinx_autodoc_typehints/__init__.py @@ -64,7 +64,7 @@ def get_annotation_class_name(annotation: Any, module: str) -> str: return origin._name # type: ignore # deduced Any annotation_cls = annotation if inspect.isclass(annotation) else type(annotation) - return annotation_cls.__qualname__.lstrip("_") # type: ignore # deduced Any + return annotation_cls.__qualname__.lstrip("_") def get_annotation_args(annotation: Any, module: str, class_name: str) -> tuple[Any, ...]: From 49de7fcbb1f42390b42c19bf18a6a4eddf7a2951 Mon Sep 17 00:00:00 2001 From: Numerlor Date: Mon, 19 Sep 2022 18:41:47 +0200 Subject: [PATCH 5/6] ignore undefined semantics on paramspec arguments --- tests/test_sphinx_autodoc_typehints.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_sphinx_autodoc_typehints.py b/tests/test_sphinx_autodoc_typehints.py index 9d818eb0..48013eea 100644 --- a/tests/test_sphinx_autodoc_typehints.py +++ b/tests/test_sphinx_autodoc_typehints.py @@ -57,9 +57,9 @@ S = TypeVar("S", bound="miss") # type: ignore # miss not defined on purpose # noqa: F821 W = NewType("W", str) P = typing_extensions.ParamSpec("P") -P_co = typing_extensions.ParamSpec("P_co", covariant=True) -P_contra = typing_extensions.ParamSpec("P_contra", contravariant=True) -P_bound = typing_extensions.ParamSpec("P_bound", bound=str) +P_co = typing_extensions.ParamSpec("P_co", covariant=True) # type: ignore +P_contra = typing_extensions.ParamSpec("P_contra", contravariant=True) # type: ignore +P_bound = typing_extensions.ParamSpec("P_bound", bound=str) # type: ignore # Mypy does not support recursive type aliases, but # other type checkers do. From 98607085d47d0adb3c9ed765418eaa061ed6fd3a Mon Sep 17 00:00:00 2001 From: Numerlor Date: Tue, 20 Sep 2022 01:08:59 +0200 Subject: [PATCH 6/6] use dash instead of underscore for extra the underscore caused pip to miss it, and tests to fail --- pyproject.toml | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ab792c78..0e4bbe09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ optional-dependencies.testing = [ "sphobjinv>=2.2.2", "typing-extensions>=4.3", ] -optional-dependencies.type_comment = ['typed-ast>=1.5.4; python_version < "3.8"'] +optional-dependencies.type-comment = ['typed-ast>=1.5.4; python_version < "3.8"'] dynamic = ["version"] classifiers = [ "Development Status :: 5 - Production/Stable", diff --git a/tox.ini b/tox.ini index dbc09722..4f80f90f 100644 --- a/tox.ini +++ b/tox.ini @@ -22,7 +22,7 @@ setenv = COVERAGE_FILE = {toxworkdir}{/}.coverage.{envname} extras = testing - type_comments + type-comment commands = pytest {tty:--color=yes} {posargs: \ --junitxml {toxworkdir}{/}junit.{envname}.xml --cov {envsitepackagesdir}{/}sphinx_autodoc_typehints --cov {toxinidir}{/}tests \