Skip to content

Commit d8a9b9c

Browse files
authored
Add support for paramspec (#255)
1 parent ccc75d2 commit d8a9b9c

File tree

5 files changed

+16
-6
lines changed

5 files changed

+16
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 1.20
44

55
- Use hatchling instead of setuptools
6+
- Add support for typing.ParamSpec
67

78
## 1.19.2
89

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ optional-dependencies.testing = [
2828
"sphobjinv>=2.2.2",
2929
"typing-extensions>=4.3",
3030
]
31-
optional-dependencies.type_comment = ['typed-ast>=1.5.4; python_version < "3.8"']
31+
optional-dependencies.type-comment = ['typed-ast>=1.5.4; python_version < "3.8"']
3232
dynamic = ["version"]
3333
classifiers = [
3434
"Development Status :: 5 - Production/Stable",

src/sphinx_autodoc_typehints/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def get_annotation_module(annotation: Any) -> str:
2626
if annotation is None:
2727
return "builtins"
2828
is_new_type = sys.version_info >= (3, 10) and isinstance(annotation, NewType)
29-
if is_new_type or isinstance(annotation, TypeVar):
29+
if is_new_type or isinstance(annotation, TypeVar) or type(annotation).__name__ == "ParamSpec":
3030
return "typing"
3131
if hasattr(annotation, "__module__"):
3232
return annotation.__module__ # type: ignore # deduced Any
@@ -63,8 +63,8 @@ def get_annotation_class_name(annotation: Any, module: str) -> str:
6363
elif getattr(origin, "_name", None): # Required for Union on Python 3.7+
6464
return origin._name # type: ignore # deduced Any
6565

66-
annotation_cls = annotation if inspect.isclass(annotation) else annotation.__class__
67-
return annotation_cls.__qualname__.lstrip("_") # type: ignore # deduced Any
66+
annotation_cls = annotation if inspect.isclass(annotation) else type(annotation)
67+
return annotation_cls.__qualname__.lstrip("_")
6868

6969

7070
def get_annotation_args(annotation: Any, module: str, class_name: str) -> tuple[Any, ...]:
@@ -153,7 +153,7 @@ def format_annotation(annotation: Any, config: Config) -> str: # noqa: C901 # t
153153
if full_name == "typing.NewType":
154154
args_format = f"\\(``{annotation.__name__}``, {{}})"
155155
role = "class" if sys.version_info >= (3, 10) else "func"
156-
elif full_name == "typing.TypeVar":
156+
elif full_name in {"typing.TypeVar", "typing.ParamSpec"}:
157157
params = {k: getattr(annotation, f"__{k}__") for k in ("bound", "covariant", "contravariant")}
158158
params = {k: v for k, v in params.items() if v}
159159
if "bound" in params:

tests/test_sphinx_autodoc_typehints.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@
5656
Z = TypeVar("Z", bound="A")
5757
S = TypeVar("S", bound="miss") # type: ignore # miss not defined on purpose # noqa: F821
5858
W = NewType("W", str)
59+
P = typing_extensions.ParamSpec("P")
60+
P_co = typing_extensions.ParamSpec("P_co", covariant=True) # type: ignore
61+
P_contra = typing_extensions.ParamSpec("P_contra", contravariant=True) # type: ignore
62+
P_bound = typing_extensions.ParamSpec("P_bound", bound=str) # type: ignore
5963

6064
# Mypy does not support recursive type aliases, but
6165
# other type checkers do.
@@ -239,6 +243,11 @@ def test_parse_annotation(annotation: Any, module: str, class_name: str, args: t
239243
(Y, ":py:class:`~typing.TypeVar`\\(``Y``, bound= :py:class:`str`)"),
240244
(Z, ":py:class:`~typing.TypeVar`\\(``Z``, bound= A)"),
241245
(S, ":py:class:`~typing.TypeVar`\\(``S``, bound= miss)"),
246+
# ParamSpec should behave like TypeVar, except for missing constraints
247+
(P, ":py:class:`~typing.ParamSpec`\\(``P``)"),
248+
(P_co, ":py:class:`~typing.ParamSpec`\\(``P_co``, covariant=True)"),
249+
(P_contra, ":py:class:`~typing.ParamSpec`\\(``P_contra``, contravariant=True)"),
250+
(P_bound, ":py:class:`~typing.ParamSpec`\\(``P_bound``, bound= :py:class:`str`)"),
242251
# ## These test for correct internal tuple rendering, even if not all are valid Tuple types
243252
# Zero-length tuple remains
244253
(Tuple[()], ":py:data:`~typing.Tuple`"),

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ setenv =
2222
COVERAGE_FILE = {toxworkdir}{/}.coverage.{envname}
2323
extras =
2424
testing
25-
type_comments
25+
type-comment
2626
commands =
2727
pytest {tty:--color=yes} {posargs: \
2828
--junitxml {toxworkdir}{/}junit.{envname}.xml --cov {envsitepackagesdir}{/}sphinx_autodoc_typehints --cov {toxinidir}{/}tests \

0 commit comments

Comments
 (0)