[Python-checkins] bpo-34812: subprocess._args_from_interpreter_flags(): add isolated (GH-10675) (GH-10688)
Victor Stinner
webhook-mailer at python.org
Fri Nov 23 13:02:29 EST 2018
https://github.com/python/cpython/commit/cc0e0a2214d6515cf6ba4c7b164902a87e321b45
commit: cc0e0a2214d6515cf6ba4c7b164902a87e321b45
branch: 3.6
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2018-11-23T19:02:26+01:00
summary:
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 9de363271519e0616f4a7b59427057c4810d3acc)
files:
A Misc/NEWS.d/next/Security/2018-11-23-15-00-23.bpo-34812.84VQnb.rst
M Lib/subprocess.py
M Lib/test/test_support.py
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 290ae44f03d7..8c3fa1bf9c8e 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -232,15 +232,13 @@ def _optim_args_from_interpreter_flags():
def _args_from_interpreter_flags():
"""Return a list of command-line arguments reproducing the current
- settings in sys.flags and sys.warnoptions."""
+ settings in sys.flags, sys.warnoptions and sys._xoptions."""
flag_opt_map = {
'debug': 'd',
# 'inspect': 'i',
# 'interactive': 'i',
'dont_write_bytecode': 'B',
- 'no_user_site': 's',
'no_site': 'S',
- 'ignore_environment': 'E',
'verbose': 'v',
'bytes_warning': 'b',
'quiet': 'q',
@@ -251,8 +249,30 @@ def _args_from_interpreter_flags():
v = getattr(sys.flags, flag)
if v > 0:
args.append('-' + opt * v)
+
+ if sys.flags.isolated:
+ args.append('-I')
+ else:
+ if sys.flags.ignore_environment:
+ args.append('-E')
+ if sys.flags.no_user_site:
+ args.append('-s')
+
for opt in sys.warnoptions:
args.append('-W' + opt)
+
+ # -X options
+ xoptions = getattr(sys, '_xoptions', {})
+ for opt in ('faulthandler', 'tracemalloc',
+ 'showalloccount', 'showrefcount', 'utf8'):
+ 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 45cdc94393eb..adc59b622998 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -1,13 +1,14 @@
+import errno
import importlib
+import os
import shutil
+import socket
import stat
+import subprocess
import sys
-import os
-import unittest
-import socket
import tempfile
import textwrap
-import errno
+import unittest
from test import support
from test.support import script_helper
@@ -394,6 +395,65 @@ def test_check__all__(self):
self.assertRaises(AssertionError, support.check__all__, self, unittest)
+ def check_options(self, args, func, expected=None):
+ 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)
+ if expected is None:
+ expected = args
+ self.assertEqual(proc.stdout.rstrip(), repr(expected))
+ 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'],
+ ['-I'],
+ # same option multiple times
+ ['-bb'],
+ ['-vvv'],
+ # -W options
+ ['-Wignore'],
+ # -X options
+ ['-X', 'faulthandler'],
+ ['-X', 'showalloccount'],
+ ['-X', 'showrefcount'],
+ ['-X', 'tracemalloc'],
+ ['-X', 'tracemalloc=3'],
+ ):
+ with self.subTest(opts=opts):
+ self.check_options(opts, 'args_from_interpreter_flags')
+
+ self.check_options(['-I', '-E', '-s'], 'args_from_interpreter_flags',
+ ['-I'])
+
+ 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')
+
def test_match_test(self):
class Test:
def __init__(self, test_id):
@@ -485,7 +545,6 @@ def test_fd_count(self):
# reap_threads
# reap_children
# strip_python_stderr
- # args_from_interpreter_flags
# can_symlink
# skip_unless_symlink
# SuppressCrashReport
diff --git a/Misc/NEWS.d/next/Security/2018-11-23-15-00-23.bpo-34812.84VQnb.rst b/Misc/NEWS.d/next/Security/2018-11-23-15-00-23.bpo-34812.84VQnb.rst
new file mode 100644
index 000000000000..860404f019d2
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2018-11-23-15-00-23.bpo-34812.84VQnb.rst
@@ -0,0 +1,4 @@
+The :option:`-I` command line option (run Python in isolated mode) is now
+also copied by the :mod:`multiprocessing` and :mod:`distutils` modules when
+spawning child processes. Previously, only :option:`-E` and :option:`-s` options
+(enabled by :option:`-I`) were copied.
More information about the Python-checkins
mailing list