Skip to content

Commit 23378be

Browse files
authored
Don't turn list defaults for ParamSpecs into tuples (#394)
1 parent 479ac33 commit 23378be

File tree

3 files changed

+18
-13
lines changed

3 files changed

+18
-13
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
- It is now disallowed to use a `TypeVar` with a default value after a
1919
`TypeVarTuple` in a type parameter list. This matches the CPython
2020
implementation of PEP 696 on Python 3.13+.
21+
- Fix bug in PEP-696 implementation where default values for `ParamSpec`s
22+
would be cast to tuples if a list was provided as the default value.
23+
Patch by Alex Waygood.
2124
- Fix `Protocol` tests on Python 3.13.0a6 and newer. 3.13.0a6 adds a new
2225
`__static_attributes__` attribute to all classes in Python,
2326
which broke some assumptions made by the implementation of

src/test_typing_extensions.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -4997,7 +4997,7 @@ def test_pickle(self):
49974997
P = ParamSpec('P')
49984998
P_co = ParamSpec('P_co', covariant=True)
49994999
P_contra = ParamSpec('P_contra', contravariant=True)
5000-
P_default = ParamSpec('P_default', default=int)
5000+
P_default = ParamSpec('P_default', default=[int])
50015001
for proto in range(pickle.HIGHEST_PROTOCOL):
50025002
with self.subTest(f'Pickle protocol {proto}'):
50035003
for paramspec in (P, P_co, P_contra, P_default):
@@ -6363,8 +6363,8 @@ def test_typevar_none(self):
63636363
self.assertTrue(U_None.has_default())
63646364

63656365
def test_paramspec(self):
6366-
P = ParamSpec('P', default=(str, int))
6367-
self.assertEqual(P.__default__, (str, int))
6366+
P = ParamSpec('P', default=[str, int])
6367+
self.assertEqual(P.__default__, [str, int])
63686368
self.assertTrue(P.has_default())
63696369
self.assertIsInstance(P, ParamSpec)
63706370
if hasattr(typing, "ParamSpec"):
@@ -6457,6 +6457,17 @@ def test_pickle(self):
64576457
self.assertEqual(z.__bound__, typevar.__bound__)
64586458
self.assertEqual(z.__default__, typevar.__default__)
64596459

6460+
def test_strange_defaults_are_allowed(self):
6461+
# Leave it to type checkers to check whether strange default values
6462+
# should be allowed or disallowed
6463+
def not_a_type(): ...
6464+
6465+
for typevarlike_cls in TypeVar, ParamSpec, TypeVarTuple:
6466+
for default in not_a_type, 42, bytearray(), (int, not_a_type, 42):
6467+
with self.subTest(typevarlike_cls=typevarlike_cls, default=default):
6468+
T = typevarlike_cls("T", default=default)
6469+
self.assertEqual(T.__default__, default)
6470+
64606471
@skip_if_py313_beta_1
64616472
def test_allow_default_after_non_default_in_alias(self):
64626473
T_default = TypeVar('T_default', default=int)

src/typing_extensions.py

+1-10
Original file line numberDiff line numberDiff line change
@@ -1467,16 +1467,7 @@ def __reduce__(self):
14671467

14681468
def _set_default(type_param, default):
14691469
type_param.has_default = lambda: default is not NoDefault
1470-
if isinstance(default, (tuple, list)):
1471-
type_param.__default__ = tuple((typing._type_check(d, "Default must be a type")
1472-
for d in default))
1473-
elif default in (None, NoDefault):
1474-
type_param.__default__ = default
1475-
else:
1476-
if isinstance(type_param, ParamSpec) and default is ...: # ... not valid <3.11
1477-
type_param.__default__ = default
1478-
else:
1479-
type_param.__default__ = typing._type_check(default, "Default must be a type")
1470+
type_param.__default__ = default
14801471

14811472

14821473
def _set_module(typevarlike):

0 commit comments

Comments
 (0)