Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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 incorrect behaviour on Python 3.9 and Python 3.10 that meant that
calling `isinstance` with `typing_extensions.Concatenate[...]` or
`typing_extensions.Unpack[...]` as the first argument could have a different
Expand Down
24 changes: 24 additions & 0 deletions src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,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)
Expand Down Expand Up @@ -6792,6 +6796,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):
Expand Down
17 changes: 15 additions & 2 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2634,10 +2634,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):
Expand Down Expand Up @@ -2715,7 +2723,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+
Expand Down