From c1bd8aaae8829f39b8cb817e5bfa96c5427f7da7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 20 Nov 2017 21:52:23 +0100 Subject: [PATCH 1/2] bpo-32094: Update subprocess for -X dev 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 | 14 ++++++++++- Lib/test/test_support.py | 51 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 43be1f9bffa387b..272639f1fbe4c63 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -260,8 +260,20 @@ def _args_from_interpreter_flags(): v = getattr(sys.flags, flag) if v > 0: args.append('-' + opt * v) - for opt in sys.warnoptions: + + if hasattr(sys, '_xoptions'): + xdev = ('dev' in sys._xoptions) + else: + xdev = False + + warnoptions = sys.warnoptions + if xdev 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) + if xdev: + args.extend(('-X', 'dev')) return args diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 8632837780c9c75..4fce7c2c3eec4e0 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -6,6 +6,7 @@ import shutil import socket import stat +import subprocess import sys import tempfile import time @@ -426,6 +427,55 @@ def test_reap_children(self): # 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 and -X dev + ['-Wignore'], + ['-X', 'dev'], + ['-Wignore', '-X', 'dev'], + ): + 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 +497,6 @@ def test_reap_children(self): # threading_cleanup # reap_threads # strip_python_stderr - # args_from_interpreter_flags # can_symlink # skip_unless_symlink # SuppressCrashReport From 6b60309901ffd6e71997dec0f9e7c9cb0e214ee7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 20 Nov 2017 22:08:14 +0100 Subject: [PATCH 2/2] Handle more -X options --- Lib/subprocess.py | 23 ++++++++++++++++------- Lib/test/test_support.py | 9 ++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 272639f1fbe4c63..97b449365efdccc 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -261,19 +261,28 @@ def _args_from_interpreter_flags(): if v > 0: args.append('-' + opt * v) - if hasattr(sys, '_xoptions'): - xdev = ('dev' in sys._xoptions) - else: - xdev = False - + # -W options warnoptions = sys.warnoptions - if xdev and warnoptions and warnoptions[-1] == 'default': + 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) - if xdev: + + # -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 4fce7c2c3eec4e0..4a577efbeb9ccb2 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -456,10 +456,17 @@ def test_args_from_interpreter_flags(self): # same option multiple times ['-bb'], ['-vvv'], - # -W and -X dev + # -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')