From 392c6d94bdfd4e436d55134bbcc5750f70219b7d Mon Sep 17 00:00:00 2001
From: Ivan Levkivskyi
Date: Thu, 23 Feb 2017 00:26:05 +0100
Subject: [PATCH 1/3] Initial implementation (tests and PY2 port needed)
---
src/typing.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/typing.py b/src/typing.py
index efe358faf..e1bdaf477 100644
--- a/src/typing.py
+++ b/src/typing.py
@@ -1158,6 +1158,12 @@ def __copy__(self):
self.__parameters__, self.__args__, self.__origin__,
self.__extra__, self.__orig_bases__)
+ def __setattr__(self, attr, value):
+ if attr.startswith('__') and attr.endswith('__'):
+ type.__setattr__(self, attr, value)
+ else:
+ type.__setattr__(_gorg(self), attr, value)
+
# Prevent checks for Generic to crash when defining Generic.
Generic = None
From db133c1bfe9895eeec037c30fe72cbc75c190722 Mon Sep 17 00:00:00 2001
From: Ivan Levkivskyi
Date: Thu, 23 Feb 2017 14:29:34 +0100
Subject: [PATCH 2/3] Tests and PY2 backport
---
python2/test_typing.py | 27 +++++++++++++++++++++++++++
python2/typing.py | 7 +++++++
src/test_typing.py | 27 +++++++++++++++++++++++++++
src/typing.py | 1 +
4 files changed, 62 insertions(+)
diff --git a/python2/test_typing.py b/python2/test_typing.py
index 0c8d1bbba..7f8c3a985 100644
--- a/python2/test_typing.py
+++ b/python2/test_typing.py
@@ -642,6 +642,33 @@ class C(B[int]):
c.bar = 'abc'
self.assertEqual(c.__dict__, {'bar': 'abc'})
+ def test_subscripted_generics_as_proxies(self):
+ T = TypeVar('T')
+ class C(Generic[T]):
+ x = 'def'
+ self.assertEqual(C[int].x, 'def')
+ self.assertEqual(C[C[int]].x, 'def')
+ C[C[int]].x = 'changed'
+ self.assertEqual(C.x, 'changed')
+ self.assertEqual(C[str].x, 'changed')
+ C[List[str]].z = 'new'
+ self.assertEqual(C.z, 'new')
+ self.assertEqual(C[Tuple[int]].z, 'new')
+
+ self.assertEqual(C().x, 'changed')
+ self.assertEqual(C[Tuple[str]]().z, 'new')
+
+ class D(C[T]):
+ pass
+ self.assertEqual(D[int].x, 'changed')
+ self.assertEqual(D.z, 'new')
+ D.z = 'from derived z'
+ D[int].x = 'from derived x'
+ self.assertEqual(C.x, 'changed')
+ self.assertEqual(C[int].z, 'new')
+ self.assertEqual(D.x, 'from derived x')
+ self.assertEqual(D[str].z, 'from derived z')
+
def test_false_subclasses(self):
class MyMapping(MutableMapping[str, str]): pass
self.assertNotIsInstance({}, MyMapping)
diff --git a/python2/typing.py b/python2/typing.py
index 5cbfd4164..d77b1b2a1 100644
--- a/python2/typing.py
+++ b/python2/typing.py
@@ -1243,6 +1243,13 @@ def __copy__(self):
self.__parameters__, self.__args__, self.__origin__,
self.__extra__, self.__orig_bases__)
+ def __setattr__(self, attr, value):
+ # We consider all the subscripted genrics as proxies for original class
+ if attr.startswith('__') and attr.endswith('__'):
+ type.__setattr__(self, attr, value)
+ else:
+ type.__setattr__(_gorg(self), attr, value)
+
# Prevent checks for Generic to crash when defining Generic.
Generic = None
diff --git a/src/test_typing.py b/src/test_typing.py
index 64d827665..3a82b595d 100644
--- a/src/test_typing.py
+++ b/src/test_typing.py
@@ -674,6 +674,33 @@ class C(B[int]):
c.bar = 'abc'
self.assertEqual(c.__dict__, {'bar': 'abc'})
+ def test_subscripted_generics_as_proxies(self):
+ T = TypeVar('T')
+ class C(Generic[T]):
+ x = 'def'
+ self.assertEqual(C[int].x, 'def')
+ self.assertEqual(C[C[int]].x, 'def')
+ C[C[int]].x = 'changed'
+ self.assertEqual(C.x, 'changed')
+ self.assertEqual(C[str].x, 'changed')
+ C[List[str]].z = 'new'
+ self.assertEqual(C.z, 'new')
+ self.assertEqual(C[Tuple[int]].z, 'new')
+
+ self.assertEqual(C().x, 'changed')
+ self.assertEqual(C[Tuple[str]]().z, 'new')
+
+ class D(C[T]):
+ pass
+ self.assertEqual(D[int].x, 'changed')
+ self.assertEqual(D.z, 'new')
+ D.z = 'from derived z'
+ D[int].x = 'from derived x'
+ self.assertEqual(C.x, 'changed')
+ self.assertEqual(C[int].z, 'new')
+ self.assertEqual(D.x, 'from derived x')
+ self.assertEqual(D[str].z, 'from derived z')
+
def test_false_subclasses(self):
class MyMapping(MutableMapping[str, str]): pass
self.assertNotIsInstance({}, MyMapping)
diff --git a/src/typing.py b/src/typing.py
index e1bdaf477..677b65ea7 100644
--- a/src/typing.py
+++ b/src/typing.py
@@ -1159,6 +1159,7 @@ def __copy__(self):
self.__extra__, self.__orig_bases__)
def __setattr__(self, attr, value):
+ # We consider all the subscripted genrics as proxies for original class
if attr.startswith('__') and attr.endswith('__'):
type.__setattr__(self, attr, value)
else:
From dce0a273b0f7b076ab40a963b6d8736b35fb2de1 Mon Sep 17 00:00:00 2001
From: Ivan Levkivskyi
Date: Thu, 23 Feb 2017 19:56:19 +0100
Subject: [PATCH 3/3] Be more cooperative, use super()
---
python2/typing.py | 4 ++--
src/typing.py | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/python2/typing.py b/python2/typing.py
index d77b1b2a1..867fa5353 100644
--- a/python2/typing.py
+++ b/python2/typing.py
@@ -1246,9 +1246,9 @@ def __copy__(self):
def __setattr__(self, attr, value):
# We consider all the subscripted genrics as proxies for original class
if attr.startswith('__') and attr.endswith('__'):
- type.__setattr__(self, attr, value)
+ super(GenericMeta, self).__setattr__(attr, value)
else:
- type.__setattr__(_gorg(self), attr, value)
+ super(GenericMeta, _gorg(self)).__setattr__(attr, value)
# Prevent checks for Generic to crash when defining Generic.
diff --git a/src/typing.py b/src/typing.py
index 677b65ea7..fc2ed94cf 100644
--- a/src/typing.py
+++ b/src/typing.py
@@ -1161,9 +1161,9 @@ def __copy__(self):
def __setattr__(self, attr, value):
# We consider all the subscripted genrics as proxies for original class
if attr.startswith('__') and attr.endswith('__'):
- type.__setattr__(self, attr, value)
+ super(GenericMeta, self).__setattr__(attr, value)
else:
- type.__setattr__(_gorg(self), attr, value)
+ super(GenericMeta, _gorg(self)).__setattr__(attr, value)
# Prevent checks for Generic to crash when defining Generic.