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
24 changes: 24 additions & 0 deletions python2/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,30 @@ class Node(Generic[T]): pass
self.assertEqual(t, deepcopy(t))
self.assertEqual(t, copy(t))

def test_copy_generic_instances(self):
T = TypeVar('T')
class C(Generic[T]):
def __init__(self, attr):
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
22 changes: 17 additions & 5 deletions python2/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import re as stdlib_re # Avoid confusion with the re we export.
import sys
import types
import copy
try:
import collections.abc as collections_abc
except ImportError:
Expand Down Expand Up @@ -1253,11 +1254,6 @@ def __instancecheck__(self, instance):
return issubclass(instance.__class__, self)
return False

def __copy__(self):
return self.__class__(self.__name__, self.__bases__, dict(self.__dict__),
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 (
Expand All @@ -1269,6 +1265,16 @@ def __setattr__(self, attr, value):
super(GenericMeta, self._gorg).__setattr__(attr, value)


def _copy_generic(self):
"""Hack to work around https://bugs.python.org/issue11480 on Python 2"""
return self.__class__(self.__name__, self.__bases__, dict(self.__dict__),
self.__parameters__, self.__args__, self.__origin__,
self.__extra__, self.__orig_bases__)


copy._copy_dispatch[GenericMeta] = _copy_generic


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

Expand Down Expand Up @@ -1365,6 +1371,9 @@ def __subclasscheck__(self, cls):
"with issubclass().")


copy._copy_dispatch[TupleMeta] = _copy_generic


class Tuple(tuple):
"""Tuple type; Tuple[X, Y] is the cross-product type of X and Y.

Expand Down Expand Up @@ -1443,6 +1452,9 @@ def __getitem_inner__(self, parameters):
return super(CallableMeta, self).__getitem__(parameters)


copy._copy_dispatch[CallableMeta] = _copy_generic


class Callable(object):
"""Callable type; Callable[[int], str] is a function of (int) -> str.

Expand Down
24 changes: 24 additions & 0 deletions src/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,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
6 changes: 0 additions & 6 deletions src/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,12 +1160,6 @@ 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 (
Expand Down