From 735d82388d06977420e617c254ce10b5aa1f4111 Mon Sep 17 00:00:00 2001 From: hahuy Date: Thu, 28 May 2026 03:12:42 +0700 Subject: [PATCH 1/2] fix unittest.mock: make mock_open.__exit__ accept variable args Fixes gh#150484. ExitStack.__exit__ in Python 3.13 passes 4 args (exc_info tuple) but mock_open's _exit_side_effect only accepted 3. Changed _exit_side_effect to accept *exc_details to handle all Python versions. --- Lib/test/test_unittest/testmock/testmock.py | 10 ++++++++++ Lib/unittest/mock.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py index 764585ec5d54688..f5b4502b3c4f5e4 100644 --- a/Lib/test/test_unittest/testmock/testmock.py +++ b/Lib/test/test_unittest/testmock/testmock.py @@ -2108,6 +2108,16 @@ def test_mock_open_after_eof(self): self.assertEqual([], h.readlines()) self.assertEqual([], h.readlines()) + def test_mock_open_exit_stack_issue_150484(self): + # Regression test for gh#150484 + # mock_open().__exit__ must accept 4 args (ExitStack passes + # exc_info tuple) while previously it only accepted 3. + from contextlib import ExitStack + with mock.patch('builtins.open', mock.mock_open()): + with mock.mock_open() as m: + with ExitStack() as exit_stack: + exit_stack.enter_context(open('/tmp/test.txt', 'w')) + def test_mock_parents(self): for Klass in Mock, MagicMock: m = Klass() diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 56cdc37942d65d8..1eae054c1448879 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -3002,7 +3002,7 @@ def _next_side_effect(): return handle.readline.return_value return next(_state[0]) - def _exit_side_effect(exctype, excinst, exctb): + def _exit_side_effect(*exc_details): handle.close() global file_spec From c44f1a5b515a9334eb8e5f36b68887ac6de90b02 Mon Sep 17 00:00:00 2001 From: hahuy Date: Thu, 28 May 2026 14:47:01 +0700 Subject: [PATCH 2/2] add news fragment for gh-150484 mock_open fix --- .../Library/2026-05-28-14-35-00.gh-issue-150484.mock_open.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-28-14-35-00.gh-issue-150484.mock_open.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-28-14-35-00.gh-issue-150484.mock_open.rst b/Misc/NEWS.d/next/Library/2026-05-28-14-35-00.gh-issue-150484.mock_open.rst new file mode 100644 index 000000000000000..d6db722505c244b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-28-14-35-00.gh-issue-150484.mock_open.rst @@ -0,0 +1,3 @@ +Fix :meth:`unittest.mock.mock_open.__exit__` to accept variable arguments +(``*exc_details``) to support Python 3.13+ where ``ExitStack.__exit__`` +passes the full exc_info tuple.