From cf9cc2d80e4fd5a0435cb08bd4400b88814e885e Mon Sep 17 00:00:00 2001 From: Anshul Singh <72524975+ekanshul@users.noreply.github.com> Date: Wed, 19 Aug 2026 23:02:20 +0530 Subject: [PATCH] gh-156062: Fix SynchronizedBase instantiation without a lock or a ctx ``SynchronizedBase.__init__`` called ``get_context(force=True)`` when it was given neither a lock nor a context, but ``get_context()`` has never accepted a ``force`` argument (``set_start_method()`` does), so instantiating ``Synchronized``, ``SynchronizedArray`` or ``SynchronizedString`` directly raised ``TypeError``. The module-level helpers always pass a context down, which is why this went unnoticed since the contexts were introduced. --- Lib/multiprocessing/sharedctypes.py | 2 +- Lib/test/_test_multiprocessing.py | 19 +++++++++++++++++++ ...-08-19-17-31-12.gh-issue-156062.-nTriK.rst | 4 ++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-08-19-17-31-12.gh-issue-156062.-nTriK.rst diff --git a/Lib/multiprocessing/sharedctypes.py b/Lib/multiprocessing/sharedctypes.py index eee1172e6e9135c..a1adb5ba6caab2f 100644 --- a/Lib/multiprocessing/sharedctypes.py +++ b/Lib/multiprocessing/sharedctypes.py @@ -189,7 +189,7 @@ def __init__(self, obj, lock=None, ctx=None): if lock: self._lock = lock else: - ctx = ctx or get_context(force=True) + ctx = ctx or get_context() self._lock = ctx.RLock() self.acquire = self._lock.acquire self.release = self._lock.release diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index e5f618f5f2e84f4..dfa91913e41cc90 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -4628,6 +4628,25 @@ def test_sharedctypes(self, lock=False): def test_synchronize(self): self.test_sharedctypes(lock=True) + def test_synchronized_wrapper_default_context(self): + # gh-156062: SynchronizedBase used to call get_context() with an + # unexpected argument when neither a lock nor a context was given, + # so the wrapper classes could not be instantiated directly. + from multiprocessing.sharedctypes import ( + RawValue, RawArray, + Synchronized, SynchronizedArray, SynchronizedString, + ) + for wrapper, obj in [ + (Synchronized, RawValue('i', 7)), + (SynchronizedArray, RawArray('d', [1.0, 2.0])), + (SynchronizedString, RawArray('c', 8)), + ]: + with self.subTest(wrapper=wrapper.__name__): + wrapped = wrapper(obj) + self.assertIs(wrapped.get_obj(), obj) + with wrapped: + pass + def test_copy(self): foo = _Foo(2, 5.0, 2 ** 33) bar = copy(foo) diff --git a/Misc/NEWS.d/next/Library/2026-08-19-17-31-12.gh-issue-156062.-nTriK.rst b/Misc/NEWS.d/next/Library/2026-08-19-17-31-12.gh-issue-156062.-nTriK.rst new file mode 100644 index 000000000000000..228e97d09f6f638 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-19-17-31-12.gh-issue-156062.-nTriK.rst @@ -0,0 +1,4 @@ +Fix :class:`!multiprocessing.sharedctypes.SynchronizedBase` and its subclasses +raising :exc:`TypeError` when instantiated without a *lock* or a *ctx* +argument: they called :func:`multiprocessing.get_context` with an +unsupported ``force`` argument.