Skip to content

Commit

Permalink
Add support for paramspec (#255)
Browse files Browse the repository at this point in the history
  • Loading branch information
Numerlor authored Sep 20, 2022
1 parent ccc75d2 commit d8a9b9c
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 1.20

- Use hatchling instead of setuptools
- Add support for typing.ParamSpec

## 1.19.2

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions src/sphinx_autodoc_typehints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -63,8 +63,8 @@ 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__
return annotation_cls.__qualname__.lstrip("_") # type: ignore # deduced Any
annotation_cls = annotation if inspect.isclass(annotation) else type(annotation)
return annotation_cls.__qualname__.lstrip("_")


def get_annotation_args(annotation: Any, module: str, class_name: str) -> tuple[Any, ...]:
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 9 additions & 0 deletions tests/test_sphinx_autodoc_typehints.py
Original file line number Diff line number Diff line change
Expand Up @@ -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) # 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.
Expand Down Expand Up @@ -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`"),
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down

0 comments on commit d8a9b9c

Please sign in to comment.