diff --git a/CHANGELOG.md b/CHANGELOG.md index f35c4827..98aaab62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Unreleased +- Update error message when attempting to subclass `typing_extensions.TypeVarTuple` + to align with the message produced by `typing` in Python 3.12+. + Patch by Jan-Eric Nitschke. - Fix setting of `__required_keys__` and `__optional_keys__` when inheriting keys with the same name. - Fix incorrect behaviour on Python 3.9 and Python 3.10 that meant that diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index c7025321..4fbed731 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -111,6 +111,10 @@ KT = TypeVar("KT") VT = TypeVar("VT") +CANNOT_SUBCLASS_TYPE = 'Cannot subclass special typing classes' +NOT_A_BASE_TYPE = r"type '(?:typing|typing_extensions).%s' is not an acceptable base type" +CANNOT_SUBCLASS_INSTANCE = 'Cannot subclass an instance of %s' + # Flags used to mark tests that only apply after a specific # version of the typing module. TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0) @@ -6838,6 +6842,26 @@ def test_pickle(self): self.assertEqual(z.__name__, typevartuple.__name__) self.assertEqual(z.__default__, typevartuple.__default__) + def test_cannot_subclass(self): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'TypeVarTuple'): + class C(TypeVarTuple): pass + Ts = TypeVarTuple('Ts') + with self.assertRaisesRegex(TypeError, + CANNOT_SUBCLASS_INSTANCE % 'TypeVarTuple'): + class D(Ts): pass + with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + class E(type(Unpack)): pass + with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + class F(type(*Ts)): pass + with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + class G(type(Unpack[Ts])): pass + with self.assertRaises(TypeError): + class H(Unpack): pass + with self.assertRaises(TypeError): + class I(*Ts): pass # noqa: E742 + with self.assertRaises(TypeError): + class J(Unpack[Ts]): pass + class FinalDecoratorTests(BaseTestCase): def test_final_unmodified(self): diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 05d4522c..da481aac 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -2697,10 +2697,18 @@ def _typevartuple_prepare_subst(alias, args): ) tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst + + def __mro_entries__(bases): + raise TypeError("Cannot subclass an instance of TypeVarTuple.") + tvt.__mro_entries__ = __mro_entries__ + return tvt def __init_subclass__(self, *args, **kwds): - raise TypeError("Cannot subclass special typing classes") + raise TypeError( + f"type '{__name__}.TypeVarTuple' is not an acceptable base type" + ) + else: # <=3.10 class TypeVarTuple(_DefaultMixin): @@ -2778,7 +2786,12 @@ def __reduce__(self): def __init_subclass__(self, *args, **kwds): if '_root' not in kwds: - raise TypeError("Cannot subclass special typing classes") + raise TypeError( + f"type '{__name__}.TypeVarTuple' is not an acceptable base type" + ) + + def __mro_entries__(self, bases): + raise TypeError("Cannot subclass an instance of TypeVarTuple.") if hasattr(typing, "reveal_type"): # 3.11+