From e156dd48183054ce48cd523015a19df47211bb05 Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Fri, 7 Aug 2026 19:40:02 +0100 Subject: [PATCH] gh-153967: handle invalid file object in argparse._print_message (GH-153969) (cherry picked from commit 115400b5090f14233b72b255e483b4485c868100) Co-authored-by: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Co-authored-by: Peter Bierma Co-authored-by: Chris Eibl <138194463+chris-eibl@users.noreply.github.com> Co-authored-by: Savannah Ostrowski --- Lib/argparse.py | 9 ++++++--- Lib/test/test_argparse.py | 18 ++++++++++++++++++ ...6-07-18-16-05-38.gh-issue-153967.-OUNXe.rst | 3 +++ 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-18-16-05-38.gh-issue-153967.-OUNXe.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index bae204ac5a4d24f..87821822e14bdd6 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2916,11 +2916,14 @@ def print_help(self, file=None): self._print_message(help_text, file) def _print_message(self, message, file=None): - if message: - file = file or _sys.stderr + if not message: + return + if file is None: + file = _sys.stderr + if file is not None: try: file.write(message) - except (AttributeError, OSError): + except OSError: pass def _get_theme(self, file=None): diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index c8954b20740019b..725ac3a76c866d0 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -79,6 +79,24 @@ def test_skip_invalid_stdout(self): func() self.assertRegex(mocked_stderr.getvalue(), r'usage:') + def test_invalid_file_only(self): + parser = argparse.ArgumentParser() + for func in (parser.print_usage, parser.print_help): + for invalid_f in ("invalid file", "", 0): + with ( + self.subTest(func=func, invalid_f=invalid_f), + self.assertRaises(AttributeError), + ): + func(file=invalid_f) + + def test_exit_when_stderr_oserror(self): + parser = argparse.ArgumentParser() + with (mock.patch('argparse._sys.stderr.write', + side_effect=OSError('not raise this')), + self.assertRaises(SystemExit), + ): + parser.exit(status=0, message='foo') + class TestLazyImports(unittest.TestCase): LAZY_IMPORTS = { diff --git a/Misc/NEWS.d/next/Library/2026-07-18-16-05-38.gh-issue-153967.-OUNXe.rst b/Misc/NEWS.d/next/Library/2026-07-18-16-05-38.gh-issue-153967.-OUNXe.rst new file mode 100644 index 000000000000000..5f520140f43a8ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-18-16-05-38.gh-issue-153967.-OUNXe.rst @@ -0,0 +1,3 @@ +:meth:`argparse.ArgumentParser.print_usage` and +:meth:`argparse.ArgumentParser.print_help` won't silently fail when an invalid +file object is specified. Patch by Timothy Poon.