https://github.com/python/cpython/commit/af1cb1cdb883a3cd4ec0f284cc714cfc246f12cd
commit: af1cb1cdb883a3cd4ec0f284cc714cfc246f12cd
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: savannahostrowski <[email protected]>
date: 2025-10-09T17:19:54Z
summary:

[3.14] GH-139809: Fix argparse subcommand prog not respecting color environment 
variables (GH-139818) (#139866)

GH-139809: Fix argparse subcommand prog not respecting color environment 
variables (GH-139818)
(cherry picked from commit 9fc4366f09904fd9aac797d542e332e8a4c1a921)

Co-authored-by: Savannah Ostrowski <[email protected]>

files:
A Misc/NEWS.d/next/Library/2025-10-09-03-06-19.gh-issue-139809.lzHJNu.rst
M Lib/argparse.py
M Lib/test/test_argparse.py

diff --git a/Lib/argparse.py b/Lib/argparse.py
index 01d30a278496fc..88c1f5a7ef3342 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1960,7 +1960,9 @@ def add_subparsers(self, **kwargs):
         # prog defaults to the usage message of this parser, skipping
         # optional arguments and with no "usage:" prefix
         if kwargs.get('prog') is None:
-            formatter = self._get_formatter()
+            # Create formatter without color to avoid storing ANSI codes in 
prog
+            formatter = self.formatter_class(prog=self.prog)
+            formatter._set_color(False)
             positionals = self._get_positional_actions()
             groups = self._mutually_exclusive_groups
             formatter.add_usage(None, positionals, groups, '')
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 7de1d3e2373c33..af7cbcafcbea25 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -22,6 +22,7 @@
     captured_stderr,
     force_not_colorized,
     force_not_colorized_test_class,
+    swap_attr,
 )
 from test.support import import_helper
 from test.support import os_helper
@@ -7128,7 +7129,8 @@ class TestColorized(TestCase):
     def setUp(self):
         super().setUp()
         # Ensure color even if ran with NO_COLOR=1
-        _colorize.can_colorize = lambda *args, **kwargs: True
+        self.enterContext(swap_attr(_colorize, 'can_colorize',
+                                     lambda *args, **kwargs: True))
         self.theme = _colorize.get_theme(force_color=True).argparse
 
     def test_argparse_color(self):
@@ -7355,6 +7357,17 @@ def __init__(self, prog):
                  {short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset}  
foo help
         '''))
 
+    def test_subparser_prog_is_stored_without_color(self):
+        parser = argparse.ArgumentParser(prog='complex', color=True)
+        sub = parser.add_subparsers(dest='command')
+        demo_parser = sub.add_parser('demo')
+
+        self.assertNotIn('\x1b[', demo_parser.prog)
+
+        demo_parser.color = False
+        help_text = demo_parser.format_help()
+        self.assertNotIn('\x1b[', help_text)
+
 
 def tearDownModule():
     # Remove global references to avoid looking like we have refleaks.
diff --git 
a/Misc/NEWS.d/next/Library/2025-10-09-03-06-19.gh-issue-139809.lzHJNu.rst 
b/Misc/NEWS.d/next/Library/2025-10-09-03-06-19.gh-issue-139809.lzHJNu.rst
new file mode 100644
index 00000000000000..498b8f7fd27bd3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-10-09-03-06-19.gh-issue-139809.lzHJNu.rst
@@ -0,0 +1 @@
+Prevent premature colorization of subparser ``prog`` in 
:meth:`argparse.ArgumentParser.add_subparsers` to respect color environment 
variable changes after parser creation.

_______________________________________________
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]

Reply via email to