summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/script_helper.py35
-rw-r--r--Lib/test/test_cmd_line.py4
-rwxr-xr-xLib/test/test_script_helper.py41
-rw-r--r--Lib/test/test_tracemalloc.py4
4 files changed, 82 insertions, 2 deletions
diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py
index 87a781e..6a8bea6 100644
--- a/Lib/test/script_helper.py
+++ b/Lib/test/script_helper.py
@@ -15,6 +15,41 @@ import zipfile
from importlib.util import source_from_cache
from test.support import make_legacy_pyc, strip_python_stderr, temp_dir
+
+# Cached result of the expensive test performed in the function below.
+__cached_interp_requires_environment = None
+
+def _interpreter_requires_environment():
+ """
+ Returns True if our sys.executable interpreter requires environment
+ variables in order to be able to run at all.
+
+ This is designed to be used with @unittest.skipIf() to annotate tests
+ that need to use an assert_python*() function to launch an isolated
+ mode (-I) or no environment mode (-E) sub-interpreter process.
+
+ A normal build & test does not run into this situation but it can happen
+ when trying to run the standard library test suite from an interpreter that
+ doesn't have an obvious home with Python's current home finding logic.
+
+ Setting PYTHONHOME is one way to get most of the testsuite to run in that
+ situation. PYTHONPATH or PYTHONUSERSITE are other common envirnonment
+ variables that might impact whether or not the interpreter can start.
+ """
+ global __cached_interp_requires_environment
+ if __cached_interp_requires_environment is None:
+ # Try running an interpreter with -E to see if it works or not.
+ try:
+ subprocess.check_call([sys.executable, '-E',
+ '-c', 'import sys; sys.exit(0)'])
+ except subprocess.CalledProcessError:
+ __cached_interp_requires_environment = True
+ else:
+ __cached_interp_requires_environment = False
+
+ return __cached_interp_requires_environment
+
+
# Executing the interpreter in a subprocess
def _assert_python(expected_success, *args, **env_vars):
if '__isolated' in env_vars:
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index 327c145..3683a48 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -8,6 +8,7 @@ import shutil
import sys
import subprocess
import tempfile
+from test import script_helper
from test.script_helper import (spawn_python, kill_python, assert_python_ok,
assert_python_failure)
@@ -439,7 +440,8 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(err.splitlines().count(b'Unknown option: -a'), 1)
self.assertEqual(b'', out)
-
+ @unittest.skipIf(script_helper._interpreter_requires_environment(),
+ 'Cannot run -I tests when PYTHON env vars are required.')
def test_isolatedmode(self):
self.verify_valid_flag('-I')
self.verify_valid_flag('-IEs')
diff --git a/Lib/test/test_script_helper.py b/Lib/test/test_script_helper.py
index ea73fd8..da61265 100755
--- a/Lib/test/test_script_helper.py
+++ b/Lib/test/test_script_helper.py
@@ -1,7 +1,10 @@
"""Unittests for test.script_helper. Who tests the test helper?"""
+import subprocess
+import sys
from test import script_helper
import unittest
+from unittest import mock
class TestScriptHelper(unittest.TestCase):
@@ -31,5 +34,43 @@ class TestScriptHelper(unittest.TestCase):
msg='unexpected command line.')
+class TestScriptHelperEnvironment(unittest.TestCase):
+ """Code coverage for _interpreter_requires_environment()."""
+
+ def setUp(self):
+ self.assertTrue(
+ hasattr(script_helper, '__cached_interp_requires_environment'))
+ # Reset the private cached state.
+ script_helper.__dict__['__cached_interp_requires_environment'] = None
+
+ def tearDown(self):
+ # Reset the private cached state.
+ script_helper.__dict__['__cached_interp_requires_environment'] = None
+
+ @mock.patch('subprocess.check_call')
+ def test_interpreter_requires_environment_true(self, mock_check_call):
+ mock_check_call.side_effect = subprocess.CalledProcessError('', '')
+ self.assertTrue(script_helper._interpreter_requires_environment())
+ self.assertTrue(script_helper._interpreter_requires_environment())
+ self.assertEqual(1, mock_check_call.call_count)
+
+ @mock.patch('subprocess.check_call')
+ def test_interpreter_requires_environment_false(self, mock_check_call):
+ # The mocked subprocess.check_call fakes a no-error process.
+ script_helper._interpreter_requires_environment()
+ self.assertFalse(script_helper._interpreter_requires_environment())
+ self.assertEqual(1, mock_check_call.call_count)
+
+ @mock.patch('subprocess.check_call')
+ def test_interpreter_requires_environment_details(self, mock_check_call):
+ script_helper._interpreter_requires_environment()
+ self.assertFalse(script_helper._interpreter_requires_environment())
+ self.assertFalse(script_helper._interpreter_requires_environment())
+ self.assertEqual(1, mock_check_call.call_count)
+ check_call_command = mock_check_call.call_args[0][0]
+ self.assertEqual(sys.executable, check_call_command[0])
+ self.assertIn('-E', check_call_command)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py
index bc22450..48ccab2 100644
--- a/Lib/test/test_tracemalloc.py
+++ b/Lib/test/test_tracemalloc.py
@@ -5,7 +5,7 @@ import tracemalloc
import unittest
from unittest.mock import patch
from test.script_helper import assert_python_ok, assert_python_failure
-from test import support
+from test import script_helper, support
try:
import threading
except ImportError:
@@ -755,6 +755,8 @@ class TestCommandLine(unittest.TestCase):
stdout = stdout.rstrip()
self.assertEqual(stdout, b'False')
+ @unittest.skipIf(script_helper._interpreter_requires_environment(),
+ 'Cannot run -E tests when PYTHON env vars are required.')
def test_env_var_ignored_with_E(self):
"""PYTHON* environment variables must be ignored when -E is present."""
code = 'import tracemalloc; print(tracemalloc.is_tracing())'