Skip to content

Commit 73dd9fc

Browse files
authored
Restore support for typing.ParamSpec (#12581)
1 parent 18ac58b commit 73dd9fc

File tree

3 files changed

+42
-3
lines changed

3 files changed

+42
-3
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Bugs fixed
1818

1919
* Fix invalid HTML when a rubric node with invalid ``heading-level`` is used.
2020
Patch by Adam Turner.
21+
* #12579, #12581: Restore support for ``typing.ParamSpec`` in autodoc.
22+
Patch by Adam Turner.
2123

2224
Testing
2325
-------

sphinx/util/typing.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ def _is_unpack_form(obj: Any) -> bool:
212212

213213
def _typing_internal_name(obj: Any) -> str | None:
214214
if sys.version_info[:2] >= (3, 10):
215-
return obj.__name__
215+
try:
216+
return obj.__name__
217+
except AttributeError:
218+
# e.g. ParamSpecArgs, ParamSpecKwargs
219+
return ''
216220
return getattr(obj, '_name', None)
217221

218222

@@ -237,7 +241,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
237241
raise ValueError(msg)
238242

239243
# things that are not types
240-
if cls in {None, NoneType}:
244+
if cls is None or cls == NoneType:
241245
return ':py:obj:`None`'
242246
if cls is Ellipsis:
243247
return '...'
@@ -388,7 +392,7 @@ def stringify_annotation(
388392
raise ValueError(msg)
389393

390394
# things that are not types
391-
if annotation in {None, NoneType}:
395+
if annotation is None or annotation == NoneType:
392396
return 'None'
393397
if annotation is Ellipsis:
394398
return '...'

tests/test_util/test_util_typing.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,21 @@ def test_restify_mock():
385385
assert restify(unknown.secret.Class, "smart") == ':py:class:`~unknown.secret.Class`'
386386

387387

388+
@pytest.mark.xfail(sys.version_info[:2] <= (3, 9), reason='ParamSpec not supported in Python 3.9.')
389+
def test_restify_type_hints_paramspec():
390+
from typing import ParamSpec
391+
P = ParamSpec('P')
392+
393+
assert restify(P) == ":py:obj:`tests.test_util.test_util_typing.P`"
394+
assert restify(P, "smart") == ":py:obj:`~tests.test_util.test_util_typing.P`"
395+
396+
assert restify(P.args) == "P.args"
397+
assert restify(P.args, "smart") == "P.args"
398+
399+
assert restify(P.kwargs) == "P.kwargs"
400+
assert restify(P.kwargs, "smart") == "P.kwargs"
401+
402+
388403
def test_stringify_annotation():
389404
assert stringify_annotation(int, 'fully-qualified-except-typing') == "int"
390405
assert stringify_annotation(int, "smart") == "int"
@@ -722,3 +737,21 @@ def test_stringify_type_ForwardRef():
722737
assert stringify_annotation(Tuple[dict[ForwardRef("MyInt"), str], list[List[int]]]) == "Tuple[dict[MyInt, str], list[List[int]]]" # type: ignore[attr-defined]
723738
assert stringify_annotation(Tuple[dict[ForwardRef("MyInt"), str], list[List[int]]], 'fully-qualified-except-typing') == "Tuple[dict[MyInt, str], list[List[int]]]" # type: ignore[attr-defined]
724739
assert stringify_annotation(Tuple[dict[ForwardRef("MyInt"), str], list[List[int]]], 'smart') == "~typing.Tuple[dict[MyInt, str], list[~typing.List[int]]]" # type: ignore[attr-defined]
740+
741+
742+
@pytest.mark.xfail(sys.version_info[:2] <= (3, 9), reason='ParamSpec not supported in Python 3.9.')
743+
def test_stringify_type_hints_paramspec():
744+
from typing import ParamSpec
745+
P = ParamSpec('P')
746+
747+
assert stringify_annotation(P, 'fully-qualified') == "~P"
748+
assert stringify_annotation(P, 'fully-qualified-except-typing') == "~P"
749+
assert stringify_annotation(P, "smart") == "~P"
750+
751+
assert stringify_annotation(P.args, 'fully-qualified') == "typing.~P"
752+
assert stringify_annotation(P.args, 'fully-qualified-except-typing') == "~P"
753+
assert stringify_annotation(P.args, "smart") == "~typing.~P"
754+
755+
assert stringify_annotation(P.kwargs, 'fully-qualified') == "typing.~P"
756+
assert stringify_annotation(P.kwargs, 'fully-qualified-except-typing') == "~P"
757+
assert stringify_annotation(P.kwargs, "smart") == "~typing.~P"

0 commit comments

Comments
 (0)