unit tests for the copy module import copy import copyreg import weakref import abc from operator import le lt ge gt eq ne attrgetter import unittest from test import support ordercomparisons le lt ge gt equalitycomparisons eq ne comparisons ordercomparisons equalitycomparisons class testcopyunittest testcase attempt full line coverage of copy py from top to bottom def testexceptionsself self assertiscopy error copy error self asserttrueissubclasscopy error exception the copy method def testcopybasicself x 42 y copy copyx self assertequalx y def testcopycopyself class cobject def initself foo self foo foo def copyself return cself foo x c42 y copy copyx self assertequaly class x class self assertequaly foo x foo def testcopyregistryself class cobject def newcls foo obj object newcls obj foo foo return obj def picklecobj return c obj foo x c42 self assertraisestypeerror copy copy x copyreg picklec picklec c y copy copyx self assertisnotx y self assertequaltypey c self assertequaly foo x foo def testcopyreduceexself class cobject def reduceexself proto c append1 return def reduceself self failshouldn t call this c x c y copy copyx self assertisy x self assertequalc 1 def testcopyreduceself class cobject def reduceself c append1 return c x c y copy copyx self assertisy x self assertequalc 1 def testcopycantself class cobject def getattributeself name if name startswithreduce raise attributeerrorname return object getattributeself name x c self assertraisescopy error copy copy x typespecific copyxxx methods def testcopyatomicself class newstyle pass def f pass class withmetaclassmetaclassabc abcmeta pass tests none notimplemented 42 2100 3 14 true false 1j hello hellou1234 f code bworld bytesrange256 range10 slice1 10 2 newstyle max withmetaclass property for x in tests self assertiscopy copyx x def testcopylistself x 1 2 3 y copy copyx self assertequaly x self assertisnoty x x y copy copyx self assertequaly x self assertisnoty x def testcopytupleself x 1 2 3 self assertiscopy copyx x x self assertiscopy copyx x x 1 2 3 self assertiscopy copyx x def testcopydictself x foo 1 bar 2 y copy copyx self assertequaly x self assertisnoty x x y copy copyx self assertequaly x self assertisnoty x def testcopysetself x 1 2 3 y copy copyx self assertequaly x self assertisnoty x x set y copy copyx self assertequaly x self assertisnoty x def testcopyfrozensetself x frozenset1 2 3 self assertiscopy copyx x x frozenset self assertiscopy copyx x def testcopybytearrayself x bytearrayb abc y copy copyx self assertequaly x self assertisnoty x x bytearray y copy copyx self assertequaly x self assertisnoty x def testcopyinstvanillaself class c def initself foo self foo foo def eqself other return self foo other foo x c42 self assertequalcopy copyx x def testcopyinstcopyself class c def initself foo self foo foo def copyself return cself foo def eqself other return self foo other foo x c42 self assertequalcopy copyx x def testcopyinstgetinitargsself class c def initself foo self foo foo def getinitargsself return self foo def eqself other return self foo other foo x c42 self assertequalcopy copyx x def testcopyinstgetnewargsself class cint def newcls foo self int newcls self foo foo return self def getnewargsself return self foo def eqself other return self foo other foo x c42 y copy copyx self assertisinstancey c self assertequaly x self assertisnoty x self assertequaly foo x foo def testcopyinstgetnewargsexself class cint def newcls foo self int newcls self foo foo return self def getnewargsexself return foo self foo def eqself other return self foo other foo x cfoo42 y copy copyx self assertisinstancey c self assertequaly x self assertisnoty x self assertequaly foo x foo def testcopyinstgetstateself class c def initself foo self foo foo def getstateself return foo self foo def eqself other return self foo other foo x c42 self assertequalcopy copyx x def testcopyinstsetstateself class c def initself foo self foo foo def setstateself state self foo statefoo def eqself other return self foo other foo x c42 self assertequalcopy copyx x def testcopyinstgetstatesetstateself class c def initself foo self foo foo def getstateself return self foo def setstateself state self foo state def eqself other return self foo other foo x c42 self assertequalcopy copyx x state with boolean value is false issue 25718 x c0 0 self assertequalcopy copyx x the deepcopy method def testdeepcopybasicself x 42 y copy deepcopyx self assertequaly x def testdeepcopymemoself tests of reflexive objects are under typespecific sections below this tests only repetitions of objects x x x x y copy deepcopyx self assertequaly x self assertisnoty x self assertisnoty0 x0 self assertisy0 y1 def testdeepcopyissubclassself 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 metatype pass class cmetaclassmeta pass self assertequalcopy deepcopyc c def testdeepcopydeepcopyself class cobject def initself foo self foo foo def deepcopyself memonone return cself foo x c42 y copy deepcopyx self assertequaly class x class self assertequaly foo x foo def testdeepcopyregistryself class cobject def newcls foo obj object newcls obj foo foo return obj def picklecobj return c obj foo x c42 self assertraisestypeerror copy deepcopy x copyreg picklec picklec c y copy deepcopyx self assertisnotx y self assertequaltypey c self assertequaly foo x foo def testdeepcopyreduceexself class cobject def reduceexself proto c append1 return def reduceself self failshouldn t call this c x c y copy deepcopyx self assertisy x self assertequalc 1 def testdeepcopyreduceself class cobject def reduceself c append1 return c x c y copy deepcopyx self assertisy x self assertequalc 1 def testdeepcopycantself class cobject def getattributeself name if name startswithreduce raise attributeerrorname return object getattributeself name x c self assertraisescopy error copy deepcopy x typespecific deepcopyxxx methods def testdeepcopyatomicself class newstyle pass def f pass tests none notimplemented 42 2100 3 14 true false 1j bbytes hello hellou1234 f code newstyle range10 max property for x in tests self assertiscopy deepcopyx x def testdeepcopylistself x 1 2 3 y copy deepcopyx self assertequaly x self assertisnotx y self assertisnotx0 y0 def testdeepcopyreflexivelistself x x appendx y copy deepcopyx for op in comparisons self assertraisesrecursionerror op y x self assertisnoty x self assertisy0 y self assertequalleny 1 def testdeepcopyemptytupleself x y copy deepcopyx self assertisx y def testdeepcopytupleself x 1 2 3 y copy deepcopyx self assertequaly x self assertisnotx y self assertisnotx0 y0 def testdeepcopytupleofimmutablesself x 1 2 3 y copy deepcopyx self assertisx y def testdeepcopyreflexivetupleself x x0 appendx y copy deepcopyx for op in comparisons self assertraisesrecursionerror op y x self assertisnoty x self assertisnoty0 x0 self assertisy00 y def testdeepcopydictself x foo 1 2 bar 3 y copy deepcopyx self assertequaly x self assertisnotx y self assertisnotxfoo yfoo def testdeepcopyreflexivedictself x x foo x y copy deepcopyx for op in ordercomparisons self assertraisestypeerror op y x for op in equalitycomparisons self assertraisesrecursionerror op y x self assertisnoty x self assertisy foo y self assertequalleny 1 def testdeepcopykeepaliveself memo x y copy deepcopyx memo self assertismemoidmemo0 x def testdeepcopydontmemoimmutableself memo x 1 2 3 4 y copy deepcopyx memo self assertequaly x there s the entry for the new list and the keep alive self assertequallenmemo 2 memo x 1 2 y copy deepcopyx memo self assertequaly x tuples with immutable contents are immutable for deepcopy self assertequallenmemo 2 def testdeepcopyinstvanillaself class c def initself foo self foo foo def eqself other return self foo other foo x c42 y copy deepcopyx self assertequaly x self assertisnoty foo x foo def testdeepcopyinstdeepcopyself class c def initself foo self foo foo def deepcopyself memo return ccopy deepcopyself foo memo def eqself other return self foo other foo x c42 y copy deepcopyx self assertequaly x self assertisnoty x self assertisnoty foo x foo def testdeepcopyinstgetinitargsself class c def initself foo self foo foo def getinitargsself return self foo def eqself other return self foo other foo x c42 y copy deepcopyx self assertequaly x self assertisnoty x self assertisnoty foo x foo def testdeepcopyinstgetnewargsself class cint def newcls foo self int newcls self foo foo return self def getnewargsself return self foo def eqself other return self foo other foo x c42 y copy deepcopyx self assertisinstancey c self assertequaly x self assertisnoty x self assertequaly foo x foo self assertisnoty foo x foo def testdeepcopyinstgetnewargsexself class cint def newcls foo self int newcls self foo foo return self def getnewargsexself return foo self foo def eqself other return self foo other foo x cfoo42 y copy deepcopyx self assertisinstancey c self assertequaly x self assertisnoty x self assertequaly foo x foo self assertisnoty foo x foo def testdeepcopyinstgetstateself class c def initself foo self foo foo def getstateself return foo self foo def eqself other return self foo other foo x c42 y copy deepcopyx self assertequaly x self assertisnoty x self assertisnoty foo x foo def testdeepcopyinstsetstateself class c def initself foo self foo foo def setstateself state self foo statefoo def eqself other return self foo other foo x c42 y copy deepcopyx self assertequaly x self assertisnoty x self assertisnoty foo x foo def testdeepcopyinstgetstatesetstateself class c def initself foo self foo foo def getstateself return self foo def setstateself state self foo state def eqself other return self foo other foo x c42 y copy deepcopyx self assertequaly x self assertisnoty x self assertisnoty foo x foo state with boolean value is false issue 25718 x c y copy deepcopyx self assertequaly x self assertisnoty x self assertisnoty foo x foo def testdeepcopyreflexiveinstself class c pass x c x foo x y copy deepcopyx self assertisnoty x self assertisy foo y reconstruct def testreconstructstringself class cobject def reduceself return x c y copy copyx self assertisy x y copy deepcopyx self assertisy x def testreconstructnostateself class cobject def reduceself return c x c x foo 42 y copy copyx self assertisy class x class y copy deepcopyx self assertisy class x class def testreconstructstateself class cobject def reduceself return c self dict def eqself other return self dict other dict x c x foo 42 y copy copyx self assertequaly x y copy deepcopyx self assertequaly x self assertisnoty foo x foo def testreconstructstatesetstateself class cobject def reduceself return c self dict def setstateself state self dict updatestate def eqself other return self dict other dict x c x foo 42 y copy copyx self assertequaly x y copy deepcopyx self assertequaly x self assertisnoty foo x foo def testreconstructreflexiveself class cobject pass x c x foo x y copy deepcopyx self assertisnoty x self assertisy foo y additions for python 2 3 and pickle protocol 2 def testreduce4tupleself class clist def reduceself return c self dict iterself def eqself other return listself listother and self dict other dict x c1 2 3 y copy copyx self assertequalx y self assertisnotx y self assertisx0 y0 y copy deepcopyx self assertequalx y self assertisnotx y self assertisnotx0 y0 def testreduce5tupleself class cdict def reduceself return c self dict none self items def eqself other return dictself dictother and self dict other dict x cfoo 1 2 bar 3 y copy copyx self assertequalx y self assertisnotx y self assertisxfoo yfoo y copy deepcopyx self assertequalx y self assertisnotx y self assertisnotxfoo yfoo def testreduce6tupleself def statesetterargs kwargs self failshouldn t call this class c def reduceself return c self dict none none statesetter x c with self assertraisestypeerror copy copyx with self assertraisestypeerror copy deepcopyx def testreduce6tuplenoneself class c def reduceself return c self dict none none none x c with self assertraisestypeerror copy copyx with self assertraisestypeerror copy deepcopyx def testcopyslotsself class cobject slots foo x c x foo 42 y copy copyx self assertisx foo y foo def testdeepcopyslotsself class cobject slots foo x c x foo 42 y copy deepcopyx self assertequalx foo y foo self assertisnotx foo y foo def testdeepcopydictsubclassself class cdict def initself dnone if not d d self keys listd keys super initd def setitemself key item super setitemkey item if key not in self keys self keys appendkey x cd foo 0 y copy deepcopyx self assertequalx y self assertequalx keys y keys self assertisnotx y x bar 1 self assertnotequalx y self assertnotequalx keys y keys def testcopylistsubclassself class clist pass x c1 2 3 x foo 4 5 y copy copyx self assertequallistx listy self assertequalx foo y foo self assertisx0 y0 self assertisx foo y foo def testdeepcopylistsubclassself class clist pass x c1 2 3 x foo 4 5 y copy deepcopyx self assertequallistx listy self assertequalx foo y foo self assertisnotx0 y0 self assertisnotx foo y foo def testcopytuplesubclassself class ctuple pass x c1 2 3 self assertequaltuplex 1 2 3 y copy copyx self assertequaltupley 1 2 3 def testdeepcopytuplesubclassself class ctuple pass x c1 2 3 self assertequaltuplex 1 2 3 y copy deepcopyx self assertequaltupley 1 2 3 self assertisnotx y self assertisnotx0 y0 def testgetstateexcself class evilstateobject def getstateself raise valueerrorain t got no stickin state self assertraisesvalueerror copy copy evilstate def testcopyfunctionself self assertequalcopy copyglobalfoo globalfoo def foox y return xy self assertequalcopy copyfoo foo bar lambda none self assertequalcopy copybar bar def testdeepcopyfunctionself self assertequalcopy deepcopyglobalfoo globalfoo def foox y return xy self assertequalcopy deepcopyfoo foo bar lambda none self assertequalcopy deepcopybar bar def checkweakrefself copy class cobject pass obj c x weakref refobj y copyx self assertisy x del obj y copyx self assertisy x def testcopyweakrefself self checkweakrefcopy copy def testdeepcopyweakrefself self checkweakrefcopy deepcopy def checkcopyweakdictself dicttype class cobject pass a b c d c for i in range4 u dicttype ua b uc d v copy copyu self assertisnotv u self assertequalv u self assertequalva b self assertequalvc d self assertequallenv 2 del c d support gccollect for pypy or other gcs self assertequallenv 1 x y c c the underlying containers are decoupled vx y self assertnotinx u def testcopyweakkeydictself self checkcopyweakdictweakref weakkeydictionary def testcopyweakvaluedictself self checkcopyweakdictweakref weakvaluedictionary def testdeepcopyweakkeydictself class cobject def initself i self i i a b c d ci for i in range4 u weakref weakkeydictionary ua b uc d keys aren t copied values are v copy deepcopyu self assertnotequalv u self assertequallenv 2 self assertisnotva b self assertisnotvc d self assertequalva i b i self assertequalvc i d i del c support gccollect for pypy or other gcs self assertequallenv 1 def testdeepcopyweakvaluedictself class cobject def initself i self i i a b c d ci for i in range4 u weakref weakvaluedictionary ua b uc d keys are copied values aren t v copy deepcopyu self assertnotequalv u self assertequallenv 2 x y z t sortedv items keylambda pair pair0 i self assertisnotx a self assertequalx i a i self assertisy b self assertisnotz c self assertequalz i c i self assertist d del x y z t del d support gccollect for pypy or other gcs self assertequallenv 1 def testdeepcopyboundmethodself class fooobject def mself pass f foo f b f m g copy deepcopyf self assertequalg m g b self assertisg b self g g b class testreplaceunittest testcase def testunsupportedself self assertraisestypeerror copy replace 1 self assertraisestypeerror copy replace self assertraisestypeerror copy replace def f pass self assertraisestypeerror copy replace f class a pass self assertraisestypeerror copy replace a self assertraisestypeerror copy replace a def testreplacemethodself class a def newcls x y0 self object newcls self x x self y y return self def initself args kwargs self z self x self y def replaceself changes x changes get x self x y changes get y self y return typeselfx y attrs attrgetter x y z a a11 22 self assertequalattrscopy replacea 11 22 33 self assertequalattrscopy replacea x1 1 22 23 self assertequalattrscopy replacea y2 11 2 13 self assertequalattrscopy replacea x1 y2 1 2 3 def testnamedtupleself from collections import namedtuple from typing import namedtuple pointfromcall namedtuple point x y defaults0 class pointfrominheritancepointfromcall pass class pointfromclassnamedtuple x int y int 0 for point in pointfromcall pointfrominheritance pointfromclass with self subtestpointpoint p point11 22 self assertisinstancep point self assertequalcopy replacep 11 22 self assertisinstancecopy replacep point self assertequalcopy replacep x1 1 22 self assertequalcopy replacep y2 11 2 self assertequalcopy replacep x1 y2 1 2 with self assertraisesregexvalueerror unexpected field name copy replacep x1 error2 def testdataclassself from dataclasses import dataclass dataclass class c x int y int 0 attrs attrgetter x y c c11 22 self assertequalattrscopy replacec 11 22 self assertequalattrscopy replacec x1 1 22 self assertequalattrscopy replacec y2 11 2 self assertequalattrscopy replacec x1 y2 1 2 with self assertraisesregextypeerror unexpected keyword argument copy replacec x1 error2 def globalfoox y return xy if name main unittest main attempt full line coverage of copy py from top to bottom the copy method type specific _copy_xxx methods state with boolean value is false issue 25718 the deepcopy method tests of reflexive objects are under type specific sections below this tests only repetitions of objects 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 type specific _deepcopy_xxx methods there s the entry for the new list and the keep alive tuples with immutable contents are immutable for deepcopy state with boolean value is false issue 25718 _reconstruct additions for python 2 3 and pickle protocol 2 for pypy or other gcs the underlying containers are decoupled keys aren t copied values are for pypy or other gcs keys are copied values aren t for pypy or other gcs
import copy
import copyreg
import weakref
import abc
from operator import le, lt, ge, gt, eq, ne, attrgetter

import unittest
from test import support

order_comparisons = le, lt, ge, gt
equality_comparisons = eq, ne
comparisons = order_comparisons + equality_comparisons

class TestCopy(unittest.TestCase):

    

    def test_exceptions(self):
        self.assertIs(copy.Error, copy.error)
        self.assertTrue(issubclass(copy.Error, Exception))

    

    def test_copy_basic(self):
        x = 42
        y = copy.copy(x)
        self.assertEqual(x, y)

    def test_copy_copy(self):
        class C(object):
            def __init__(self, foo):
                self.foo = foo
            def __copy__(self):
                return C(self.foo)
        x = C(42)
        y = copy.copy(x)
        self.assertEqual(y.__class__, x.__class__)
        self.assertEqual(y.foo, x.foo)

    def test_copy_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.copy, x)
        copyreg.pickle(C, pickle_C, C)
        y = copy.copy(x)
        self.assertIsNot(x, y)
        self.assertEqual(type(y), C)
        self.assertEqual(y.foo, x.foo)

    def test_copy_reduce_ex(self):
        class C(object):
            def __reduce_ex__(self, proto):
                c.append(1)
                return ""
            def __reduce__(self):
                self.fail("shouldn't call this")
        c = []
        x = C()
        y = copy.copy(x)
        self.assertIs(y, x)
        self.assertEqual(c, [1])

    def test_copy_reduce(self):
        class C(object):
            def __reduce__(self):
                c.append(1)
                return ""
        c = []
        x = C()
        y = copy.copy(x)
        self.assertIs(y, x)
        self.assertEqual(c, [1])

    def test_copy_cant(self):
        class C(object):
            def __getattribute__(self, name):
                if name.startswith("__reduce"):
                    raise AttributeError(name)
                return object.__getattribute__(self, name)
        x = C()
        self.assertRaises(copy.Error, copy.copy, x)

    

    def test_copy_atomic(self):
        class NewStyle:
            pass
        def f():
            pass
        class WithMetaclass(metaclass=abc.ABCMeta):
            pass
        tests = [None, ..., NotImplemented,
                 42, 2**100, 3.14, True, False, 1j,
                 "hello", "hello\u1234", f.__code__,
                 b"world", bytes(range(256)), range(10), slice(1, 10, 2),
                 NewStyle, max, WithMetaclass, property()]
        for x in tests:
            self.assertIs(copy.copy(x), x)

    def test_copy_list(self):
        x = [1, 2, 3]
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)
        x = []
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)

    def test_copy_tuple(self):
        x = (1, 2, 3)
        self.assertIs(copy.copy(x), x)
        x = ()
        self.assertIs(copy.copy(x), x)
        x = (1, 2, 3, [])
        self.assertIs(copy.copy(x), x)

    def test_copy_dict(self):
        x = {"foo": 1, "bar": 2}
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)
        x = {}
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)

    def test_copy_set(self):
        x = {1, 2, 3}
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)
        x = set()
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)

    def test_copy_frozenset(self):
        x = frozenset({1, 2, 3})
        self.assertIs(copy.copy(x), x)
        x = frozenset()
        self.assertIs(copy.copy(x), x)

    def test_copy_bytearray(self):
        x = bytearray(b'abc')
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)
        x = bytearray()
        y = copy.copy(x)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)

    def test_copy_inst_vanilla(self):
        class C:
            def __init__(self, foo):
                self.foo = foo
            def __eq__(self, other):
                return self.foo == other.foo
        x = C(42)
        self.assertEqual(copy.copy(x), x)

    def test_copy_inst_copy(self):
        class C:
            def __init__(self, foo):
                self.foo = foo
            def __copy__(self):
                return C(self.foo)
            def __eq__(self, other):
                return self.foo == other.foo
        x = C(42)
        self.assertEqual(copy.copy(x), x)

    def test_copy_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.assertEqual(copy.copy(x), x)

    def test_copy_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.copy(x)
        self.assertIsInstance(y, C)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)
        self.assertEqual(y.foo, x.foo)

    def test_copy_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.copy(x)
        self.assertIsInstance(y, C)
        self.assertEqual(y, x)
        self.assertIsNot(y, x)
        self.assertEqual(y.foo, x.foo)

    def test_copy_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)
        self.assertEqual(copy.copy(x), x)

    def test_copy_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)
        self.assertEqual(copy.copy(x), x)

    def test_copy_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)
        self.assertEqual(copy.copy(x), x)
        
        x = C(0.0)
        self.assertEqual(copy.copy(x), x)

    

    def test_deepcopy_basic(self):
        x = 42
        y = copy.deepcopy(x)
        self.assertEqual(y, x)

    def test_deepcopy_memo(self):
        
        
        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):
        
        
        
        
        class Meta(type):
            pass
        class C(metaclass=Meta):
            pass
        self.assertEqual(copy.deepcopy(C), C)

    def test_deepcopy_deepcopy(self):
        class C(object):
            def __init__(self, foo):
                self.foo = foo
            def __deepcopy__(self, memo=None):
                return C(self.foo)
        x = C(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)
        copyreg.pickle(C, pickle_C, C)
        y = copy.deepcopy(x)
        self.assertIsNot(x, y)
        self.assertEqual(type(y), C)
        self.assertEqual(y.foo, x.foo)

    def test_deepcopy_reduce_ex(self):
        class C(object):
            def __reduce_ex__(self, proto):
                c.append(1)
                return ""
            def __reduce__(self):
                self.fail("shouldn't call this")
        c = []
        x = C()
        y = copy.deepcopy(x)
        self.assertIs(y, x)
        self.assertEqual(c, [1])

    def test_deepcopy_reduce(self):
        class C(object):
            def __reduce__(self):
                c.append(1)
                return ""
        c = []
        x = C()
        y = copy.deepcopy(x)
        self.assertIs(y, x)
        self.assertEqual(c, [1])

    def test_deepcopy_cant(self):
        class C(object):
            def __getattribute__(self, name):
                if name.startswith("__reduce"):
                    raise AttributeError(name)
                return object.__getattribute__(self, name)
        x = C()
        self.assertRaises(copy.Error, copy.deepcopy, x)

    

    def test_deepcopy_atomic(self):
        class NewStyle:
            pass
        def f():
            pass
        tests = [None, ..., NotImplemented, 42, 2**100, 3.14, True, False, 1j,
                 b"bytes", "hello", "hello\u1234", f.__code__,
                 NewStyle, range(10), max, property()]
        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_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)
        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)
        
        self.assertEqual(len(memo), 2)

        memo = {}
        x = [(1, 2)]
        y = copy.deepcopy(x, memo)
        self.assertEqual(y, x)
        
        self.assertEqual(len(memo), 2)

    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)

    def test_deepcopy_inst_deepcopy(self):
        class C:
            def __init__(self, foo):
                self.foo = foo
            def __deepcopy__(self, memo):
                return C(copy.deepcopy(self.foo, memo))
            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_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])
        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)
        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)
        
        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_reconstruct_string(self):
        class C(object):
            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):
        class C(object):
            def __reduce__(self):
                return (C, ())
        x = C()
        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):
        class C(object):
            def __reduce__(self):
                return (C, (), self.__dict__)
            def __eq__(self, other):
                return self.__dict__ == other.__dict__
        x = C()
        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):
        class C(object):
            def __reduce__(self):
                return (C, (), self.__dict__)
            def __setstate__(self, state):
                self.__dict__.update(state)
            def __eq__(self, other):
                return self.__dict__ == other.__dict__
        x = C()
        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_reflexive(self):
        class C(object):
            pass
        x = C()
        x.foo = x
        y = copy.deepcopy(x)
        self.assertIsNot(y, x)
        self.assertIs(y.foo, y)

    

    def test_reduce_4tuple(self):
        class C(list):
            def __reduce__(self):
                return (C, (), self.__dict__, iter(self))
            def __eq__(self, other):
                return (list(self) == list(other) and
                        self.__dict__ == other.__dict__)
        x = C([[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):
        class C(dict):
            def __reduce__(self):
                return (C, (), self.__dict__, None, self.items())
            def __eq__(self, other):
                return (dict(self) == dict(other) and
                        self.__dict__ == other.__dict__)
        x = C([("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_reduce_6tuple(self):
        def state_setter(*args, **kwargs):
            self.fail("shouldn't call this")
        class C:
            def __reduce__(self):
                return C, (), self.__dict__, None, None, state_setter
        x = C()
        with self.assertRaises(TypeError):
            copy.copy(x)
        with self.assertRaises(TypeError):
            copy.deepcopy(x)

    def test_reduce_6tuple_none(self):
        class C:
            def __reduce__(self):
                return C, (), self.__dict__, None, None, None
        x = C()
        with self.assertRaises(TypeError):
            copy.copy(x)
        with self.assertRaises(TypeError):
            copy.deepcopy(x)

    def test_copy_slots(self):
        class C(object):
            __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(tuple(x), (1, 2, 3))
        y = copy.copy(x)
        self.assertEqual(tuple(y), (1, 2, 3))

    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
        support.gc_collect()  
        self.assertEqual(len(v), 1)
        x, y = C(), C()
        
        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
        
        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
        support.gc_collect()  
        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
        
        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
        support.gc_collect()  
        self.assertEqual(len(v), 1)

    def test_deepcopy_bound_method(self):
        class Foo(object):
            def m(self):
                pass
        f = Foo()
        f.b = f.m
        g = copy.deepcopy(f)
        self.assertEqual(g.m, g.b)
        self.assertIs(g.b.__self__, g)
        g.b()


class TestReplace(unittest.TestCase):

    def test_unsupported(self):
        self.assertRaises(TypeError, copy.replace, 1)
        self.assertRaises(TypeError, copy.replace, [])
        self.assertRaises(TypeError, copy.replace, {})
        def f(): pass
        self.assertRaises(TypeError, copy.replace, f)
        class A: pass
        self.assertRaises(TypeError, copy.replace, A)
        self.assertRaises(TypeError, copy.replace, A())

    def test_replace_method(self):
        class A:
            def __new__(cls, x, y=0):
                self = object.__new__(cls)
                self.x = x
                self.y = y
                return self

            def __init__(self, *args, **kwargs):
                self.z = self.x + self.y

            def __replace__(self, **changes):
                x = changes.get('x', self.x)
                y = changes.get('y', self.y)
                return type(self)(x, y)

        attrs = attrgetter('x', 'y', 'z')
        a = A(11, 22)
        self.assertEqual(attrs(copy.replace(a)), (11, 22, 33))
        self.assertEqual(attrs(copy.replace(a, x=1)), (1, 22, 23))
        self.assertEqual(attrs(copy.replace(a, y=2)), (11, 2, 13))
        self.assertEqual(attrs(copy.replace(a, x=1, y=2)), (1, 2, 3))

    def test_namedtuple(self):
        from collections import namedtuple
        from typing import NamedTuple
        PointFromCall = namedtuple('Point', 'x y', defaults=(0,))
        class PointFromInheritance(PointFromCall):
            pass
        class PointFromClass(NamedTuple):
            x: int
            y: int = 0
        for Point in (PointFromCall, PointFromInheritance, PointFromClass):
            with self.subTest(Point=Point):
                p = Point(11, 22)
                self.assertIsInstance(p, Point)
                self.assertEqual(copy.replace(p), (11, 22))
                self.assertIsInstance(copy.replace(p), Point)
                self.assertEqual(copy.replace(p, x=1), (1, 22))
                self.assertEqual(copy.replace(p, y=2), (11, 2))
                self.assertEqual(copy.replace(p, x=1, y=2), (1, 2))
                with self.assertRaisesRegex(ValueError, 'unexpected field name'):
                    copy.replace(p, x=1, error=2)

    def test_dataclass(self):
        from dataclasses import dataclass
        @dataclass
        class C:
            x: int
            y: int = 0

        attrs = attrgetter('x', 'y')
        c = C(11, 22)
        self.assertEqual(attrs(copy.replace(c)), (11, 22))
        self.assertEqual(attrs(copy.replace(c, x=1)), (1, 22))
        self.assertEqual(attrs(copy.replace(c, y=2)), (11, 2))
        self.assertEqual(attrs(copy.replace(c, x=1, y=2)), (1, 2))
        with self.assertRaisesRegex(TypeError, 'unexpected keyword argument'):
            copy.replace(c, x=1, error=2)


def global_foo(x, y): return x+y


if __name__ == "__main__":
    unittest.main()