Kaydet (Commit) 775fd66d authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Issue #2116: Weak references and weak dictionaries now support copy()ing and deepcopy()ing.

üst 52035a04
...@@ -49,6 +49,7 @@ __getstate__() and __setstate__(). See the documentation for module ...@@ -49,6 +49,7 @@ __getstate__() and __setstate__(). See the documentation for module
""" """
import types import types
import weakref
from copy_reg import dispatch_table from copy_reg import dispatch_table
class Error(Exception): class Error(Exception):
...@@ -102,7 +103,7 @@ def _copy_immutable(x): ...@@ -102,7 +103,7 @@ def _copy_immutable(x):
for t in (type(None), int, long, float, bool, str, tuple, for t in (type(None), int, long, float, bool, str, tuple,
frozenset, type, xrange, types.ClassType, frozenset, type, xrange, types.ClassType,
types.BuiltinFunctionType, type(Ellipsis), types.BuiltinFunctionType, type(Ellipsis),
types.FunctionType): types.FunctionType, weakref.ref):
d[t] = _copy_immutable d[t] = _copy_immutable
for name in ("ComplexType", "UnicodeType", "CodeType"): for name in ("ComplexType", "UnicodeType", "CodeType"):
t = getattr(types, name, None) t = getattr(types, name, None)
...@@ -220,6 +221,7 @@ d[xrange] = _deepcopy_atomic ...@@ -220,6 +221,7 @@ d[xrange] = _deepcopy_atomic
d[types.ClassType] = _deepcopy_atomic d[types.ClassType] = _deepcopy_atomic
d[types.BuiltinFunctionType] = _deepcopy_atomic d[types.BuiltinFunctionType] = _deepcopy_atomic
d[types.FunctionType] = _deepcopy_atomic d[types.FunctionType] = _deepcopy_atomic
d[weakref.ref] = _deepcopy_atomic
def _deepcopy_list(x, memo): def _deepcopy_list(x, memo):
y = [] y = []
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
import copy import copy
import copy_reg import copy_reg
import weakref
import operator
import unittest import unittest
from test import test_support from test import test_support
...@@ -585,6 +587,92 @@ class TestCopy(unittest.TestCase): ...@@ -585,6 +587,92 @@ class TestCopy(unittest.TestCase):
bar = lambda: None bar = lambda: None
self.assertEqual(copy.deepcopy(bar), bar) 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.assertTrue(y is x)
del obj
y = _copy(x)
self.assertTrue(y is 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 xrange(4)]
u = _dicttype()
u[a] = b
u[c] = d
v = copy.copy(u)
self.assertFalse(v is 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.assertFalse(x in 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 xrange(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.assertFalse(v[a] is b)
self.assertFalse(v[c] is 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 xrange(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 (k, v): k.i)
self.assertFalse(x is a)
self.assertEqual(x.i, a.i)
self.assertTrue(y is b)
self.assertFalse(z is c)
self.assertEqual(z.i, c.i)
self.assertTrue(t is d)
del x, y, z, t
del d
self.assertEqual(len(v), 1)
def global_foo(x, y): return x+y def global_foo(x, y): return x+y
def test_main(): def test_main():
......
...@@ -85,6 +85,17 @@ class WeakValueDictionary(UserDict.UserDict): ...@@ -85,6 +85,17 @@ class WeakValueDictionary(UserDict.UserDict):
new[key] = o new[key] = o
return new return new
__copy__ = copy
def __deepcopy__(self, memo):
from copy import deepcopy
new = self.__class__()
for key, wr in self.data.items():
o = wr()
if o is not None:
new[deepcopy(key, memo)] = o
return new
def get(self, key, default=None): def get(self, key, default=None):
try: try:
wr = self.data[key] wr = self.data[key]
...@@ -256,6 +267,17 @@ class WeakKeyDictionary(UserDict.UserDict): ...@@ -256,6 +267,17 @@ class WeakKeyDictionary(UserDict.UserDict):
new[o] = value new[o] = value
return new return new
__copy__ = copy
def __deepcopy__(self, memo):
from copy import deepcopy
new = self.__class__()
for key, value in self.data.items():
o = key()
if o is not None:
new[o] = deepcopy(value, memo)
return new
def get(self, key, default=None): def get(self, key, default=None):
return self.data.get(ref(key),default) return self.data.get(ref(key),default)
......
...@@ -293,6 +293,9 @@ Core and Builtins ...@@ -293,6 +293,9 @@ Core and Builtins
Library Library
------- -------
- Issue #2116: Weak references and weak dictionaries now support copy()ing and
deepcopy()ing.
- Issue #1655: Make imaplib IPv6-capable. Patch by Derek Morr. - Issue #1655: Make imaplib IPv6-capable. Patch by Derek Morr.
- Issue #5918: Fix a crash in the parser module. - Issue #5918: Fix a crash in the parser module.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment