From 8f1ed21ecf57cc8b8095d9d1058af2b9b3ed0413 Mon Sep 17 00:00:00 2001 From: Curtis Bucher Date: Tue, 24 Mar 2020 18:51:29 -0700 Subject: [PATCH] bpo-36144: Add union operators to WeakValueDictionary584 (#19127) --- Doc/library/weakref.rst | 3 ++ Lib/test/test_weakref.py | 37 +++++++++++++++++++ Lib/weakref.py | 19 ++++++++++ .../2020-03-18-14-51-41.bpo-36144.lQm_RK.rst | 1 + 4 files changed, 60 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-03-18-14-51-41.bpo-36144.lQm_RK.rst diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index c10f436bea4..12eb985c344 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -200,6 +200,9 @@ than needed. by the program during iteration may cause items in the dictionary to vanish "by magic" (as a side effect of garbage collection). + .. versionchanged:: 3.9 + Added support for ``|`` and ``|=`` operators, as specified in :pep:`584`. + :class:`WeakValueDictionary` objects have an additional method that has the same issues as the :meth:`keyrefs` method of :class:`WeakKeyDictionary` objects. diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 250ed40b20c..563507fee3d 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1609,6 +1609,43 @@ class MappingTestCase(TestBase): self.assertEqual(list(d.keys()), [kw]) self.assertEqual(d[kw], o) + def test_weak_valued_union_operators(self): + a = C() + b = C() + c = C() + wvd1 = weakref.WeakValueDictionary({1: a}) + wvd2 = weakref.WeakValueDictionary({1: b, 2: a}) + wvd3 = wvd1.copy() + d1 = {1: c, 3: b} + pairs = [(5, c), (6, b)] + + tmp1 = wvd1 | wvd2 # Between two WeakValueDictionaries + self.assertEqual(dict(tmp1), dict(wvd1) | dict(wvd2)) + self.assertIs(type(tmp1), weakref.WeakValueDictionary) + wvd1 |= wvd2 + self.assertEqual(wvd1, tmp1) + + tmp2 = wvd2 | d1 # Between WeakValueDictionary and mapping + self.assertEqual(dict(tmp2), dict(wvd2) | d1) + self.assertIs(type(tmp2), weakref.WeakValueDictionary) + wvd2 |= d1 + self.assertEqual(wvd2, tmp2) + + tmp3 = wvd3.copy() # Between WeakValueDictionary and iterable key, value + tmp3 |= pairs + self.assertEqual(dict(tmp3), dict(wvd3) | dict(pairs)) + self.assertIs(type(tmp3), weakref.WeakValueDictionary) + + tmp4 = d1 | wvd3 # Testing .__ror__ + self.assertEqual(dict(tmp4), d1 | dict(wvd3)) + self.assertIs(type(tmp4), weakref.WeakValueDictionary) + + del a + self.assertNotIn(2, tmp1) + self.assertNotIn(2, tmp2) + self.assertNotIn(1, tmp3) + self.assertNotIn(1, tmp4) + def test_weak_keyed_dict_update(self): self.check_update(weakref.WeakKeyDictionary, {C(): 1, C(): 2, C(): 3}) diff --git a/Lib/weakref.py b/Lib/weakref.py index 759ad6dfa39..5fa851dd6d7 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -310,6 +310,25 @@ class WeakValueDictionary(_collections_abc.MutableMapping): self._commit_removals() return list(self.data.values()) + def __ior__(self, other): + self.update(other) + return self + + def __or__(self, other): + if isinstance(other, _collections_abc.Mapping): + c = self.copy() + c.update(other) + return c + return NotImplemented + + def __ror__(self, other): + if isinstance(other, _collections_abc.Mapping): + c = self.__class__() + c.update(other) + c.update(self) + return c + return NotImplemented + class KeyedRef(ref): """Specialized reference that includes a key corresponding to the value. diff --git a/Misc/NEWS.d/next/Library/2020-03-18-14-51-41.bpo-36144.lQm_RK.rst b/Misc/NEWS.d/next/Library/2020-03-18-14-51-41.bpo-36144.lQm_RK.rst new file mode 100644 index 00000000000..daf1101601f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-03-18-14-51-41.bpo-36144.lQm_RK.rst @@ -0,0 +1 @@ +Added :pep:`584` operators to :class:`weakref.WeakValueDictionary`.