Skip to content

Commit 07fdb60

Browse files
authored
Treat subscripted generics as "proxies" for original class. (#393)
* Initial implementation (tests and PY2 port needed) * Tests and PY2 backport * Be more cooperative, use super()
1 parent c53963f commit 07fdb60

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

python2/test_typing.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,33 @@ class C(B[int]):
642642
c.bar = 'abc'
643643
self.assertEqual(c.__dict__, {'bar': 'abc'})
644644

645+
def test_subscripted_generics_as_proxies(self):
646+
T = TypeVar('T')
647+
class C(Generic[T]):
648+
x = 'def'
649+
self.assertEqual(C[int].x, 'def')
650+
self.assertEqual(C[C[int]].x, 'def')
651+
C[C[int]].x = 'changed'
652+
self.assertEqual(C.x, 'changed')
653+
self.assertEqual(C[str].x, 'changed')
654+
C[List[str]].z = 'new'
655+
self.assertEqual(C.z, 'new')
656+
self.assertEqual(C[Tuple[int]].z, 'new')
657+
658+
self.assertEqual(C().x, 'changed')
659+
self.assertEqual(C[Tuple[str]]().z, 'new')
660+
661+
class D(C[T]):
662+
pass
663+
self.assertEqual(D[int].x, 'changed')
664+
self.assertEqual(D.z, 'new')
665+
D.z = 'from derived z'
666+
D[int].x = 'from derived x'
667+
self.assertEqual(C.x, 'changed')
668+
self.assertEqual(C[int].z, 'new')
669+
self.assertEqual(D.x, 'from derived x')
670+
self.assertEqual(D[str].z, 'from derived z')
671+
645672
def test_false_subclasses(self):
646673
class MyMapping(MutableMapping[str, str]): pass
647674
self.assertNotIsInstance({}, MyMapping)

python2/typing.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,13 @@ def __copy__(self):
12431243
self.__parameters__, self.__args__, self.__origin__,
12441244
self.__extra__, self.__orig_bases__)
12451245

1246+
def __setattr__(self, attr, value):
1247+
# We consider all the subscripted genrics as proxies for original class
1248+
if attr.startswith('__') and attr.endswith('__'):
1249+
super(GenericMeta, self).__setattr__(attr, value)
1250+
else:
1251+
super(GenericMeta, _gorg(self)).__setattr__(attr, value)
1252+
12461253

12471254
# Prevent checks for Generic to crash when defining Generic.
12481255
Generic = None

src/test_typing.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,33 @@ class C(B[int]):
674674
c.bar = 'abc'
675675
self.assertEqual(c.__dict__, {'bar': 'abc'})
676676

677+
def test_subscripted_generics_as_proxies(self):
678+
T = TypeVar('T')
679+
class C(Generic[T]):
680+
x = 'def'
681+
self.assertEqual(C[int].x, 'def')
682+
self.assertEqual(C[C[int]].x, 'def')
683+
C[C[int]].x = 'changed'
684+
self.assertEqual(C.x, 'changed')
685+
self.assertEqual(C[str].x, 'changed')
686+
C[List[str]].z = 'new'
687+
self.assertEqual(C.z, 'new')
688+
self.assertEqual(C[Tuple[int]].z, 'new')
689+
690+
self.assertEqual(C().x, 'changed')
691+
self.assertEqual(C[Tuple[str]]().z, 'new')
692+
693+
class D(C[T]):
694+
pass
695+
self.assertEqual(D[int].x, 'changed')
696+
self.assertEqual(D.z, 'new')
697+
D.z = 'from derived z'
698+
D[int].x = 'from derived x'
699+
self.assertEqual(C.x, 'changed')
700+
self.assertEqual(C[int].z, 'new')
701+
self.assertEqual(D.x, 'from derived x')
702+
self.assertEqual(D[str].z, 'from derived z')
703+
677704
def test_false_subclasses(self):
678705
class MyMapping(MutableMapping[str, str]): pass
679706
self.assertNotIsInstance({}, MyMapping)

src/typing.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,13 @@ def __copy__(self):
11581158
self.__parameters__, self.__args__, self.__origin__,
11591159
self.__extra__, self.__orig_bases__)
11601160

1161+
def __setattr__(self, attr, value):
1162+
# We consider all the subscripted genrics as proxies for original class
1163+
if attr.startswith('__') and attr.endswith('__'):
1164+
super(GenericMeta, self).__setattr__(attr, value)
1165+
else:
1166+
super(GenericMeta, _gorg(self)).__setattr__(attr, value)
1167+
11611168

11621169
# Prevent checks for Generic to crash when defining Generic.
11631170
Generic = None

0 commit comments

Comments
 (0)