Restore support for `typing.ParamSpec` (#12581)

This commit is contained in:
Adam Turner 2024-07-15 11:00:13 +01:00 committed by GitHub
parent 18ac58bd53
commit 73dd9fcb9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 3 deletions

View File

@ -18,6 +18,8 @@ Bugs fixed
* Fix invalid HTML when a rubric node with invalid ``heading-level`` is used. * Fix invalid HTML when a rubric node with invalid ``heading-level`` is used.
Patch by Adam Turner. Patch by Adam Turner.
* #12579, #12581: Restore support for ``typing.ParamSpec`` in autodoc.
Patch by Adam Turner.
Testing Testing
------- -------

View File

@ -212,7 +212,11 @@ def _is_unpack_form(obj: Any) -> bool:
def _typing_internal_name(obj: Any) -> str | None: def _typing_internal_name(obj: Any) -> str | None:
if sys.version_info[:2] >= (3, 10): if sys.version_info[:2] >= (3, 10):
return obj.__name__ try:
return obj.__name__
except AttributeError:
# e.g. ParamSpecArgs, ParamSpecKwargs
return ''
return getattr(obj, '_name', None) return getattr(obj, '_name', None)
@ -237,7 +241,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
raise ValueError(msg) raise ValueError(msg)
# things that are not types # things that are not types
if cls in {None, NoneType}: if cls is None or cls == NoneType:
return ':py:obj:`None`' return ':py:obj:`None`'
if cls is Ellipsis: if cls is Ellipsis:
return '...' return '...'
@ -388,7 +392,7 @@ def stringify_annotation(
raise ValueError(msg) raise ValueError(msg)
# things that are not types # things that are not types
if annotation in {None, NoneType}: if annotation is None or annotation == NoneType:
return 'None' return 'None'
if annotation is Ellipsis: if annotation is Ellipsis:
return '...' return '...'

View File

@ -385,6 +385,21 @@ def test_restify_mock():
assert restify(unknown.secret.Class, "smart") == ':py:class:`~unknown.secret.Class`' assert restify(unknown.secret.Class, "smart") == ':py:class:`~unknown.secret.Class`'
@pytest.mark.xfail(sys.version_info[:2] <= (3, 9), reason='ParamSpec not supported in Python 3.9.')
def test_restify_type_hints_paramspec():
from typing import ParamSpec
P = ParamSpec('P')
assert restify(P) == ":py:obj:`tests.test_util.test_util_typing.P`"
assert restify(P, "smart") == ":py:obj:`~tests.test_util.test_util_typing.P`"
assert restify(P.args) == "P.args"
assert restify(P.args, "smart") == "P.args"
assert restify(P.kwargs) == "P.kwargs"
assert restify(P.kwargs, "smart") == "P.kwargs"
def test_stringify_annotation(): def test_stringify_annotation():
assert stringify_annotation(int, 'fully-qualified-except-typing') == "int" assert stringify_annotation(int, 'fully-qualified-except-typing') == "int"
assert stringify_annotation(int, "smart") == "int" assert stringify_annotation(int, "smart") == "int"
@ -722,3 +737,21 @@ def test_stringify_type_ForwardRef():
assert stringify_annotation(Tuple[dict[ForwardRef("MyInt"), str], list[List[int]]]) == "Tuple[dict[MyInt, str], list[List[int]]]" # type: ignore[attr-defined] assert stringify_annotation(Tuple[dict[ForwardRef("MyInt"), str], list[List[int]]]) == "Tuple[dict[MyInt, str], list[List[int]]]" # type: ignore[attr-defined]
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] 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]
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] 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]
@pytest.mark.xfail(sys.version_info[:2] <= (3, 9), reason='ParamSpec not supported in Python 3.9.')
def test_stringify_type_hints_paramspec():
from typing import ParamSpec
P = ParamSpec('P')
assert stringify_annotation(P, 'fully-qualified') == "~P"
assert stringify_annotation(P, 'fully-qualified-except-typing') == "~P"
assert stringify_annotation(P, "smart") == "~P"
assert stringify_annotation(P.args, 'fully-qualified') == "typing.~P"
assert stringify_annotation(P.args, 'fully-qualified-except-typing') == "~P"
assert stringify_annotation(P.args, "smart") == "~typing.~P"
assert stringify_annotation(P.kwargs, 'fully-qualified') == "typing.~P"
assert stringify_annotation(P.kwargs, 'fully-qualified-except-typing') == "~P"
assert stringify_annotation(P.kwargs, "smart") == "~typing.~P"