Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
from test import mod_generics_cache


PY36 = sys.version_info[:2] >= (3, 6)


class BaseTestCase(TestCase):

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

@skipUnless(PY36, "__init_subclass__ support required")
def test_init_subclass(self):
class X(typing.Generic[T]):
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.attr = 42
class Y(X):
pass
self.assertEqual(Y.attr, 42)
with self.assertRaises(AttributeError):
X.attr
X.attr = 1
Y.attr = 2
class Z(Y):
pass
class W(X[int]):
pass
self.assertEqual(Y.attr, 2)
self.assertEqual(Z.attr, 42)
self.assertEqual(W.attr, 42)

def test_repr(self):
self.assertEqual(repr(SimpleMapping),
__name__ + '.' + 'SimpleMapping')
Expand Down Expand Up @@ -1080,6 +1104,30 @@ class Node(Generic[T]): ...
self.assertTrue(t is copy(t))
self.assertTrue(t is deepcopy(t))

def test_copy_generic_instances(self):
T = TypeVar('T')
class C(Generic[T]):
def __init__(self, attr: T) -> None:
self.attr = attr

c = C(42)
self.assertEqual(copy(c).attr, 42)
self.assertEqual(deepcopy(c).attr, 42)
self.assertIsNot(copy(c), c)
self.assertIsNot(deepcopy(c), c)
c.attr = 1
self.assertEqual(copy(c).attr, 1)
self.assertEqual(deepcopy(c).attr, 1)
ci = C[int](42)
self.assertEqual(copy(ci).attr, 42)
self.assertEqual(deepcopy(ci).attr, 42)
self.assertIsNot(copy(ci), ci)
self.assertIsNot(deepcopy(ci), ci)
ci.attr = 1
self.assertEqual(copy(ci).attr, 1)
self.assertEqual(deepcopy(ci).attr, 1)
self.assertEqual(ci.__orig_class__, C[int])

def test_weakref_all(self):
T = TypeVar('T')
things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any],
Expand Down Expand Up @@ -1580,8 +1628,6 @@ async def __aexit__(self, etype, eval, tb):
asyncio = None
AwaitableWrapper = AsyncIteratorWrapper = ACM = object

PY36 = sys.version_info[:2] >= (3, 6)

PY36_TESTS = """
from test import ann_module, ann_module2, ann_module3
from typing import AsyncContextManager
Expand Down
12 changes: 4 additions & 8 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,8 @@ def __new__(cls, name, bases, namespace,
# remove bare Generic from bases if there are other generic bases
if any(isinstance(b, GenericMeta) and b is not Generic for b in bases):
bases = tuple(b for b in bases if b is not Generic)
namespace.update({'__origin__': origin, '__extra__': extra})
namespace.update({'__origin__': origin, '__extra__': extra,
'_gorg': None if not origin else origin._gorg})
self = super().__new__(cls, name, bases, namespace, _root=True)
super(GenericMeta, self).__setattr__('_gorg',
self if not origin else origin._gorg)
Expand Down Expand Up @@ -1160,17 +1161,12 @@ def __instancecheck__(self, instance):
# classes are supposed to be rare anyways.
return issubclass(instance.__class__, self)

def __copy__(self):
return self.__class__(self.__name__, self.__bases__,
_no_slots_copy(self.__dict__),
self.__parameters__, self.__args__, self.__origin__,
self.__extra__, self.__orig_bases__)

def __setattr__(self, attr, value):
# We consider all the subscripted generics as proxies for original class
if (
attr.startswith('__') and attr.endswith('__') or
attr.startswith('_abc_')
attr.startswith('_abc_') or
self._gorg is None # The class is not fully created, see #typing/506
):
super(GenericMeta, self).__setattr__(attr, value)
else:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Two minor fixes for ``typing`` module: allow shallow copying instances of
generic classes, improve interaction of ``__init_subclass__`` with generics.
Original PRs by Ivan Levkivskyi.