From 26da5718c1860d56b91b43bb24e6ac9799d45f96 Mon Sep 17 00:00:00 2001 From: Denis Sergeev Date: Mon, 15 Sep 2025 09:36:04 +0300 Subject: [PATCH 1/4] gh-138813: Default `BaseProcess` `kwargs` to `None` (#138814) Set `BaseProcess.__init__(..., kwargs=None)` and initialize `kwargs` with `dict(kwargs) if kwargs else {}`. This avoids a shared mutable default and matches threading.Thread behavior. Co-authored-by: Dmitrii Chuprov --- Lib/multiprocessing/process.py | 4 ++-- Lib/test/_test_multiprocessing.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py index 9db322be1aa6d6..262513f295fde5 100644 --- a/Lib/multiprocessing/process.py +++ b/Lib/multiprocessing/process.py @@ -77,7 +77,7 @@ class BaseProcess(object): def _Popen(self): raise NotImplementedError - def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, + def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None): assert group is None, 'group argument must be None for now' count = next(_process_counter) @@ -89,7 +89,7 @@ def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, self._closed = False self._target = target self._args = tuple(args) - self._kwargs = dict(kwargs) + self._kwargs = dict(kwargs) if kwargs else {} self._name = name or type(self).__name__ + '-' + \ ':'.join(str(i) for i in self._identity) if daemon is not None: diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index d9e572961152b3..850744e47d0e0b 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5278,6 +5278,23 @@ def test_invalid_handles(self): multiprocessing.connection.Connection, -1) +# +# Regression tests for BaseProcess kwargs handling +# + +class TestBaseProcessKwargs(unittest.TestCase): + def test_default_kwargs_not_shared_between_instances(self): + # Creating multiple Process instances without passing kwargs + # must create independent empty dicts (no shared state). + p1 = multiprocessing.Process(target=lambda: None) + p2 = multiprocessing.Process(target=lambda: None) + self.assertIsInstance(p1._kwargs, dict) + self.assertIsInstance(p2._kwargs, dict) + self.assertIsNot(p1._kwargs, p2._kwargs) + # Mutating one should not affect the other + p1._kwargs['x'] = 1 + self.assertNotIn('x', p2._kwargs) + @hashlib_helper.requires_hashdigest('sha256') class OtherTest(unittest.TestCase): From b6f292f7e0a0bc8e1033ad2c4b648844cb219e6a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 08:32:45 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst diff --git a/Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst b/Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst new file mode 100644 index 00000000000000..03c60663219494 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst @@ -0,0 +1 @@ +:class:!`multiprocessing.BaseProcess` defaults ``kwargs`` to ``None`` instead of a shared dictionary. From ca614a3fddcee27d9c482f7f1f223b73e2e11352 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Wed, 17 Sep 2025 13:45:04 +0000 Subject: [PATCH 3/4] DummyProcess kwargs=None (which threading.Thread accepts properly) --- Lib/multiprocessing/dummy/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/multiprocessing/dummy/__init__.py b/Lib/multiprocessing/dummy/__init__.py index 6a1468609e347b..7dc5d1c8dde848 100644 --- a/Lib/multiprocessing/dummy/__init__.py +++ b/Lib/multiprocessing/dummy/__init__.py @@ -33,7 +33,7 @@ class DummyProcess(threading.Thread): - def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): + def __init__(self, group=None, target=None, name=None, args=(), kwargs=None): threading.Thread.__init__(self, group, target, name, args, kwargs) self._pid = None self._children = weakref.WeakKeyDictionary() From 1ad9d542cfef81d7c8f6038d892de80e83013fb6 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Wed, 17 Sep 2025 13:47:07 +0000 Subject: [PATCH 4/4] news typo --- .../next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst b/Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst index 03c60663219494..97f4d76bb2f454 100644 --- a/Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst +++ b/Misc/NEWS.d/next/Library/2025-09-17-08-32-43.gh-issue-138813.LHkHjX.rst @@ -1 +1 @@ -:class:!`multiprocessing.BaseProcess` defaults ``kwargs`` to ``None`` instead of a shared dictionary. +:class:`!multiprocessing.BaseProcess` defaults ``kwargs`` to ``None`` instead of a shared dictionary.