Skip to content

Commit

Permalink
Cut out variadic type substitution logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mrahtz committed Mar 5, 2022
1 parent f094905 commit b9b1c80
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 366 deletions.
178 changes: 27 additions & 151 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

from typing import Any, NoReturn, Never, assert_never
from typing import TypeVar, TypeVarTuple, Unpack, AnyStr
from typing import _determine_typevar_substitution
from typing import T, KT, VT # Not in __all__.
from typing import Union, Optional, Literal
from typing import Tuple, List, Dict, MutableMapping
Expand Down Expand Up @@ -479,45 +478,48 @@ class A(Generic[Unpack[Ts]]): pass

B = A[Unpack[Ts]]
self.assertTrue(repr(B).endswith('A[*Ts]'))
self.assertTrue(repr(B[()]).endswith('A[()]'))
self.assertTrue(repr(B[float]).endswith('A[float]'))
self.assertTrue(repr(B[float, str]).endswith('A[float, str]'))
with self.assertRaises(NotImplementedError):
B[()]
with self.assertRaises(NotImplementedError):
B[float]
with self.assertRaises(NotImplementedError):
B[float, str]

C = A[Unpack[Ts], int]
self.assertTrue(repr(C).endswith('A[*Ts, int]'))
self.assertTrue(repr(C[()]).endswith('A[int]'))
self.assertTrue(repr(C[float]).endswith('A[float, int]'))
self.assertTrue(repr(C[float, str]).endswith('A[float, str, int]'))
with self.assertRaises(NotImplementedError):
C[()]
with self.assertRaises(NotImplementedError):
C[float]
with self.assertRaises(NotImplementedError):
C[float, str]

D = A[int, Unpack[Ts]]
self.assertTrue(repr(D).endswith('A[int, *Ts]'))
self.assertTrue(repr(D[()]).endswith('A[int]'))
self.assertTrue(repr(D[float]).endswith('A[int, float]'))
self.assertTrue(repr(D[float, str]).endswith('A[int, float, str]'))
with self.assertRaises(NotImplementedError):
D[()]
with self.assertRaises(NotImplementedError):
D[float]
with self.assertRaises(NotImplementedError):
D[float, str]

E = A[int, Unpack[Ts], str]
self.assertTrue(repr(E).endswith('A[int, *Ts, str]'))
self.assertTrue(repr(E[()]).endswith('A[int, str]'))
self.assertTrue(repr(E[float]).endswith('A[int, float, str]'))
self.assertTrue(repr(E[float, bool]).endswith('A[int, float, bool, str]'))
with self.assertRaises(NotImplementedError):
E[()]
with self.assertRaises(NotImplementedError):
E[float]
with self.assertRaises(NotImplementedError):
E[float, bool]

F = A[Unpack[Ts], Unpack[tuple[str, ...]]]
self.assertTrue(repr(F).endswith('A[*Ts, *tuple[str, ...]]'))
self.assertTrue(repr(
with self.assertRaises(NotImplementedError):
F[()]
).endswith(
'A[*tuple[str, ...]]')
)
self.assertTrue(repr(
with self.assertRaises(NotImplementedError):
F[float]
).endswith(
'A[float, *tuple[str, ...]]'
))
self.assertTrue(repr(
with self.assertRaises(NotImplementedError):
F[float, int]
).endswith(
'A[float, int, *tuple[str, ...]]'
))

def test_cannot_subclass_class(self):
with self.assertRaises(TypeError):
Expand Down Expand Up @@ -791,132 +793,6 @@ class C(Generic[Unpack[Ts]]): pass
Ts2 = TypeVarTuple('Ts2')
self.assertNotEqual(C[Unpack[Ts1]], C[Unpack[Ts2]])

def test_typevar_substitution(self):
T1 = TypeVar('T1')
T2 = TypeVar('T2')
Ts = TypeVarTuple('Ts')

# Cases which should generate a TypeError.
# These are tuples of (typevars, args) arguments to
# _determine_typevar_substitution..
test_cases = [
# Too few args

# One TypeVar: if (potentially) 0 args
((T1,), ()),
((T1,), (Unpack[tuple[()]],)),
((T1,), (Unpack[tuple[int, ...]],)),
((T1,), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
# Two TypeVars: if (potentially) <= 1 args
((T1, T2), (int,)),
((T1, T2), (Unpack[tuple[int]],)),
((T1, T2), (Unpack[tuple[int, ...]],)),
((T1, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((T1, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
# One TypeVarTuple and one TypeVar: if (potentially) 0 args
# TypeVarTuple first
((Ts, T1), ()),
((Ts, T1), (Unpack[tuple[()]],)),
((Ts, T1), (Unpack[tuple[int, ...]],)),
((Ts, T1), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((Ts, T1), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
# TypeVarTuple last
((T1, Ts), ()),
((T1, Ts), (Unpack[tuple[()]],)),
((T1, Ts), (Unpack[tuple[int, ...]],)),
((T1, Ts), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((T1, Ts), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
# OneTypeVarTuple and two TypeVars: if (potentially) <= 1 args
# TypeVarTuple first
((Ts, T1, T2), ()),
((Ts, T1, T2), (int,)),
((Ts, T1, T2), (Unpack[tuple[int]],)),
((Ts, T1, T2), (Unpack[tuple[int, ...]],)),
((Ts, T1, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((Ts, T1, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((Ts, T1, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
# TypeVarTuple in middle
((T1, Ts, T2), ()),
((T1, Ts, T2), (int,)),
((T1, Ts, T2), (Unpack[tuple[int]],)),
((T1, Ts, T2), (Unpack[tuple[int, ...]],)),
((T1, Ts, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((T1, Ts, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((T1, Ts, T2), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
# TypeVarTuple last
((T1, T2, Ts), ()),
((T1, T2, Ts), (int,)),
((T1, T2, Ts), (Unpack[tuple[int]],)),
((T1, T2, Ts), (Unpack[tuple[int, ...]],)),
((T1, T2, Ts), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((T1, T2, Ts), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),
((T1, T2, Ts), (Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]], Unpack[tuple[int, ...]])),

# Too many args

# One TypeVar: if (potentially) >= 2 args
((T1,), (int, int)),
((T1,), (Unpack[tuple[int, int]],)),
((T1,), (Unpack[tuple[int]], Unpack[tuple[int]])),
((T1,), (int, Unpack[tuple[int, ...]])),
# Two TypeVars: if (potentially) >= 3 args
((T1, T2), (int, int, int)),
((T1, T2), (Unpack[tuple[int, int, int]],)),
((T1, T2), (Unpack[tuple[int]], Unpack[tuple[int]], Unpack[tuple[int]])),
((T1, T2), (int, int, Unpack[tuple[int, ...]],)),

# Too many TypeVarTuples

((Ts, Ts), ()),
((Ts, Ts), (int,)),
((Ts, Ts), (int, str)),
]
for typevars, args in test_cases:
with self.subTest(f'typevars={typevars}, args={args}'):
with self.assertRaises(TypeError):
_determine_typevar_substitution(typevars, args)

# Cases which should succeed.
# These are tuples of (typevars, args, expected_result).
test_cases = [
# Correct number of args, TypeVars only
((T1,), (int,), {T1: int}),
((T1,), (Unpack[tuple[int]],), {T1: int}),
((T1, T2), (int, str), {T1: int, T2: str}),
((T1, T2), (Unpack[tuple[int, str]],), {T1: int, T2: str}),
# Correct number of args, TypeVarTuple only
((Ts,), (), {Ts: ()}),
((Ts,), (int,), {Ts: (int,)}),
((Ts,), (Unpack[tuple[int]],), {Ts: (int,)}),
((Ts,), (int, str), {Ts: (int, str)}),
((Ts,), (Unpack[tuple[int, ...]],), {Ts: (Unpack[tuple[int, ...]],)}),
# Correct number of args, TypeVarTuple at the beginning
((Ts, T1), (int,), {Ts: (), T1: int}),
((Ts, T1), (int, str), {Ts: (int,), T1: str}),
((Ts, T1), (int, str, float), {Ts: (int, str), T1: float}),
((Ts, T1), (Unpack[tuple[int, ...]], str), {Ts: (Unpack[tuple[int, ...]],), T1: str}),
((Ts, T1), (Unpack[tuple[int, ...]], str, bool), {Ts: (Unpack[tuple[int, ...]], str), T1: bool}),
# Correct number of args, TypeVarTuple at the end
((T1, Ts), (int,), {T1: int, Ts: ()}),
((T1, Ts), (int, str), {T1: int, Ts: (str,)}),
((T1, Ts), (int, str, float), {T1: int, Ts: (str, float)}),
((T1, Ts), (int, Unpack[tuple[str, ...]]), {T1: int, Ts: (Unpack[tuple[str, ...]],)}),
((T1, Ts), (int, str, Unpack[tuple[float, ...]]), {T1: int, Ts: (str, Unpack[tuple[float, ...]],)}),
# Correct number of args, TypeVarTuple in the middle
((T1, Ts, T2), (int, str), {T1: int, Ts: (), T2: str}),
((T1, Ts, T2), (int, float, str), {T1: int, Ts: (float,), T2: str}),
((T1, Ts, T2), (int, Unpack[tuple[int, ...]], str), {T1: int, Ts: (Unpack[tuple[int, ...]],), T2: str}),
((T1, Ts, T2), (int, float, Unpack[tuple[bool, ...]], str), {T1: int, Ts: (float, Unpack[tuple[bool, ...]],), T2: str}),
((T1, Ts, T2), (int, Unpack[tuple[bool, ...]], float, str), {T1: int, Ts: (Unpack[tuple[bool, ...]], float), T2: str}),
((T1, Ts, T2), (int, complex, Unpack[tuple[bool, ...]], float, str), {T1: int, Ts: (complex, Unpack[tuple[bool, ...]], float), T2: str}),
]
for typevars, args, result_or_exception in test_cases:
with self.subTest(f'typevars={typevars}, args={args}'):
self.assertEqual(
_determine_typevar_substitution(typevars, args),
result_or_exception
)


class UnionTests(BaseTestCase):

Expand Down
Loading

0 comments on commit b9b1c80

Please sign in to comment.