From e690883ccf8081e5baab0e9d71f596f26245b569 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 19 Feb 2003 01:19:28 +0000 Subject: Use __reduce_ex__ in copy.py. The test_*copy_cant() tests are simpler again. --- Lib/copy.py | 56 +++++++++++++++++++++++++++++++-------------------- Lib/copy_reg.py | 11 +++++++--- Lib/test/test_copy.py | 32 +++++++++++++++++++++-------- 3 files changed, 66 insertions(+), 33 deletions(-) diff --git a/Lib/copy.py b/Lib/copy.py index b57fa89..9b9f5b3 100644 --- a/Lib/copy.py +++ b/Lib/copy.py @@ -79,14 +79,20 @@ def copy(x): return copier(x) reductor = dispatch_table.get(cls) - if not reductor: - reductor = getattr(cls, "__reduce__", None) - if reductor == object.__reduce__: - reductor = _better_reduce - elif not reductor: - raise Error("un(shallow)copyable object of type %s" % cls) - - return _reconstruct(x, reductor(x), 0) + if reductor: + rv = reductor(x) + else: + reductor = getattr(x, "__reduce_ex__", None) + if reductor: + rv = reductor(2) + else: + reductor = getattr(x, "__reduce__", None) + if reductor: + rv = reductor() + else: + raise Error("un(shallow)copyable object of type %s" % cls) + + return _reconstruct(x, rv, 0) _copy_dispatch = d = {} @@ -176,21 +182,27 @@ def deepcopy(x, memo=None, _nil=[]): except TypeError: # cls is not a class (old Boost; see SF #502085) issc = 0 if issc: - copier = _deepcopy_atomic + y = _deepcopy_atomic(x, memo) else: - copier = getattr(cls, "__deepcopy__", None) - - if copier: - y = copier(x, memo) - else: - reductor = dispatch_table.get(cls) - if not reductor: - reductor = getattr(cls, "__reduce__", None) - if reductor == object.__reduce__: - reductor = _better_reduce - elif not reductor: - raise Error("un(deep)copyable object of type %s" % cls) - y = _reconstruct(x, reductor(x), 1, memo) + copier = getattr(x, "__deepcopy__", None) + if copier: + y = copier(memo) + else: + reductor = dispatch_table.get(cls) + if reductor: + rv = reductor(x) + else: + reductor = getattr(x, "__reduce_ex__", None) + if reductor: + rv = reductor(2) + else: + reductor = getattr(x, "__reduce__", None) + if reductor: + rv = reductor() + else: + raise Error( + "un(deep)copyable object of type %s" % cls) + y = _reconstruct(x, rv, 1, memo) memo[d] = y _keep_alive(x, memo) # Make sure x lives at least as long as d diff --git a/Lib/copy_reg.py b/Lib/copy_reg.py index fa4ce72..fcef409 100644 --- a/Lib/copy_reg.py +++ b/Lib/copy_reg.py @@ -113,9 +113,14 @@ def _better_reduce(obj): def _reduce_ex(obj, proto=0): obj_reduce = getattr(obj, "__reduce__", None) - if obj_reduce and obj.__class__.__reduce__ is not object.__reduce__: - return obj_reduce() - elif proto < 2: + # XXX This fails in test_copy.py line 61 + if obj_reduce: + try: + if obj.__class__.__reduce__ is not object.__reduce__: + return obj_reduce() + except AttributeError: + pass + if proto < 2: return _reduce(obj) else: return _better_reduce(obj) diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py index 6a31f75..cde545d 100644 --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -46,6 +46,16 @@ class TestCopy(unittest.TestCase): copy_reg.pickle(C, pickle_C, C) y = copy.copy(x) + def test_copy_reduce_ex(self): + class C(object): + def __reduce_ex__(self, proto): + return "" + def __reduce__(self): + raise test_support.TestFailed, "shouldn't call this" + x = C() + y = copy.copy(x) + self.assert_(y is x) + def test_copy_reduce(self): class C(object): def __reduce__(self): @@ -55,13 +65,11 @@ class TestCopy(unittest.TestCase): self.assert_(y is x) def test_copy_cant(self): - class Meta(type): + class C(object): def __getattribute__(self, name): - if name == "__reduce__": + if name.startswith("__reduce"): raise AttributeError, name return object.__getattribute__(self, name) - class C: - __metaclass__ = Meta x = C() self.assertRaises(copy.Error, copy.copy, x) @@ -209,6 +217,16 @@ class TestCopy(unittest.TestCase): copy_reg.pickle(C, pickle_C, C) y = copy.deepcopy(x) + def test_deepcopy_reduce_ex(self): + class C(object): + def __reduce_ex__(self, proto): + return "" + def __reduce__(self): + raise test_support.TestFailed, "shouldn't call this" + x = C() + y = copy.deepcopy(x) + self.assert_(y is x) + def test_deepcopy_reduce(self): class C(object): def __reduce__(self): @@ -218,13 +236,11 @@ class TestCopy(unittest.TestCase): self.assert_(y is x) def test_deepcopy_cant(self): - class Meta(type): + class C(object): def __getattribute__(self, name): - if name == "__reduce__": + if name.startswith("__reduce"): raise AttributeError, name return object.__getattribute__(self, name) - class C: - __metaclass__ = Meta x = C() self.assertRaises(copy.Error, copy.deepcopy, x) -- cgit v0.12