Skip to content

Commit cc0e0a2

Browse files
authored
bpo-34812: subprocess._args_from_interpreter_flags(): add isolated (GH-10675) (GH-10688)
The "-I" command line option (run Python in isolated mode) and -X options (like -X faulthandler) are now also copied by the multiprocessing and distutils modules when spawning child processes. Previously, only -E and -s options (enabled by -I) were copied. subprocess._args_from_interpreter_flags() now copies the -I flag and options from sys._xoptions like -X dev. (cherry picked from commit 9de3632)
1 parent eef813b commit cc0e0a2

File tree

3 files changed

+91
-8
lines changed

3 files changed

+91
-8
lines changed

‎Lib/subprocess.py‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,15 +232,13 @@ def _optim_args_from_interpreter_flags():
232232

233233
def _args_from_interpreter_flags():
234234
"""Return a list of command-line arguments reproducing the current
235-
settings in sys.flags and sys.warnoptions."""
235+
settings in sys.flags, sys.warnoptions and sys._xoptions."""
236236
flag_opt_map = {
237237
'debug': 'd',
238238
# 'inspect': 'i',
239239
# 'interactive': 'i',
240240
'dont_write_bytecode': 'B',
241-
'no_user_site': 's',
242241
'no_site': 'S',
243-
'ignore_environment': 'E',
244242
'verbose': 'v',
245243
'bytes_warning': 'b',
246244
'quiet': 'q',
@@ -251,8 +249,30 @@ def _args_from_interpreter_flags():
251249
v = getattr(sys.flags, flag)
252250
if v > 0:
253251
args.append('-' + opt * v)
252+
253+
if sys.flags.isolated:
254+
args.append('-I')
255+
else:
256+
if sys.flags.ignore_environment:
257+
args.append('-E')
258+
if sys.flags.no_user_site:
259+
args.append('-s')
260+
254261
for opt in sys.warnoptions:
255262
args.append('-W' + opt)
263+
264+
# -X options
265+
xoptions = getattr(sys, '_xoptions', {})
266+
for opt in ('faulthandler', 'tracemalloc',
267+
'showalloccount', 'showrefcount', 'utf8'):
268+
if opt in xoptions:
269+
value = xoptions[opt]
270+
if value is True:
271+
arg = opt
272+
else:
273+
arg = '%s=%s' % (opt, value)
274+
args.extend(('-X', arg))
275+
256276
return args
257277

258278

‎Lib/test/test_support.py‎

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import errno
12
import importlib
3+
import os
24
import shutil
5+
import socket
36
import stat
7+
import subprocess
48
import sys
5-
import os
6-
import unittest
7-
import socket
89
import tempfile
910
import textwrap
10-
import errno
11+
import unittest
1112
from test import support
1213
from test.support import script_helper
1314

@@ -394,6 +395,65 @@ def test_check__all__(self):
394395

395396
self.assertRaises(AssertionError, support.check__all__, self, unittest)
396397

398+
def check_options(self, args, func, expected=None):
399+
code = f'from test.support import {func}; print(repr({func}()))'
400+
cmd = [sys.executable, *args, '-c', code]
401+
env = {key: value for key, value in os.environ.items()
402+
if not key.startswith('PYTHON')}
403+
proc = subprocess.run(cmd,
404+
stdout=subprocess.PIPE,
405+
stderr=subprocess.DEVNULL,
406+
universal_newlines=True,
407+
env=env)
408+
if expected is None:
409+
expected = args
410+
self.assertEqual(proc.stdout.rstrip(), repr(expected))
411+
self.assertEqual(proc.returncode, 0)
412+
413+
def test_args_from_interpreter_flags(self):
414+
# Test test.support.args_from_interpreter_flags()
415+
for opts in (
416+
# no option
417+
[],
418+
# single option
419+
['-B'],
420+
['-s'],
421+
['-S'],
422+
['-E'],
423+
['-v'],
424+
['-b'],
425+
['-q'],
426+
['-I'],
427+
# same option multiple times
428+
['-bb'],
429+
['-vvv'],
430+
# -W options
431+
['-Wignore'],
432+
# -X options
433+
['-X', 'faulthandler'],
434+
['-X', 'showalloccount'],
435+
['-X', 'showrefcount'],
436+
['-X', 'tracemalloc'],
437+
['-X', 'tracemalloc=3'],
438+
):
439+
with self.subTest(opts=opts):
440+
self.check_options(opts, 'args_from_interpreter_flags')
441+
442+
self.check_options(['-I', '-E', '-s'], 'args_from_interpreter_flags',
443+
['-I'])
444+
445+
def test_optim_args_from_interpreter_flags(self):
446+
# Test test.support.optim_args_from_interpreter_flags()
447+
for opts in (
448+
# no option
449+
[],
450+
['-O'],
451+
['-OO'],
452+
['-OOOO'],
453+
):
454+
with self.subTest(opts=opts):
455+
self.check_options(opts, 'optim_args_from_interpreter_flags')
456+
397457
def test_match_test(self):
398458
class Test:
399459
def __init__(self, test_id):
@@ -485,7 +545,6 @@ def test_fd_count(self):
485545
# reap_threads
486546
# reap_children
487547
# strip_python_stderr
488-
# args_from_interpreter_flags
489548
# can_symlink
490549
# skip_unless_symlink
491550
# SuppressCrashReport
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The :option:`-I` command line option (run Python in isolated mode) is now
2+
also copied by the :mod:`multiprocessing` and :mod:`distutils` modules when
3+
spawning child processes. Previously, only :option:`-E` and :option:`-s` options
4+
(enabled by :option:`-I`) were copied.

0 commit comments

Comments
 (0)