mirror of
https://github.com/python/cpython.git
synced 2025-07-31 07:04:42 +00:00
Issue #2116: Weak references and weak dictionaries now support copy()ing and deepcopy()ing.
This commit is contained in:
parent
52035a04ab
commit
775fd66d7b
4 changed files with 116 additions and 1 deletions
|
@ -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):
|
||||||
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
|
||||||
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 @@
|
||||||
|
|
||||||
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):
|
||||||
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):
|
||||||
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):
|
||||||
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
|
||||||
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.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue