diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cd98764..19fb1003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ called on a concrete subclass of a generic class. Patch by Alex Waygood (backporting https://github.com/python/cpython/pull/107584, by James Hilton-Balfe). +- Fix bug where `ParamSpec(default=...)` would raise a `TypeError` on Python + versions <3.11. Patch by James Hilton-Balfe # Release 4.7.1 (July 2, 2023) diff --git a/doc/index.rst b/doc/index.rst index ea7ff549..33492e52 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -278,6 +278,11 @@ Special typing primitives The implementation was changed for compatibility with Python 3.12. + .. versionchanged:: 4.8.0 + + Passing an ellipsis literal (``...``) to *default* now works on Python + 3.10 and lower. + .. class:: ParamSpecArgs .. class:: ParamSpecKwargs diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index e741d699..fcebf131 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -5593,6 +5593,9 @@ def test_paramspec(self): class A(Generic[P]): ... Alias = typing.Callable[P, None] + P_default = ParamSpec('P_default', default=...) + self.assertIs(P_default.__default__, ...) + def test_typevartuple(self): Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]]) self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]]) diff --git a/src/typing_extensions.py b/src/typing_extensions.py index b0b1bceb..97a0d1cd 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -1277,7 +1277,10 @@ def _set_default(type_param, default): type_param.__default__ = tuple((typing._type_check(d, "Default must be a type") for d in default)) elif default != _marker: - type_param.__default__ = typing._type_check(default, "Default must be a type") + if isinstance(type_param, ParamSpec) and default is ...: # ... not valid <3.11 + type_param.__default__ = default + else: + type_param.__default__ = typing._type_check(default, "Default must be a type") else: type_param.__default__ = None