From 8464fbc42ecc9ce504faac499711dcdc6eedef16 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 25 Jan 2022 09:09:06 +0200 Subject: [PATCH] bpo-40280: Skip subprocess-based tests on wasm32-emscripten (GH-30615) --- Lib/distutils/tests/test_build_clib.py | 5 ++++- Lib/distutils/tests/test_build_ext.py | 2 ++ Lib/distutils/tests/test_build_py.py | 4 +++- Lib/distutils/tests/test_config_cmd.py | 5 ++++- Lib/distutils/tests/test_install.py | 3 ++- Lib/distutils/tests/test_install_lib.py | 4 +++- Lib/distutils/tests/test_spawn.py | 4 +++- Lib/distutils/tests/test_sysconfig.py | 3 ++- Lib/lib2to3/tests/test_parser.py | 3 +++ Lib/test/support/__init__.py | 17 +++++++++++++---- Lib/test/support/script_helper.py | 8 ++++++++ Lib/test/test_audit.py | 3 +++ Lib/test/test_capi.py | 1 + Lib/test/test_cmd_line.py | 2 ++ Lib/test/test_embed.py | 2 ++ Lib/test/test_faulthandler.py | 3 +++ Lib/test/test_file_eintr.py | 5 ++++- Lib/test/test_gc.py | 3 ++- Lib/test/test_gzip.py | 4 +++- Lib/test/test_os.py | 8 ++++++++ Lib/test/test_platform.py | 2 ++ Lib/test/test_poll.py | 3 ++- Lib/test/test_popen.py | 1 + Lib/test/test_py_compile.py | 1 + Lib/test/test_quopri.py | 3 +++ Lib/test/test_regrtest.py | 2 ++ Lib/test/test_repl.py | 7 ++++++- Lib/test/test_runpy.py | 3 ++- Lib/test/test_signal.py | 3 +++ Lib/test/test_site.py | 9 +++++++++ Lib/test/test_source_encoding.py | 3 ++- Lib/test/test_subprocess.py | 3 +++ Lib/test/test_support.py | 1 + Lib/test/test_sys.py | 7 +++++++ Lib/test/test_sysconfig.py | 4 +++- Lib/test/test_threading.py | 3 ++- Lib/test/test_traceback.py | 4 +++- Lib/test/test_utf8_mode.py | 1 + Lib/test/test_venv.py | 4 +++- Lib/test/test_webbrowser.py | 2 ++ Lib/test/test_zipfile.py | 4 +++- .../2022-01-14-23-22-41.bpo-40280.nHLWoD.rst | 3 +++ 42 files changed, 139 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2022-01-14-23-22-41.bpo-40280.nHLWoD.rst diff --git a/Lib/distutils/tests/test_build_clib.py b/Lib/distutils/tests/test_build_clib.py index 601a1b10fa100c..95f928288e0048 100644 --- a/Lib/distutils/tests/test_build_clib.py +++ b/Lib/distutils/tests/test_build_clib.py @@ -4,7 +4,9 @@ import sys import sysconfig -from test.support import run_unittest, missing_compiler_executable +from test.support import ( + run_unittest, missing_compiler_executable, requires_subprocess +) from distutils.command.build_clib import build_clib from distutils.errors import DistutilsSetupError @@ -112,6 +114,7 @@ def test_finalize_options(self): self.assertRaises(DistutilsSetupError, cmd.finalize_options) @unittest.skipIf(sys.platform == 'win32', "can't test on Windows") + @requires_subprocess() def test_run(self): pkg_dir, dist = self.create_dist() cmd = build_clib(dist) diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 3ee567d0455085..460b62f50bc12e 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -56,6 +56,7 @@ def tearDown(self): def build_ext(self, *args, **kwargs): return build_ext(*args, **kwargs) + @support.requires_subprocess() def test_build_ext(self): cmd = support.missing_compiler_executable() if cmd is not None: @@ -332,6 +333,7 @@ def test_compiler_option(self): cmd.run() self.assertEqual(cmd.compiler, 'unix') + @support.requires_subprocess() def test_get_outputs(self): cmd = support.missing_compiler_executable() if cmd is not None: diff --git a/Lib/distutils/tests/test_build_py.py b/Lib/distutils/tests/test_build_py.py index a590a485a2b929..44a06cc963aa3c 100644 --- a/Lib/distutils/tests/test_build_py.py +++ b/Lib/distutils/tests/test_build_py.py @@ -9,7 +9,7 @@ from distutils.errors import DistutilsFileError from distutils.tests import support -from test.support import run_unittest +from test.support import run_unittest, requires_subprocess class BuildPyTestCase(support.TempdirManager, @@ -89,6 +89,7 @@ def test_empty_package_dir(self): self.fail("failed package_data test when package_dir is ''") @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled') + @requires_subprocess() def test_byte_compile(self): project_dir, dist = self.create_dist(py_modules=['boiledeggs']) os.chdir(project_dir) @@ -106,6 +107,7 @@ def test_byte_compile(self): ['boiledeggs.%s.pyc' % sys.implementation.cache_tag]) @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled') + @requires_subprocess() def test_byte_compile_optimized(self): project_dir, dist = self.create_dist(py_modules=['boiledeggs']) os.chdir(project_dir) diff --git a/Lib/distutils/tests/test_config_cmd.py b/Lib/distutils/tests/test_config_cmd.py index 072f9ebe714aa7..c79db68aae115d 100644 --- a/Lib/distutils/tests/test_config_cmd.py +++ b/Lib/distutils/tests/test_config_cmd.py @@ -3,7 +3,9 @@ import os import sys import sysconfig -from test.support import run_unittest, missing_compiler_executable +from test.support import ( + run_unittest, missing_compiler_executable, requires_subprocess +) from distutils.command.config import dump_file, config from distutils.tests import support @@ -42,6 +44,7 @@ def test_dump_file(self): self.assertEqual(len(self._logs), numlines+1) @unittest.skipIf(sys.platform == 'win32', "can't test on Windows") + @requires_subprocess() def test_search_cpp(self): cmd = missing_compiler_executable(['preprocessor']) if cmd is not None: diff --git a/Lib/distutils/tests/test_install.py b/Lib/distutils/tests/test_install.py index b2a3887f0bbc98..c38f98b8b2c294 100644 --- a/Lib/distutils/tests/test_install.py +++ b/Lib/distutils/tests/test_install.py @@ -5,7 +5,7 @@ import unittest import site -from test.support import captured_stdout, run_unittest +from test.support import captured_stdout, run_unittest, requires_subprocess from distutils import sysconfig from distutils.command.install import install, HAS_USER_SITE @@ -208,6 +208,7 @@ def test_record(self): 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] self.assertEqual(found, expected) + @requires_subprocess() def test_record_extensions(self): cmd = test_support.missing_compiler_executable() if cmd is not None: diff --git a/Lib/distutils/tests/test_install_lib.py b/Lib/distutils/tests/test_install_lib.py index 652653f2b2c2bc..f840d1a94665ed 100644 --- a/Lib/distutils/tests/test_install_lib.py +++ b/Lib/distutils/tests/test_install_lib.py @@ -8,7 +8,7 @@ from distutils.extension import Extension from distutils.tests import support from distutils.errors import DistutilsOptionError -from test.support import run_unittest +from test.support import run_unittest, requires_subprocess class InstallLibTestCase(support.TempdirManager, @@ -35,6 +35,7 @@ def test_finalize_options(self): self.assertEqual(cmd.optimize, 2) @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled') + @requires_subprocess() def test_byte_compile(self): project_dir, dist = self.create_dist() os.chdir(project_dir) @@ -90,6 +91,7 @@ def test_get_inputs(self): inputs = cmd.get_inputs() self.assertEqual(len(inputs), 2, inputs) + @requires_subprocess() def test_dont_write_bytecode(self): # makes sure byte_compile is not used dist = self.create_dist()[1] diff --git a/Lib/distutils/tests/test_spawn.py b/Lib/distutils/tests/test_spawn.py index 631d6455d45725..a0a1145da5df8e 100644 --- a/Lib/distutils/tests/test_spawn.py +++ b/Lib/distutils/tests/test_spawn.py @@ -3,7 +3,7 @@ import stat import sys import unittest.mock -from test.support import run_unittest, unix_shell +from test.support import run_unittest, unix_shell, requires_subprocess from test.support import os_helper from distutils.spawn import find_executable @@ -11,6 +11,8 @@ from distutils.errors import DistutilsExecError from distutils.tests import support + +@requires_subprocess() class SpawnTestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py index 3697206229d205..7a88c88f6cdc50 100644 --- a/Lib/distutils/tests/test_sysconfig.py +++ b/Lib/distutils/tests/test_sysconfig.py @@ -10,7 +10,7 @@ from distutils import sysconfig from distutils.ccompiler import get_default_compiler from distutils.tests import support -from test.support import run_unittest, swap_item +from test.support import run_unittest, swap_item, requires_subprocess from test.support.os_helper import TESTFN from test.support.warnings_helper import check_warnings @@ -247,6 +247,7 @@ def test_SO_in_vars(self): self.assertIsNotNone(vars['SO']) self.assertEqual(vars['SO'], vars['EXT_SUFFIX']) + @requires_subprocess() def test_customize_compiler_before_get_config_vars(self): # Issue #21923: test that a Distribution compiler # instance can be called without an explicit call to diff --git a/Lib/lib2to3/tests/test_parser.py b/Lib/lib2to3/tests/test_parser.py index 5eefb5aad7d49e..ff4f8078878d8d 100644 --- a/Lib/lib2to3/tests/test_parser.py +++ b/Lib/lib2to3/tests/test_parser.py @@ -61,6 +61,9 @@ def test_load_grammar_from_pickle(self): shutil.rmtree(tmpdir) @unittest.skipIf(sys.executable is None, 'sys.executable required') + @unittest.skipIf( + sys.platform == 'emscripten', 'requires working subprocess' + ) def test_load_grammar_from_subprocess(self): tmpdir = tempfile.mkdtemp() tmpsubdir = os.path.join(tmpdir, 'subdir') diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ca903d302bdd31..1e4935fc3e6174 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -40,11 +40,12 @@ "bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute", "requires_IEEE_754", "requires_zlib", "has_fork_support", "requires_fork", + "has_subprocess_support", "requires_subprocess", "anticipate_failure", "load_package_tests", "detect_api_mismatch", "check__all__", "skip_if_buggy_ucrt_strfptime", "check_disallow_instantiation", # sys - "is_jython", "is_android", "is_emscripten", + "is_jython", "is_android", "is_emscripten", "is_wasi", "check_impl_detail", "unix_shell", "setswitchinterval", # network "open_urlresource", @@ -467,15 +468,23 @@ def requires_debug_ranges(reason='requires co_positions / debug_ranges'): else: unix_shell = None -# wasm32-emscripten is POSIX-like but does not provide a -# working fork() or subprocess API. +# wasm32-emscripten and -wasi are POSIX-like but do not +# have subprocess or fork support. is_emscripten = sys.platform == "emscripten" +is_wasi = sys.platform == "wasi" -has_fork_support = hasattr(os, "fork") and not is_emscripten +has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi def requires_fork(): return unittest.skipUnless(has_fork_support, "requires working os.fork()") +has_subprocess_support = not is_emscripten and not is_wasi + +def requires_subprocess(): + """Used for subprocess, os.spawn calls""" + return unittest.skipUnless(has_subprocess_support, "requires subprocess support") + + # Define the URL of a dedicated HTTP server for the network tests. # The URL must use clear-text HTTP: no redirection to encrypted HTTPS. TEST_HTTP_URL = "http://www.pythontest.net" diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py index 6d699c8486cd20..c2b43f4060eb55 100644 --- a/Lib/test/support/script_helper.py +++ b/Lib/test/support/script_helper.py @@ -42,6 +42,10 @@ def interpreter_requires_environment(): if 'PYTHONHOME' in os.environ: __cached_interp_requires_environment = True return True + # cannot run subprocess, assume we don't need it + if not support.has_subprocess_support: + __cached_interp_requires_environment = False + return False # Try running an interpreter with -E to see if it works or not. try: @@ -87,6 +91,7 @@ def fail(self, cmd_line): # Executing the interpreter in a subprocess +@support.requires_subprocess() def run_python_until_end(*args, **env_vars): env_required = interpreter_requires_environment() cwd = env_vars.pop('__cwd', None) @@ -139,6 +144,7 @@ def run_python_until_end(*args, **env_vars): return _PythonRunResult(rc, out, err), cmd_line +@support.requires_subprocess() def _assert_python(expected_success, /, *args, **env_vars): res, cmd_line = run_python_until_end(*args, **env_vars) if (res.rc and expected_success) or (not res.rc and not expected_success): @@ -171,6 +177,7 @@ def assert_python_failure(*args, **env_vars): return _assert_python(False, *args, **env_vars) +@support.requires_subprocess() def spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw): """Run a Python subprocess with the given arguments. @@ -273,6 +280,7 @@ def make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, return zip_name, os.path.join(zip_name, script_name_in_zip) +@support.requires_subprocess() def run_test_script(script): # use -u to try to get the full output if the test hangs or crash if support.verbose: diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index d99b3b7ed7d36d..0fa2d74835cba6 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -16,6 +16,8 @@ class AuditTest(unittest.TestCase): + + @support.requires_subprocess() def do_test(self, *args): with subprocess.Popen( [sys.executable, "-Xutf8", AUDIT_TESTS_PY, *args], @@ -29,6 +31,7 @@ def do_test(self, *args): if p.returncode: self.fail("".join(p.stderr)) + @support.requires_subprocess() def run_python(self, *args): events = [] with subprocess.Popen( diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 0957f3253d7a66..a5db8a11c5f672 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -66,6 +66,7 @@ def test_instancemethod(self): self.assertEqual(testfunction.attribute, "test") self.assertRaises(AttributeError, setattr, inst.testfunction, "attribute", "test") + @support.requires_subprocess() def test_no_FatalError_infinite_loop(self): with support.SuppressCrashReport(): p = subprocess.Popen([sys.executable, "-c", diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index fa5f39ea5fa972..352109ed4b2ff1 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -15,6 +15,8 @@ interpreter_requires_environment ) +if not support.has_subprocess_support: + raise unittest.SkipTest("test module requires subprocess") # Debug build? Py_DEBUG = hasattr(sys, "gettotalrefcount") diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 19c53c392607b6..15c6b05916f34d 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -17,6 +17,8 @@ import tempfile import textwrap +if not support.has_subprocess_support: + raise unittest.SkipTest("test module requires subprocess") MS_WINDOWS = (os.name == 'nt') MACOS = (sys.platform == 'darwin') diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index de986a3cbea97a..f7eaa779424768 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -412,6 +412,7 @@ def test_is_enabled(self): finally: sys.stderr = orig_stderr + @support.requires_subprocess() def test_disabled_by_default(self): # By default, the module should be disabled code = "import faulthandler; print(faulthandler.is_enabled())" @@ -420,6 +421,7 @@ def test_disabled_by_default(self): output = subprocess.check_output(args) self.assertEqual(output.rstrip(), b"False") + @support.requires_subprocess() def test_sys_xoptions(self): # Test python -X faulthandler code = "import faulthandler; print(faulthandler.is_enabled())" @@ -432,6 +434,7 @@ def test_sys_xoptions(self): output = subprocess.check_output(args, env=env) self.assertEqual(output.rstrip(), b"True") + @support.requires_subprocess() def test_env_var(self): # empty env var code = "import faulthandler; print(faulthandler.is_enabled())" diff --git a/Lib/test/test_file_eintr.py b/Lib/test/test_file_eintr.py index 01408d838a83cc..f9236f45ca4be8 100644 --- a/Lib/test/test_file_eintr.py +++ b/Lib/test/test_file_eintr.py @@ -15,12 +15,15 @@ import sys import time import unittest +from test import support + +if not support.has_subprocess_support: + raise unittest.SkipTest("test module requires subprocess") # Test import all of the things we're about to try testing up front. import _io import _pyio - @unittest.skipUnless(os.name == 'posix', 'tests requires a posix system.') class TestFileIOSignalInterrupt: def setUp(self): diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index 52948f1c7bde51..c4d4355dec9c6d 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -1,7 +1,7 @@ import unittest import unittest.mock from test.support import (verbose, refcount_test, - cpython_only) + cpython_only, requires_subprocess) from test.support.import_helper import import_module from test.support.os_helper import temp_dir, TESTFN, unlink from test.support.script_helper import assert_python_ok, make_script @@ -661,6 +661,7 @@ def do_work(): gc.collect() # this blows up (bad C pointer) when it fails @cpython_only + @requires_subprocess() def test_garbage_at_shutdown(self): import subprocess code = """if 1: diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index aa66d2f07f508c..497e66cd553b7f 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -12,7 +12,7 @@ from subprocess import PIPE, Popen from test.support import import_helper from test.support import os_helper -from test.support import _4G, bigmemtest +from test.support import _4G, bigmemtest, requires_subprocess from test.support.script_helper import assert_python_ok, assert_python_failure gzip = import_helper.import_module('gzip') @@ -760,6 +760,7 @@ def wrapper(*args, **kwargs): class TestCommandLine(unittest.TestCase): data = b'This is a simple test with gzip' + @requires_subprocess() def test_decompress_stdin_stdout(self): with io.BytesIO() as bytes_io: with gzip.GzipFile(fileobj=bytes_io, mode='wb') as gzip_file: @@ -795,6 +796,7 @@ def test_decompress_infile_outfile_error(self): self.assertEqual(rc, 1) self.assertEqual(out, b'') + @requires_subprocess() @create_and_remove_directory(TEMPDIR) def test_compress_stdin_outfile(self): args = sys.executable, '-m', 'gzip' diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 89e5e4190c640d..84c27f346c3409 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1096,6 +1096,7 @@ def test_environb(self): value_str = value.decode(sys.getfilesystemencoding(), 'surrogateescape') self.assertEqual(os.environ['bytes'], value_str) + @support.requires_subprocess() def test_putenv_unsetenv(self): name = "PYTHONTESTVAR" value = "testvalue" @@ -2279,6 +2280,7 @@ def test_setreuid(self): self.assertRaises(OverflowError, os.setreuid, 0, self.UID_OVERFLOW) @unittest.skipUnless(hasattr(os, 'setreuid'), 'test needs os.setreuid()') + @support.requires_subprocess() def test_setreuid_neg1(self): # Needs to accept -1. We run this in a subprocess to avoid # altering the test runner's process state (issue8045). @@ -2287,6 +2289,7 @@ def test_setreuid_neg1(self): 'import os,sys;os.setreuid(-1,-1);sys.exit(0)']) @unittest.skipUnless(hasattr(os, 'setregid'), 'test needs os.setregid()') + @support.requires_subprocess() def test_setregid(self): if os.getuid() != 0 and not HAVE_WHEEL_GROUP: self.assertRaises(OSError, os.setregid, 0, 0) @@ -2296,6 +2299,7 @@ def test_setregid(self): self.assertRaises(OverflowError, os.setregid, 0, self.GID_OVERFLOW) @unittest.skipUnless(hasattr(os, 'setregid'), 'test needs os.setregid()') + @support.requires_subprocess() def test_setregid_neg1(self): # Needs to accept -1. We run this in a subprocess to avoid # altering the test runner's process state (issue8045). @@ -2469,6 +2473,7 @@ def _kill_with_event(self, event, name): self.fail("subprocess did not stop on {}".format(name)) @unittest.skip("subprocesses aren't inheriting Ctrl+C property") + @support.requires_subprocess() def test_CTRL_C_EVENT(self): from ctypes import wintypes import ctypes @@ -2487,6 +2492,7 @@ def test_CTRL_C_EVENT(self): self._kill_with_event(signal.CTRL_C_EVENT, "CTRL_C_EVENT") + @support.requires_subprocess() def test_CTRL_BREAK_EVENT(self): self._kill_with_event(signal.CTRL_BREAK_EVENT, "CTRL_BREAK_EVENT") @@ -2924,6 +2930,7 @@ def test_device_encoding(self): self.assertTrue(codecs.lookup(encoding)) +@support.requires_subprocess() class PidTests(unittest.TestCase): @unittest.skipUnless(hasattr(os, 'getppid'), "test needs os.getppid") def test_getppid(self): @@ -2996,6 +3003,7 @@ def kill_process(pid): self.check_waitpid(code, exitcode=-signum, callback=kill_process) +@support.requires_subprocess() class SpawnTests(unittest.TestCase): def create_args(self, *, with_env=False, use_bytes=False): self.exitcode = 17 diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 1a688775f46309..d70ef155271f51 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -79,6 +79,7 @@ def test_architecture(self): res = platform.architecture() @os_helper.skip_unless_symlink + @support.requires_subprocess() def test_architecture_via_symlink(self): # issue3762 with support.PythonSymlink() as py: cmd = "-c", "import platform; print(platform.architecture())" @@ -269,6 +270,7 @@ def test_uname_slices(self): self.assertEqual(res[:5], expected[:5]) @unittest.skipIf(sys.platform in ['win32', 'OpenVMS'], "uname -p not used") + @support.requires_subprocess() def test_uname_processor(self): """ On some systems, the processor must match the output diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py index 82bbb3af9f1b39..ae3ffc77e9924a 100644 --- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py @@ -7,7 +7,7 @@ import threading import time import unittest -from test.support import cpython_only +from test.support import cpython_only, requires_subprocess from test.support import threading_helper from test.support.os_helper import TESTFN @@ -120,6 +120,7 @@ def fileno(self): # Another test case for poll(). This is copied from the test case for # select(), modified to use poll() instead. + @requires_subprocess() def test_poll2(self): cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done' proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, diff --git a/Lib/test/test_popen.py b/Lib/test/test_popen.py index cac2f6177f3257..e6bfc480cbd12c 100644 --- a/Lib/test/test_popen.py +++ b/Lib/test/test_popen.py @@ -19,6 +19,7 @@ if ' ' in python: python = '"' + python + '"' # quote embedded space for cmdline +@support.requires_subprocess() class PopenTest(unittest.TestCase): def _do_test_commandline(self, cmdline, expected): diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py index 5ed98dbff1737e..794d6436b61ab0 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -230,6 +230,7 @@ def setUp(self): def tearDown(self): os_helper.rmtree(self.directory) + @support.requires_subprocess() def pycompilecmd(self, *args, **kwargs): # assert_python_* helpers don't return proc object. We'll just use # subprocess.run() instead of spawn_python() and its friends to test diff --git a/Lib/test/test_quopri.py b/Lib/test/test_quopri.py index 715544c8a9669d..152d1858dcdd24 100644 --- a/Lib/test/test_quopri.py +++ b/Lib/test/test_quopri.py @@ -3,6 +3,7 @@ import sys, io, subprocess import quopri +from test import support ENCSAMPLE = b"""\ @@ -180,6 +181,7 @@ def test_decode_header(self): for p, e in self.HSTRINGS: self.assertEqual(quopri.decodestring(e, header=True), p) + @support.requires_subprocess() def test_scriptencode(self): (p, e) = self.STRINGS[-1] process = subprocess.Popen([sys.executable, "-mquopri"], @@ -196,6 +198,7 @@ def test_scriptencode(self): self.assertEqual(cout[i], e[i]) self.assertEqual(cout, e) + @support.requires_subprocess() def test_scriptdecode(self): (p, e) = self.STRINGS[-1] process = subprocess.Popen([sys.executable, "-mquopri", "-d"], diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 08e2c87e15c4d8..babc8a690877a2 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -22,6 +22,8 @@ from test.support import os_helper from test.libregrtest import utils, setup +if not support.has_subprocess_support: + raise unittest.SkipTest("test module requires subprocess") Py_DEBUG = hasattr(sys, 'gettotalrefcount') ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..') diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index a8d04a425e278b..ddb4aa68048df1 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -5,9 +5,14 @@ import unittest import subprocess from textwrap import dedent -from test.support import cpython_only, SuppressCrashReport +from test.support import cpython_only, has_subprocess_support, SuppressCrashReport from test.support.script_helper import kill_python + +if not has_subprocess_support: + raise unittest.SkipTest("test module requires subprocess") + + def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw): """Run the Python REPL with the given arguments. diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index 2954dfedc7e428..80e695a5f3f790 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -12,7 +12,7 @@ import textwrap import unittest import warnings -from test.support import no_tracing, verbose +from test.support import no_tracing, verbose, requires_subprocess from test.support.import_helper import forget, make_legacy_pyc, unload from test.support.os_helper import create_empty_file, temp_dir from test.support.script_helper import make_script, make_zip_script @@ -781,6 +781,7 @@ def run(self, *args, **kwargs): ) super().run(*args, **kwargs) + @requires_subprocess() def assertSigInt(self, *args, **kwargs): proc = subprocess.run(*args, **kwargs, text=True, stderr=subprocess.PIPE) self.assertTrue(proc.stderr.endswith("\nKeyboardInterrupt\n")) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index ac4626d0c456e2..09de608bb771fb 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -116,6 +116,7 @@ def test_valid_signals(self): self.assertLess(len(s), signal.NSIG) @unittest.skipUnless(sys.executable, "sys.executable required.") + @support.requires_subprocess() def test_keyboard_interrupt_exit_code(self): """KeyboardInterrupt triggers exit via SIGINT.""" process = subprocess.run( @@ -166,6 +167,7 @@ def test_issue9324(self): signal.signal(7, handler) @unittest.skipUnless(sys.executable, "sys.executable required.") + @support.requires_subprocess() def test_keyboard_interrupt_exit_code(self): """KeyboardInterrupt triggers an exit using STATUS_CONTROL_C_EXIT.""" # We don't test via os.kill(os.getpid(), signal.CTRL_C_EVENT) here @@ -637,6 +639,7 @@ def handler(signum, frame): @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") @unittest.skipUnless(hasattr(signal, 'siginterrupt'), "needs signal.siginterrupt()") +@support.requires_subprocess() class SiginterruptTest(unittest.TestCase): def readpipe_interrupted(self, interrupt): diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index c54d868cb234fd..032a1be3aa5290 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -211,6 +211,7 @@ def test_get_path(self): @unittest.skipUnless(site.ENABLE_USER_SITE, "requires access to PEP 370 " "user-site (site.ENABLE_USER_SITE)") + @support.requires_subprocess() def test_s_option(self): # (ncoghlan) Change this to use script_helper... usersite = site.USER_SITE @@ -497,6 +498,7 @@ def test_license_exists_at_url(self): class StartupImportTests(unittest.TestCase): + @support.requires_subprocess() def test_startup_imports(self): # Get sys.path in isolated mode (python3 -I) popen = subprocess.Popen([sys.executable, '-X', 'utf8', '-I', @@ -547,17 +549,20 @@ def test_startup_imports(self): }.difference(sys.builtin_module_names) self.assertFalse(modules.intersection(collection_mods), stderr) + @support.requires_subprocess() def test_startup_interactivehook(self): r = subprocess.Popen([sys.executable, '-c', 'import sys; sys.exit(hasattr(sys, "__interactivehook__"))']).wait() self.assertTrue(r, "'__interactivehook__' not added by site") + @support.requires_subprocess() def test_startup_interactivehook_isolated(self): # issue28192 readline is not automatically enabled in isolated mode r = subprocess.Popen([sys.executable, '-I', '-c', 'import sys; sys.exit(hasattr(sys, "__interactivehook__"))']).wait() self.assertFalse(r, "'__interactivehook__' added in isolated mode") + @support.requires_subprocess() def test_startup_interactivehook_isolated_explicit(self): # issue28192 readline can be explicitly enabled in isolated mode r = subprocess.Popen([sys.executable, '-I', '-c', @@ -607,6 +612,7 @@ def _calc_sys_path_for_underpth_nosite(self, sys_prefix, lines): sys_path.append(abs_path) return sys_path + @support.requires_subprocess() def test_underpth_basic(self): libpath = test.support.STDLIB_DIR exe_prefix = os.path.dirname(sys.executable) @@ -627,6 +633,7 @@ def test_underpth_basic(self): "sys.path is incorrect" ) + @support.requires_subprocess() def test_underpth_nosite_file(self): libpath = test.support.STDLIB_DIR exe_prefix = os.path.dirname(sys.executable) @@ -655,6 +662,7 @@ def test_underpth_nosite_file(self): "sys.path is incorrect" ) + @support.requires_subprocess() def test_underpth_file(self): libpath = test.support.STDLIB_DIR exe_prefix = os.path.dirname(sys.executable) @@ -679,6 +687,7 @@ def test_underpth_file(self): )], env=env) self.assertTrue(rc, "sys.path is incorrect") + @support.requires_subprocess() def test_underpth_dll_file(self): libpath = test.support.STDLIB_DIR exe_prefix = os.path.dirname(sys.executable) diff --git a/Lib/test/test_source_encoding.py b/Lib/test/test_source_encoding.py index a0cb605c1651cc..a0375fda0d3656 100644 --- a/Lib/test/test_source_encoding.py +++ b/Lib/test/test_source_encoding.py @@ -1,7 +1,7 @@ # -*- coding: koi8-r -*- import unittest -from test.support import script_helper, captured_stdout +from test.support import script_helper, captured_stdout, requires_subprocess from test.support.os_helper import TESTFN, unlink, rmtree from test.support.import_helper import unload import importlib @@ -65,6 +65,7 @@ def test_issue7820(self): # two bytes in common with the UTF-8 BOM self.assertRaises(SyntaxError, eval, b'\xef\xbb\x20') + @requires_subprocess() def test_20731(self): sub = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3af523e8346c46..99a25e279df92c 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -48,6 +48,9 @@ if support.PGO: raise unittest.SkipTest("test is not helpful for PGO") +if not support.has_subprocess_support: + raise unittest.SkipTest("test module requires subprocess") + mswindows = (sys.platform == "win32") # diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 4dac7f6cd42000..1ce3c826d6b1bc 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -491,6 +491,7 @@ def test_reap_children(self): # pending child process support.reap_children() + @support.requires_subprocess() def check_options(self, args, func, expected=None): code = f'from test.support import {func}; print(repr({func}()))' cmd = [sys.executable, *args, '-c', code] diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index f6da57f55f1617..41c4618ad10d40 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -694,6 +694,7 @@ def test_sys_getwindowsversion_no_instantiation(self): def test_clear_type_cache(self): sys._clear_type_cache() + @support.requires_subprocess() def test_ioencoding(self): env = dict(os.environ) @@ -741,6 +742,7 @@ def test_ioencoding(self): 'requires OS support of non-ASCII encodings') @unittest.skipUnless(sys.getfilesystemencoding() == locale.getpreferredencoding(False), 'requires FS encoding to match locale') + @support.requires_subprocess() def test_ioencoding_nonascii(self): env = dict(os.environ) @@ -753,6 +755,7 @@ def test_ioencoding_nonascii(self): @unittest.skipIf(sys.base_prefix != sys.prefix, 'Test is not venv-compatible') + @support.requires_subprocess() def test_executable(self): # sys.executable should be absolute self.assertEqual(os.path.abspath(sys.executable), sys.executable) @@ -854,9 +857,11 @@ def check_locale_surrogateescape(self, locale): 'stdout: surrogateescape\n' 'stderr: backslashreplace\n') + @support.requires_subprocess() def test_c_locale_surrogateescape(self): self.check_locale_surrogateescape('C') + @support.requires_subprocess() def test_posix_locale_surrogateescape(self): self.check_locale_surrogateescape('POSIX') @@ -1005,6 +1010,7 @@ def test_getandroidapilevel(self): self.assertIsInstance(level, int) self.assertGreater(level, 0) + @support.requires_subprocess() def test_sys_tracebacklimit(self): code = """if 1: import sys @@ -1051,6 +1057,7 @@ def test__enablelegacywindowsfsencoding(self): out = out.decode('ascii', 'replace').rstrip() self.assertEqual(out, 'mbcs replace') + @support.requires_subprocess() def test_orig_argv(self): code = textwrap.dedent(''' import sys diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index 6fbb80d77f793c..80fe9c8a8b1e0e 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -5,7 +5,7 @@ import shutil from copy import copy -from test.support import (captured_stdout, PythonSymlink) +from test.support import (captured_stdout, PythonSymlink, requires_subprocess) from test.support.import_helper import import_module from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink, change_cwd) @@ -273,6 +273,7 @@ def test_get_scheme_names(self): self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) @skip_unless_symlink + @requires_subprocess() def test_symlink(self): # Issue 7880 with PythonSymlink() as py: cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" @@ -326,6 +327,7 @@ def test_ldshared_value(self): self.assertIn(ldflags, ldshared) @unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX") + @requires_subprocess() def test_platform_in_subprocess(self): my_platform = sysconfig.get_platform() diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index f03a64232e17c3..4830571474b5bf 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -3,7 +3,7 @@ """ import test.support -from test.support import threading_helper +from test.support import threading_helper, requires_subprocess from test.support import verbose, cpython_only, os_helper from test.support.import_helper import import_module from test.support.script_helper import assert_python_ok, assert_python_failure @@ -1259,6 +1259,7 @@ def test_releasing_unacquired_lock(self): lock = threading.Lock() self.assertRaises(RuntimeError, lock.release) + @requires_subprocess() def test_recursion_limit(self): # Issue 9670 # test that excessive recursion within a non-main thread causes diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 966ff2a1241ca6..e0884fb9b78141 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -9,7 +9,8 @@ import re from test import support from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ, - requires_debug_ranges, has_no_debug_ranges) + requires_debug_ranges, has_no_debug_ranges, + requires_subprocess) from test.support.os_helper import TESTFN, unlink from test.support.script_helper import assert_python_ok, assert_python_failure @@ -203,6 +204,7 @@ def __str__(self): str_name = '.'.join([X.__module__, X.__qualname__]) self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value)) + @requires_subprocess() def test_encoded_file(self): # Test that tracebacks are correctly printed for encoded source files: # - correct line number (Issue2384) diff --git a/Lib/test/test_utf8_mode.py b/Lib/test/test_utf8_mode.py index 8b6332ee22771b..2b96f76df305fe 100644 --- a/Lib/test/test_utf8_mode.py +++ b/Lib/test/test_utf8_mode.py @@ -255,6 +255,7 @@ def test_optim_level(self): @unittest.skipIf(MS_WINDOWS, "os.device_encoding() doesn't implement " "the UTF-8 Mode on Windows") + @support.requires_subprocess() def test_device_encoding(self): # Use stdout as TTY if not sys.stdout.isatty(): diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index ca37abcf79854a..043158c79214b4 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -15,7 +15,8 @@ import sys import tempfile from test.support import (captured_stdout, captured_stderr, requires_zlib, - skip_if_broken_multiprocessing_synchronize, verbose) + skip_if_broken_multiprocessing_synchronize, verbose, + requires_subprocess) from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv @@ -33,6 +34,7 @@ or sys._base_executable != sys.executable, 'cannot run venv.create from within a venv on this platform') +@requires_subprocess() def check_output(cmd, encoding=None): p = subprocess.Popen(cmd, stdout=subprocess.PIPE, diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py index dbfd2e5a0f280b..9d608d63a01ed3 100644 --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -8,6 +8,8 @@ from test.support import import_helper from test.support import os_helper +if not support.has_subprocess_support: + raise unittest.SkipTest("test webserver requires subprocess") URL = 'http://www.example.com' CMD_NAME = 'test' diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index df48fabff951d8..e226dd741d7a75 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -21,7 +21,7 @@ from test.support import script_helper from test.support import (findfile, requires_zlib, requires_bz2, - requires_lzma, captured_stdout) + requires_lzma, captured_stdout, requires_subprocess) from test.support.os_helper import TESTFN, unlink, rmtree, temp_dir, temp_cwd @@ -2771,6 +2771,7 @@ def test_read_zip64_with_exe_prepended(self): @unittest.skipUnless(sys.executable, 'sys.executable required.') @unittest.skipUnless(os.access('/bin/bash', os.X_OK), 'Test relies on #!/bin/bash working.') + @requires_subprocess() def test_execute_zip2(self): output = subprocess.check_output([self.exe_zip, sys.executable]) self.assertIn(b'number in executable: 5', output) @@ -2778,6 +2779,7 @@ def test_execute_zip2(self): @unittest.skipUnless(sys.executable, 'sys.executable required.') @unittest.skipUnless(os.access('/bin/bash', os.X_OK), 'Test relies on #!/bin/bash working.') + @requires_subprocess() def test_execute_zip64(self): output = subprocess.check_output([self.exe_zip64, sys.executable]) self.assertIn(b'number in executable: 5', output) diff --git a/Misc/NEWS.d/next/Tests/2022-01-14-23-22-41.bpo-40280.nHLWoD.rst b/Misc/NEWS.d/next/Tests/2022-01-14-23-22-41.bpo-40280.nHLWoD.rst new file mode 100644 index 00000000000000..67134f1191cd28 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-01-14-23-22-41.bpo-40280.nHLWoD.rst @@ -0,0 +1,3 @@ +Add :func:`test.support.requires_subprocess` decorator to mark tests which +require working :mod:`subprocess` module or ``os.spawn*``. The +wasm32-emscripten platform has no support for processes.