https://github.com/python/cpython/commit/e7613f2735d5c45d86351729e0483db25af50a21
commit: e7613f2735d5c45d86351729e0483db25af50a21
branch: main
author: Hugo van Kemenade <[email protected]>
committer: hugovk <[email protected]>
date: 2026-05-06T16:48:04+03:00
summary:

gh-148766: Add colour to Python help (#148767)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-04-19-22-35-39.gh-issue-148766.coLWln.rst
M Doc/whatsnew/3.15.rst
M Lib/test/test_cmd_line.py
M Python/initconfig.c

diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 1a5e5fe2fc0be6..1043fe08d5b075 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -652,6 +652,11 @@ Other language changes
 
   (Contributed by Adam Turner in :gh:`133711`; PEP 686 written by Inada Naoki.)
 
+* The interpreter help (such as ``python --help``) is now in color.
+  This can be controlled by :ref:`environment variables
+  <using-on-controlling-color>`.
+  (Contributed by Hugo van Kemenade in :gh:`148766`.)
+
 * Unraisable exceptions are now highlighted with color by default. This can be
   controlled by :ref:`environment variables <using-on-controlling-color>`.
   (Contributed by Peter Bierma in :gh:`134170`.)
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index 8740f65b7b0d1d..7f9e44d70001b7 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -57,6 +57,7 @@ def verify_valid_flag(self, cmd_line):
         return out
 
     @support.cpython_only
+    @support.force_not_colorized
     def test_help(self):
         self.verify_valid_flag('-h')
         self.verify_valid_flag('-?')
@@ -68,6 +69,7 @@ def test_help(self):
         self.assertLess(len(lines), 50)
 
     @support.cpython_only
+    @support.force_not_colorized
     def test_help_env(self):
         out = self.verify_valid_flag('--help-env')
         self.assertIn(b'PYTHONHOME', out)
@@ -81,6 +83,7 @@ def test_help_env(self):
                              "env vars should be sorted alphabetically")
 
     @support.cpython_only
+    @support.force_not_colorized
     def test_help_xoptions(self):
         out = self.verify_valid_flag('--help-xoptions')
         self.assertIn(b'-X dev', out)
@@ -89,6 +92,7 @@ def test_help_xoptions(self):
                          "options should be sorted alphabetically")
 
     @support.cpython_only
+    @support.force_not_colorized
     def test_help_all(self):
         out = self.verify_valid_flag('--help-all')
         lines = out.splitlines()
@@ -100,6 +104,25 @@ def test_help_all(self):
         # but the rest should be ASCII-only
         b''.join(lines[1:]).decode('ascii')
 
+    @support.cpython_only
+    @support.force_colorized
+    def test_help_colorized(self):
+        rc, out, err = assert_python_ok("--help", FORCE_COLOR="1")
+        # Check ANSI color codes are present
+        self.assertIn(b"\x1b[", out)
+        # Check that key text elements are still present
+        self.assertIn(b"usage:", out)
+        self.assertIn(b"-h", out)
+        self.assertIn(b"--help-all", out)
+        self.assertIn(b"cmd", out)
+        self.assertIn(b"Arguments:", out)
+
+    @support.cpython_only
+    @support.force_not_colorized
+    def test_help_not_colorized(self):
+        rc, out, err = assert_python_ok("--help")
+        self.assertNotIn(b"\x1b[", out)
+
     def test_optimize(self):
         self.verify_valid_flag('-O')
         self.verify_valid_flag('-OO')
@@ -1063,6 +1086,7 @@ def test_argv0_normalization(self):
         self.assertEqual(proc.stdout.strip(), b'0')
 
     @support.cpython_only
+    @support.force_not_colorized
     def test_parsing_error(self):
         args = [sys.executable, '-I', '--unknown-option']
         proc = subprocess.run(args,
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-19-22-35-39.gh-issue-148766.coLWln.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-19-22-35-39.gh-issue-148766.coLWln.rst
new file mode 100644
index 00000000000000..946473d700f13a
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-19-22-35-39.gh-issue-148766.coLWln.rst
@@ -0,0 +1,2 @@
+The interpreter help (such as ``python --help``) is now in color. Patch by
+Hugo van Kemenade.
diff --git a/Python/initconfig.c b/Python/initconfig.c
index 8dc9602ff13df7..a996fb117aab9d 100644
--- a/Python/initconfig.c
+++ b/Python/initconfig.c
@@ -250,224 +250,340 @@ static void initconfig_free_config(const PyConfig 
*config);
 
 /* --- Command line options --------------------------------------- */
 
-/* Short usage message (with %s for argv0) */
+/*
+ * Help text markup (matching Lib/_colorize.py Argparse theme).
+ *
+ * Color spans, #X{...}  where "}" resets to default color:
+ *   #b{...}  label              bold yellow
+ *   #B{...}  summary label      yellow
+ *   #E{...}  env var (primary)  bold cyan
+ *   #e{...}  env var reference  cyan
+ *   #h{...}  heading            bold blue
+ *   #L{...}  long option        bold cyan
+ *   #s{...}  short option       bold green
+ *   #S{...}  summary short opt  green
+ *
+ * Runtime substitutions (no "{" follows):
+ *   #P  program name (bold magenta)
+ *   #D  path separator (DELIM)
+ *   #H  PYTHONHOMEHELP default search path
+ *
+ * fprint_help() walks the string, expanding color codes only when colorize=1
+ * and substituting runtime values regardless.
+ */
+
+#if defined(MS_WINDOWS)
+#  define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
+#else
+#  define PYTHONHOMEHELP "<prefix>/lib/pythonX.X"
+#endif
+
+/* Determine if we can emit ANSI color codes on the given stream.
+ * Logic mirrors Lib/_colorize.py:can_colorize(). */
+static int
+_Py_can_colorize(FILE *f)
+{
+    const char *env;
+
+    env = Py_GETENV("PYTHON_COLORS");
+    if (env) {
+        if (strcmp(env, "0") == 0) {
+            return 0;
+        }
+        if (strcmp(env, "1") == 0) {
+            return 1;
+        }
+    }
+    if (getenv("NO_COLOR")) {
+        return 0;
+    }
+    if (getenv("FORCE_COLOR")) {
+        return 1;
+    }
+    env = getenv("TERM");
+    if (env && strcmp(env, "dumb") == 0) {
+        return 0;
+    }
+#if defined(MS_WINDOWS) && defined(HAVE_WINDOWS_CONSOLE_IO)
+    {
+        DWORD mode = 0;
+        DWORD nStdHandle = (f == stderr) ? STD_ERROR_HANDLE
+                                         : STD_OUTPUT_HANDLE;
+        HANDLE handle = GetStdHandle(nStdHandle);
+        if (!GetConsoleMode(handle, &mode)
+            || !(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
+        {
+            return 0;
+        }
+    }
+#endif
+    return isatty(fileno(f));
+}
+
+/* Walk help text, expanding markup:
+ *   #X{...}  color span (only emitted when colorize=1; '}' resets).
+ *   #X       runtime substitution (program name, DELIM, PYTHONHOMEHELP).
+ * See the markup table above the macro/comment block. */
+static void
+fprint_help(FILE *f, const char *text, int colorize, const wchar_t *program)
+{
+    for (const char *p = text; *p; ) {
+        if (*p == '#' && p[1]) {
+            char code = p[1];
+            if (p[2] == '{') {
+                /* Color span open */
+                const char *seq = NULL;
+                switch (code) {
+                case 'h': seq = "\x1b[1;34m"; break;  // heading
+                case 'E': seq = "\x1b[1;36m"; break;  // env var primary
+                case 'e': seq = "\x1b[36m";   break;  // env var reference
+                case 'L': seq = "\x1b[1;36m"; break;  // long option
+                case 'b': seq = "\x1b[1;33m"; break;  // label
+                case 'B': seq = "\x1b[33m";   break;  // summary label
+                case 's': seq = "\x1b[1;32m"; break;  // short option
+                case 'S': seq = "\x1b[32m";   break;  // summary short option
+                }
+                if (colorize && seq) fputs(seq, f);
+                p += 3;  // skip "#X{"
+                continue;
+            }
+            /* Runtime substitution */
+            switch (code) {
+            case 'P':  // program name with bold magenta
+                if (colorize) fputs("\x1b[1;35m", f);
+                if (program) fprintf(f, "%ls", program);
+                if (colorize) fputs("\x1b[0m", f);
+                break;
+            case 'D':
+                fputc((char)DELIM, f);
+                break;
+            case 'H':
+                fputs(PYTHONHOMEHELP, f);
+                break;
+            default:  // unknown: emit literally
+                fputc('#', f);
+                fputc(code, f);
+                break;
+            }
+            p += 2;  // skip "#X"
+            continue;
+        }
+        if (*p == '}') {
+            if (colorize) fputs("\x1b[0m", f);
+            p++;
+            continue;
+        }
+        fputc(*p++, f);
+    }
+}
+
+/* Short usage message */
 static const char usage_line[] =
-"usage: %ls [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
+"#h{usage:} #P [#S{option}] #S{...} "
+"[#S{-c} #B{cmd} | #S{-m} #B{mod} | #S{file} | #S{-}] "
+"[#S{arg}] #S{...}\n"
+;
 
 /* Long help message */
 /* Lines sorted by option name; keep in sync with usage_envvars* below */
-static const char usage_help[] = "\
-Options (and corresponding environment variables):\n\
--b     : issue warnings about converting bytes/bytearray to str and 
comparing\n\
-         bytes/bytearray with str or bytes with int. (-bb: issue errors)\n\
-         deprecated since 3.15 and will become no-op in 3.17.\n\
--B     : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\
--c cmd : program passed in as string (terminates option list)\n\
--d     : turn on parser debugging output (for experts only, only works on\n\
-         debug builds); also PYTHONDEBUG=x\n\
--E     : ignore PYTHON* environment variables (such as PYTHONPATH)\n\
--h     : print this help message and exit (also -? or --help)\n\
--i     : inspect interactively after running script; forces a prompt even\n\
-         if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n\
--I     : isolate Python from the user's environment (implies -E, -P and -s)\n\
--m mod : run library module as a script (terminates option list)\n\
--O     : remove assert and __debug__-dependent statements; add .opt-1 before\n\
-         .pyc extension; also PYTHONOPTIMIZE=x\n\
--OO    : do -O changes and also discard docstrings; add .opt-2 before\n\
-         .pyc extension\n\
--P     : don't prepend a potentially unsafe path to sys.path; also\n\
-         PYTHONSAFEPATH\n\
--q     : don't print version and copyright messages on interactive startup\n\
--s     : don't add user site directory to sys.path; also PYTHONNOUSERSITE=x\n\
--S     : don't imply 'import site' on initialization\n\
--u     : force the stdout and stderr streams to be unbuffered;\n\
-         this option has no effect on stdin; also PYTHONUNBUFFERED=x\n\
--v     : verbose (trace import statements); also PYTHONVERBOSE=x\n\
-         can be supplied multiple times to increase verbosity\n\
--V     : print the Python version number and exit (also --version)\n\
-         when given twice, print more information about the build\n\
--W arg : warning control; arg is action:message:category:module:lineno\n\
-         also PYTHONWARNINGS=arg\n\
--x     : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
--X opt : set implementation-specific option\n\
---check-hash-based-pycs always|default|never:\n\
-         control how Python invalidates hash-based .pyc files\n\
---help-env: print help about Python environment variables and exit\n\
---help-xoptions: print help about implementation-specific -X options and 
exit\n\
---help-all: print complete help information and exit\n\
-\n\
-Arguments:\n\
-file   : program read from script file\n\
--      : program read from stdin (default; interactive mode if a tty)\n\
-arg ...: arguments passed to program in sys.argv[1:]\n\
-";
-
-static const char usage_xoptions[] = "\
-The following implementation-specific options are available:\n\
--X context_aware_warnings=[0|1]: if true (1) then the warnings module will\n\
-         use a context variables; if false (0) then the warnings module will\n\
-         use module globals, which is not concurrent-safe; set to true for\n\
-         free-threaded builds and false otherwise; also\n\
-         PYTHON_CONTEXT_AWARE_WARNINGS\n\
--X cpu_count=N: override the return value of os.cpu_count();\n\
-         -X cpu_count=default cancels overriding; also PYTHON_CPU_COUNT\n\
--X dev : enable Python Development Mode; also PYTHONDEVMODE\n\
--X disable-remote-debug: disable remote debugging; also 
PYTHON_DISABLE_REMOTE_DEBUG\n\
--X faulthandler: dump the Python traceback on fatal errors;\n\
-         also PYTHONFAULTHANDLER\n\
--X frozen_modules=[on|off]: whether to use frozen modules; the default is 
\"on\"\n\
-         for installed Python and \"off\" for a local build;\n\
-         also PYTHON_FROZEN_MODULES\n\
-"
+static const char usage_help[] =
+"#h{Options (and corresponding environment variables):}\n"
+"#s{-b}     : issue warnings about converting bytes/bytearray to str and 
comparing\n"
+"         bytes/bytearray with str or bytes with int. (#S{-bb}: issue 
errors)\n"
+"         deprecated since 3.15 and will become no-op in 3.17.\n"
+"#s{-B}     : don't write .pyc files on import; also 
#e{PYTHONDONTWRITEBYTECODE}#B{=x}\n"
+"#s{-c} #b{cmd} : program passed in as string (terminates option list)\n"
+"#s{-d}     : turn on parser debugging output (for experts only, only works 
on\n"
+"         debug builds); also #e{PYTHONDEBUG}#B{=x}\n"
+"#s{-E}     : ignore #e{PYTHON*} environment variables (such as 
#e{PYTHONPATH})\n"
+"#s{-h}     : print this help message and exit (also #S{-?} or #e{--help})\n"
+"#s{-i}     : inspect interactively after running script; forces a prompt 
even\n"
+"         if stdin does not appear to be a terminal; also 
#e{PYTHONINSPECT}#B{=x}\n"
+"#s{-I}     : isolate Python from the user's environment (implies #S{-E}, 
#S{-P} and #S{-s})\n"
+"#s{-m} #b{mod} : run library module as a script (terminates option list)\n"
+"#s{-O}     : remove assert and __debug__-dependent statements; add .opt-1 
before\n"
+"         .pyc extension; also #e{PYTHONOPTIMIZE}#B{=x}\n"
+"#s{-OO}    : do #S{-O} changes and also discard docstrings; add .opt-2 
before\n"
+"         .pyc extension\n"
+"#s{-P}     : don't prepend a potentially unsafe path to sys.path; also\n"
+"         #e{PYTHONSAFEPATH}\n"
+"#s{-q}     : don't print version and copyright messages on interactive 
startup\n"
+"#s{-s}     : don't add user site directory to sys.path; also 
#e{PYTHONNOUSERSITE}#B{=x}\n"
+"#s{-S}     : don't imply 'import site' on initialization\n"
+"#s{-u}     : force the stdout and stderr streams to be unbuffered;\n"
+"         this option has no effect on stdin; also 
#e{PYTHONUNBUFFERED}#B{=x}\n"
+"#s{-v}     : verbose (trace import statements); also 
#e{PYTHONVERBOSE}#B{=x}\n"
+"         can be supplied multiple times to increase verbosity\n"
+"#s{-V}     : print the Python version number and exit (also #e{--version})\n"
+"         when given twice, print more information about the build\n"
+"#s{-W} #b{arg} : warning control; #B{arg} is 
action:message:category:module:lineno\n"
+"         also #e{PYTHONWARNINGS}#B{=arg}\n"
+"#s{-x}     : skip first line of source, allowing use of non-Unix forms of 
#!cmd\n"
+"#s{-X} #b{opt} : set implementation-specific option\n"
+"#L{--check-hash-based-pycs} #b{always|default|never}:\n"
+"         control how Python invalidates hash-based .pyc files\n"
+"#L{--help-env}: print help about Python environment variables and exit\n"
+"#L{--help-xoptions}: print help about implementation-specific #S{-X} options 
and exit\n"
+"#L{--help-all}: print complete help information and exit\n"
+"\n"
+"#h{Arguments:}\n"
+"#s{file}   : program read from script file\n"
+"#s{-}      : program read from stdin (default; interactive mode if a tty)\n"
+"#s{arg} #b{...}: arguments passed to program in sys.argv[1:]\n"
+;
+
+static const char usage_xoptions[] =
+"#h{The following implementation-specific options are available:}\n"
+"#s{-X} #L{context_aware_warnings}#b{=[0|1]}: if true (#B{1}) then the 
warnings module will\n"
+"         use a context variables; if false (#B{0}) then the warnings module 
will\n"
+"         use module globals, which is not concurrent-safe; set to true for\n"
+"         free-threaded builds and false otherwise; also\n"
+"         #e{PYTHON_CONTEXT_AWARE_WARNINGS}\n"
+"#s{-X} #L{cpu_count}#b{=N}: override the return value of os.cpu_count();\n"
+"         #S{-X} #e{cpu_count}#B{=default} cancels overriding; also 
#e{PYTHON_CPU_COUNT}\n"
+"#s{-X} #L{dev} : enable Python Development Mode; also #e{PYTHONDEVMODE}\n"
+"#s{-X} #L{disable-remote-debug}: disable remote debugging; also 
#e{PYTHON_DISABLE_REMOTE_DEBUG}\n"
+"#s{-X} #L{faulthandler}: dump the Python traceback on fatal errors;\n"
+"         also #e{PYTHONFAULTHANDLER}\n"
+"#s{-X} #L{frozen_modules}#b{=[on|off]}: whether to use frozen modules; the 
default is \"#B{on}\"\n"
+"         for installed Python and \"#B{off}\" for a local build;\n"
+"         also #e{PYTHON_FROZEN_MODULES}\n"
 #ifdef Py_GIL_DISABLED
-"-X gil=[0|1]: enable (1) or disable (0) the GIL; also PYTHON_GIL\n"
+"#s{-X} #L{gil}#b{=[0|1]}: enable (#B{1}) or disable (#B{0}) the GIL; also 
#e{PYTHON_GIL}\n"
 #endif
-"\
--X importtime[=2]: show how long each import takes; use -X importtime=2 to\n\
-         log imports of already-loaded modules; also PYTHONPROFILEIMPORTTIME\n\
--X int_max_str_digits=N: limit the size of int<->str conversions;\n\
-         0 disables the limit; also PYTHONINTMAXSTRDIGITS\n\
--X lazy_imports=[all|none|normal]: control global lazy imports;\n\
-         default is normal; also PYTHON_LAZY_IMPORTS\n\
--X no_debug_ranges: don't include extra location information in code 
objects;\n\
-         also PYTHONNODEBUGRANGES\n\
--X pathconfig_warnings=[0|1]: if true (1) then path configuration is allowed\n\
-         to log warnings into stderr; if false (0) suppress these warnings;\n\
-         set to true by default; also PYTHON_PATHCONFIG_WARNINGS\n\
--X perf: support the Linux \"perf\" profiler; also PYTHONPERFSUPPORT=1\n\
--X perf_jit: support the Linux \"perf\" profiler with DWARF support;\n\
-         also PYTHON_PERF_JIT_SUPPORT=1\n\
-"
+"#s{-X} #L{importtime}#b{[=2]}: show how long each import takes; use #S{-X} 
#e{importtime}#B{=2} to\n"
+"         log imports of already-loaded modules; also 
#e{PYTHONPROFILEIMPORTTIME}\n"
+"#s{-X} #L{int_max_str_digits}#b{=N}: limit the size of int<->str 
conversions;\n"
+"         0 disables the limit; also #e{PYTHONINTMAXSTRDIGITS}\n"
+"#s{-X} #L{lazy_imports}#b{=[all|none|normal]}: control global lazy imports;\n"
+"         default is #B{normal}; also #e{PYTHON_LAZY_IMPORTS}\n"
+"#s{-X} #L{no_debug_ranges}: don't include extra location information in code 
objects;\n"
+"         also #e{PYTHONNODEBUGRANGES}\n"
+"#s{-X} #L{pathconfig_warnings}#b{=[0|1]}: if true (#B{1}) then path 
configuration is allowed\n"
+"         to log warnings into stderr; if false (#B{0}) suppress these 
warnings;\n"
+"         set to true by default; also #e{PYTHON_PATHCONFIG_WARNINGS}\n"
+"#s{-X} #L{perf}: support the Linux \"perf\" profiler; also 
#e{PYTHONPERFSUPPORT}#B{=1}\n"
+"#s{-X} #L{perf_jit}: support the Linux \"perf\" profiler with DWARF 
support;\n"
+"         also #e{PYTHON_PERF_JIT_SUPPORT}#B{=1}\n"
 #ifdef Py_DEBUG
-"-X presite=MOD: import this module before site; also PYTHON_PRESITE\n"
+"#s{-X} #L{presite}#b{=MOD}: import this module before site; also 
#e{PYTHON_PRESITE}\n"
 #endif
-"\
--X pycache_prefix=PATH: write .pyc files to a parallel tree instead of to 
the\n\
-         code tree; also PYTHONPYCACHEPREFIX\n\
-"
+"#s{-X} #L{pycache_prefix}#b{=PATH}: write .pyc files to a parallel tree 
instead of to the\n"
+"         code tree; also #e{PYTHONPYCACHEPREFIX}\n"
 #ifdef Py_STATS
-"-X pystats: enable pystats collection at startup; also PYTHONSTATS\n"
+"#s{-X} #L{pystats}: enable pystats collection at startup; also 
#e{PYTHONSTATS}\n"
 #endif
-"\
--X showrefcount: output the total reference count and number of used\n\
-         memory blocks when the program finishes or after each statement in\n\
-         the interactive interpreter; only works on debug builds\n\
--X thread_inherit_context=[0|1]: enable (1) or disable (0) threads 
inheriting\n\
-         context vars by default; enabled by default in the free-threaded\n\
-         build and disabled otherwise; also PYTHON_THREAD_INHERIT_CONTEXT\n\
-"
+"#s{-X} #L{showrefcount}: output the total reference count and number of 
used\n"
+"         memory blocks when the program finishes or after each statement in\n"
+"         the interactive interpreter; only works on debug builds\n"
+"#s{-X} #L{thread_inherit_context}#b{=[0|1]}: enable (#B{1}) or disable 
(#B{0}) threads inheriting\n"
+"         context vars by default; enabled by default in the free-threaded\n"
+"         build and disabled otherwise; also 
#e{PYTHON_THREAD_INHERIT_CONTEXT}\n"
 #ifdef Py_GIL_DISABLED
-"-X tlbc=[0|1]: enable (1) or disable (0) thread-local bytecode. Also\n\
-         PYTHON_TLBC\n"
+"#s{-X} #L{tlbc}#b{=[0|1]}: enable (#B{1}) or disable (#B{0}) thread-local 
bytecode. Also\n"
+"         #e{PYTHON_TLBC}\n"
 #endif
-"\
--X tracemalloc[=N]: trace Python memory allocations; N sets a traceback 
limit\n\
-         of N frames (default: 1); also PYTHONTRACEMALLOC=N\n\
--X utf8[=0|1]: enable (1) or disable (0) UTF-8 mode; also PYTHONUTF8\n\
--X warn_default_encoding: enable opt-in EncodingWarning for 'encoding=None';\n\
-         also PYTHONWARNDEFAULTENCODING\
-";
+"#s{-X} #L{tracemalloc}#b{[=N]}: trace Python memory allocations; N sets a 
traceback limit\n"
+"         of #B{N} frames (default: #B{1}); also #e{PYTHONTRACEMALLOC}#B{=N}\n"
+"#s{-X} #L{utf8}#b{[=0|1]}: enable (#B{1}) or disable (#B{0}) UTF-8 mode; also 
#e{PYTHONUTF8}\n"
+"#s{-X} #L{warn_default_encoding}: enable opt-in EncodingWarning for 
'encoding=None';\n"
+"         also #e{PYTHONWARNDEFAULTENCODING}\n"
+;
 
 /* Envvars that don't have equivalent command-line options are listed first */
 static const char usage_envvars[] =
-"Environment variables that change behavior:\n"
-"PYTHONASYNCIODEBUG: enable asyncio debug mode\n"
-"PYTHON_BASIC_REPL: use the traditional parser-based REPL\n"
-"PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n"
+"#h{Environment variables that change behavior:}\n"
+"#E{PYTHONASYNCIODEBUG}: enable asyncio debug mode\n"
+"#E{PYTHON_BASIC_REPL}: use the traditional parser-based REPL\n"
+"#E{PYTHONBREAKPOINT}: if this variable is set to #B{0}, it disables the 
default\n"
 "                  debugger.  It can be set to the callable of your debugger 
of\n"
 "                  choice.\n"
-"PYTHONCASEOK    : ignore case in 'import' statements (Windows)\n"
-"PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale\n"
-"                  coercion behavior.  Use PYTHONCOERCECLOCALE=warn to 
request\n"
+"#E{PYTHONCASEOK}    : ignore case in 'import' statements (Windows)\n"
+"#E{PYTHONCOERCECLOCALE}: if this variable is set to #B{0}, it disables the 
locale\n"
+"                  coercion behavior.  Use #e{PYTHONCOERCECLOCALE}#B{=warn} to 
request\n"
 "                  display of locale coercion and locale compatibility 
warnings\n"
 "                  on stderr.\n"
-"PYTHON_COLORS   : if this variable is set to 1, the interpreter will 
colorize\n"
-"                  various kinds of output.  Setting it to 0 deactivates\n"
+"#E{PYTHON_COLORS}   : if this variable is set to #B{1}, the interpreter will 
colorize\n"
+"                  various kinds of output.  Setting it to #B{0} deactivates\n"
 "                  this behavior.\n"
 #ifdef Py_TRACE_REFS
-"PYTHONDUMPREFS  : dump objects and reference counts still alive after 
shutdown\n"
-"PYTHONDUMPREFSFILE: dump objects and reference counts to the specified file\n"
+"#E{PYTHONDUMPREFS}  : dump objects and reference counts still alive after 
shutdown\n"
+"#E{PYTHONDUMPREFSFILE}: dump objects and reference counts to the specified 
file\n"
 #endif
 #ifdef __APPLE__
-"PYTHONEXECUTABLE: set sys.argv[0] to this value (macOS only)\n"
+"#E{PYTHONEXECUTABLE}: set sys.argv[0] to this value (macOS only)\n"
 #endif
-"PYTHONHASHSEED  : if this variable is set to 'random', a random value is 
used\n"
+"#E{PYTHONHASHSEED}  : if this variable is set to 'random', a random value is 
used\n"
 "                  to seed the hashes of str and bytes objects.  It can also 
be\n"
 "                  set to an integer in the range [0,4294967295] to get hash\n"
 "                  values with a predictable seed.\n"
-"PYTHON_HISTORY  : the location of a .python_history file.\n"
-"PYTHONHOME      : alternate <prefix> directory (or 
<prefix>%lc<exec_prefix>).\n"
-"                  The default module search path uses %s.\n"
-"PYTHONIOENCODING: encoding[:errors] used for stdin/stdout/stderr\n"
+"#E{PYTHON_HISTORY}  : the location of a .python_history file.\n"
+"#E{PYTHONHOME}      : alternate <prefix> directory (or 
<prefix>#D<exec_prefix>).\n"
+"                  The default module search path uses #H.\n"
+"#E{PYTHONIOENCODING}: encoding[:errors] used for stdin/stdout/stderr\n"
 #ifdef MS_WINDOWS
-"PYTHONLEGACYWINDOWSFSENCODING: use legacy \"mbcs\" encoding for file system\n"
-"PYTHONLEGACYWINDOWSSTDIO: use legacy Windows stdio\n"
+"#E{PYTHONLEGACYWINDOWSFSENCODING}: use legacy \"mbcs\" encoding for file 
system\n"
+"#E{PYTHONLEGACYWINDOWSSTDIO}: use legacy Windows stdio\n"
 #endif
-"PYTHONMALLOC    : set the Python memory allocators and/or install debug 
hooks\n"
-"                  on Python memory allocators.  Use PYTHONMALLOC=debug to\n"
+"#E{PYTHONMALLOC}    : set the Python memory allocators and/or install debug 
hooks\n"
+"                  on Python memory allocators.  Use 
#e{PYTHONMALLOC}#B{=debug} to\n"
 "                  install debug hooks.\n"
-"PYTHONMALLOCSTATS: print memory allocator statistics\n"
-"PYTHONPATH      : '%lc'-separated list of directories prefixed to the\n"
+"#E{PYTHONMALLOCSTATS}: print memory allocator statistics\n"
+"#E{PYTHONPATH}      : '#D'-separated list of directories prefixed to the\n"
 "                  default module search path.  The result is sys.path.\n"
-"PYTHONPLATLIBDIR: override sys.platlibdir\n"
-"PYTHONSTARTUP   : file executed on interactive startup (no default)\n"
-"PYTHONUSERBASE  : defines the user base directory (site.USER_BASE)\n"
+"#E{PYTHONPLATLIBDIR}: override sys.platlibdir\n"
+"#E{PYTHONSTARTUP}   : file executed on interactive startup (no default)\n"
+"#E{PYTHONUSERBASE}  : defines the user base directory (site.USER_BASE)\n"
 "\n"
-"These variables have equivalent command-line options (see --help for 
details):\n"
-"PYTHON_CONTEXT_AWARE_WARNINGS: if true (1), enable thread-safe warnings\n"
-"                  module behaviour (-X context_aware_warnings)\n"
-"PYTHON_CPU_COUNT: override the return value of os.cpu_count() (-X 
cpu_count)\n"
-"PYTHONDEBUG     : enable parser debug mode (-d)\n"
-"PYTHONDEVMODE   : enable Python Development Mode (-X dev)\n"
-"PYTHONDONTWRITEBYTECODE: don't write .pyc files (-B)\n"
-"PYTHONFAULTHANDLER: dump the Python traceback on fatal errors (-X 
faulthandler)\n"
-"PYTHON_FROZEN_MODULES: whether to use frozen modules; the default is \"on\"\n"
-"                  for installed Python and \"off\" for a local build\n"
-"                  (-X frozen_modules)\n"
+"#h{These variables have equivalent command-line options (see }#e{--help} for 
details):\n"
+"#E{PYTHON_CONTEXT_AWARE_WARNINGS}: if true (#B{1}), enable thread-safe 
warnings\n"
+"                  module behaviour (#S{-X} #e{context_aware_warnings})\n"
+"#E{PYTHON_CPU_COUNT}: override the return value of os.cpu_count() (#S{-X} 
#e{cpu_count})\n"
+"#E{PYTHONDEBUG}     : enable parser debug mode (#S{-d})\n"
+"#E{PYTHONDEVMODE}   : enable Python Development Mode (#S{-X} #e{dev})\n"
+"#E{PYTHONDONTWRITEBYTECODE}: don't write .pyc files (#S{-B})\n"
+"#E{PYTHONFAULTHANDLER}: dump the Python traceback on fatal errors (#S{-X} 
#e{faulthandler})\n"
+"#E{PYTHON_FROZEN_MODULES}: whether to use frozen modules; the default is 
\"#B{on}\"\n"
+"                  for installed Python and \"#B{off}\" for a local build\n"
+"                  (#S{-X} #e{frozen_modules})\n"
 #ifdef Py_GIL_DISABLED
-"PYTHON_GIL      : when set to 0, disables the GIL (-X gil)\n"
+"#E{PYTHON_GIL}      : when set to #B{0}, disables the GIL (#S{-X} #e{gil})\n"
 #endif
-"PYTHONINSPECT   : inspect interactively after running script (-i)\n"
-"PYTHONINTMAXSTRDIGITS: limit the size of int<->str conversions;\n"
-"                  0 disables the limit (-X int_max_str_digits=N)\n"
-"PYTHON_LAZY_IMPORTS: control global lazy imports (-X lazy_imports)\n"
-"PYTHONNODEBUGRANGES: don't include extra location information in code 
objects\n"
-"                  (-X no_debug_ranges)\n"
-"PYTHONNOUSERSITE: disable user site directory (-s)\n"
-"PYTHONOPTIMIZE  : enable level 1 optimizations (-O)\n"
-"PYTHON_PERF_JIT_SUPPORT: enable Linux \"perf\" profiler support with JIT\n"
-"                  (-X perf_jit)\n"
-"PYTHONPERFSUPPORT: support the Linux \"perf\" profiler (-X perf)\n"
+"#E{PYTHONINSPECT}   : inspect interactively after running script (#S{-i})\n"
+"#E{PYTHONINTMAXSTRDIGITS}: limit the size of int<->str conversions;\n"
+"                  0 disables the limit (#S{-X} 
#e{int_max_str_digits}#B{=N})\n"
+"#E{PYTHON_LAZY_IMPORTS}: control global lazy imports (#S{-X} 
#e{lazy_imports})\n"
+"#E{PYTHONNODEBUGRANGES}: don't include extra location information in code 
objects\n"
+"                  (#S{-X} #e{no_debug_ranges})\n"
+"#E{PYTHONNOUSERSITE}: disable user site directory (#S{-s})\n"
+"#E{PYTHONOPTIMIZE}  : enable level 1 optimizations (#S{-O})\n"
+"#E{PYTHON_PERF_JIT_SUPPORT}: enable Linux \"perf\" profiler support with 
JIT\n"
+"                  (#S{-X} #e{perf_jit})\n"
+"#E{PYTHONPERFSUPPORT}: support the Linux \"perf\" profiler (#S{-X} 
#e{perf})\n"
 #ifdef Py_DEBUG
-"PYTHON_PRESITE: import this module before site (-X presite)\n"
+"#E{PYTHON_PRESITE}: import this module before site (#S{-X} #e{presite})\n"
 #endif
-"PYTHONPROFILEIMPORTTIME: show how long each import takes (-X importtime)\n"
-"PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files\n"
-"                  (-X pycache_prefix)\n"
-"PYTHONSAFEPATH  : don't prepend a potentially unsafe path to sys.path.\n"
+"#E{PYTHONPROFILEIMPORTTIME}: show how long each import takes (#S{-X} 
#e{importtime})\n"
+"#E{PYTHONPYCACHEPREFIX}: root directory for bytecode cache (pyc) files\n"
+"                  (#S{-X} #e{pycache_prefix})\n"
+"#E{PYTHONSAFEPATH}  : don't prepend a potentially unsafe path to sys.path.\n"
 #ifdef Py_STATS
-"PYTHONSTATS     : turns on statistics gathering (-X pystats)\n"
+"#E{PYTHONSTATS}     : turns on statistics gathering (#S{-X} #e{pystats})\n"
 #endif
-"PYTHON_THREAD_INHERIT_CONTEXT: if true (1), threads inherit context vars\n"
-"                  (-X thread_inherit_context)\n"
+"#E{PYTHON_THREAD_INHERIT_CONTEXT}: if true (#B{1}), threads inherit context 
vars\n"
+"                  (#S{-X} #e{thread_inherit_context})\n"
 #ifdef Py_GIL_DISABLED
-"PYTHON_TLBC     : when set to 0, disables thread-local bytecode (-X tlbc)\n"
+"#E{PYTHON_TLBC}     : when set to #B{0}, disables thread-local bytecode 
(#S{-X} #e{tlbc})\n"
 #endif
-"PYTHONTRACEMALLOC: trace Python memory allocations (-X tracemalloc)\n"
-"PYTHONUNBUFFERED: disable stdout/stderr buffering (-u)\n"
-"PYTHONUTF8      : control the UTF-8 mode (-X utf8)\n"
-"PYTHONVERBOSE   : trace import statements (-v)\n"
-"PYTHONWARNDEFAULTENCODING: enable opt-in EncodingWarning for 
'encoding=None'\n"
-"                  (-X warn_default_encoding)\n"
-"PYTHONWARNINGS  : warning control (-W)\n"
+"#E{PYTHONTRACEMALLOC}: trace Python memory allocations (#S{-X} 
#e{tracemalloc})\n"
+"#E{PYTHONUNBUFFERED}: disable stdout/stderr buffering (#S{-u})\n"
+"#E{PYTHONUTF8}      : control the UTF-8 mode (#S{-X} #e{utf8})\n"
+"#E{PYTHONVERBOSE}   : trace import statements (#S{-v})\n"
+"#E{PYTHONWARNDEFAULTENCODING}: enable opt-in EncodingWarning for 
'encoding=None'\n"
+"                  (#S{-X} #e{warn_default_encoding})\n"
+"#E{PYTHONWARNINGS}  : warning control (#S{-W})\n"
 ;
 
-#if defined(MS_WINDOWS)
-#  define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
-#else
-#  define PYTHONHOMEHELP "<prefix>/lib/pythonX.X"
-#endif
-
 
 /* --- Global configuration variables ----------------------------- */
 
@@ -2935,25 +3051,29 @@ static void
 config_usage(int error, const wchar_t* program)
 {
     FILE *f = error ? stderr : stdout;
+    int colorize = _Py_can_colorize(f);
 
-    fprintf(f, usage_line, program);
-    if (error)
+    fprint_help(f, usage_line, colorize, program);
+    if (error) {
         fprintf(f, "Try `python -h' for more information.\n");
+    }
     else {
-        fputs(usage_help, f);
+        fprint_help(f, usage_help, colorize, NULL);
     }
 }
 
 static void
 config_envvars_usage(void)
 {
-    printf(usage_envvars, (wint_t)DELIM, PYTHONHOMEHELP, (wint_t)DELIM);
+    int colorize = _Py_can_colorize(stdout);
+    fprint_help(stdout, usage_envvars, colorize, NULL);
 }
 
 static void
 config_xoptions_usage(void)
 {
-    puts(usage_xoptions);
+    int colorize = _Py_can_colorize(stdout);
+    fprint_help(stdout, usage_xoptions, colorize, NULL);
 }
 
 static void

_______________________________________________
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