2009-11-16 02:49:25 -04:00
|
|
|
# Common utility functions used by various script execution tests
|
|
|
|
# e.g. test_cmd_line, test_cmd_line_script and test_runpy
|
|
|
|
|
2012-04-27 14:52:03 -03:00
|
|
|
import importlib
|
2009-11-16 02:49:25 -04:00
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import os.path
|
|
|
|
import tempfile
|
|
|
|
import subprocess
|
|
|
|
import py_compile
|
|
|
|
import contextlib
|
|
|
|
import shutil
|
|
|
|
import zipfile
|
|
|
|
|
2013-06-15 18:11:25 -03:00
|
|
|
from importlib.util import source_from_cache
|
2013-07-28 09:11:50 -03:00
|
|
|
from test.support import make_legacy_pyc, strip_python_stderr, temp_dir
|
2010-04-16 21:19:56 -03:00
|
|
|
|
2009-11-16 02:49:25 -04:00
|
|
|
# Executing the interpreter in a subprocess
|
2010-11-09 17:33:55 -04:00
|
|
|
def _assert_python(expected_success, *args, **env_vars):
|
2013-10-12 09:44:01 -03:00
|
|
|
if '__isolated' in env_vars:
|
|
|
|
isolated = env_vars.pop('__isolated')
|
|
|
|
else:
|
|
|
|
isolated = not env_vars
|
2013-06-25 16:24:36 -03:00
|
|
|
cmd_line = [sys.executable, '-X', 'faulthandler']
|
2013-10-12 09:44:01 -03:00
|
|
|
if isolated:
|
|
|
|
# isolated mode: ignore Python environment variables, ignore user
|
|
|
|
# site-packages, and don't add the current directory to sys.path
|
|
|
|
cmd_line.append('-I')
|
|
|
|
elif not env_vars:
|
|
|
|
# ignore Python environment variables
|
2010-11-09 17:33:55 -04:00
|
|
|
cmd_line.append('-E')
|
2010-11-09 18:04:44 -04:00
|
|
|
# Need to preserve the original environment, for in-place testing of
|
|
|
|
# shared library builds.
|
|
|
|
env = os.environ.copy()
|
2012-02-20 14:54:16 -04:00
|
|
|
# But a special flag that can be set to override -- in this case, the
|
|
|
|
# caller is responsible to pass the full environment.
|
|
|
|
if env_vars.pop('__cleanenv', None):
|
|
|
|
env = {}
|
2010-11-09 18:04:44 -04:00
|
|
|
env.update(env_vars)
|
2012-02-20 14:54:16 -04:00
|
|
|
cmd_line.extend(args)
|
2010-10-08 15:05:42 -03:00
|
|
|
p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
|
2010-11-09 17:33:55 -04:00
|
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
|
|
env=env)
|
2010-10-08 15:05:42 -03:00
|
|
|
try:
|
|
|
|
out, err = p.communicate()
|
|
|
|
finally:
|
|
|
|
subprocess._cleanup()
|
2010-11-01 11:00:33 -03:00
|
|
|
p.stdout.close()
|
|
|
|
p.stderr.close()
|
2010-10-08 15:05:42 -03:00
|
|
|
rc = p.returncode
|
2013-08-11 20:48:44 -03:00
|
|
|
err = strip_python_stderr(err)
|
2010-10-08 15:05:42 -03:00
|
|
|
if (rc and expected_success) or (not rc and not expected_success):
|
|
|
|
raise AssertionError(
|
|
|
|
"Process return code is %d, "
|
|
|
|
"stderr follows:\n%s" % (rc, err.decode('ascii', 'ignore')))
|
|
|
|
return rc, out, err
|
|
|
|
|
2010-11-09 17:33:55 -04:00
|
|
|
def assert_python_ok(*args, **env_vars):
|
|
|
|
"""
|
|
|
|
Assert that running the interpreter with `args` and optional environment
|
2013-08-11 20:48:44 -03:00
|
|
|
variables `env_vars` succeeds (rc == 0) and return a (return code, stdout,
|
|
|
|
stderr) tuple.
|
2013-10-12 09:44:01 -03:00
|
|
|
|
|
|
|
If the __cleanenv keyword is set, env_vars is used a fresh environment.
|
|
|
|
|
|
|
|
Python is started in isolated mode (command line option -I),
|
|
|
|
except if the __isolated keyword is set to False.
|
2010-11-09 17:33:55 -04:00
|
|
|
"""
|
|
|
|
return _assert_python(True, *args, **env_vars)
|
2010-10-08 15:05:42 -03:00
|
|
|
|
2010-11-09 17:33:55 -04:00
|
|
|
def assert_python_failure(*args, **env_vars):
|
|
|
|
"""
|
|
|
|
Assert that running the interpreter with `args` and optional environment
|
2013-08-11 20:48:44 -03:00
|
|
|
variables `env_vars` fails (rc != 0) and return a (return code, stdout,
|
|
|
|
stderr) tuple.
|
2013-10-12 09:44:01 -03:00
|
|
|
|
|
|
|
See assert_python_ok() for more options.
|
2010-11-09 17:33:55 -04:00
|
|
|
"""
|
|
|
|
return _assert_python(False, *args, **env_vars)
|
2009-11-16 02:49:25 -04:00
|
|
|
|
2014-05-11 08:42:17 -03:00
|
|
|
def spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
|
2013-08-11 20:48:44 -03:00
|
|
|
"""Run a Python subprocess with the given arguments.
|
|
|
|
|
|
|
|
kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
|
|
|
|
object.
|
|
|
|
"""
|
2009-11-16 02:49:25 -04:00
|
|
|
cmd_line = [sys.executable, '-E']
|
|
|
|
cmd_line.extend(args)
|
2014-05-11 11:59:16 -03:00
|
|
|
# Under Fedora (?), GNU readline can output junk on stderr when initialized,
|
|
|
|
# depending on the TERM setting. Setting TERM=vt100 is supposed to disable
|
|
|
|
# that. References:
|
|
|
|
# - http://reinout.vanrees.org/weblog/2009/08/14/readline-invisible-character-hack.html
|
|
|
|
# - http://stackoverflow.com/questions/15760712/python-readline-module-prints-escape-character-during-import
|
|
|
|
# - http://lists.gnu.org/archive/html/bug-readline/2007-08/msg00004.html
|
2014-05-11 14:13:43 -03:00
|
|
|
env = kw.setdefault('env', dict(os.environ))
|
|
|
|
env['TERM'] = 'vt100'
|
2009-11-16 02:49:25 -04:00
|
|
|
return subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
|
2014-05-11 08:42:17 -03:00
|
|
|
stdout=stdout, stderr=stderr,
|
2011-03-30 20:31:06 -03:00
|
|
|
**kw)
|
2009-11-16 02:49:25 -04:00
|
|
|
|
|
|
|
def kill_python(p):
|
2013-08-11 20:48:44 -03:00
|
|
|
"""Run the given Popen process until completion and return stdout."""
|
2009-11-16 02:49:25 -04:00
|
|
|
p.stdin.close()
|
|
|
|
data = p.stdout.read()
|
|
|
|
p.stdout.close()
|
|
|
|
# try to cleanup the child so we don't appear to leak when running
|
2009-12-08 15:27:24 -04:00
|
|
|
# with regrtest -R.
|
|
|
|
p.wait()
|
2009-11-16 02:49:25 -04:00
|
|
|
subprocess._cleanup()
|
|
|
|
return data
|
|
|
|
|
2013-12-15 06:33:02 -04:00
|
|
|
def make_script(script_dir, script_basename, source, omit_suffix=False):
|
|
|
|
script_filename = script_basename
|
|
|
|
if not omit_suffix:
|
|
|
|
script_filename += os.extsep + 'py'
|
2009-11-16 02:49:25 -04:00
|
|
|
script_name = os.path.join(script_dir, script_filename)
|
2010-02-27 12:12:22 -04:00
|
|
|
# The script should be encoded to UTF-8, the default string encoding
|
|
|
|
script_file = open(script_name, 'w', encoding='utf-8')
|
2009-11-16 02:49:25 -04:00
|
|
|
script_file.write(source)
|
|
|
|
script_file.close()
|
2012-04-27 14:52:03 -03:00
|
|
|
importlib.invalidate_caches()
|
2009-11-16 02:49:25 -04:00
|
|
|
return script_name
|
|
|
|
|
|
|
|
def make_zip_script(zip_dir, zip_basename, script_name, name_in_zip=None):
|
|
|
|
zip_filename = zip_basename+os.extsep+'zip'
|
|
|
|
zip_name = os.path.join(zip_dir, zip_filename)
|
|
|
|
zip_file = zipfile.ZipFile(zip_name, 'w')
|
|
|
|
if name_in_zip is None:
|
2010-04-16 21:19:56 -03:00
|
|
|
parts = script_name.split(os.sep)
|
|
|
|
if len(parts) >= 2 and parts[-2] == '__pycache__':
|
|
|
|
legacy_pyc = make_legacy_pyc(source_from_cache(script_name))
|
|
|
|
name_in_zip = os.path.basename(legacy_pyc)
|
|
|
|
script_name = legacy_pyc
|
|
|
|
else:
|
|
|
|
name_in_zip = os.path.basename(script_name)
|
2009-11-16 02:49:25 -04:00
|
|
|
zip_file.write(script_name, name_in_zip)
|
|
|
|
zip_file.close()
|
2010-07-28 13:39:41 -03:00
|
|
|
#if test.support.verbose:
|
2009-11-16 02:49:25 -04:00
|
|
|
# zip_file = zipfile.ZipFile(zip_name, 'r')
|
|
|
|
# print 'Contents of %r:' % zip_name
|
|
|
|
# zip_file.printdir()
|
|
|
|
# zip_file.close()
|
|
|
|
return zip_name, os.path.join(zip_name, name_in_zip)
|
|
|
|
|
2010-08-17 10:06:11 -03:00
|
|
|
def make_pkg(pkg_dir, init_source=''):
|
2009-11-16 02:49:25 -04:00
|
|
|
os.mkdir(pkg_dir)
|
2010-08-17 10:06:11 -03:00
|
|
|
make_script(pkg_dir, '__init__', init_source)
|
2009-11-16 02:49:25 -04:00
|
|
|
|
|
|
|
def make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename,
|
|
|
|
source, depth=1, compiled=False):
|
|
|
|
unlink = []
|
|
|
|
init_name = make_script(zip_dir, '__init__', '')
|
|
|
|
unlink.append(init_name)
|
|
|
|
init_basename = os.path.basename(init_name)
|
|
|
|
script_name = make_script(zip_dir, script_basename, source)
|
|
|
|
unlink.append(script_name)
|
|
|
|
if compiled:
|
2014-06-20 18:49:10 -03:00
|
|
|
init_name = py_compile.compile(init_name, doraise=True)
|
|
|
|
script_name = py_compile.compile(script_name, doraise=True)
|
2009-11-16 02:49:25 -04:00
|
|
|
unlink.extend((init_name, script_name))
|
|
|
|
pkg_names = [os.sep.join([pkg_name]*i) for i in range(1, depth+1)]
|
|
|
|
script_name_in_zip = os.path.join(pkg_names[-1], os.path.basename(script_name))
|
|
|
|
zip_filename = zip_basename+os.extsep+'zip'
|
|
|
|
zip_name = os.path.join(zip_dir, zip_filename)
|
|
|
|
zip_file = zipfile.ZipFile(zip_name, 'w')
|
|
|
|
for name in pkg_names:
|
|
|
|
init_name_in_zip = os.path.join(name, init_basename)
|
|
|
|
zip_file.write(init_name, init_name_in_zip)
|
|
|
|
zip_file.write(script_name, script_name_in_zip)
|
|
|
|
zip_file.close()
|
|
|
|
for name in unlink:
|
|
|
|
os.unlink(name)
|
2010-07-28 13:39:41 -03:00
|
|
|
#if test.support.verbose:
|
2009-11-16 02:49:25 -04:00
|
|
|
# zip_file = zipfile.ZipFile(zip_name, 'r')
|
|
|
|
# print 'Contents of %r:' % zip_name
|
|
|
|
# zip_file.printdir()
|
|
|
|
# zip_file.close()
|
|
|
|
return zip_name, os.path.join(zip_name, script_name_in_zip)
|