""" This file was modified from CPython. Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Python Software Foundation; All Rights Reserved """ import copy, types # import copy_reg # import weakref # import abc from operator import le, lt, ge, gt, eq, ne import unittest order_comparisons = le, lt, ge, gt equality_comparisons = eq, ne comparisons = order_comparisons + equality_comparisons n = [] class _deep_reduce_ex: def __reduce_ex__(self, proto): n.append(1) print "append to n" return "" def __reduce__(self): self.fail("shouldn't call this") class Deepcopy_Deepcopy: def __init__(self, foo): self.foo = foo def __deepcopy__(self, memo=None): return Deepcopy_Deepcopy(self.foo) e = [] class deep_reduce: def __reduce__(self): e.append(1) print "append to e" return "" class Inst_Deepcopy: def __init__(self, foo): self.foo = foo def __deepcopy__(self, memo): return Inst_Deepcopy(copy.deepcopy(self.foo, memo)) def __eq__(self, other): return self.foo == other.foo class reconstruct_nostate(object): def __reduce__(self): return (reconstruct_nostate, ()) class reconstruct_state(): def __reduce__(self): return (reconstruct_state, (), self.__dict__) def __eq__(self, other): return self.__dict__ == other.__dict__ class reconstruct_state_setstate(object): def __reduce__(self): return (reconstruct_state_setstate, (), self.__dict__) def __setstate__(self, state): self.__dict__.update(state) def __eq__(self, other): return self.__dict__ == other.__dict__ class reduce_4tuple(list): def __reduce__(self): return (reduce_4tuple, (), self.__dict__, iter(self)) def __eq__(self, other): return (list(self) == list(other) and self.__dict__ == other.__dict__) class reduce_5tuple(dict): def __reduce__(self): return (reduce_5tuple, (), self.__dict__, None, self.items()) def __eq__(self, other): return (dict(self) == dict(other) and self.__dict__ == other.__dict__) class TestCopy(unittest.TestCase): # # The deepcopy() method def test_deepcopy_basic(self): x = 42 y = copy.deepcopy(x) self.assertEqual(y, x) def test_deepcopy_memo(self): # Tests of reflexive objects are under type-specific sections below. # This tests only repetitions of objects. x = [] x = [x, x] y = copy.deepcopy(x) self.assertEqual(y, x) self.assertIsNot(y, x) self.assertIsNot(y[0], x[0]) self.assertIs(y[0], y[1]) def test_deepcopy_issubclass(self): # XXX Note: there's no way to test the TypeError coming out of # issubclass() -- this can only happen when an extension # module defines a "type" that doesn't formally inherit from # type. # class Meta(type): class Meta(): pass class C(Meta): pass self.assertEqual(copy.deepcopy(C), C) def test_deepcopy_deepcopy(self): x = Deepcopy_Deepcopy(42) y = copy.deepcopy(x) self.assertEqual(y.__class__, x.__class__) self.assertEqual(y.foo, x.foo) # def test_deepcopy_registry(self): # class C(object): # def __new__(cls, foo): # obj = object.__new__(cls) # obj.foo = foo # return obj # def pickle_C(obj): # return (C, (obj.foo,)) # x = C(42) # self.assertRaises(TypeError, copy.deepcopy, x) # # copy_reg.pickle(C, pickle_C, C) # # y = copy.deepcopy(x) def test_deepcopy_reduce_ex(self): x = _deep_reduce_ex() y = copy.deepcopy(x) self.assertEqual(n, []) # def test_deepcopy_reduce(self): # x = deep_reduce() # y = copy.deepcopy(x) # self.assertIs(y, x) # self.assertEqual(e, [1]) # def test_deepcopy_cant(self): # class C: # def __getattribute__(self, name): # if name.startswith("__reduce"): # raise AttributeError(name) # return object.__getattribute__(self, name) # x = C() # # print "Should have error here", copy.deepcopy(x) # self.assertRaises(TypeError, copy.deepcopy, x) # # Type-specific _deepcopy_xxx() methods def test_deepcopy_atomic(self): class Classic: pass class NewStyle(object): pass def f(): pass tests = [None, 42, 3.14, True, False, "hello"] # not implemented yet : f.__code__, 2**100, 1j, NewStyle, max, "hello\u1234", Classic] for x in tests: self.assertIs(copy.deepcopy(x), x) def test_deepcopy_list(self): x = [[1, 2], 3] y = copy.deepcopy(x) self.assertEqual(y, x) self.assertIsNot(x, y) self.assertIsNot(x[0], y[0]) def test_deepcopy_reflexive_list(self): x = [] x.append(x) y = copy.deepcopy(x) # for op in comparisons: # self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIs(y[0], y) self.assertEqual(len(y), 1) def test_deepcopy_set(self): class FooSet: def bar(self): pass a = set([1,2,3]) b = copy.deepcopy(a) a = set([1,2,3]) b = copy.deepcopy(a) self.assertTrue(a == b) self.assertFalse(a is b) mixed = set([(1,2), FooSet.bar]) mixedcopy = copy.deepcopy(mixed) self.assertTrue(mixed == mixedcopy) self.assertFalse(mixed is mixedcopy) mixed.add(9) mixedcopy2 = copy.deepcopy(mixed) self.assertTrue(mixed == mixedcopy2) self.assertFalse(mixed is mixedcopy2) def test_deepcopy_empty_tuple(self): x = () y = copy.deepcopy(x) self.assertIs(x, y) def test_deepcopy_tuple(self): x = ([1, 2], 3) y = copy.deepcopy(x) self.assertEqual(y, x) self.assertIsNot(x, y) self.assertIsNot(x[0], y[0]) def test_deepcopy_tuple_of_immutables(self): x = ((1, 2), 3) y = copy.deepcopy(x) self.assertIs(x, y) # def test_deepcopy_reflexive_tuple(self): # x = ([],) # x[0].append(x) # print "here is x", x # print type(x[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]) # y = copy.deepcopy(x) # # for op in comparisons: # # self.assertRaises(RecursionError, op, y, x) # self.assertIsNot(y, x) # # self.assertIsNot(y[0], x[0]) # # self.assertIs(y[0][0], y) def test_deepcopy_dict(self): x = {"foo": [1, 2], "bar": 3} y = copy.deepcopy(x) self.assertEqual(y, x) self.assertIsNot(x, y) self.assertIsNot(x["foo"], y["foo"]) def test_deepcopy_reflexive_dict(self): x = {} x['foo'] = x y = copy.deepcopy(x) # for op in order_comparisons: # self.assertRaises(TypeError, op, y, x) # for op in equality_comparisons: # self.assertRaises(RecursionError, op, y, x) self.assertIsNot(y, x) self.assertIs(y['foo'], y) self.assertEqual(len(y), 1) def test_deepcopy_keepalive(self): memo = {} x = [] y = copy.deepcopy(x, memo) self.assertIs(memo[id(memo)][0], x) def test_deepcopy_dont_memo_immutable(self): memo = {} x = [1, 2, 3, 4] y = copy.deepcopy(x, memo) self.assertEqual(y, x) # There's the entry for the new list, and the keep alive. self.assertEqual(len(memo), 6) memo = {} x = [(1, 2)] y = copy.deepcopy(x, memo) self.assertEqual(y, x) # Tuples with immutable contents are immutable for deepcopy. self.assertEqual(len(memo), 5) memo = {} n = [False, True, None, "string"] o = copy.deepcopy(n, memo) self.assertEqual(len(memo), 6) def test_deepcopy_inst_vanilla(self): class C: def __init__(self, foo): self.foo = foo def __eq__(self, other): return self.foo == other.foo x = C([42]) y = copy.deepcopy(x) self.assertEqual(y, x) self.assertIsNot(y.foo, x.foo) # print "types", type(y), type(x), x.__class__, y.__class__ def test_deepcopy_inst_deepcopy(self): x = Inst_Deepcopy([42]) y = copy.deepcopy(x) self.assertEqual(y, x) self.assertIsNot(y, x) self.assertIsNot(y.foo, x.foo) def test_deepcopy_inst_getinitargs(self): class C: def __init__(self, foo): self.foo = foo def __getinitargs__(self): return (self.foo,) def __eq__(self, other): return self.foo == other.foo x = C([42]) self.assertRaises(NotImplementedError, copy.deepcopy, x) # y = copy.deepcopy(x) # self.assertEqual(y, x) # self.assertIsNot(y, x) # self.assertIsNot(y.foo, x.foo) # # def test_deepcopy_inst_getnewargs(self): # # class C(int): # # def __new__(cls, foo): # # self = int.__new__(cls) # # self.foo = foo # # return self # # def __getnewargs__(self): # # return self.foo, # # def __eq__(self, other): # # return self.foo == other.foo # # x = C(42) # # y = copy.deepcopy(x) # # self.assertIsInstance(y, C) # # print isinstance(y, C) # # self.assertEqual(y, x) # # self.assertIsNot(y, x) # # self.assertEqual(y.foo, x.foo) # # self.assertIsNot(y.foo, x.foo) # # def test_deepcopy_inst_getnewargs_ex(self): # # class C(int): # # def __new__(cls, *, foo): # # self = int.__new__(cls) # # self.foo = foo # # return self # # def __getnewargs_ex__(self): # # return (), {'foo': self.foo} # # def __eq__(self, other): # # return self.foo == other.foo # # x = C(foo=[42]) # # y = copy.deepcopy(x) # # self.assertIsInstance(y, C) # # self.assertEqual(y, x) # # self.assertIsNot(y, x) # # self.assertEqual(y.foo, x.foo) # # self.assertIsNot(y.foo, x.foo) # def test_deepcopy_inst_getstate(self): # class C: # def __init__(self, foo): # self.foo = foo # def __getstate__(self): # return {"foo": self.foo} # def __eq__(self, other): # return self.foo == other.foo # x = C([42]) # y = copy.deepcopy(x) # self.assertEqual(y, x) # self.assertIsNot(y, x) # self.assertIsNot(y.foo, x.foo) # def test_deepcopy_inst_setstate(self): # class C: # def __init__(self, foo): # self.foo = foo # def __setstate__(self, state): # self.foo = state["foo"] # def __eq__(self, other): # return self.foo == other.foo # x = C([42]) # y = copy.deepcopy(x) # self.assertEqual(y, x) # self.assertIsNot(y, x) # self.assertIsNot(y.foo, x.foo) # # def test_deepcopy_inst_getstate_setstate(self): # # class C: # # def __init__(self, foo): # # self.foo = foo # # def __getstate__(self): # # return self.foo # # def __setstate__(self, state): # # self.foo = state # # def __eq__(self, other): # # return self.foo == other.foo # # x = C([42]) # # y = copy.deepcopy(x) # # self.assertEqual(y, x) # # self.assertIsNot(y, x) # # self.assertIsNot(y.foo, x.foo) # # # State with boolean value is false (issue #25718) # # x = C([]) # # y = copy.deepcopy(x) # # self.assertEqual(y, x) # # self.assertIsNot(y, x) # # self.assertIsNot(y.foo, x.foo) # def test_deepcopy_reflexive_inst(self): # class C: # pass # x = C() # x.foo = x # y = copy.deepcopy(x) # self.assertIsNot(y, x) # self.assertIs(y.foo, y) # def test_deepcopy_range(self): # class I(int): # pass # x = range(I(10)) # y = copy.deepcopy(x) # self.assertIsNot(y, x) # self.assertEqual(y, x) # self.assertIsNot(y.stop, x.stop) # self.assertEqual(y.stop, x.stop) # self.assertIsInstance(y.stop, I) # # # _reconstruct() # def test_reconstruct_string(self): # class C: # def __reduce__(self): # return "" # x = C() # y = copy.copy(x) # self.assertIs(y, x) # y = copy.deepcopy(x) # self.assertIs(y, x) def test_reconstruct_nostate(self): x = reconstruct_nostate() x.foo = 42 y = copy.copy(x) # self.assertIs(y.__class__, x.__class__) y = copy.deepcopy(x) # self.assertIs(y.__class__, x.__class__) def test_reconstruct_state(self): x = reconstruct_state() x.foo = [42] y = copy.copy(x) # self.assertEqual(y, x) y = copy.deepcopy(x) # self.assertEqual(y, x) self.assertIsNot(y.foo, x.foo) def test_reconstruct_state_setstate(self): x = reconstruct_state_setstate() x.foo = [42] # y = copy.copy(x) self.assertRaises(NotImplementedError, copy.copy, x) # self.assertEqual(y, x) # y = copy.deepcopy(x) # self.assertEqual(y, x) # self.assertIsNot(y.foo, x.foo) def test_reconstruct_reflexive(self): class C(object): pass x = C() x.foo = x y = copy.deepcopy(x) self.assertIsNot(y, x) self.assertIs(y.foo, y) # # Additions for Python 2.3 and pickle protocol 2 # def test_reduce_4tuple(self): # x = reduce_4tuple([[1, 2], 3]) # y = copy.copy(x) # self.assertEqual(x, y) # self.assertIsNot(x, y) # self.assertIs(x[0], y[0]) # y = copy.deepcopy(x) # self.assertEqual(x, y) # self.assertIsNot(x, y) # self.assertIsNot(x[0], y[0]) # def test_reduce_5tuple(self): # x = reduce_5tuple([("foo", [1, 2]), ("bar", 3)]) # y = copy.copy(x) # # self.assertEqual(x, y) # self.assertIsNot(x, y) # self.assertIs(x["foo"], y["foo"]) # y = copy.deepcopy(x) # # self.assertEqual(x, y) # self.assertIsNot(x, y) # self.assertIsNot(x["foo"], y["foo"]) def test_copy_slots(self): class C: __slots__ = ["foo"] x = C() x.foo = [42] y = copy.copy(x) self.assertIs(x.foo, y.foo) def test_deepcopy_slots(self): class C(object): __slots__ = ["foo"] x = C() x.foo = [42] y = copy.deepcopy(x) self.assertEqual(x.foo, y.foo) self.assertIsNot(x.foo, y.foo) # def test_deepcopy_dict_subclass(self): # class C(dict): # def __init__(self, d=None): # if not d: # d = {} # self._keys = list(d.keys()) # super().__init__(d) # def __setitem__(self, key, item): # super().__setitem__(key, item) # if key not in self._keys: # self._keys.append(key) # x = C(d={'foo':0}) # y = copy.deepcopy(x) # self.assertEqual(x, y) # self.assertEqual(x._keys, y._keys) # self.assertIsNot(x, y) # x['bar'] = 1 # self.assertNotEqual(x, y) # self.assertNotEqual(x._keys, y._keys) # def test_copy_list_subclass(self): # class C(list): # pass # x = C([[1, 2], 3]) # x.foo = [4, 5] # y = copy.copy(x) # self.assertEqual(list(x), list(y)) # self.assertEqual(x.foo, y.foo) # self.assertIs(x[0], y[0]) # self.assertIs(x.foo, y.foo) # def test_deepcopy_list_subclass(self): # class C(list): # pass # x = C([[1, 2], 3]) # x.foo = [4, 5] # y = copy.deepcopy(x) # self.assertEqual(list(x), list(y)) # self.assertEqual(x.foo, y.foo) # self.assertIsNot(x[0], y[0]) # self.assertIsNot(x.foo, y.foo) # def test_copy_tuple_subclass(self): # class C(tuple): # pass # x = C([1, 2, 3]) # # self.assertEqual(tus # def test_deepcopy_tuple_subclass(self): # class C(tuple): # pass # x = C([[1, 2], 3]) # self.assertEqual(tuple(x), ([1, 2], 3)) # y = copy.deepcopy(x) # self.assertEqual(tuple(y), ([1, 2], 3)) # self.assertIsNot(x, y) # self.assertIsNot(x[0], y[0]) # def test_getstate_exc(self): # class EvilState(object): # def __getstate__(self): # raise ValueError("ain't got no stickin' state") # self.assertRaises(ValueError, copy.copy, EvilState()) def test_copy_function(self): self.assertEqual(copy.copy(global_foo), global_foo) def foo(x, y): return x+y self.assertEqual(copy.copy(foo), foo) bar = lambda: None self.assertEqual(copy.copy(bar), bar) def test_deepcopy_function(self): self.assertEqual(copy.deepcopy(global_foo), global_foo) def foo(x, y): return x+y self.assertEqual(copy.deepcopy(foo), foo) bar = lambda: None self.assertEqual(copy.deepcopy(bar), bar) # def _check_weakref(self, _copy): # class C(object): # pass # obj = C() # x = weakref.ref(obj) # y = _copy(x) # self.assertIs(y, x) # del obj # y = _copy(x) # self.assertIs(y, x) # def test_copy_weakref(self): # self._check_weakref(copy.copy) # def test_deepcopy_weakref(self): # self._check_weakref(copy.deepcopy) def _check_copy_weakdict(self, _dicttype): class C(object): pass a, b, c, d = [C() for i in range(4)] u = _dicttype() u[a] = b u[c] = d v = copy.copy(u) self.assertIsNot(v, u) self.assertEqual(v, u) self.assertEqual(v[a], b) self.assertEqual(v[c], d) self.assertEqual(len(v), 2) del c, d self.assertEqual(len(v), 1) x, y = C(), C() # The underlying containers are decoupled v[x] = y self.assertNotIn(x, u) # def test_copy_weakkeydict(self): # self._check_copy_weakdict(weakref.WeakKeyDictionary) # def test_copy_weakvaluedict(self): # self._check_copy_weakdict(weakref.WeakValueDictionary) # def test_deepcopy_weakkeydict(self): # class C(object): # def __init__(self, i): # self.i = i # a, b, c, d = [C(i) for i in range(4)] # u = weakref.WeakKeyDictionary() # u[a] = b # u[c] = d # # Keys aren't copied, values are # v = copy.deepcopy(u) # self.assertNotEqual(v, u) # self.assertEqual(len(v), 2) # self.assertIsNot(v[a], b) # self.assertIsNot(v[c], d) # self.assertEqual(v[a].i, b.i) # self.assertEqual(v[c].i, d.i) # del c # self.assertEqual(len(v), 1) # def test_deepcopy_weakvaluedict(self): # class C(object): # def __init__(self, i): # self.i = i # a, b, c, d = [C(i) for i in range(4)] # u = weakref.WeakValueDictionary() # u[a] = b # u[c] = d # # Keys are copied, values aren't # v = copy.deepcopy(u) # self.assertNotEqual(v, u) # self.assertEqual(len(v), 2) # (x, y), (z, t) = sorted(v.items(), key=lambda pair: pair[0].i) # self.assertIsNot(x, a) # self.assertEqual(x.i, a.i) # self.assertIs(y, b) # self.assertIsNot(z, c) # self.assertEqual(z.i, c.i) # self.assertIs(t, d) # del x, y, z, t # del d # self.assertEqual(len(v), 1) def test_deepcopy_methods(self): class potato: def cut(self): print "slices" mashed = potato() d1 = {"a": mashed.cut} d2 = copy.deepcopy(d1) # self.assertFalse(d1 == d2) # self.assertFalse(d1 is d2) # im = mashed.cut # im_dc = copy.deepcopy(im) # self.assertTrue(isinstance, (im, types.MethodType)) # self.assertFalse(im == im_dc) # self.assertFalse(im is im_dc) def global_foo(x, y): return x+y if __name__ == "__main__": unittest.main()