From bd5b81cb332ff184eb1e5c26860f40ffedcf14fd Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Mon, 10 Feb 2025 19:47:57 +0900 Subject: [PATCH 01/39] https://github.com/python/cpython/issues/129948: support `multiprocessing.manager.set` --- Lib/multiprocessing/managers.py | 15 +++++- Lib/test/_test_multiprocessing.py | 80 +++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 040f4674d735c0..fb0e0a8b47e9e3 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1217,6 +1217,19 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.terminate() +_BaseSetProxy = MakeProxyType('_BaseSetProxy', ( + '__and__', '__contains__', '__iand__', '__ior__', '__isub__', '__iter__', + '__ixor__', '__len__', '__or__', '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__', + 'add', 'clear', 'copy', 'remove', 'pop', 'discard', 'update', 'intersection', 'intersection_update', + 'difference', 'difference_update', 'symmetric_difference', 'symmetric_difference_update', 'union', + 'isdisjoint', 'issubset', 'issuperset', + )) + +class SetProxy(_BaseSetProxy): + __class_getitem__ = classmethod(types.GenericAlias) + +collections.abc.MutableMapping.register(_BaseSetProxy) + # # Definition of SyncManager # @@ -1248,7 +1261,7 @@ class SyncManager(BaseManager): SyncManager.register('Value', Value, ValueProxy) SyncManager.register('Array', Array, ArrayProxy) SyncManager.register('Namespace', Namespace, NamespaceProxy) - +SyncManager.register('set', set, SetProxy) # types returned by methods of PoolProxy SyncManager.register('Iterator', proxytype=IteratorProxy, create_method=False) SyncManager.register('AsyncResult', create_method=False) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 4b7c3e7fa8bdd7..61b01ea0f9ddde 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6441,6 +6441,86 @@ def test_namespace(self): o.y = 1 self.run_worker(self._test_namespace, o) + @classmethod + def _test_set(cls, obj): + case = unittest.TestCase() + obj.update(['a', 'b', 'c']) + case.assertEqual(len(obj), 3) + result = obj & {'b', 'c', 'd'} + case.assertEqual(result, {'b', 'c'}) + case.assertTrue('a' in obj) + case.assertFalse('d' in obj) + obj &= {'b', 'c', 'd'} + case.assertEqual(obj, {'b', 'c'}) + obj.update(['a', 'b', 'c']) + obj |= {'d', 'e'} + case.assertEqual(obj, {'a', 'b', 'c', 'd', 'e'}) + obj -= {'a', 'b'} + case.assertEqual(obj, {'c', 'd', 'e'}) + obj ^= {'b', 'c', 'd'} + case.assertEqual(obj, {'b', 'e'}) + obj.clear() + obj.update(['a', 'b', 'c']) + result = obj | {'d', 'e'} + case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) + result = {'d', 'e'} | obj + case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) + result = {'a', 'b', 'd'} - obj + case.assertEqual(result, {'d'}) + result = {'b', 'c', 'd'} ^ obj + case.assertEqual(result, {'a', 'd'}) + result = obj - {'a', 'b'} + case.assertEqual(result, {'c'}) + result = obj ^ {'b', 'c', 'd'} + case.assertEqual(result, {'a', 'd'}) + obj.clear() + obj.add('d') + case.assertIn('d', obj) + obj.clear() + obj.update(['a', 'b', 'c']) + copy_obj = obj.copy() + case.assertEqual(copy_obj, obj) + obj.remove('a') + case.assertNotIn('a', obj) + with case.assertRaises(KeyError): + obj.remove('d') + obj.update(['a']) + popped = obj.pop() + case.assertNotIn(popped, obj) + obj.clear() + obj.update(['a', 'b', 'c']) + result = obj.intersection({'b', 'c', 'd'}) + case.assertEqual(result, {'b', 'c'}) + obj.intersection_update({'b', 'c', 'd'}) + case.assertEqual(obj, {'b', 'c'}) + obj.clear() + obj.update(['a', 'b', 'c']) + result = obj.difference({'a', 'b'}) + case.assertEqual(result, {'c'}) + obj.difference_update({'a', 'b'}) + case.assertEqual(obj, {'c'}) + obj.clear() + obj.update(['a', 'b', 'c']) + result = obj.symmetric_difference({'b', 'c', 'd'}) + case.assertEqual(result, {'a', 'd'}) + obj.clear() + obj.update(['a', 'b', 'c']) + obj.symmetric_difference_update({'b', 'c', 'd'}) + case.assertEqual(obj, {'a', 'd'}) + obj.clear() + obj.update(['a', 'b', 'c']) + result = obj.union({'d', 'e'}) + case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) + case.assertTrue(obj.isdisjoint({'d', 'e'})) + case.assertFalse(obj.isdisjoint({'a', 'd'})) + case.assertTrue(obj.issubset({'a', 'b', 'c', 'd'})) + case.assertFalse(obj.issubset({'a', 'b'})) + case.assertTrue(obj.issuperset({'a', 'b'})) + case.assertFalse(obj.issuperset({'a', 'b', 'd'})) + + def test_set(self): + o = self.manager.set() + self.run_worker(self._test_set, o) class TestNamedResource(unittest.TestCase): @only_run_in_spawn_testsuite("spawn specific test.") From d7626613a289f0b52b1118dab81d85693f13031e Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Mon, 10 Feb 2025 19:53:54 +0900 Subject: [PATCH 02/39] fix lint --- Lib/test/_test_multiprocessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 61b01ea0f9ddde..dda54022294939 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6462,7 +6462,7 @@ def _test_set(cls, obj): obj.clear() obj.update(['a', 'b', 'c']) result = obj | {'d', 'e'} - case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) + case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) result = {'d', 'e'} | obj case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) result = {'a', 'b', 'd'} - obj From 3514b42a68309e55f55a0ec3842ba04f1808139c Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:02:23 +0000 Subject: [PATCH 03/39] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst diff --git a/Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst b/Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst new file mode 100644 index 00000000000000..a5dcbf87f803a8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst @@ -0,0 +1 @@ +Add set() to multiprocessing.managers.SyncManager From e529f5f5270427f04ed4e16a119fd573e6a993c0 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:36:58 +0000 Subject: [PATCH 04/39] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst new file mode 100644 index 00000000000000..0993aec19f0f66 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst @@ -0,0 +1,5 @@ +Propose Feature: Support for :func:`set` in :class:`multiprocessing.managers.SyncManager` + +I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. +:class:`SetProxy`, which inherits from :class:`BaseProxy`, has been added. +:class:`SetProxy` supports all functions that the primitive type :class:`set` provides. From f0f7d255b0ea95924483831184e43671743b3b6a Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Tue, 11 Feb 2025 15:38:41 +0900 Subject: [PATCH 05/39] remove first doc --- .../next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst diff --git a/Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst b/Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst deleted file mode 100644 index a5dcbf87f803a8..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-02-10-11-02-22.gh-issue-129948.cZ6zht.rst +++ /dev/null @@ -1 +0,0 @@ -Add set() to multiprocessing.managers.SyncManager From 41cb4a60634c95846cba3a9db0be6e16b12d7c96 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Tue, 11 Feb 2025 15:41:20 +0900 Subject: [PATCH 06/39] remove doc --- .../Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst deleted file mode 100644 index 0993aec19f0f66..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-02-11-06-36-56.gh-issue-129948.7ODk-3.rst +++ /dev/null @@ -1,5 +0,0 @@ -Propose Feature: Support for :func:`set` in :class:`multiprocessing.managers.SyncManager` - -I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. -:class:`SetProxy`, which inherits from :class:`BaseProxy`, has been added. -:class:`SetProxy` supports all functions that the primitive type :class:`set` provides. From 479681673d6537c0d1bd7e097403731406fe768e Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:42:18 +0000 Subject: [PATCH 07/39] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst new file mode 100644 index 00000000000000..89fcb50cdd5242 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst @@ -0,0 +1,6 @@ +Propose Feature: Support for :func:`set` in :class:`multiprocessing.managers.SyncManager` + +I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. + +:class:`SetProxy`, which inherits from :class:`BaseProxy`, has been added. +:class:`SetProxy` supports all functions that the primitive type :class:`set` provides. From 40c60cc2923298a44bf04befac0048ec799be765 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Tue, 11 Feb 2025 15:45:44 +0900 Subject: [PATCH 08/39] fix lint --- .../Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst index 89fcb50cdd5242..1c1fd203a9c889 100644 --- a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst +++ b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst @@ -1,6 +1,5 @@ Propose Feature: Support for :func:`set` in :class:`multiprocessing.managers.SyncManager` -I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. - -:class:`SetProxy`, which inherits from :class:`BaseProxy`, has been added. -:class:`SetProxy` supports all functions that the primitive type :class:`set` provides. +I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. +:class:`SetProxy`, which inherits from :class:`BaseProxy`, has been added. +:class:`SetProxy` supports all functions that the primitive type :class:`set` provides. From 5e0977fe81c13ce1d92cb9b2f179e1075d8b7c8a Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Tue, 11 Feb 2025 16:20:13 +0900 Subject: [PATCH 09/39] fix doc lint --- .../Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst index 1c1fd203a9c889..d655f9e4605dd0 100644 --- a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst +++ b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst @@ -1,5 +1,5 @@ Propose Feature: Support for :func:`set` in :class:`multiprocessing.managers.SyncManager` I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. -:class:`SetProxy`, which inherits from :class:`BaseProxy`, has been added. -:class:`SetProxy` supports all functions that the primitive type :class:`set` provides. +`SetProxy`, which inherits from `BaseProxy`, has been added. +`SetProxy` supports all functions that the primitive type :func:`set` provides. From 5c0294066ecc1d2bdba3ee475e5bd7f4c0963994 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Tue, 11 Feb 2025 16:29:44 +0900 Subject: [PATCH 10/39] doc: update comment --- .../Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst index d655f9e4605dd0..eaa4e1ac545af4 100644 --- a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst +++ b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst @@ -1,5 +1,4 @@ Propose Feature: Support for :func:`set` in :class:`multiprocessing.managers.SyncManager` I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. -`SetProxy`, which inherits from `BaseProxy`, has been added. -`SetProxy` supports all functions that the primitive type :func:`set` provides. +:class:`multiprocessing.managers.SyncManager` have :func:`dict`, :func:`list` functions, but it does not have a :func:`set` function. From 3132d2acf1a328324a9a4a67a2fdaa06ff6c198e Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Tue, 11 Feb 2025 22:10:27 +0900 Subject: [PATCH 11/39] Remove hard coding in MakeProxyType --- Lib/multiprocessing/managers.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index fb0e0a8b47e9e3..b254ac1a57cc78 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1217,13 +1217,12 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.terminate() -_BaseSetProxy = MakeProxyType('_BaseSetProxy', ( - '__and__', '__contains__', '__iand__', '__ior__', '__isub__', '__iter__', - '__ixor__', '__len__', '__or__', '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__', - 'add', 'clear', 'copy', 'remove', 'pop', 'discard', 'update', 'intersection', 'intersection_update', - 'difference', 'difference_update', 'symmetric_difference', 'symmetric_difference_update', 'union', - 'isdisjoint', 'issubset', 'issuperset', - )) +_set_proxy_methods = set(dir(set)) - set(dir(object)) +_set_proxy_methods = sorted(_set_proxy_methods) +_BaseSetProxy = MakeProxyType( + '_BaseSetProxy', _set_proxy_methods +) +del _set_proxy_methods class SetProxy(_BaseSetProxy): __class_getitem__ = classmethod(types.GenericAlias) From deb8b738eb23bec579bbc1aa47d386a9ca38eadc Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Tue, 11 Feb 2025 22:11:48 +0900 Subject: [PATCH 12/39] test: Seperate test_set, Add test_set_contain_all_method --- Lib/test/_test_multiprocessing.py | 45 +++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index dda54022294939..bc19e61b8735c8 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6442,7 +6442,7 @@ def test_namespace(self): self.run_worker(self._test_namespace, o) @classmethod - def _test_set(cls, obj): + def _test_set_operator_symbols(cls, obj): case = unittest.TestCase() obj.update(['a', 'b', 'c']) case.assertEqual(len(obj), 3) @@ -6471,15 +6471,16 @@ def _test_set(cls, obj): case.assertEqual(result, {'a', 'd'}) result = obj - {'a', 'b'} case.assertEqual(result, {'c'}) - result = obj ^ {'b', 'c', 'd'} - case.assertEqual(result, {'a', 'd'}) - obj.clear() + + @classmethod + def _test_set_operator_methods(cls, obj): + case = unittest.TestCase() obj.add('d') case.assertIn('d', obj) obj.clear() obj.update(['a', 'b', 'c']) copy_obj = obj.copy() - case.assertEqual(copy_obj, obj) + case.assertSetEqual(copy_obj, obj) obj.remove('a') case.assertNotIn('a', obj) with case.assertRaises(KeyError): @@ -6490,24 +6491,23 @@ def _test_set(cls, obj): obj.clear() obj.update(['a', 'b', 'c']) result = obj.intersection({'b', 'c', 'd'}) - case.assertEqual(result, {'b', 'c'}) + case.assertSetEqual(result, {'b', 'c'}) obj.intersection_update({'b', 'c', 'd'}) - case.assertEqual(obj, {'b', 'c'}) + case.assertSetEqual(obj, {'b', 'c'}) obj.clear() obj.update(['a', 'b', 'c']) result = obj.difference({'a', 'b'}) case.assertEqual(result, {'c'}) obj.difference_update({'a', 'b'}) - case.assertEqual(obj, {'c'}) + case.assertSetEqual(obj, {'c'}) obj.clear() obj.update(['a', 'b', 'c']) result = obj.symmetric_difference({'b', 'c', 'd'}) case.assertEqual(result, {'a', 'd'}) - obj.clear() - obj.update(['a', 'b', 'c']) - obj.symmetric_difference_update({'b', 'c', 'd'}) - case.assertEqual(obj, {'a', 'd'}) - obj.clear() + + @classmethod + def _test_set_miscellaneous(cls, obj): + case = unittest.TestCase() obj.update(['a', 'b', 'c']) result = obj.union({'d', 'e'}) case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) @@ -6520,7 +6520,24 @@ def _test_set(cls, obj): def test_set(self): o = self.manager.set() - self.run_worker(self._test_set, o) + self.run_worker(self._test_set_operator_symbols, o) + o.clear() + self.run_worker(self._test_set_operator_methods, o) + o.clear() + self.run_worker(self._test_set_miscellaneous, o) + + def test_set_contain_all_method(self): + o = self.manager.set() + set_methods = ( + '__and__', '__class_getitem__', '__contains__', '__iand__', '__ior__', + '__isub__', '__iter__', '__ixor__', '__len__', '__or__', '__rand__', + '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__', + 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', + 'intersection', 'intersection_update', 'isdisjoint', 'issubset', + 'issuperset', 'pop', 'remove', 'symmetric_difference', + 'symmetric_difference_update', 'union', 'update', + ) + self.assertTrue(set(dir(o)).issuperset(set_methods)) class TestNamedResource(unittest.TestCase): @only_run_in_spawn_testsuite("spawn specific test.") From b0b3d3f90c902d98d7e5be0da793d9815df0061e Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Tue, 11 Feb 2025 22:13:14 +0900 Subject: [PATCH 13/39] Update blurb to simply --- .../Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst index eaa4e1ac545af4..637b2a194ebfcb 100644 --- a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst +++ b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst @@ -1,4 +1 @@ -Propose Feature: Support for :func:`set` in :class:`multiprocessing.managers.SyncManager` - -I propose adding support for the :func:`set` function in the :class:`multiprocessing.managers.SyncManager`. -:class:`multiprocessing.managers.SyncManager` have :func:`dict`, :func:`list` functions, but it does not have a :func:`set` function. +Added support for :func:`set` to :class:`multiprocessing.managers.SyncManager`. From a381b1daf1447de4d999638e67892a1d615c8b50 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Tue, 11 Feb 2025 22:31:27 +0900 Subject: [PATCH 14/39] doc: multiprocessing and 3.14 what's news --- Doc/library/multiprocessing.rst | 11 ++++++++--- Doc/whatsnew/3.14.rst | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 783cb025826483..fed0837bd07fb2 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -377,32 +377,37 @@ However, if you really do need to use some shared data then :class:`list`, :class:`dict`, :class:`~managers.Namespace`, :class:`Lock`, :class:`RLock`, :class:`Semaphore`, :class:`BoundedSemaphore`, :class:`Condition`, :class:`Event`, :class:`Barrier`, - :class:`Queue`, :class:`Value` and :class:`Array`. For example, :: + :class:`Queue`, :class:`Value`, :class:`Array` and :class:`set`. For example, :: from multiprocessing import Process, Manager - def f(d, l): + def f(d, l, s): d[1] = '1' d['2'] = 2 d[0.25] = None l.reverse() + s.add('a') + s.add('b') if __name__ == '__main__': with Manager() as manager: d = manager.dict() l = manager.list(range(10)) + s = manager.set() - p = Process(target=f, args=(d, l)) + p = Process(target=f, args=(d, l, s)) p.start() p.join() print(d) print(l) + print(s) will print :: {0.25: None, 1: '1', '2': 2} [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] + {'a', 'b'} Server process managers are more flexible than using shared memory objects because they can be made to support arbitrary object types. Also, a single diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index f8df4c52a36147..647de3bdea91c1 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -581,7 +581,9 @@ multiprocessing ``d |= {'b': 2}`` for proxies of :class:`dict`. (Contributed by Roy Hyunjin Han for :gh:`103134`.) - +* The :class:`multiprocessing.managers.SyncManager` now supports the :class:`set` type. + :func:`multiprocessing.Manager.set` method is now available. + (Contributed by Mingyu Park for :gh:`129949`.) operator -------- From e332082cdf1aefbaaf84745f19f7118cf71d4978 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Tue, 11 Feb 2025 22:47:03 +0900 Subject: [PATCH 15/39] fix doc ref --- Doc/whatsnew/3.14.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 647de3bdea91c1..84680e3509d7e7 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -582,7 +582,7 @@ multiprocessing (Contributed by Roy Hyunjin Han for :gh:`103134`.) * The :class:`multiprocessing.managers.SyncManager` now supports the :class:`set` type. - :func:`multiprocessing.Manager.set` method is now available. + The :func:`set` in :func:`multiprocessing.Manager` method is now available. (Contributed by Mingyu Park for :gh:`129949`.) operator From 928ad6d88be47d750c4b1071c3b189fc1946640a Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Wed, 12 Feb 2025 00:38:16 +0900 Subject: [PATCH 16/39] Add set document in multiprocessing.rst --- Doc/library/multiprocessing.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index fed0837bd07fb2..7c314556438528 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1941,6 +1941,12 @@ their parent process exits. The manager classes are defined in the Create a shared :class:`list` object and return a proxy for it. + .. method:: set() + set(sequence) + set(mapping) + + Create a shared :class:`set` object and return a proxy for it. + .. versionchanged:: 3.6 Shared objects are capable of being nested. For example, a shared container object such as a shared list can contain other shared objects From b89beb938c89c5f7f6856ce52be4b3f5514888ce Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Wed, 12 Feb 2025 00:40:38 +0900 Subject: [PATCH 17/39] fix lint --- Doc/library/multiprocessing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 7c314556438528..7f424900043790 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1944,7 +1944,7 @@ their parent process exits. The manager classes are defined in the .. method:: set() set(sequence) set(mapping) - + Create a shared :class:`set` object and return a proxy for it. .. versionchanged:: 3.6 From e88f5c7a7e1a622a1e0b02c09c7a80c4e4fe4b51 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 09:05:39 +0900 Subject: [PATCH 18/39] Update Doc/whatsnew/3.14.rst --- Doc/whatsnew/3.14.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 84680e3509d7e7..c47f0e37ad4a7e 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -581,9 +581,10 @@ multiprocessing ``d |= {'b': 2}`` for proxies of :class:`dict`. (Contributed by Roy Hyunjin Han for :gh:`103134`.) -* The :class:`multiprocessing.managers.SyncManager` now supports the :class:`set` type. +* * Add support for shared :class:`set` objects via + :meth:`SyncManager.set() `. The :func:`set` in :func:`multiprocessing.Manager` method is now available. - (Contributed by Mingyu Park for :gh:`129949`.) + (Contributed by Mingyu Park in :gh:`129949`.) operator -------- From 3d5d828dac869b8ddd7b417fa0d87c5d1f8f268a Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 09:23:22 +0900 Subject: [PATCH 19/39] Update _test_multiprocessing --- Lib/test/_test_multiprocessing.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index bc19e61b8735c8..3bd78aae40ce8c 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6521,14 +6521,14 @@ def _test_set_miscellaneous(cls, obj): def test_set(self): o = self.manager.set() self.run_worker(self._test_set_operator_symbols, o) - o.clear() + o = self.manager.set() self.run_worker(self._test_set_operator_methods, o) - o.clear() + o = self.manager.set() self.run_worker(self._test_set_miscellaneous, o) def test_set_contain_all_method(self): o = self.manager.set() - set_methods = ( + set_methods = { '__and__', '__class_getitem__', '__contains__', '__iand__', '__ior__', '__isub__', '__iter__', '__ixor__', '__len__', '__or__', '__rand__', '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__', @@ -6536,8 +6536,8 @@ def test_set_contain_all_method(self): 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update', - ) - self.assertTrue(set(dir(o)).issuperset(set_methods)) + } + self.assertTrue(set_methods <= set(dir(o))) class TestNamedResource(unittest.TestCase): @only_run_in_spawn_testsuite("spawn specific test.") From 9c3478de20b73ec02d0a72308503378e43458655 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 09:24:52 +0900 Subject: [PATCH 20/39] Update blurb --- .../Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst index 637b2a194ebfcb..85f7f966d83da3 100644 --- a/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst +++ b/Misc/NEWS.d/next/Library/2025-02-11-06-42-17.gh-issue-129948.ZcugY9.rst @@ -1 +1,2 @@ -Added support for :func:`set` to :class:`multiprocessing.managers.SyncManager`. +Add support for shared :class:`set` to :class:`multiprocessing.managers.SyncManager` +via :meth:`SyncManager.set() `. From 7658e24b1e6067aaf1c7c715ec1edfe4ad3ec7e0 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 09:28:08 +0900 Subject: [PATCH 21/39] Add version change at multiprocessing.rst --- Doc/library/multiprocessing.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 7f424900043790..55e8c4fcbdbcbc 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1952,6 +1952,10 @@ their parent process exits. The manager classes are defined in the container object such as a shared list can contain other shared objects which will all be managed and synchronized by the :class:`SyncManager`. + .. versionchanged:: 3.14 + Add support for shared :class:`set` to :class:`multiprocessing.managers.SyncManager` + via :meth:`SyncManager.set() `. + .. class:: Namespace A type that can register with :class:`SyncManager`. From d2052a7784a3149a7f48efb0a5bb2faf42583f03 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 09:50:59 +0900 Subject: [PATCH 22/39] Fix typo --- Doc/whatsnew/3.14.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index c47f0e37ad4a7e..1c8993c4510eaf 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -581,7 +581,7 @@ multiprocessing ``d |= {'b': 2}`` for proxies of :class:`dict`. (Contributed by Roy Hyunjin Han for :gh:`103134`.) -* * Add support for shared :class:`set` objects via +* Add support for shared :class:`set` objects via :meth:`SyncManager.set() `. The :func:`set` in :func:`multiprocessing.Manager` method is now available. (Contributed by Mingyu Park in :gh:`129949`.) From 74db275ffd498e27ff173952c7d0b76c6b92600d Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 09:57:34 +0900 Subject: [PATCH 23/39] update version change to next --- Doc/library/multiprocessing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 55e8c4fcbdbcbc..37d7927a9df2b7 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1952,7 +1952,7 @@ their parent process exits. The manager classes are defined in the container object such as a shared list can contain other shared objects which will all be managed and synchronized by the :class:`SyncManager`. - .. versionchanged:: 3.14 + .. versionchanged:: next Add support for shared :class:`set` to :class:`multiprocessing.managers.SyncManager` via :meth:`SyncManager.set() `. From 920e06a590897ac9e733093dc182afe36c8c2d4e Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 11:45:03 +0900 Subject: [PATCH 24/39] Addressed all comment in reviewing --- Doc/library/multiprocessing.rst | 6 ++--- Doc/whatsnew/3.14.rst | 2 ++ Lib/multiprocessing/managers.py | 22 ++++++++--------- Lib/test/_test_multiprocessing.py | 41 ++++++++++++++++++------------- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 37d7927a9df2b7..b63130a2a8daf0 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -374,10 +374,10 @@ However, if you really do need to use some shared data then proxies. A manager returned by :func:`Manager` will support types - :class:`list`, :class:`dict`, :class:`~managers.Namespace`, :class:`Lock`, + :class:`list`, :class:`dict`, :class:`set`, :class:`~managers.Namespace`, :class:`Lock`, :class:`RLock`, :class:`Semaphore`, :class:`BoundedSemaphore`, :class:`Condition`, :class:`Event`, :class:`Barrier`, - :class:`Queue`, :class:`Value`, :class:`Array` and :class:`set`. For example, :: + :class:`Queue`, :class:`Value` and :class:`Array`. For example, :: from multiprocessing import Process, Manager @@ -1953,7 +1953,7 @@ their parent process exits. The manager classes are defined in the which will all be managed and synchronized by the :class:`SyncManager`. .. versionchanged:: next - Add support for shared :class:`set` to :class:`multiprocessing.managers.SyncManager` + Add support for shared :class:`set`\s to :class:`multiprocessing.managers.SyncManager` via :meth:`SyncManager.set() `. .. class:: Namespace diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 1c8993c4510eaf..a1e35e181e3455 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -581,11 +581,13 @@ multiprocessing ``d |= {'b': 2}`` for proxies of :class:`dict`. (Contributed by Roy Hyunjin Han for :gh:`103134`.) + * Add support for shared :class:`set` objects via :meth:`SyncManager.set() `. The :func:`set` in :func:`multiprocessing.Manager` method is now available. (Contributed by Mingyu Park in :gh:`129949`.) + operator -------- diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index b254ac1a57cc78..07898376863eaf 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1195,6 +1195,16 @@ def __ior__(self, value): collections.abc.MutableMapping.register(_BaseDictProxy) +_set_proxy_methods = set(dir(set)) - set(dir(object)) +_set_proxy_methods = sorted(_set_proxy_methods) +_BaseSetProxy = MakeProxyType("_BaseSetProxy", _set_proxy_methods) +del _set_proxy_methods + +class SetProxy(_BaseSetProxy): + __class_getitem__ = classmethod(types.GenericAlias) + +collections.abc.MutableMapping.register(_BaseSetProxy) + ArrayProxy = MakeProxyType('ArrayProxy', ( '__len__', '__getitem__', '__setitem__' )) @@ -1217,18 +1227,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.terminate() -_set_proxy_methods = set(dir(set)) - set(dir(object)) -_set_proxy_methods = sorted(_set_proxy_methods) -_BaseSetProxy = MakeProxyType( - '_BaseSetProxy', _set_proxy_methods -) -del _set_proxy_methods - -class SetProxy(_BaseSetProxy): - __class_getitem__ = classmethod(types.GenericAlias) - -collections.abc.MutableMapping.register(_BaseSetProxy) - # # Definition of SyncManager # diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 3bd78aae40ce8c..cd357ea2d278dd 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6447,30 +6447,30 @@ def _test_set_operator_symbols(cls, obj): obj.update(['a', 'b', 'c']) case.assertEqual(len(obj), 3) result = obj & {'b', 'c', 'd'} - case.assertEqual(result, {'b', 'c'}) - case.assertTrue('a' in obj) - case.assertFalse('d' in obj) + case.assertSetEqual(result, {'b', 'c'}) + case.assertIn('a', obj) + case.assertNotIn('d', obj) obj &= {'b', 'c', 'd'} - case.assertEqual(obj, {'b', 'c'}) + case.assertSetEqual(obj, {'b', 'c'}) obj.update(['a', 'b', 'c']) obj |= {'d', 'e'} - case.assertEqual(obj, {'a', 'b', 'c', 'd', 'e'}) + case.assertSetEqual(obj, {'a', 'b', 'c', 'd', 'e'}) obj -= {'a', 'b'} - case.assertEqual(obj, {'c', 'd', 'e'}) + case.assertSetEqual(obj, {'c', 'd', 'e'}) obj ^= {'b', 'c', 'd'} - case.assertEqual(obj, {'b', 'e'}) + case.assertSetEqual(obj, {'b', 'e'}) obj.clear() obj.update(['a', 'b', 'c']) result = obj | {'d', 'e'} - case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) + case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) result = {'d', 'e'} | obj - case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) + case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) result = {'a', 'b', 'd'} - obj - case.assertEqual(result, {'d'}) + case.assertSetEqual(result, {'d'}) result = {'b', 'c', 'd'} ^ obj - case.assertEqual(result, {'a', 'd'}) + case.assertSetEqual(result, {'a', 'd'}) result = obj - {'a', 'b'} - case.assertEqual(result, {'c'}) + case.assertSetEqual(result, {'c'}) @classmethod def _test_set_operator_methods(cls, obj): @@ -6483,8 +6483,7 @@ def _test_set_operator_methods(cls, obj): case.assertSetEqual(copy_obj, obj) obj.remove('a') case.assertNotIn('a', obj) - with case.assertRaises(KeyError): - obj.remove('d') + case.assertRaises(KeyError, obj.remove, 'd') obj.update(['a']) popped = obj.pop() case.assertNotIn(popped, obj) @@ -6497,20 +6496,20 @@ def _test_set_operator_methods(cls, obj): obj.clear() obj.update(['a', 'b', 'c']) result = obj.difference({'a', 'b'}) - case.assertEqual(result, {'c'}) + case.assertSetEqual(result, {'c'}) obj.difference_update({'a', 'b'}) case.assertSetEqual(obj, {'c'}) obj.clear() obj.update(['a', 'b', 'c']) result = obj.symmetric_difference({'b', 'c', 'd'}) - case.assertEqual(result, {'a', 'd'}) + case.assertSetEqual(result, {'a', 'd'}) @classmethod def _test_set_miscellaneous(cls, obj): case = unittest.TestCase() obj.update(['a', 'b', 'c']) result = obj.union({'d', 'e'}) - case.assertEqual(result, {'a', 'b', 'c', 'd', 'e'}) + case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) case.assertTrue(obj.isdisjoint({'d', 'e'})) case.assertFalse(obj.isdisjoint({'a', 'd'})) case.assertTrue(obj.issubset({'a', 'b', 'c', 'd'})) @@ -6525,6 +6524,13 @@ def test_set(self): self.run_worker(self._test_set_operator_methods, o) o = self.manager.set() self.run_worker(self._test_set_miscellaneous, o) + self.assertRaises(RemoteError, self.manager.set, 1234) + o = self.manager.set({'a', 'b', 'c'}) + self.assertSetEqual(o, {'a', 'b', 'c'}) + o = self.manager.set(["a", "b", "c"]) + self.assertSetEqual(o, {"a", "b", "c"}) + o = self.manager.set({"a": 1, "b": 2, "c": 3}) + self.assertSetEqual(o, {"a", "b", "c"}) def test_set_contain_all_method(self): o = self.manager.set() @@ -6539,6 +6545,7 @@ def test_set_contain_all_method(self): } self.assertTrue(set_methods <= set(dir(o))) + class TestNamedResource(unittest.TestCase): @only_run_in_spawn_testsuite("spawn specific test.") def test_global_named_resource_spawn(self): From 12a65e30edd6b5c8424e8a151c1c6cce9697e0e8 Mon Sep 17 00:00:00 2001 From: "mingyu.park" Date: Wed, 12 Feb 2025 12:19:56 +0900 Subject: [PATCH 25/39] refactor test --- Lib/test/_test_multiprocessing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index cd357ea2d278dd..0905bd914f4d9b 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6524,13 +6524,15 @@ def test_set(self): self.run_worker(self._test_set_operator_methods, o) o = self.manager.set() self.run_worker(self._test_set_miscellaneous, o) - self.assertRaises(RemoteError, self.manager.set, 1234) + + def test_set_init(self): o = self.manager.set({'a', 'b', 'c'}) self.assertSetEqual(o, {'a', 'b', 'c'}) o = self.manager.set(["a", "b", "c"]) self.assertSetEqual(o, {"a", "b", "c"}) o = self.manager.set({"a": 1, "b": 2, "c": 3}) self.assertSetEqual(o, {"a", "b", "c"}) + self.assertRaises(RemoteError, self.manager.set, 1234) def test_set_contain_all_method(self): o = self.manager.set() From d70769159306efc22b6741d1967c09ee9913a1ef Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Wed, 12 Feb 2025 23:39:55 +0900 Subject: [PATCH 26/39] Enhance set operator tests with additional assertions and edge case handling --- Lib/test/_test_multiprocessing.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 0905bd914f4d9b..44d8dec8d251c5 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6471,6 +6471,10 @@ def _test_set_operator_symbols(cls, obj): case.assertSetEqual(result, {'a', 'd'}) result = obj - {'a', 'b'} case.assertSetEqual(result, {'c'}) + case.assertGreater(obj, {'a'}) + case.assertGreaterEqual(obj, {'a', 'b'}) + case.assertLess(obj, {'a', 'b', 'c', 'd'}) + case.assertLessEqual(obj, {'a', 'b', 'c'}) @classmethod def _test_set_operator_methods(cls, obj): @@ -6483,7 +6487,13 @@ def _test_set_operator_methods(cls, obj): case.assertSetEqual(copy_obj, obj) obj.remove('a') case.assertNotIn('a', obj) - case.assertRaises(KeyError, obj.remove, 'd') + case.assertRaises(KeyError, obj.remove, 'a') + obj.clear() + obj.update(['a']) + obj.discard('a') + case.assertNotIn('a', obj) + obj.discard('a') + case.assertNotIn('a', obj) obj.update(['a']) popped = obj.pop() case.assertNotIn(popped, obj) @@ -6503,6 +6513,8 @@ def _test_set_operator_methods(cls, obj): obj.update(['a', 'b', 'c']) result = obj.symmetric_difference({'b', 'c', 'd'}) case.assertSetEqual(result, {'a', 'd'}) + obj.symmetric_difference_update({'b', 'c', 'd'}) + case.assertSetEqual(obj, {'a', 'd'}) @classmethod def _test_set_miscellaneous(cls, obj): From 0eb6fdbb6fe780f2be41e474ee49b52cbf8d9629 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Wed, 12 Feb 2025 23:54:20 +0900 Subject: [PATCH 27/39] Add test case of __iter__, __xor__, __and__, __rand__ --- Lib/test/_test_multiprocessing.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 44d8dec8d251c5..19ca9c642c7734 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6467,14 +6467,21 @@ def _test_set_operator_symbols(cls, obj): case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) result = {'a', 'b', 'd'} - obj case.assertSetEqual(result, {'d'}) - result = {'b', 'c', 'd'} ^ obj - case.assertSetEqual(result, {'a', 'd'}) result = obj - {'a', 'b'} case.assertSetEqual(result, {'c'}) + result = {'b', 'c', 'd'} ^ obj + case.assertSetEqual(result, {'a', 'd'}) + result = obj ^ {'b', 'c', 'd'} + case.assertSetEqual(result, {'a', 'd'}) + result = obj & {'b', 'c', 'd'} + case.assertSetEqual(result, {'b', 'c'}) + result = {'b', 'c', 'd'} & obj + case.assertSetEqual(result, {'b', 'c'}) case.assertGreater(obj, {'a'}) case.assertGreaterEqual(obj, {'a', 'b'}) case.assertLess(obj, {'a', 'b', 'c', 'd'}) case.assertLessEqual(obj, {'a', 'b', 'c'}) + case.assertSetEqual({o for o in obj}, {'a', 'b', 'c'}) @classmethod def _test_set_operator_methods(cls, obj): From dd295c36f5f6d27827ce944c2080542b8ce8add0 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Thu, 13 Feb 2025 00:26:04 +0900 Subject: [PATCH 28/39] Reordering set operator tests to improve clarity --- Lib/test/_test_multiprocessing.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 19ca9c642c7734..94e5f76569c5a6 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6446,37 +6446,40 @@ def _test_set_operator_symbols(cls, obj): case = unittest.TestCase() obj.update(['a', 'b', 'c']) case.assertEqual(len(obj), 3) - result = obj & {'b', 'c', 'd'} - case.assertSetEqual(result, {'b', 'c'}) case.assertIn('a', obj) case.assertNotIn('d', obj) - obj &= {'b', 'c', 'd'} - case.assertSetEqual(obj, {'b', 'c'}) - obj.update(['a', 'b', 'c']) - obj |= {'d', 'e'} - case.assertSetEqual(obj, {'a', 'b', 'c', 'd', 'e'}) - obj -= {'a', 'b'} - case.assertSetEqual(obj, {'c', 'd', 'e'}) - obj ^= {'b', 'c', 'd'} - case.assertSetEqual(obj, {'b', 'e'}) - obj.clear() - obj.update(['a', 'b', 'c']) result = obj | {'d', 'e'} case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) result = {'d', 'e'} | obj case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) + obj |= {'d', 'e'} + case.assertSetEqual(obj, {'a', 'b', 'c', 'd', 'e'}) + obj.clear() + obj.update(['a', 'b', 'c']) result = {'a', 'b', 'd'} - obj case.assertSetEqual(result, {'d'}) result = obj - {'a', 'b'} case.assertSetEqual(result, {'c'}) + obj -= {'a', 'b'} + case.assertSetEqual(obj, {'c'}) + obj.clear() + obj.update(['a', 'b', 'c']) result = {'b', 'c', 'd'} ^ obj case.assertSetEqual(result, {'a', 'd'}) result = obj ^ {'b', 'c', 'd'} case.assertSetEqual(result, {'a', 'd'}) + obj ^= {'b', 'c', 'd'} + case.assertSetEqual(obj, {'a', 'd'}) + obj.clear() + obj.update(['a', 'b', 'c']) result = obj & {'b', 'c', 'd'} case.assertSetEqual(result, {'b', 'c'}) result = {'b', 'c', 'd'} & obj case.assertSetEqual(result, {'b', 'c'}) + obj &= {'b', 'c', 'd'} + case.assertSetEqual(obj, {'b', 'c'}) + obj.clear() + obj.update(['a', 'b', 'c']) case.assertGreater(obj, {'a'}) case.assertGreaterEqual(obj, {'a', 'b'}) case.assertLess(obj, {'a', 'b', 'c', 'd'}) From cf8ef27d249ca988132931d84cb7b2993d1bbc80 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Sun, 23 Feb 2025 00:59:22 +0900 Subject: [PATCH 29/39] Change register order after dict --- Lib/multiprocessing/managers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 07898376863eaf..52a308461309de 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1255,10 +1255,10 @@ class SyncManager(BaseManager): SyncManager.register('Pool', pool.Pool, PoolProxy) SyncManager.register('list', list, ListProxy) SyncManager.register('dict', dict, DictProxy) +SyncManager.register('set', set, SetProxy) SyncManager.register('Value', Value, ValueProxy) SyncManager.register('Array', Array, ArrayProxy) SyncManager.register('Namespace', Namespace, NamespaceProxy) -SyncManager.register('set', set, SetProxy) # types returned by methods of PoolProxy SyncManager.register('Iterator', proxytype=IteratorProxy, create_method=False) SyncManager.register('AsyncResult', create_method=False) From 3706c7833ea0793ac96838b16043355982e016b5 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Sun, 23 Feb 2025 09:21:31 +0900 Subject: [PATCH 30/39] Fix the bug where SetProxy's __ior__, __ixor__, __iand__, and __isub__ return a set instead of a SetProxy --- Lib/multiprocessing/managers.py | 21 +++++++++++++++++++++ Lib/test/_test_multiprocessing.py | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 52a308461309de..e9d8201216534c 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1201,6 +1201,27 @@ def __ior__(self, value): del _set_proxy_methods class SetProxy(_BaseSetProxy): + def __ior__(self, value): + self._callmethod('__ior__', (value,)) + return self + def __iand__(self, value): + self._callmethod('__iand__', (value,)) + return self + def __ixor__(self, value): + self._callmethod('__ixor__', (value,)) + return self + def __isub__(self, value): + self._callmethod('__isub__', (value,)) + return self + def __le__(self, value): + return self._callmethod('__le__', (value,)) + def __lt__(self, value): + return self._callmethod('__lt__', (value,)) + def __ge__(self, value): + return self._callmethod('__ge__', (value,)) + def __gt__(self, value): + return self._callmethod('__gt__', (value,)) + __class_getitem__ = classmethod(types.GenericAlias) collections.abc.MutableMapping.register(_BaseSetProxy) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 94e5f76569c5a6..fb513741844476 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6454,6 +6454,7 @@ def _test_set_operator_symbols(cls, obj): case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) obj |= {'d', 'e'} case.assertSetEqual(obj, {'a', 'b', 'c', 'd', 'e'}) + case.assertIsInstance(obj, multiprocessing.managers.SetProxy) obj.clear() obj.update(['a', 'b', 'c']) result = {'a', 'b', 'd'} - obj @@ -6462,6 +6463,7 @@ def _test_set_operator_symbols(cls, obj): case.assertSetEqual(result, {'c'}) obj -= {'a', 'b'} case.assertSetEqual(obj, {'c'}) + case.assertIsInstance(obj, multiprocessing.managers.SetProxy) obj.clear() obj.update(['a', 'b', 'c']) result = {'b', 'c', 'd'} ^ obj @@ -6470,6 +6472,7 @@ def _test_set_operator_symbols(cls, obj): case.assertSetEqual(result, {'a', 'd'}) obj ^= {'b', 'c', 'd'} case.assertSetEqual(obj, {'a', 'd'}) + case.assertIsInstance(obj, multiprocessing.managers.SetProxy) obj.clear() obj.update(['a', 'b', 'c']) result = obj & {'b', 'c', 'd'} @@ -6477,6 +6480,7 @@ def _test_set_operator_symbols(cls, obj): result = {'b', 'c', 'd'} & obj case.assertSetEqual(result, {'b', 'c'}) obj &= {'b', 'c', 'd'} + case.assertIsInstance(obj, multiprocessing.managers.SetProxy) case.assertSetEqual(obj, {'b', 'c'}) obj.clear() obj.update(['a', 'b', 'c']) From a259b395ed98aa3fbf09b23a08b269db226bb797 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Sun, 23 Feb 2025 09:22:47 +0900 Subject: [PATCH 31/39] Fix missing __ge__, __gt__, __le__, and __lt__ methods in SetProxy --- Lib/multiprocessing/managers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index e9d8201216534c..c8a0313eca1855 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1195,7 +1195,9 @@ def __ior__(self, value): collections.abc.MutableMapping.register(_BaseDictProxy) -_set_proxy_methods = set(dir(set)) - set(dir(object)) +_set_proxy_methods = set(dir(set)) - set(dir(object)) | { + '__ge__', '__gt__', '__le__', '__lt__' + } _set_proxy_methods = sorted(_set_proxy_methods) _BaseSetProxy = MakeProxyType("_BaseSetProxy", _set_proxy_methods) del _set_proxy_methods From 121b742acda7072d5bee16a8721c3c89a180e48b Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Sun, 23 Feb 2025 10:00:13 +0900 Subject: [PATCH 32/39] Addressed code review comments --- Doc/library/multiprocessing.rst | 6 ++---- Lib/multiprocessing/managers.py | 9 +-------- Lib/test/_test_multiprocessing.py | 26 ++++++++++++++++++-------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index b63130a2a8daf0..911b19e18ecdde 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1947,15 +1947,13 @@ their parent process exits. The manager classes are defined in the Create a shared :class:`set` object and return a proxy for it. + .. versionadded:: next + .. versionchanged:: 3.6 Shared objects are capable of being nested. For example, a shared container object such as a shared list can contain other shared objects which will all be managed and synchronized by the :class:`SyncManager`. - .. versionchanged:: next - Add support for shared :class:`set`\s to :class:`multiprocessing.managers.SyncManager` - via :meth:`SyncManager.set() `. - .. class:: Namespace A type that can register with :class:`SyncManager`. diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index c8a0313eca1855..5d50bde580b667 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1215,14 +1215,6 @@ def __ixor__(self, value): def __isub__(self, value): self._callmethod('__isub__', (value,)) return self - def __le__(self, value): - return self._callmethod('__le__', (value,)) - def __lt__(self, value): - return self._callmethod('__lt__', (value,)) - def __ge__(self, value): - return self._callmethod('__ge__', (value,)) - def __gt__(self, value): - return self._callmethod('__gt__', (value,)) __class_getitem__ = classmethod(types.GenericAlias) @@ -1282,6 +1274,7 @@ class SyncManager(BaseManager): SyncManager.register('Value', Value, ValueProxy) SyncManager.register('Array', Array, ArrayProxy) SyncManager.register('Namespace', Namespace, NamespaceProxy) + # types returned by methods of PoolProxy SyncManager.register('Iterator', proxytype=IteratorProxy, create_method=False) SyncManager.register('AsyncResult', create_method=False) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index fb513741844476..cfccbc5f364a71 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6455,6 +6455,7 @@ def _test_set_operator_symbols(cls, obj): obj |= {'d', 'e'} case.assertSetEqual(obj, {'a', 'b', 'c', 'd', 'e'}) case.assertIsInstance(obj, multiprocessing.managers.SetProxy) + obj.clear() obj.update(['a', 'b', 'c']) result = {'a', 'b', 'd'} - obj @@ -6464,6 +6465,7 @@ def _test_set_operator_symbols(cls, obj): obj -= {'a', 'b'} case.assertSetEqual(obj, {'c'}) case.assertIsInstance(obj, multiprocessing.managers.SetProxy) + obj.clear() obj.update(['a', 'b', 'c']) result = {'b', 'c', 'd'} ^ obj @@ -6473,6 +6475,7 @@ def _test_set_operator_symbols(cls, obj): obj ^= {'b', 'c', 'd'} case.assertSetEqual(obj, {'a', 'd'}) case.assertIsInstance(obj, multiprocessing.managers.SetProxy) + obj.clear() obj.update(['a', 'b', 'c']) result = obj & {'b', 'c', 'd'} @@ -6480,21 +6483,19 @@ def _test_set_operator_symbols(cls, obj): result = {'b', 'c', 'd'} & obj case.assertSetEqual(result, {'b', 'c'}) obj &= {'b', 'c', 'd'} - case.assertIsInstance(obj, multiprocessing.managers.SetProxy) case.assertSetEqual(obj, {'b', 'c'}) + case.assertIsInstance(obj, multiprocessing.managers.SetProxy) + obj.clear() obj.update(['a', 'b', 'c']) - case.assertGreater(obj, {'a'}) - case.assertGreaterEqual(obj, {'a', 'b'}) - case.assertLess(obj, {'a', 'b', 'c', 'd'}) - case.assertLessEqual(obj, {'a', 'b', 'c'}) - case.assertSetEqual({o for o in obj}, {'a', 'b', 'c'}) + case.assertSetEqual(set(obj), {'a', 'b', 'c'}) @classmethod def _test_set_operator_methods(cls, obj): case = unittest.TestCase() obj.add('d') case.assertIn('d', obj) + obj.clear() obj.update(['a', 'b', 'c']) copy_obj = obj.copy() @@ -6502,6 +6503,7 @@ def _test_set_operator_methods(cls, obj): obj.remove('a') case.assertNotIn('a', obj) case.assertRaises(KeyError, obj.remove, 'a') + obj.clear() obj.update(['a']) obj.discard('a') @@ -6511,18 +6513,21 @@ def _test_set_operator_methods(cls, obj): obj.update(['a']) popped = obj.pop() case.assertNotIn(popped, obj) + obj.clear() obj.update(['a', 'b', 'c']) result = obj.intersection({'b', 'c', 'd'}) case.assertSetEqual(result, {'b', 'c'}) obj.intersection_update({'b', 'c', 'd'}) case.assertSetEqual(obj, {'b', 'c'}) + obj.clear() obj.update(['a', 'b', 'c']) result = obj.difference({'a', 'b'}) case.assertSetEqual(result, {'c'}) obj.difference_update({'a', 'b'}) case.assertSetEqual(obj, {'c'}) + obj.clear() obj.update(['a', 'b', 'c']) result = obj.symmetric_difference({'b', 'c', 'd'}) @@ -6531,7 +6536,7 @@ def _test_set_operator_methods(cls, obj): case.assertSetEqual(obj, {'a', 'd'}) @classmethod - def _test_set_miscellaneous(cls, obj): + def _test_set_comparisons(cls, obj): case = unittest.TestCase() obj.update(['a', 'b', 'c']) result = obj.union({'d', 'e'}) @@ -6542,6 +6547,10 @@ def _test_set_miscellaneous(cls, obj): case.assertFalse(obj.issubset({'a', 'b'})) case.assertTrue(obj.issuperset({'a', 'b'})) case.assertFalse(obj.issuperset({'a', 'b', 'd'})) + case.assertGreater(obj, {'a'}) + case.assertGreaterEqual(obj, {'a', 'b'}) + case.assertLess(obj, {'a', 'b', 'c', 'd'}) + case.assertLessEqual(obj, {'a', 'b', 'c'}) def test_set(self): o = self.manager.set() @@ -6549,7 +6558,7 @@ def test_set(self): o = self.manager.set() self.run_worker(self._test_set_operator_methods, o) o = self.manager.set() - self.run_worker(self._test_set_miscellaneous, o) + self.run_worker(self._test_set_comparisons, o) def test_set_init(self): o = self.manager.set({'a', 'b', 'c'}) @@ -6566,6 +6575,7 @@ def test_set_contain_all_method(self): '__and__', '__class_getitem__', '__contains__', '__iand__', '__ior__', '__isub__', '__iter__', '__ixor__', '__len__', '__or__', '__rand__', '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__', + '__ge__', '__gt__', '__le__', '__lt__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', From e8b449f87c7a46401902b42b8aef773bfc71f74c Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Sun, 23 Feb 2025 10:16:42 +0900 Subject: [PATCH 33/39] Hardcode SetProxy methods --- Lib/multiprocessing/managers.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 5d50bde580b667..3af2076eea1693 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1195,9 +1195,16 @@ def __ior__(self, value): collections.abc.MutableMapping.register(_BaseDictProxy) -_set_proxy_methods = set(dir(set)) - set(dir(object)) | { - '__ge__', '__gt__', '__le__', '__lt__' - } +_set_proxy_methods = { + '__and__', '__class_getitem__', '__contains__', '__iand__', '__ior__', + '__isub__', '__iter__', '__ixor__', '__len__', '__or__', '__rand__', + '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__', + '__ge__', '__gt__', '__le__', '__lt__', + 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', + 'intersection', 'intersection_update', 'isdisjoint', 'issubset', + 'issuperset', 'pop', 'remove', 'symmetric_difference', + 'symmetric_difference_update', 'union', 'update', +} _set_proxy_methods = sorted(_set_proxy_methods) _BaseSetProxy = MakeProxyType("_BaseSetProxy", _set_proxy_methods) del _set_proxy_methods From c3c3075379a1b67f91e6c6751210c3ac30bd40f5 Mon Sep 17 00:00:00 2001 From: Mingyu Park Date: Sun, 23 Feb 2025 10:18:23 +0900 Subject: [PATCH 34/39] Grouping tests for issuperset and issubset --- Lib/test/_test_multiprocessing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index cfccbc5f364a71..47e9dfc4d294b4 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6545,12 +6545,12 @@ def _test_set_comparisons(cls, obj): case.assertFalse(obj.isdisjoint({'a', 'd'})) case.assertTrue(obj.issubset({'a', 'b', 'c', 'd'})) case.assertFalse(obj.issubset({'a', 'b'})) + case.assertLess(obj, {'a', 'b', 'c', 'd'}) + case.assertLessEqual(obj, {'a', 'b', 'c'}) case.assertTrue(obj.issuperset({'a', 'b'})) case.assertFalse(obj.issuperset({'a', 'b', 'd'})) case.assertGreater(obj, {'a'}) case.assertGreaterEqual(obj, {'a', 'b'}) - case.assertLess(obj, {'a', 'b', 'c', 'd'}) - case.assertLessEqual(obj, {'a', 'b', 'c'}) def test_set(self): o = self.manager.set() From 13c18c7b233c226fb42da26c2cf7a030a742aa30 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 23 Feb 2025 11:11:44 -0800 Subject: [PATCH 35/39] Update Lib/test/_test_multiprocessing.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/_test_multiprocessing.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 47e9dfc4d294b4..c6191ef7d46fa8 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6543,10 +6543,12 @@ def _test_set_comparisons(cls, obj): case.assertSetEqual(result, {'a', 'b', 'c', 'd', 'e'}) case.assertTrue(obj.isdisjoint({'d', 'e'})) case.assertFalse(obj.isdisjoint({'a', 'd'})) + case.assertTrue(obj.issubset({'a', 'b', 'c', 'd'})) case.assertFalse(obj.issubset({'a', 'b'})) case.assertLess(obj, {'a', 'b', 'c', 'd'}) case.assertLessEqual(obj, {'a', 'b', 'c'}) + case.assertTrue(obj.issuperset({'a', 'b'})) case.assertFalse(obj.issuperset({'a', 'b', 'd'})) case.assertGreater(obj, {'a'}) From af37eaeb47ccab07ff2d088410fdcadb6995a3e9 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 23 Feb 2025 11:12:04 -0800 Subject: [PATCH 36/39] Update Lib/multiprocessing/managers.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/multiprocessing/managers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 3af2076eea1693..f787c9b2700617 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1227,6 +1227,7 @@ def __isub__(self, value): collections.abc.MutableMapping.register(_BaseSetProxy) + ArrayProxy = MakeProxyType('ArrayProxy', ( '__len__', '__getitem__', '__setitem__' )) From a34e4616e632880bb844ecf69dc6925187d01a78 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 23 Feb 2025 11:12:13 -0800 Subject: [PATCH 37/39] Update Lib/multiprocessing/managers.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/multiprocessing/managers.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index f787c9b2700617..c1f09d2b409052 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -1195,7 +1195,7 @@ def __ior__(self, value): collections.abc.MutableMapping.register(_BaseDictProxy) -_set_proxy_methods = { +_BaseSetProxy = MakeProxyType("_BaseSetProxy", ( '__and__', '__class_getitem__', '__contains__', '__iand__', '__ior__', '__isub__', '__iter__', '__ixor__', '__len__', '__or__', '__rand__', '__ror__', '__rsub__', '__rxor__', '__sub__', '__xor__', @@ -1204,10 +1204,7 @@ def __ior__(self, value): 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update', -} -_set_proxy_methods = sorted(_set_proxy_methods) -_BaseSetProxy = MakeProxyType("_BaseSetProxy", _set_proxy_methods) -del _set_proxy_methods +)) class SetProxy(_BaseSetProxy): def __ior__(self, value): From df6330aff5dcb70c95355c6f22d576ca231772da Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 23 Feb 2025 11:19:57 -0800 Subject: [PATCH 38/39] Update Lib/test/_test_multiprocessing.py --- Lib/test/_test_multiprocessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index c6191ef7d46fa8..5dd89bd5af7daa 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6583,7 +6583,7 @@ def test_set_contain_all_method(self): 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update', } - self.assertTrue(set_methods <= set(dir(o))) + self.assertLessEqual(set_methods, set(dir(o))) class TestNamedResource(unittest.TestCase): From 9d131292a67ad0a6ed794e7b89e15efc19d0dc1a Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 23 Feb 2025 11:25:11 -0800 Subject: [PATCH 39/39] Update Doc/library/multiprocessing.rst --- Doc/library/multiprocessing.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index eeb0b2cca243b9..41ade9f2d943a5 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1954,6 +1954,7 @@ their parent process exits. The manager classes are defined in the Create a shared :class:`set` object and return a proxy for it. .. versionadded:: next + :class:`set` support was added. .. versionchanged:: 3.6 Shared objects are capable of being nested. For example, a shared