Skip to content

Commit 8c6aaf3

Browse files
committed
Merge pull request #195 from python/new_generic
Revamped generic class behavior to conform to updated PEP 484
2 parents baf2d91 + e0d1c5d commit 8c6aaf3

File tree

5 files changed

+503
-306
lines changed

5 files changed

+503
-306
lines changed

python2/test_typing.py

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ def test_basic_constrained(self):
132132
def test_constrained_error(self):
133133
with self.assertRaises(TypeError):
134134
X = TypeVar('X', int)
135+
X
135136

136137
def test_union_unique(self):
137138
X = TypeVar('X')
@@ -316,6 +317,7 @@ def test_union_instance_type_error(self):
316317
def test_union_str_pattern(self):
317318
# Shouldn't crash; see http://bugs.python.org/issue25390
318319
A = Union[str, Pattern]
320+
A
319321

320322

321323
class TypeVarUnionTests(TestCase):
@@ -478,7 +480,7 @@ def get(self, key, default=None):
478480
pass
479481

480482

481-
class MySimpleMapping(SimpleMapping):
483+
class MySimpleMapping(SimpleMapping[XK, XV]):
482484

483485
def __init__(self):
484486
self.store = {}
@@ -533,14 +535,17 @@ def test_protocol_instance_type_error(self):
533535
class GenericTests(TestCase):
534536

535537
def test_basics(self):
536-
X = SimpleMapping[unicode, Any]
537-
Y = SimpleMapping[XK, unicode]
538-
X[unicode, unicode]
539-
Y[unicode, unicode]
538+
X = SimpleMapping[str, Any]
539+
assert X.__parameters__ == ()
540+
with self.assertRaises(TypeError):
541+
X[unicode]
540542
with self.assertRaises(TypeError):
541-
X[int, unicode]
543+
X[unicode, unicode]
544+
Y = SimpleMapping[XK, unicode]
545+
assert Y.__parameters__ == (XK,)
546+
Y[unicode]
542547
with self.assertRaises(TypeError):
543-
Y[unicode, bytes]
548+
Y[unicode, unicode]
544549

545550
def test_init(self):
546551
T = TypeVar('T')
@@ -552,9 +557,33 @@ def test_init(self):
552557

553558
def test_repr(self):
554559
self.assertEqual(repr(SimpleMapping),
555-
__name__ + '.' + 'SimpleMapping[~XK, ~XV]')
560+
__name__ + '.' + 'SimpleMapping<~XK, ~XV>')
556561
self.assertEqual(repr(MySimpleMapping),
557-
__name__ + '.' + 'MySimpleMapping[~XK, ~XV]')
562+
__name__ + '.' + 'MySimpleMapping<~XK, ~XV>')
563+
564+
def test_chain_repr(self):
565+
T = TypeVar('T')
566+
S = TypeVar('S')
567+
568+
class C(Generic[T]):
569+
pass
570+
571+
X = C[Tuple[S, T]]
572+
assert X == C[Tuple[S, T]]
573+
assert X != C[Tuple[T, S]]
574+
575+
Y = X[T, int]
576+
assert Y == X[T, int]
577+
assert Y != X[S, int]
578+
assert Y != X[T, str]
579+
580+
Z = Y[str]
581+
assert Z == Y[str]
582+
assert Z != Y[int]
583+
assert Z != Y[T]
584+
585+
assert str(Z).endswith(
586+
'.C<~T>[typing.Tuple[~S, ~T]]<~S, ~T>[~T, int]<~T>[str]')
558587

559588
def test_dict(self):
560589
T = TypeVar('T')
@@ -609,20 +638,20 @@ class C(Generic[T]):
609638
assert C.__module__ == __name__
610639
if not PY32:
611640
assert C.__qualname__ == 'GenericTests.test_repr_2.<locals>.C'
612-
assert repr(C).split('.')[-1] == 'C[~T]'
641+
assert repr(C).split('.')[-1] == 'C<~T>'
613642
X = C[int]
614643
assert X.__module__ == __name__
615644
if not PY32:
616645
assert X.__qualname__ == 'C'
617-
assert repr(X).split('.')[-1] == 'C[int]'
646+
assert repr(X).split('.')[-1] == 'C<~T>[int]'
618647

619648
class Y(C[int]):
620649
pass
621650

622651
assert Y.__module__ == __name__
623652
if not PY32:
624653
assert Y.__qualname__ == 'GenericTests.test_repr_2.<locals>.Y'
625-
assert repr(Y).split('.')[-1] == 'Y[int]'
654+
assert repr(Y).split('.')[-1] == 'Y'
626655

627656
def test_eq_1(self):
628657
assert Generic == Generic
@@ -650,10 +679,40 @@ class A(Generic[T, VT]):
650679
class B(Generic[KT, T]):
651680
pass
652681

653-
class C(A, Generic[KT, VT], B):
682+
class C(A[T, VT], Generic[VT, T, KT], B[KT, T]):
654683
pass
655684

656-
assert C.__parameters__ == (T, VT, KT)
685+
assert C.__parameters__ == (VT, T, KT)
686+
687+
def test_nested(self):
688+
689+
G = Generic
690+
691+
class Visitor(G[T]):
692+
693+
a = None
694+
695+
def set(self, a):
696+
self.a = a
697+
698+
def get(self):
699+
return self.a
700+
701+
def visit(self):
702+
return self.a
703+
704+
V = Visitor[typing.List[int]]
705+
706+
class IntListVisitor(V):
707+
708+
def append(self, x):
709+
self.a.append(x)
710+
711+
a = IntListVisitor()
712+
a.set([])
713+
a.append(1)
714+
a.append(42)
715+
assert a.get() == [1, 42]
657716

658717
def test_type_erasure(self):
659718
T = TypeVar('T')
@@ -679,6 +738,24 @@ def foo(x):
679738

680739
foo(42)
681740

741+
def test_implicit_any(self):
742+
T = TypeVar('T')
743+
744+
class C(Generic[T]):
745+
pass
746+
747+
class D(C):
748+
pass
749+
750+
assert D.__parameters__ == ()
751+
752+
with self.assertRaises(Exception):
753+
D[int]
754+
with self.assertRaises(Exception):
755+
D[Any]
756+
with self.assertRaises(Exception):
757+
D[T]
758+
682759

683760
class VarianceTests(TestCase):
684761

@@ -988,6 +1065,15 @@ def test_basics(self):
9881065
assert Emp._fields == ('name', 'id')
9891066
assert Emp._field_types == dict(name=str, id=int)
9901067

1068+
def test_pickle(self):
1069+
global Emp # pickle wants to reference the class by name
1070+
Emp = NamedTuple('Emp', [('name', str), ('id', int)])
1071+
jane = Emp('jane', 37)
1072+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1073+
z = pickle.dumps(jane, proto)
1074+
jane2 = pickle.loads(z)
1075+
self.assertEqual(jane2, jane)
1076+
9911077

9921078
class IOTests(TestCase):
9931079

0 commit comments

Comments
 (0)