GH-148468: Accept string-like proxy objects in colorized argparse help (#154653)

savannahostrowski <[email protected]> Thu, 30 Jul 2026 12:00:28 -0400 (EDT)
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/a147366eb74ca3afd5953069d209de7ea6b5da0f
commit: a147366eb74ca3afd5953069d209de7ea6b5da0f
branch: main
author: Savannah Ostrowski <[email protected]>
committer: savannahostrowski <[email protected]>
date: 2026-07-30T15:59:59Z
summary:

GH-148468: Accept string-like proxy objects in colorized argparse help (#154653)

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-07-24-21-49-45.gh-issue-148468.pHoF_Q.rst
M Lib/argparse.py
M Lib/test/test_argparse.py

diff --git a/Lib/argparse.py b/Lib/argparse.py
index f8739d031e01c5..0840c4c45cffaa 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -713,7 +713,7 @@ def _format_args(self, action, default_metavar):
         return result
 
     def _expand_help(self, action):
-        help_string = self._get_help_string(action)
+        help_string = str(self._get_help_string(action))
         if '%' not in help_string:
             return self._apply_text_markup(help_string)
         params = dict(vars(action), prog=self._prog)
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 442cbb1aaadfe3..287fcb7a084a49 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -7898,6 +7898,41 @@ def test_backtick_markup_in_argument_help_color_disabled(self):
         self.assertIn("set the `foo` value", help_text)
         self.assertNotIn("\x1b[", help_text)
 
+    def test_argument_help_interpolation_accepts_string_like_proxy(self):
+        class LazyStr:
+            def __init__(self, message):
+                self._message = message
+
+            def __str__(self):
+                return self._message
+
+            def __getattr__(self, name):
+                return getattr(str(self), name)
+
+            def __contains__(self, item):
+                return item in self._message
+
+            def __mod__(self, other):
+                return self._message % other
+
+        parser = argparse.ArgumentParser(prog="PROG", color=True)
+        parser.add_argument(
+            "--foo",
+            default="bar",
+            help=LazyStr("foo (default: %(default)s)"),
+        )
+        parser.add_argument(
+            "--baz",
+            help=LazyStr("baz plain text"),
+        )
+
+        interp = self.theme.interpolated_value
+        reset = self.theme.reset
+
+        help_text = parser.format_help()
+        self.assertIn(f"foo (default: {interp}bar{reset})", help_text)
+        self.assertIn("baz plain text", help_text)
+
     def test_help_with_format_specifiers(self):
         # GH-142950: format specifiers like %x should work with color=True
         parser = argparse.ArgumentParser(prog='PROG', color=True)
diff --git a/Misc/NEWS.d/next/Library/2026-07-24-21-49-45.gh-issue-148468.pHoF_Q.rst b/Misc/NEWS.d/next/Library/2026-07-24-21-49-45.gh-issue-148468.pHoF_Q.rst
new file mode 100644
index 00000000000000..d1d0deb139bc20
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-24-21-49-45.gh-issue-148468.pHoF_Q.rst
@@ -0,0 +1 @@
+Fix a regression in :mod:`argparse` where colorized argument help containing format specifiers did not accept string-like proxy objects.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]