subprocess._optim_args_from_interpreter_flags()

Issue #26100:

* Add subprocess._optim_args_from_interpreter_flags()
* Add test.support.optim_args_from_interpreter_flags()
* Use new functions in distutils, test_cmd_line_script, test_compileall and
  test_inspect

The change enables test_details() test of test_inspect when -O or -OO command
line option is used.
diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py
index e423325..fdcf6fa 100644
--- a/Lib/distutils/util.py
+++ b/Lib/distutils/util.py
@@ -7,8 +7,8 @@
 import os
 import re
 import importlib.util
-import sys
 import string
+import sys
 from distutils.errors import DistutilsPlatformError
 from distutils.dep_util import newer
 from distutils.spawn import spawn
@@ -350,6 +350,11 @@
     generated in indirect mode; unless you know what you're doing, leave
     it set to None.
     """
+
+    # Late import to fix a bootstrap issue: _posixsubprocess is built by
+    # setup.py, but setup.py uses distutils.
+    import subprocess
+
     # nothing is done if sys.dont_write_bytecode is True
     if sys.dont_write_bytecode:
         raise DistutilsByteCompileError('byte-compiling is disabled.')
@@ -412,11 +417,9 @@
 
             script.close()
 
-        cmd = [sys.executable, script_name]
-        if optimize == 1:
-            cmd.insert(1, "-O")
-        elif optimize == 2:
-            cmd.insert(1, "-OO")
+        cmd = [sys.executable]
+        cmd.extend(subprocess._optim_args_from_interpreter_flags())
+        cmd.append(script_name)
         spawn(cmd, dry_run=dry_run)
         execute(os.remove, (script_name,), "removing %s" % script_name,
                 dry_run=dry_run)
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index d1324b8..640519d 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -520,6 +520,16 @@
 # but it's here so that it can be imported when Python is compiled without
 # threads.
 
+def _optim_args_from_interpreter_flags():
+    """Return a list of command-line arguments reproducing the current
+    optimization settings in sys.flags."""
+    args = []
+    value = sys.flags.optimize
+    if value > 0:
+        args.append('-' + 'O' * value)
+    return args
+
+
 def _args_from_interpreter_flags():
     """Return a list of command-line arguments reproducing the current
     settings in sys.flags and sys.warnoptions."""
@@ -527,7 +537,6 @@
         'debug': 'd',
         # 'inspect': 'i',
         # 'interactive': 'i',
-        'optimize': 'O',
         'dont_write_bytecode': 'B',
         'no_user_site': 's',
         'no_site': 'S',
@@ -535,8 +544,9 @@
         'verbose': 'v',
         'bytes_warning': 'b',
         'quiet': 'q',
+        # -O is handled in _optim_args_from_interpreter_flags()
     }
-    args = []
+    args = _optim_args_from_interpreter_flags()
     for flag, opt in flag_opt_map.items():
         v = getattr(sys.flags, flag)
         if v > 0:
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 2969b36..58dcc8a 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2053,6 +2053,11 @@
     settings in sys.flags and sys.warnoptions."""
     return subprocess._args_from_interpreter_flags()
 
+def optim_args_from_interpreter_flags():
+    """Return a list of command-line arguments reproducing the current
+    optimization settings in sys.flags."""
+    return subprocess._optim_args_from_interpreter_flags()
+
 #============================================================
 # Support for assertions about logging.
 #============================================================
diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
index afac62a..9398040 100644
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -138,9 +138,8 @@
                             expected_argv0, expected_path0,
                             expected_package, expected_loader,
                             *cmd_line_switches):
-        if not __debug__:
-            cmd_line_switches += ('-' + 'O' * sys.flags.optimize,)
-        run_args = cmd_line_switches + (script_name,) + tuple(example_args)
+        run_args = [*support.optim_args_from_interpreter_flags(),
+                    *cmd_line_switches, script_name, *example_args]
         rc, out, err = assert_python_ok(*run_args, __isolated=False)
         self._check_output(script_name, rc, out + err, expected_file,
                            expected_argv0, expected_path0,
diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py
index 6d8a863..9b424a7 100644
--- a/Lib/test/test_compileall.py
+++ b/Lib/test/test_compileall.py
@@ -231,10 +231,9 @@
             raise unittest.SkipTest('not all entries on sys.path are writable')
 
     def _get_run_args(self, args):
-        interp_args = ['-S']
-        if sys.flags.optimize:
-            interp_args.append({1 : '-O', 2 : '-OO'}[sys.flags.optimize])
-        return interp_args + ['-m', 'compileall'] + list(args)
+        return [*support.optim_args_from_interpreter_flags(),
+                '-S', '-m', 'compileall',
+                *args]
 
     def assertRunOK(self, *args, **env_vars):
         rc, out, err = script_helper.assert_python_ok(
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 283c922..422a3d6 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -30,6 +30,7 @@
 from test.support.script_helper import assert_python_ok, assert_python_failure
 from test import inspect_fodder as mod
 from test import inspect_fodder2 as mod2
+from test import support
 
 from test.test_import import _ready_to_import
 
@@ -3536,14 +3537,14 @@
 
     def test_details(self):
         module = importlib.import_module('unittest')
-        rc, out, err = assert_python_ok('-m', 'inspect',
+        args = support.optim_args_from_interpreter_flags()
+        rc, out, err = assert_python_ok(*args, '-m', 'inspect',
                                         'unittest', '--details')
         output = out.decode()
         # Just a quick sanity check on the output
         self.assertIn(module.__name__, output)
         self.assertIn(module.__file__, output)
-        if not sys.flags.optimize:
-            self.assertIn(module.__cached__, output)
+        self.assertIn(module.__cached__, output)
         self.assertEqual(err, b'')