gh-129948: Add set() to multiprocessing.managers.SyncManager (#129949)

The SyncManager provided support for various data structures such as dict, list, and queue, but oddly, not set.
This introduces support for set by defining SetProxy and registering it with SyncManager.

---
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
mingyu 2025-02-24 05:07:33 +09:00 committed by GitHub
parent a65366ed87
commit 9f81f828c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 199 additions and 3 deletions

View file

@ -6441,6 +6441,150 @@ class TestSyncManagerTypes(unittest.TestCase):
o.y = 1
self.run_worker(self._test_namespace, o)
@classmethod
def _test_set_operator_symbols(cls, obj):
case = unittest.TestCase()
obj.update(['a', 'b', 'c'])
case.assertEqual(len(obj), 3)
case.assertIn('a', obj)
case.assertNotIn('d', obj)
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'})
case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
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'})
case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
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'})
case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
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'})
case.assertIsInstance(obj, multiprocessing.managers.SetProxy)
obj.clear()
obj.update(['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()
case.assertSetEqual(copy_obj, obj)
obj.remove('a')
case.assertNotIn('a', obj)
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)
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'})
case.assertSetEqual(result, {'a', 'd'})
obj.symmetric_difference_update({'b', 'c', 'd'})
case.assertSetEqual(obj, {'a', 'd'})
@classmethod
def _test_set_comparisons(cls, obj):
case = unittest.TestCase()
obj.update(['a', 'b', 'c'])
result = obj.union({'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'}))
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'})
def test_set(self):
o = self.manager.set()
self.run_worker(self._test_set_operator_symbols, o)
o = self.manager.set()
self.run_worker(self._test_set_operator_methods, o)
o = self.manager.set()
self.run_worker(self._test_set_comparisons, o)
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()
set_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',
}
self.assertLessEqual(set_methods, set(dir(o)))
class TestNamedResource(unittest.TestCase):
@only_run_in_spawn_testsuite("spawn specific test.")