From bc4e7e7cf5656b7709d60714da1ef6f99ca9b0e5 Mon Sep 17 00:00:00 2001 From: curtisbucher Date: Wed, 18 Mar 2020 14:53:56 -0700 Subject: [PATCH 1/5] Added | and |= operators to WeakValueDictionary Updated weakref.py Added tests Updated docs Updated news --- Doc/library/weakref.rst | 2 ++ Lib/test/test_weakref.py | 15 +++++++++++++++ Lib/weakref.py | 14 ++++++++++++++ .../2020-03-18-14-51-41.bpo-36144.lQm_RK.rst | 1 + 4 files changed, 32 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 8636e76c52a420..374ebc41a84cd5 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -201,6 +201,8 @@ than needed. same issues as the :meth:`keyrefs` method of :class:`WeakKeyDictionary` objects. + .. versionchanged:: 3.9 + Added support for ``|`` and ``|=`` operators, specified in :pep:`584`. .. method:: WeakValueDictionary.valuerefs() diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 63c725527d5f25..93302df96f73a4 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1609,6 +1609,21 @@ def test_weak_valued_dict_update(self): self.assertEqual(list(d.keys()), [kw]) self.assertEqual(d[kw], o) + def test_weak_valued_union_operators(self): + class C: pass + c1 = C() + c2 = C() + c3 = C() + + wvd1 = weakref.WeakValueDictionary({'1' : c1, '2': c2}) + wvd2 = weakref.WeakValueDictionary({'1': c3, '4': c1}) + + wvd3 = wvd1 | wvd2 + self.assertEqual(dict(wvd3), dict(wvd1) | dict(wvd2)) + + wvd1 |= wvd2 + self.assertEqual(wvd1, wvd3) + 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 e3c2ce2d9b8b86..481de0db08be0b 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -310,6 +310,20 @@ def valuerefs(self): self._commit_removals() return list(self.data.values()) + def __ior__(self, other): + self.update(other) + return self + + def __or__(self, other): + c = self.copy() + c.update(other) + return c + + def __ror__(self, other): + c = other.copy() + c.update(self) + return c + 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 00000000000000..daf1101601f4d6 --- /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`. From cef9fd2d218740eafc81329ce8f5d251a8cf23da Mon Sep 17 00:00:00 2001 From: curtisbucher Date: Mon, 23 Mar 2020 15:10:04 -0700 Subject: [PATCH 2/5] Update test_weakref.py and weakref.py --- Lib/test/test_weakref.py | 42 ++++++++++++++++++++++++++++++---------- Lib/weakref.py | 17 ++++++++++------ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 93302df96f73a4..887f0d0229cd8c 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1610,19 +1610,41 @@ def test_weak_valued_dict_update(self): self.assertEqual(d[kw], o) def test_weak_valued_union_operators(self): - class C: pass - c1 = C() - c2 = C() - c3 = C() + 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), (5, 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) - wvd1 = weakref.WeakValueDictionary({'1' : c1, '2': c2}) - wvd2 = weakref.WeakValueDictionary({'1': c3, '4': c1}) + 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) - wvd3 = wvd1 | wvd2 - self.assertEqual(dict(wvd3), dict(wvd1) | dict(wvd2)) + 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) - wvd1 |= wvd2 - self.assertEqual(wvd1, wvd3) + tmp4 = d1 | wvd3 # Testing .__ror__ + self.assertEqual(dict(tmp4), d1 | dict(wvd3)) + self.assertIs(type(tmp4), weakref.WeakValueDictionary) + + del a + self.assertNotIn(2, tmp1.keys()) + self.assertNotIn(2, tmp2.keys()) + self.assertNotIn(1, tmp3.keys()) + self.assertNotIn(1, tmp4.keys()) def test_weak_keyed_dict_update(self): self.check_update(weakref.WeakKeyDictionary, diff --git a/Lib/weakref.py b/Lib/weakref.py index 481de0db08be0b..99cccab656a73d 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -315,14 +315,19 @@ def __ior__(self, other): return self def __or__(self, other): - c = self.copy() - c.update(other) - return c + if isinstance(other, _collections_abc.Mapping): + c = self.copy() + c.update(other) + return c + return NotImplemented def __ror__(self, other): - c = other.copy() - c.update(self) - return c + if isinstance(other, _collections_abc.Mapping): + c = self.__class__() + c.update(other) + c.update(self) + return c + return NotImplemented class KeyedRef(ref): From 3829134a9de6d75fd1068daaaef02c6a18e72302 Mon Sep 17 00:00:00 2001 From: curtisbucher Date: Mon, 23 Mar 2020 15:38:36 -0700 Subject: [PATCH 3/5] Update weakref.rst and test_weakref.py Fixed styling and readibility. --- Doc/library/weakref.rst | 6 +++--- Lib/test/test_weakref.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 374ebc41a84cd5..04f62f4d22f5fb 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -197,13 +197,13 @@ 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, 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. - .. versionchanged:: 3.9 - Added support for ``|`` and ``|=`` operators, specified in :pep:`584`. - .. method:: WeakValueDictionary.valuerefs() Return an iterable of the weak references to the values. diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 887f0d0229cd8c..d9faae14327360 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1613,11 +1613,11 @@ 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}) + wvd1 = weakref.WeakValueDictionary({1: a}) + wvd2 = weakref.WeakValueDictionary({1: b, 2: a}) wvd3 = wvd1.copy() - d1 = {1 : c, 3 : b} - pairs = [(5, c), (5, b)] + d1 = {1: c, 3: b} + pairs = [(5, c), (6, b)] tmp1 = wvd1 | wvd2 # Between two WeakValueDictionaries self.assertEqual(dict(tmp1), dict(wvd1) | dict(wvd2)) @@ -1641,10 +1641,10 @@ def test_weak_valued_union_operators(self): self.assertIs(type(tmp4), weakref.WeakValueDictionary) del a - self.assertNotIn(2, tmp1.keys()) - self.assertNotIn(2, tmp2.keys()) - self.assertNotIn(1, tmp3.keys()) - self.assertNotIn(1, tmp4.keys()) + 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, From f1b6195144375ee559c9f210e2c23311bb273276 Mon Sep 17 00:00:00 2001 From: curtisbucher Date: Mon, 23 Mar 2020 15:57:31 -0700 Subject: [PATCH 4/5] Update weakref.rst --- Doc/library/weakref.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 04f62f4d22f5fb..1113e01b5f2b02 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -204,6 +204,7 @@ than needed. same issues as the :meth:`keyrefs` method of :class:`WeakKeyDictionary` objects. + .. method:: WeakValueDictionary.valuerefs() Return an iterable of the weak references to the values. From ea5465adbc28b1973b0eb778de46a82342c361e4 Mon Sep 17 00:00:00 2001 From: Curtis Bucher Date: Tue, 24 Mar 2020 13:42:01 -0700 Subject: [PATCH 5/5] Update Doc/library/weakref.rst Grammar Co-Authored-By: Kyle Stanley --- Doc/library/weakref.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 1113e01b5f2b02..9ed60e88bec1b9 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -198,7 +198,7 @@ than needed. magic" (as a side effect of garbage collection). .. versionchanged:: 3.9 - Added support for ``|`` and ``|=`` operators, specified in :pep:`584`. + 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`