Skip to content

Commit b057627

Browse files
miss-islingtonned-deily
authored andcommitted
[bpo-28556] Minor fixes for typing module (pythonGH-4710) (python#4713)
(cherry picked from commit 29bc193)
1 parent a72e7bf commit b057627

File tree

3 files changed

+55
-10
lines changed

3 files changed

+55
-10
lines changed

Lib/test/test_typing.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
from test import mod_generics_cache
3838

3939

40+
PY36 = sys.version_info[:2] >= (3, 6)
41+
42+
4043
class BaseTestCase(TestCase):
4144

4245
def assertIsSubclass(self, cls, class_or_tuple, msg=None):
@@ -633,6 +636,27 @@ def test_init(self):
633636
with self.assertRaises(TypeError):
634637
Generic[T, S, T]
635638

639+
@skipUnless(PY36, "__init_subclass__ support required")
640+
def test_init_subclass(self):
641+
class X(typing.Generic[T]):
642+
def __init_subclass__(cls, **kwargs):
643+
super().__init_subclass__(**kwargs)
644+
cls.attr = 42
645+
class Y(X):
646+
pass
647+
self.assertEqual(Y.attr, 42)
648+
with self.assertRaises(AttributeError):
649+
X.attr
650+
X.attr = 1
651+
Y.attr = 2
652+
class Z(Y):
653+
pass
654+
class W(X[int]):
655+
pass
656+
self.assertEqual(Y.attr, 2)
657+
self.assertEqual(Z.attr, 42)
658+
self.assertEqual(W.attr, 42)
659+
636660
def test_repr(self):
637661
self.assertEqual(repr(SimpleMapping),
638662
__name__ + '.' + 'SimpleMapping')
@@ -1080,6 +1104,30 @@ class Node(Generic[T]): ...
10801104
self.assertTrue(t is copy(t))
10811105
self.assertTrue(t is deepcopy(t))
10821106

1107+
def test_copy_generic_instances(self):
1108+
T = TypeVar('T')
1109+
class C(Generic[T]):
1110+
def __init__(self, attr: T) -> None:
1111+
self.attr = attr
1112+
1113+
c = C(42)
1114+
self.assertEqual(copy(c).attr, 42)
1115+
self.assertEqual(deepcopy(c).attr, 42)
1116+
self.assertIsNot(copy(c), c)
1117+
self.assertIsNot(deepcopy(c), c)
1118+
c.attr = 1
1119+
self.assertEqual(copy(c).attr, 1)
1120+
self.assertEqual(deepcopy(c).attr, 1)
1121+
ci = C[int](42)
1122+
self.assertEqual(copy(ci).attr, 42)
1123+
self.assertEqual(deepcopy(ci).attr, 42)
1124+
self.assertIsNot(copy(ci), ci)
1125+
self.assertIsNot(deepcopy(ci), ci)
1126+
ci.attr = 1
1127+
self.assertEqual(copy(ci).attr, 1)
1128+
self.assertEqual(deepcopy(ci).attr, 1)
1129+
self.assertEqual(ci.__orig_class__, C[int])
1130+
10831131
def test_weakref_all(self):
10841132
T = TypeVar('T')
10851133
things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any],
@@ -1580,8 +1628,6 @@ async def __aexit__(self, etype, eval, tb):
15801628
asyncio = None
15811629
AwaitableWrapper = AsyncIteratorWrapper = ACM = object
15821630

1583-
PY36 = sys.version_info[:2] >= (3, 6)
1584-
15851631
PY36_TESTS = """
15861632
from test import ann_module, ann_module2, ann_module3
15871633
from typing import AsyncContextManager

Lib/typing.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,8 @@ def __new__(cls, name, bases, namespace,
973973
# remove bare Generic from bases if there are other generic bases
974974
if any(isinstance(b, GenericMeta) and b is not Generic for b in bases):
975975
bases = tuple(b for b in bases if b is not Generic)
976-
namespace.update({'__origin__': origin, '__extra__': extra})
976+
namespace.update({'__origin__': origin, '__extra__': extra,
977+
'_gorg': None if not origin else origin._gorg})
977978
self = super().__new__(cls, name, bases, namespace, _root=True)
978979
super(GenericMeta, self).__setattr__('_gorg',
979980
self if not origin else origin._gorg)
@@ -1160,17 +1161,12 @@ def __instancecheck__(self, instance):
11601161
# classes are supposed to be rare anyways.
11611162
return issubclass(instance.__class__, self)
11621163

1163-
def __copy__(self):
1164-
return self.__class__(self.__name__, self.__bases__,
1165-
_no_slots_copy(self.__dict__),
1166-
self.__parameters__, self.__args__, self.__origin__,
1167-
self.__extra__, self.__orig_bases__)
1168-
11691164
def __setattr__(self, attr, value):
11701165
# We consider all the subscripted generics as proxies for original class
11711166
if (
11721167
attr.startswith('__') and attr.endswith('__') or
1173-
attr.startswith('_abc_')
1168+
attr.startswith('_abc_') or
1169+
self._gorg is None # The class is not fully created, see #typing/506
11741170
):
11751171
super(GenericMeta, self).__setattr__(attr, value)
11761172
else:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Two minor fixes for ``typing`` module: allow shallow copying instances of
2+
generic classes, improve interaction of ``__init_subclass__`` with generics.
3+
Original PRs by Ivan Levkivskyi.

0 commit comments

Comments
 (0)