[Python-checkins] bpo-27141: Fix collections.UserList and UserDict shallow copy. (GH-4094)
Miss Islington (bot)
webhook-mailer at python.org
Sun May 19 10:26:41 EDT 2019
https://github.com/python/cpython/commit/3645d29a1dc2102fdb0f5f0c0129ff2295bcd768
commit: 3645d29a1dc2102fdb0f5f0c0129ff2295bcd768
branch: 3.7
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2019-05-19T07:26:35-07:00
summary:
bpo-27141: Fix collections.UserList and UserDict shallow copy. (GH-4094)
(cherry picked from commit f4e1babf44792bdeb0c01da96821ba0800a51fd8)
Co-authored-by: Bar Harel <bzvi7919 at gmail.com>
files:
A Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst
M Lib/collections/__init__.py
M Lib/test/test_collections.py
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index 1c69b1b50961..b4592f983921 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -1036,6 +1036,13 @@ def __contains__(self, key):
# Now, add the methods in dicts but not in MutableMapping
def __repr__(self): return repr(self.data)
+ def __copy__(self):
+ inst = self.__class__.__new__(self.__class__)
+ inst.__dict__.update(self.__dict__)
+ # Create a copy and avoid triggering descriptors
+ inst.__dict__["data"] = self.__dict__["data"].copy()
+ return inst
+
def copy(self):
if self.__class__ is UserDict:
return UserDict(self.data.copy())
@@ -1048,6 +1055,7 @@ def copy(self):
self.data = data
c.update(self)
return c
+
@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
@@ -1112,6 +1120,12 @@ def __mul__(self, n):
def __imul__(self, n):
self.data *= n
return self
+ def __copy__(self):
+ inst = self.__class__.__new__(self.__class__)
+ inst.__dict__.update(self.__dict__)
+ # Create a copy and avoid triggering descriptors
+ inst.__dict__["data"] = self.__dict__["data"][:]
+ return inst
def append(self, item): self.data.append(item)
def insert(self, i, item): self.data.insert(i, item)
def pop(self, i=-1): return self.data.pop(i)
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 00b33ce27674..16735b815e53 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -38,6 +38,20 @@ def _superset_test(self, a, b):
b=b.__name__,
),
)
+
+ def _copy_test(self, obj):
+ # Test internal copy
+ obj_copy = obj.copy()
+ self.assertIsNot(obj.data, obj_copy.data)
+ self.assertEqual(obj.data, obj_copy.data)
+
+ # Test copy.copy
+ obj.test = [1234] # Make sure instance vars are also copied.
+ obj_copy = copy.copy(obj)
+ self.assertIsNot(obj.data, obj_copy.data)
+ self.assertEqual(obj.data, obj_copy.data)
+ self.assertIs(obj.test, obj_copy.test)
+
def test_str_protocol(self):
self._superset_test(UserString, str)
@@ -47,6 +61,16 @@ def test_list_protocol(self):
def test_dict_protocol(self):
self._superset_test(UserDict, dict)
+ def test_list_copy(self):
+ obj = UserList()
+ obj.append(123)
+ self._copy_test(obj)
+
+ def test_dict_copy(self):
+ obj = UserDict()
+ obj[123] = "abc"
+ self._copy_test(obj)
+
################################################################################
### ChainMap (helper class for configparser and the string module)
diff --git a/Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst b/Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst
new file mode 100644
index 000000000000..76c2abbf82d6
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-10-24-00-42-14.bpo-27141.zbAgSs.rst
@@ -0,0 +1,3 @@
+Added a ``__copy__()`` to ``collections.UserList`` and
+``collections.UserDict`` in order to correctly implement shallow copying of
+the objects. Patch by Bar Harel.
More information about the Python-checkins
mailing list