blob: 6a8bea6884d5d3be46a63b4f23610826944069ee [file] [log] [blame]
Nick Coghlan260bd3e2009-11-16 06:49:25 +00001# Common utility functions used by various script execution tests
2# e.g. test_cmd_line, test_cmd_line_script and test_runpy
3
Brett Cannonc8287ef2012-04-27 13:52:03 -04004import importlib
Nick Coghlan260bd3e2009-11-16 06:49:25 +00005import sys
6import os
7import os.path
8import tempfile
9import subprocess
10import py_compile
11import contextlib
12import shutil
13import zipfile
14
Brett Cannon9529fbf2013-06-15 17:11:25 -040015from importlib.util import source_from_cache
Nick Coghlan55175962013-07-28 22:11:50 +100016from test.support import make_legacy_pyc, strip_python_stderr, temp_dir
Barry Warsaw28a691b2010-04-17 00:19:56 +000017
Gregory P. Smithb9a3dd92015-02-04 00:59:40 -080018
19# Cached result of the expensive test performed in the function below.
20__cached_interp_requires_environment = None
21
22def _interpreter_requires_environment():
23 """
24 Returns True if our sys.executable interpreter requires environment
25 variables in order to be able to run at all.
26
27 This is designed to be used with @unittest.skipIf() to annotate tests
28 that need to use an assert_python*() function to launch an isolated
29 mode (-I) or no environment mode (-E) sub-interpreter process.
30
31 A normal build & test does not run into this situation but it can happen
32 when trying to run the standard library test suite from an interpreter that
33 doesn't have an obvious home with Python's current home finding logic.
34
35 Setting PYTHONHOME is one way to get most of the testsuite to run in that
36 situation. PYTHONPATH or PYTHONUSERSITE are other common envirnonment
37 variables that might impact whether or not the interpreter can start.
38 """
39 global __cached_interp_requires_environment
40 if __cached_interp_requires_environment is None:
41 # Try running an interpreter with -E to see if it works or not.
42 try:
43 subprocess.check_call([sys.executable, '-E',
44 '-c', 'import sys; sys.exit(0)'])
45 except subprocess.CalledProcessError:
46 __cached_interp_requires_environment = True
47 else:
48 __cached_interp_requires_environment = False
49
50 return __cached_interp_requires_environment
51
52
Nick Coghlan260bd3e2009-11-16 06:49:25 +000053# Executing the interpreter in a subprocess
Antoine Pitrou9bc35682010-11-09 21:33:55 +000054def _assert_python(expected_success, *args, **env_vars):
Victor Stinnere8785ff2013-10-12 14:44:01 +020055 if '__isolated' in env_vars:
56 isolated = env_vars.pop('__isolated')
57 else:
58 isolated = not env_vars
Victor Stinner383a8202013-06-25 21:24:36 +020059 cmd_line = [sys.executable, '-X', 'faulthandler']
Victor Stinnere8785ff2013-10-12 14:44:01 +020060 if isolated:
61 # isolated mode: ignore Python environment variables, ignore user
62 # site-packages, and don't add the current directory to sys.path
63 cmd_line.append('-I')
64 elif not env_vars:
65 # ignore Python environment variables
Antoine Pitrou9bc35682010-11-09 21:33:55 +000066 cmd_line.append('-E')
Antoine Pitrouadffced2010-11-09 22:04:44 +000067 # Need to preserve the original environment, for in-place testing of
68 # shared library builds.
69 env = os.environ.copy()
Georg Brandl2daf6ae2012-02-20 19:54:16 +010070 # But a special flag that can be set to override -- in this case, the
71 # caller is responsible to pass the full environment.
72 if env_vars.pop('__cleanenv', None):
73 env = {}
Antoine Pitrouadffced2010-11-09 22:04:44 +000074 env.update(env_vars)
Georg Brandl2daf6ae2012-02-20 19:54:16 +010075 cmd_line.extend(args)
Antoine Pitrouf51d8d32010-10-08 18:05:42 +000076 p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
Antoine Pitrou9bc35682010-11-09 21:33:55 +000077 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
78 env=env)
Antoine Pitrouf51d8d32010-10-08 18:05:42 +000079 try:
80 out, err = p.communicate()
81 finally:
82 subprocess._cleanup()
Brian Curtinc4ac8872010-11-01 14:00:33 +000083 p.stdout.close()
84 p.stderr.close()
Antoine Pitrouf51d8d32010-10-08 18:05:42 +000085 rc = p.returncode
Eli Bendersky8f2c2bc2013-08-11 16:48:44 -070086 err = strip_python_stderr(err)
Antoine Pitrouf51d8d32010-10-08 18:05:42 +000087 if (rc and expected_success) or (not rc and not expected_success):
88 raise AssertionError(
Gregory P. Smithb5684c42015-01-20 17:19:47 -080089 "Process return code is %d, command line was: %r, "
90 "stderr follows:\n%s" % (rc, cmd_line,
91 err.decode('ascii', 'ignore')))
Antoine Pitrouf51d8d32010-10-08 18:05:42 +000092 return rc, out, err
93
Antoine Pitrou9bc35682010-11-09 21:33:55 +000094def assert_python_ok(*args, **env_vars):
95 """
96 Assert that running the interpreter with `args` and optional environment
Eli Bendersky8f2c2bc2013-08-11 16:48:44 -070097 variables `env_vars` succeeds (rc == 0) and return a (return code, stdout,
98 stderr) tuple.
Victor Stinnere8785ff2013-10-12 14:44:01 +020099
100 If the __cleanenv keyword is set, env_vars is used a fresh environment.
101
102 Python is started in isolated mode (command line option -I),
103 except if the __isolated keyword is set to False.
Antoine Pitrou9bc35682010-11-09 21:33:55 +0000104 """
105 return _assert_python(True, *args, **env_vars)
Antoine Pitrouf51d8d32010-10-08 18:05:42 +0000106
Antoine Pitrou9bc35682010-11-09 21:33:55 +0000107def assert_python_failure(*args, **env_vars):
108 """
109 Assert that running the interpreter with `args` and optional environment
Eli Bendersky8f2c2bc2013-08-11 16:48:44 -0700110 variables `env_vars` fails (rc != 0) and return a (return code, stdout,
111 stderr) tuple.
Victor Stinnere8785ff2013-10-12 14:44:01 +0200112
113 See assert_python_ok() for more options.
Antoine Pitrou9bc35682010-11-09 21:33:55 +0000114 """
115 return _assert_python(False, *args, **env_vars)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000116
Antoine Pitrou9845c7e2014-05-11 13:42:17 +0200117def spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
Eli Bendersky8f2c2bc2013-08-11 16:48:44 -0700118 """Run a Python subprocess with the given arguments.
119
120 kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
121 object.
122 """
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000123 cmd_line = [sys.executable, '-E']
124 cmd_line.extend(args)
Antoine Pitrou6b4b8d02014-05-11 16:59:16 +0200125 # Under Fedora (?), GNU readline can output junk on stderr when initialized,
126 # depending on the TERM setting. Setting TERM=vt100 is supposed to disable
127 # that. References:
128 # - http://reinout.vanrees.org/weblog/2009/08/14/readline-invisible-character-hack.html
129 # - http://stackoverflow.com/questions/15760712/python-readline-module-prints-escape-character-during-import
130 # - http://lists.gnu.org/archive/html/bug-readline/2007-08/msg00004.html
Antoine Pitrou5e6b5f22014-05-11 19:13:43 +0200131 env = kw.setdefault('env', dict(os.environ))
132 env['TERM'] = 'vt100'
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000133 return subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
Antoine Pitrou9845c7e2014-05-11 13:42:17 +0200134 stdout=stdout, stderr=stderr,
Victor Stinner024e37a2011-03-31 01:31:06 +0200135 **kw)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000136
137def kill_python(p):
Eli Bendersky8f2c2bc2013-08-11 16:48:44 -0700138 """Run the given Popen process until completion and return stdout."""
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000139 p.stdin.close()
140 data = p.stdout.read()
141 p.stdout.close()
142 # try to cleanup the child so we don't appear to leak when running
Antoine Pitrou4e7dc5f2009-12-08 19:27:24 +0000143 # with regrtest -R.
144 p.wait()
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000145 subprocess._cleanup()
146 return data
147
Nick Coghlan720c7e22013-12-15 20:33:02 +1000148def make_script(script_dir, script_basename, source, omit_suffix=False):
149 script_filename = script_basename
150 if not omit_suffix:
151 script_filename += os.extsep + 'py'
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000152 script_name = os.path.join(script_dir, script_filename)
Florent Xicluna8de42e22010-02-27 16:12:22 +0000153 # The script should be encoded to UTF-8, the default string encoding
154 script_file = open(script_name, 'w', encoding='utf-8')
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000155 script_file.write(source)
156 script_file.close()
Brett Cannonc8287ef2012-04-27 13:52:03 -0400157 importlib.invalidate_caches()
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000158 return script_name
159
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000160def make_zip_script(zip_dir, zip_basename, script_name, name_in_zip=None):
161 zip_filename = zip_basename+os.extsep+'zip'
162 zip_name = os.path.join(zip_dir, zip_filename)
163 zip_file = zipfile.ZipFile(zip_name, 'w')
164 if name_in_zip is None:
Barry Warsaw28a691b2010-04-17 00:19:56 +0000165 parts = script_name.split(os.sep)
166 if len(parts) >= 2 and parts[-2] == '__pycache__':
167 legacy_pyc = make_legacy_pyc(source_from_cache(script_name))
168 name_in_zip = os.path.basename(legacy_pyc)
169 script_name = legacy_pyc
170 else:
171 name_in_zip = os.path.basename(script_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000172 zip_file.write(script_name, name_in_zip)
173 zip_file.close()
Florent Xicluna02ea12b22010-07-28 16:39:41 +0000174 #if test.support.verbose:
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000175 # zip_file = zipfile.ZipFile(zip_name, 'r')
176 # print 'Contents of %r:' % zip_name
177 # zip_file.printdir()
178 # zip_file.close()
179 return zip_name, os.path.join(zip_name, name_in_zip)
180
Nick Coghland26c18a2010-08-17 13:06:11 +0000181def make_pkg(pkg_dir, init_source=''):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000182 os.mkdir(pkg_dir)
Nick Coghland26c18a2010-08-17 13:06:11 +0000183 make_script(pkg_dir, '__init__', init_source)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000184
185def make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename,
186 source, depth=1, compiled=False):
187 unlink = []
188 init_name = make_script(zip_dir, '__init__', '')
189 unlink.append(init_name)
190 init_basename = os.path.basename(init_name)
191 script_name = make_script(zip_dir, script_basename, source)
192 unlink.append(script_name)
193 if compiled:
Terry Jan Reedy5d828952014-06-20 17:49:10 -0400194 init_name = py_compile.compile(init_name, doraise=True)
195 script_name = py_compile.compile(script_name, doraise=True)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000196 unlink.extend((init_name, script_name))
197 pkg_names = [os.sep.join([pkg_name]*i) for i in range(1, depth+1)]
198 script_name_in_zip = os.path.join(pkg_names[-1], os.path.basename(script_name))
199 zip_filename = zip_basename+os.extsep+'zip'
200 zip_name = os.path.join(zip_dir, zip_filename)
201 zip_file = zipfile.ZipFile(zip_name, 'w')
202 for name in pkg_names:
203 init_name_in_zip = os.path.join(name, init_basename)
204 zip_file.write(init_name, init_name_in_zip)
205 zip_file.write(script_name, script_name_in_zip)
206 zip_file.close()
207 for name in unlink:
208 os.unlink(name)
Florent Xicluna02ea12b22010-07-28 16:39:41 +0000209 #if test.support.verbose:
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000210 # zip_file = zipfile.ZipFile(zip_name, 'r')
211 # print 'Contents of %r:' % zip_name
212 # zip_file.printdir()
213 # zip_file.close()
214 return zip_name, os.path.join(zip_name, script_name_in_zip)