From f39b674876d2bd47ec7fc106d673b60ff24092ca Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 20 Nov 2017 15:24:56 -0800 Subject: [PATCH] bpo-32094: Update subprocess for -X dev (#4480) Modify subprocess._args_from_interpreter_flags() to handle -X dev option. Add also unit tests for test.support.args_from_interpreter_flags() and test.support.optim_args_from_interpreter_flags(). --- Lib/subprocess.py | 23 +++++++++++++++- Lib/test/test_support.py | 58 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 43be1f9bffa..97b449365ef 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -260,8 +260,29 @@ def _args_from_interpreter_flags(): v = getattr(sys.flags, flag) if v > 0: args.append('-' + opt * v) - for opt in sys.warnoptions: + + # -W options + warnoptions = sys.warnoptions + xoptions = getattr(sys, '_xoptions', {}) + if 'dev' in xoptions and warnoptions and warnoptions[-1] == 'default': + # special case: -X dev adds 'default' to sys.warnoptions + warnoptions = warnoptions[:-1] + for opt in warnoptions: args.append('-W' + opt) + + # -X options + if 'dev' in xoptions: + args.extend(('-X', 'dev')) + for opt in ('faulthandler', 'tracemalloc', 'importtime', + 'showalloccount', 'showrefcount'): + if opt in xoptions: + value = xoptions[opt] + if value is True: + arg = opt + else: + arg = '%s=%s' % (opt, value) + args.extend(('-X', arg)) + return args diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 8632837780c..4a577efbeb9 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -6,6 +6,7 @@ import os import shutil import socket import stat +import subprocess import sys import tempfile import time @@ -426,6 +427,62 @@ class TestSupport(unittest.TestCase): # pending child process support.reap_children() + def check_options(self, args, func): + code = f'from test.support import {func}; print(repr({func}()))' + cmd = [sys.executable, *args, '-c', code] + env = {key: value for key, value in os.environ.items() + if not key.startswith('PYTHON')} + proc = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + universal_newlines=True, + env=env) + self.assertEqual(proc.stdout.rstrip(), repr(args)) + self.assertEqual(proc.returncode, 0) + + def test_args_from_interpreter_flags(self): + # Test test.support.args_from_interpreter_flags() + for opts in ( + # no option + [], + # single option + ['-B'], + ['-s'], + ['-S'], + ['-E'], + ['-v'], + ['-b'], + ['-q'], + # same option multiple times + ['-bb'], + ['-vvv'], + # -W options + ['-Wignore'], + # -X options + ['-X', 'dev'], + ['-Wignore', '-X', 'dev'], + ['-X', 'faulthandler'], + ['-X', 'importtime'], + ['-X', 'showalloccount'], + ['-X', 'showrefcount'], + ['-X', 'tracemalloc'], + ['-X', 'tracemalloc=3'], + ): + with self.subTest(opts=opts): + self.check_options(opts, 'args_from_interpreter_flags') + + def test_optim_args_from_interpreter_flags(self): + # Test test.support.optim_args_from_interpreter_flags() + for opts in ( + # no option + [], + ['-O'], + ['-OO'], + ['-OOOO'], + ): + with self.subTest(opts=opts): + self.check_options(opts, 'optim_args_from_interpreter_flags') + # XXX -follows a list of untested API # make_legacy_pyc # is_resource_enabled @@ -447,7 +504,6 @@ class TestSupport(unittest.TestCase): # threading_cleanup # reap_threads # strip_python_stderr - # args_from_interpreter_flags # can_symlink # skip_unless_symlink # SuppressCrashReport