From 8c79de49b1640cf3d44be7b699f332284b080195 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 18 Mar 2022 17:47:21 +0100 Subject: [PATCH 01/13] bpo-40280: Add requires_fork and subprocess to more tests --- Lib/test/lock_tests.py | 2 +- Lib/test/test_json/test_tool.py | 1 + Lib/test/test_mailbox.py | 2 +- Lib/test/test_pdb.py | 2 ++ Lib/test/test_peg_generator/test_c_parser.py | 1 + Lib/test/test_socketserver.py | 2 +- Lib/test/test_tools/__init__.py | 4 ++++ Lib/test/test_wait3.py | 4 ++-- Lib/test/test_wait4.py | 4 +++- 9 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py index d82629368dff8a..f16c7ed952cf55 100644 --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -15,7 +15,7 @@ from test.support import threading_helper -requires_fork = unittest.skipUnless(hasattr(os, 'fork'), +requires_fork = unittest.skipUnless(support.has_fork_support, "platform doesn't support fork " "(no _at_fork_reinit method)") diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 1d7fca6efb1cc7..2b63810d53981e 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -10,6 +10,7 @@ from test.support.script_helper import assert_python_ok +@support.requires_subprocess() class TestTool(unittest.TestCase): data = """ diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index 604fc4525f53e9..20c460e300cc9d 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -1061,7 +1061,7 @@ def test_add_and_close(self): self.assertEqual(contents, f.read()) self._box = self._factory(self._path) - @unittest.skipUnless(hasattr(os, 'fork'), "Test needs fork().") + @support.requires_fork() @unittest.skipUnless(hasattr(socket, 'socketpair'), "Test needs socketpair().") def test_lock_conflict(self): # Fork off a child process that will lock the mailbox temporarily, diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index d2bf3dc90ed239..bfa2cc92d25147 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -13,6 +13,7 @@ from contextlib import ExitStack, redirect_stdout from io import StringIO +from test import support from test.support import os_helper # This little helper class is essential for testing pdb under doctest. from test.test_doctest import _FakeInput @@ -1363,6 +1364,7 @@ def test_pdb_issue_43318(): """ +@support.requires_subprocess() class PdbTestCase(unittest.TestCase): def tearDown(self): os_helper.unlink(os_helper.TESTFN) diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index b761bd493f52c7..51a4f7d7c07a08 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -70,6 +70,7 @@ def test_parse(self): """ +@support.requires_subprocess() class TestCParser(unittest.TestCase): def setUp(self): self._backup_config_vars = dict(sysconfig._CONFIG_VARS) diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py index 211321f37617e9..c498d3d12e24a7 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -28,7 +28,7 @@ HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX") requires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS, 'requires Unix sockets') -HAVE_FORKING = hasattr(os, "fork") +HAVE_FORKING = test.support.has_fork_support requires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking') def signal_alarm(n): diff --git a/Lib/test/test_tools/__init__.py b/Lib/test/test_tools/__init__.py index 34b0d3b8fb3eb0..2102b9fceff568 100644 --- a/Lib/test/test_tools/__init__.py +++ b/Lib/test/test_tools/__init__.py @@ -13,6 +13,10 @@ raise unittest.SkipTest("test too slow on ASAN/MSAN build") +if not support.has_subprocess_support: + raise unittest.SkipTest("test module requires subprocess") + + basepath = os.path.normpath( os.path.dirname( # os.path.dirname( # Lib diff --git a/Lib/test/test_wait3.py b/Lib/test/test_wait3.py index aa166baa400bc7..4ec7690ac19bbf 100644 --- a/Lib/test/test_wait3.py +++ b/Lib/test/test_wait3.py @@ -9,8 +9,8 @@ from test.fork_wait import ForkWait from test import support -if not hasattr(os, 'fork'): - raise unittest.SkipTest("os.fork not defined") +if not support.has_fork_support: + raise unittest.SkipTest("requires working os.fork()") if not hasattr(os, 'wait3'): raise unittest.SkipTest("os.wait3 not defined") diff --git a/Lib/test/test_wait4.py b/Lib/test/test_wait4.py index f8d5e13014f0c1..24f1aaec60c56b 100644 --- a/Lib/test/test_wait4.py +++ b/Lib/test/test_wait4.py @@ -9,7 +9,9 @@ from test import support # If either of these do not exist, skip this test. -support.get_attribute(os, 'fork') +if not support.has_fork_support: + raise unittest.SkipTest("requires working os.fork()") + support.get_attribute(os, 'wait4') From a528e66977eb14d1daa18a222f8e2b466521a21f Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 18 Mar 2022 17:50:28 +0100 Subject: [PATCH 02/13] bpo-40280: Skip extension tests if dlopen is not available --- Lib/test/test_importlib/extension/test_finder.py | 4 ++++ Lib/test/test_importlib/extension/test_loader.py | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py index 140f20657f7363..b6663a44845502 100644 --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -10,6 +10,10 @@ class FinderTests(abc.FinderTests): """Test the finder for extension modules.""" + def setUp(self): + if not self.machinery.EXTENSION_SUFFIXES: + raise unittest.SkipTest("Requires dynamic loading support.") + def find_spec(self, fullname): importer = self.machinery.FileFinder(util.EXTENSIONS.path, (self.machinery.ExtensionFileLoader, diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index e7a88a8f5e3218..5080009bee32ee 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -12,11 +12,14 @@ import importlib from test.support.script_helper import assert_python_failure + class LoaderTests(abc.LoaderTests): """Test load_module() for extension modules.""" def setUp(self): + if not self.machinery.EXTENSION_SUFFIXES: + raise unittest.SkipTest("Requires dynamic loading support.") self.loader = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name, util.EXTENSIONS.file_path) @@ -91,6 +94,8 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests): # Test loading extension modules with multi-phase initialization (PEP 489). def setUp(self): + if not self.machinery.EXTENSION_SUFFIXES: + raise unittest.SkipTest("Requires dynamic loading support.") self.name = '_testmultiphase' finder = self.machinery.FileFinder(None) self.spec = importlib.util.find_spec(self.name) From d578fa4f4dd57a227b4860dfb025fc64fb647d21 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 18 Mar 2022 17:50:46 +0100 Subject: [PATCH 03/13] Don't assume that _testcapi is a shared extension --- Lib/test/test_import/__init__.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 8857fd5000bb14..7cca9f9d60ab6a 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -20,7 +20,7 @@ from test.support import os_helper from test.support import ( - STDLIB_DIR, is_jython, swap_attr, swap_item, cpython_only) + STDLIB_DIR, is_jython, swap_attr, swap_item, cpython_only, is_emscripten) from test.support.import_helper import ( forget, make_legacy_pyc, unlink, unload, DirsOnSysPath, CleanImport) from test.support.os_helper import ( @@ -101,8 +101,17 @@ def test_from_import_missing_attr_has_name_and_so_path(self): with self.assertRaises(ImportError) as cm: from _testcapi import i_dont_exist self.assertEqual(cm.exception.name, '_testcapi') - self.assertEqual(cm.exception.path, _testcapi.__file__) - self.assertRegex(str(cm.exception), r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|pyd)\)") + if hasattr(_testcapi, "__file__"): + self.assertEqual(cm.exception.path, _testcapi.__file__) + self.assertRegex( + str(cm.exception), + r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|pyd)\)" + ) + else: + self.assertEqual( + str(cm.exception), + "cannot import name 'i_dont_exist' from '_testcapi' (unknown location)" + ) def test_from_import_missing_attr_has_name(self): with self.assertRaises(ImportError) as cm: @@ -525,6 +534,7 @@ class FilePermissionTests(unittest.TestCase): @unittest.skipUnless(os.name == 'posix', "test meaningful only on posix systems") + @unittest.skipIf(is_emscripten, "Emscripten's umask is a stub.") def test_creation_mode(self): mask = 0o022 with temp_umask(mask), _ready_to_import() as (name, path): From a05977ffef7da558764ce621982f4cc6563bc348 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 18 Mar 2022 18:13:30 +0100 Subject: [PATCH 04/13] Skip socket tests that don't work on Emscripten --- Lib/test/test_logging.py | 20 ++++++++++++++++++++ Lib/test/test_pydoc.py | 3 ++- Lib/test/test_robotparser.py | 3 +++ Lib/test/test_selectors.py | 4 ++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index be193dcdacf4f0..f73e35f0b19e9d 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -75,6 +75,15 @@ except ImportError: pass + +# Emscripten's socket support is limited. Logging's socket tests do not work +# on Emscripten, yet. +skip_on_emscripten = unittest.skipIf( + support.is_emscripten, + "Socket tests don't work on Emscripten." +) + + class BaseTest(unittest.TestCase): """Base class for logging tests.""" @@ -626,6 +635,9 @@ def test_path_objects(self): os.unlink(fn) @unittest.skipIf(os.name == 'nt', 'WatchedFileHandler not appropriate for Windows.') + @unittest.skipIf( + support.is_emscripten, "Emscripten cannot fstat unlinked files." + ) def test_race(self): # Issue #14632 refers. def remove_loop(fname, tries): @@ -1058,6 +1070,7 @@ class TestUnixDatagramServer(TestUDPServer): # - end of server_helper section +@skip_on_emscripten class SMTPHandlerTest(BaseTest): # bpo-14314, bpo-19665, bpo-34092: don't wait forever TIMEOUT = support.LONG_TIMEOUT @@ -1681,6 +1694,7 @@ def test_defaults_do_no_interpolation(self): os.unlink(fn) +@skip_on_emscripten class SocketHandlerTest(BaseTest): """Test for SocketHandler objects.""" @@ -1795,6 +1809,7 @@ def tearDown(self): SocketHandlerTest.tearDown(self) os_helper.unlink(self.address) +@skip_on_emscripten class DatagramHandlerTest(BaseTest): """Test for DatagramHandler.""" @@ -1876,6 +1891,7 @@ def tearDown(self): DatagramHandlerTest.tearDown(self) os_helper.unlink(self.address) +@skip_on_emscripten class SysLogHandlerTest(BaseTest): """Test for SysLogHandler using UDP.""" @@ -1985,6 +2001,7 @@ def tearDown(self): self.server_class.address_family = socket.AF_INET super(IPv6SysLogHandlerTest, self).tearDown() +@skip_on_emscripten class HTTPHandlerTest(BaseTest): """Test for HTTPHandler.""" @@ -3261,6 +3278,7 @@ def setup_via_listener(self, text, verify=None): logging.config.stopListening() threading_helper.join_thread(t) + @skip_on_emscripten def test_listen_config_10_ok(self): with support.captured_stdout() as output: self.setup_via_listener(json.dumps(self.config10)) @@ -3280,6 +3298,7 @@ def test_listen_config_10_ok(self): ('ERROR', '4'), ], stream=output) + @skip_on_emscripten def test_listen_config_1_ok(self): with support.captured_stdout() as output: self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1)) @@ -3294,6 +3313,7 @@ def test_listen_config_1_ok(self): # Original logger output is empty. self.assert_log_lines([]) + @skip_on_emscripten def test_listen_verify(self): def verify_fail(stuff): diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 7cedf76fb3af42..e2dab1207172d7 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -27,7 +27,7 @@ from test.support.script_helper import assert_python_ok, assert_python_failure from test.support import threading_helper from test.support import (reap_children, captured_output, captured_stdout, - captured_stderr, requires_docstrings) + captured_stderr, is_emscripten, requires_docstrings) from test.support.os_helper import (TESTFN, rmtree, unlink) from test import pydoc_mod @@ -1339,6 +1339,7 @@ def a_fn_with_https_link(): ) +@unittest.skipIf(is_emscripten, "Socket server not available on Emscripten.") class PydocServerTest(unittest.TestCase): """Tests for pydoc._start_server""" diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py index b0bed431d4b059..08bdf59d333d4e 100644 --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -308,6 +308,9 @@ def log_message(self, format, *args): pass +@unittest.skipIf( + support.is_emscripten, "Socket server not available on Emscripten." +) class PasswordProtectedSiteTestCase(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py index fe6b725a4bd050..c927331d438b0c 100644 --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -19,6 +19,10 @@ resource = None +if support.is_emscripten: + raise unittest.SkipTest("Cannot create socketpair on Emscripten.") + + if hasattr(socket, 'socketpair'): socketpair = socket.socketpair else: From 126f427ae1192cccc2bd4b472981fa4370409821 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 18 Mar 2022 18:21:34 +0100 Subject: [PATCH 05/13] mmap emulation is incomplete --- Lib/test/test_mmap.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 014171cbb4911b..213a44d56f37b3 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1,4 +1,6 @@ -from test.support import (requires, _2G, _4G, gc_collect, cpython_only) +from test.support import ( + requires, _2G, _4G, gc_collect, cpython_only, is_emscripten +) from test.support.import_helper import import_module from test.support.os_helper import TESTFN, unlink import unittest @@ -21,6 +23,12 @@ def random_tagname(length=10): suffix = ''.join(random.choices(string.ascii_uppercase, k=length)) return f'{tagname_prefix}_{suffix}' +# Python's mmap module dup()s the file descriptor. Emscripten's FS layer +# does not materialize file changes through a dupped fd to a new mmap. +if is_emscripten: + raise unittest.SkipTest("incompatible with Emscripten's mmap emulation.") + + class MmapTests(unittest.TestCase): def setUp(self): From 98b30c3bc455440570c8b5fe2607fa4048b745ef Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 19 Mar 2022 10:12:22 +0100 Subject: [PATCH 06/13] venv does not work yet --- Lib/test/test_venv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index db812f21dbc562..c91b75493841be 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -16,7 +16,7 @@ import tempfile from test.support import (captured_stdout, captured_stderr, requires_zlib, skip_if_broken_multiprocessing_synchronize, verbose, - requires_subprocess) + requires_subprocess, is_emscripten) from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv @@ -34,6 +34,9 @@ or sys._base_executable != sys.executable, 'cannot run venv.create from within a venv on this platform') +if is_emscripten: + raise unittest.SkipTest("venv is not available on Emscripten.") + @requires_subprocess() def check_output(cmd, encoding=None): p = subprocess.Popen(cmd, From a9102ec90ce85476d95aeaf46a0bbf1a726c9d67 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 19 Mar 2022 10:12:46 +0100 Subject: [PATCH 07/13] Cannot get libc from executable --- Lib/test/test_platform.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index d70ef155271f51..9b2cd201f3c2fe 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -364,6 +364,7 @@ def test_mac_ver_with_fork(self): # parent support.wait_process(pid, exitcode=0) + @unittest.skipIf(support.is_emscripten, "Does not apply to Emscripten") def test_libc_ver(self): # check that libc_ver(executable) doesn't raise an exception if os.path.isdir(sys.executable) and \ From 3313066e97900f4a143b33fa5e5e69c620843030 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 19 Mar 2022 10:15:07 +0100 Subject: [PATCH 08/13] Skip lots of socket tests --- Lib/test/pythoninfo.py | 3 ++- Lib/test/support/__init__.py | 12 ++++++++++++ Lib/test/test_asyncgen.py | 4 +++- Lib/test/test_asynchat.py | 2 ++ Lib/test/test_asyncio/__init__.py | 2 ++ Lib/test/test_asyncore.py | 2 ++ Lib/test/test_contextlib_async.py | 1 + Lib/test/test_doctest.py | 5 +++++ Lib/test/test_docxmlrpc.py | 3 +++ Lib/test/test_ftplib.py | 1 + Lib/test/test_httplib.py | 1 + Lib/test/test_httpservers.py | 1 + Lib/test/test_imaplib.py | 5 ++++- Lib/test/test_logging.py | 24 ++++++++---------------- Lib/test/test_poll.py | 5 ++++- Lib/test/test_poplib.py | 2 ++ Lib/test/test_select.py | 2 ++ Lib/test/test_smtplib.py | 2 ++ Lib/test/test_socket.py | 2 ++ Lib/test/test_sys_settrace.py | 1 + Lib/test/test_telnetlib.py | 2 ++ Lib/test/test_urllib2.py | 2 ++ Lib/test/test_urllib2_localnet.py | 3 +++ Lib/test/test_xmlrpc.py | 2 ++ Lib/unittest/test/__init__.py | 5 ++++- Lib/unittest/test/test_async_case.py | 2 ++ Lib/unittest/test/test_program.py | 1 + Lib/unittest/test/test_runner.py | 2 ++ Lib/unittest/test/testmock/testasync.py | 3 +++ 29 files changed, 81 insertions(+), 21 deletions(-) diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index d15a11c80b649a..b00830c279e876 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -6,6 +6,7 @@ import re import sys import traceback +import unittest import warnings @@ -615,7 +616,7 @@ def collect_resource(info_add): def collect_test_socket(info_add): try: from test import test_socket - except ImportError: + except (ImportError, unittest.SkipTest): return # all check attributes like HAVE_SOCKET_CAN diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index fc1b86bebcd1ae..cdf4a1b8f110e1 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -42,6 +42,7 @@ "requires_IEEE_754", "requires_zlib", "has_fork_support", "requires_fork", "has_subprocess_support", "requires_subprocess", + "has_socket_support", "requires_working_socket", "anticipate_failure", "load_package_tests", "detect_api_mismatch", "check__all__", "skip_if_buggy_ucrt_strfptime", "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", @@ -520,6 +521,17 @@ def requires_subprocess(): """Used for subprocess, os.spawn calls, fd inheritance""" return unittest.skipUnless(has_subprocess_support, "requires subprocess support") +# Emscripten's socket emulation has limitation. WASI doesn't have sockets yet. +has_socket_support = not is_emscripten and not is_wasi + +def requires_working_socket(*, module=False): + msg = "requires socket support" + if module: + if not has_socket_support: + raise unittest.SkipTest(msg) + else: + return unittest.skipUnless(has_socket_support, msg) + # Does strftime() support glibc extension like '%4Y'? has_strftime_extensions = False if sys.platform != "win32": diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 473bce484b47b0..fb22f411c2e296 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -4,10 +4,12 @@ import contextlib from test.support.import_helper import import_module -from test.support import gc_collect +from test.support import gc_collect, requires_working_socket asyncio = import_module("asyncio") +requires_working_socket(module=True) + _no_default = object() diff --git a/Lib/test/test_asynchat.py b/Lib/test/test_asynchat.py index 973ac1f7d97c9b..d28d67732e7886 100644 --- a/Lib/test/test_asynchat.py +++ b/Lib/test/test_asynchat.py @@ -18,6 +18,8 @@ import asynchat import asyncore +support.requires_working_socket(module=True) + HOST = socket_helper.HOST SERVER_QUIT = b'QUIT\n' diff --git a/Lib/test/test_asyncio/__init__.py b/Lib/test/test_asyncio/__init__.py index 5d415044d7dc66..ab0b5aa9489257 100644 --- a/Lib/test/test_asyncio/__init__.py +++ b/Lib/test/test_asyncio/__init__.py @@ -1,7 +1,9 @@ import os +from test import support from test.support import load_package_tests from test.support import import_helper +support.requires_working_socket(module=True) # Skip tests if we don't have concurrent.futures. import_helper.import_module('concurrent.futures') diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py index ecd1e120ecb515..e3f31bd06d0c3a 100644 --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -18,6 +18,8 @@ if support.PGO: raise unittest.SkipTest("test is not helpful for PGO") +support.requires_working_socket(module=True) + import warnings with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py index c16c7ecd19a259..462e05cc79aec8 100644 --- a/Lib/test/test_contextlib_async.py +++ b/Lib/test/test_contextlib_async.py @@ -8,6 +8,7 @@ from test.test_contextlib import TestBaseExitStack +support.requires_working_socket(module=True) def _async_test(func): """Decorator to turn an async function into a test case.""" diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 407a14c7ddf67e..49347626a61241 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -18,6 +18,11 @@ import types import contextlib + +if not support.has_subprocess_support: + raise unittest.SkipTest("test_CLI requires subprocess support.") + + # NOTE: There are some additional tests relating to interaction with # zipimport in the test_zipimport_support test module. diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py index 9a06be45855021..89d80091850f5e 100644 --- a/Lib/test/test_docxmlrpc.py +++ b/Lib/test/test_docxmlrpc.py @@ -4,6 +4,9 @@ import sys import threading import unittest +from test import support + +support.requires_working_socket(module=True) def make_request_and_skipIf(condition, reason): # If we skip the test, we have to make a request because diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py index 2f5cc06ca4b9a5..2794fccfe7c72d 100644 --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -29,6 +29,7 @@ import asyncore import asynchat +support.requires_working_socket(module=True) TIMEOUT = support.LOOPBACK_TIMEOUT DEFAULT_ENCODING = 'utf-8' diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 8265b8d1d6d2dd..15dab0356f5e35 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -19,6 +19,7 @@ from test.support import socket_helper from test.support import warnings_helper +support.requires_working_socket(module=True) here = os.path.dirname(__file__) # Self-signed cert file for 'localhost' diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 1cc020f63539de..d20b45e8e02f88 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -33,6 +33,7 @@ from test.support import os_helper from test.support import threading_helper +support.requires_working_socket(module=True) class NoLogRequestHandler: def log_message(self, *args): diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 30b553746af11a..ff13edea2d1e4a 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -11,7 +11,8 @@ import socket from test.support import (verbose, - run_with_tz, run_with_locale, cpython_only) + run_with_tz, run_with_locale, cpython_only, + requires_working_socket) from test.support import hashlib_helper from test.support import threading_helper from test.support import warnings_helper @@ -23,6 +24,8 @@ except ImportError: ssl = None +support.requires_working_socket(module=True) + CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem") CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem") diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index f73e35f0b19e9d..5f72a6dd5871ae 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -76,14 +76,6 @@ pass -# Emscripten's socket support is limited. Logging's socket tests do not work -# on Emscripten, yet. -skip_on_emscripten = unittest.skipIf( - support.is_emscripten, - "Socket tests don't work on Emscripten." -) - - class BaseTest(unittest.TestCase): """Base class for logging tests.""" @@ -1070,7 +1062,7 @@ class TestUnixDatagramServer(TestUDPServer): # - end of server_helper section -@skip_on_emscripten +@support.requires_working_socket() class SMTPHandlerTest(BaseTest): # bpo-14314, bpo-19665, bpo-34092: don't wait forever TIMEOUT = support.LONG_TIMEOUT @@ -1694,7 +1686,7 @@ def test_defaults_do_no_interpolation(self): os.unlink(fn) -@skip_on_emscripten +@support.requires_working_socket() class SocketHandlerTest(BaseTest): """Test for SocketHandler objects.""" @@ -1809,7 +1801,7 @@ def tearDown(self): SocketHandlerTest.tearDown(self) os_helper.unlink(self.address) -@skip_on_emscripten +@support.requires_working_socket() class DatagramHandlerTest(BaseTest): """Test for DatagramHandler.""" @@ -1891,7 +1883,7 @@ def tearDown(self): DatagramHandlerTest.tearDown(self) os_helper.unlink(self.address) -@skip_on_emscripten +@support.requires_working_socket() class SysLogHandlerTest(BaseTest): """Test for SysLogHandler using UDP.""" @@ -2001,7 +1993,7 @@ def tearDown(self): self.server_class.address_family = socket.AF_INET super(IPv6SysLogHandlerTest, self).tearDown() -@skip_on_emscripten +@support.requires_working_socket() class HTTPHandlerTest(BaseTest): """Test for HTTPHandler.""" @@ -3278,7 +3270,7 @@ def setup_via_listener(self, text, verify=None): logging.config.stopListening() threading_helper.join_thread(t) - @skip_on_emscripten + @support.requires_working_socket() def test_listen_config_10_ok(self): with support.captured_stdout() as output: self.setup_via_listener(json.dumps(self.config10)) @@ -3298,7 +3290,7 @@ def test_listen_config_10_ok(self): ('ERROR', '4'), ], stream=output) - @skip_on_emscripten + @support.requires_working_socket() def test_listen_config_1_ok(self): with support.captured_stdout() as output: self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1)) @@ -3313,7 +3305,7 @@ def test_listen_config_1_ok(self): # Original logger output is empty. self.assert_log_lines([]) - @skip_on_emscripten + @support.requires_working_socket() def test_listen_verify(self): def verify_fail(stuff): diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py index ae3ffc77e9924a..7d542b5cfd783d 100644 --- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py @@ -7,7 +7,9 @@ import threading import time import unittest -from test.support import cpython_only, requires_subprocess +from test.support import ( + cpython_only, requires_subprocess, requires_working_socket +) from test.support import threading_helper from test.support.os_helper import TESTFN @@ -17,6 +19,7 @@ except AttributeError: raise unittest.SkipTest("select.poll not defined") +requires_working_socket(module=True) def find_ready_matching(ready, flag): match = [] diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py index 1220ca32ef82e8..57ccc541b81fe1 100644 --- a/Lib/test/test_poplib.py +++ b/Lib/test/test_poplib.py @@ -22,6 +22,8 @@ import asynchat import asyncore +test_support.requires_working_socket(module=True) + HOST = socket_helper.HOST PORT = 0 diff --git a/Lib/test/test_select.py b/Lib/test/test_select.py index 8b59321121e494..ca2a9d9d24dabc 100644 --- a/Lib/test/test_select.py +++ b/Lib/test/test_select.py @@ -7,6 +7,8 @@ import unittest from test import support +support.requires_working_socket(module=True) + @unittest.skipIf((sys.platform[:3]=='win'), "can't easily test on this system") class SelectTestCase(unittest.TestCase): diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 1a60fef8a428b7..e798645a5ca669 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -29,6 +29,8 @@ import asyncore import smtpd +support.requires_working_socket(module=True) + HOST = socket_helper.HOST if sys.platform == 'darwin': diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 53aa5e90fa25cb..97cc6260c3c2a5 100755 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -37,6 +37,8 @@ except ImportError: fcntl = None +support.requires_working_socket(module=True) + HOST = socket_helper.HOST # test unicode string and carriage return MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index fe6f7da0fd7581..85d6bdf7221e39 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -8,6 +8,7 @@ from functools import wraps import asyncio +support.requires_working_socket(module=True) class tracecontext: """Context manager that traces its enter and exit.""" diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py index 41c4fcd4195e3a..b50df1459d1f4c 100644 --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -8,6 +8,8 @@ from test.support import socket_helper import unittest +support.requires_working_socket(module=True) + HOST = socket_helper.HOST def server(evt, serv): diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index a4772a5b1d9440..46a0ab1d83e60e 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -24,6 +24,8 @@ import urllib.error import http.client +support.requires_working_socket(module=True) + # XXX # Request # CacheFTPHandler (hard to write) diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py index 1b2baf2f366b56..36314312ac0eba 100644 --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -8,6 +8,7 @@ import unittest import hashlib +from test import support from test.support import hashlib_helper from test.support import threading_helper from test.support import warnings_helper @@ -17,6 +18,8 @@ except ImportError: ssl = None +support.requires_working_socket(module=True) + here = os.path.dirname(__file__) # Self-signed cert file for 'localhost' CERT_localhost = os.path.join(here, 'keycert.pem') diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 1f06f5fdf483e9..6c4601ddaddcbd 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -25,6 +25,8 @@ except ImportError: gzip = None +support.requires_working_socket(module=True) + alist = [{'astring': 'foo@bar.baz.spam', 'afloat': 7283.43, 'anint': 2**20, diff --git a/Lib/unittest/test/__init__.py b/Lib/unittest/test/__init__.py index cdae8a7442785a..143f4ab5a3d878 100644 --- a/Lib/unittest/test/__init__.py +++ b/Lib/unittest/test/__init__.py @@ -11,7 +11,10 @@ def suite(): for fn in os.listdir(here): if fn.startswith("test") and fn.endswith(".py"): modname = "unittest.test." + fn[:-3] - __import__(modname) + try: + __import__(modname) + except unittest.SkipTest: + continue module = sys.modules[modname] suite.addTest(loader.loadTestsFromModule(module)) suite.addTest(loader.loadTestsFromName('unittest.test.testmock')) diff --git a/Lib/unittest/test/test_async_case.py b/Lib/unittest/test/test_async_case.py index 7dc8a6bffa019e..a48140829cc219 100644 --- a/Lib/unittest/test/test_async_case.py +++ b/Lib/unittest/test/test_async_case.py @@ -3,6 +3,8 @@ import unittest from test import support +support.requires_working_socket(module=True) + class MyException(Exception): pass diff --git a/Lib/unittest/test/test_program.py b/Lib/unittest/test/test_program.py index fa9e6291caaf56..126497aa56656d 100644 --- a/Lib/unittest/test/test_program.py +++ b/Lib/unittest/test/test_program.py @@ -196,6 +196,7 @@ def run(self, test): return RESULT +@support.requires_subprocess() class TestCommandLineArgs(unittest.TestCase): def setUp(self): diff --git a/Lib/unittest/test/test_runner.py b/Lib/unittest/test/test_runner.py index c487e9ec4efcbf..18062ae5a58710 100644 --- a/Lib/unittest/test/test_runner.py +++ b/Lib/unittest/test/test_runner.py @@ -3,6 +3,7 @@ import sys import pickle import subprocess +from test import support import unittest from unittest.case import _Outcome @@ -1139,6 +1140,7 @@ def MockResultClass(*args): expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY) self.assertEqual(runner._makeResult(), expectedresult) + @support.requires_subprocess() def test_warnings(self): """ Check that warnings argument of TextTestRunner correctly affects the diff --git a/Lib/unittest/test/testmock/testasync.py b/Lib/unittest/test/testmock/testasync.py index 122e6956635d57..1bab671acdef18 100644 --- a/Lib/unittest/test/testmock/testasync.py +++ b/Lib/unittest/test/testmock/testasync.py @@ -4,6 +4,9 @@ import re import unittest from contextlib import contextmanager +from test import support + +support.requires_working_socket(module=True) from asyncio import run, iscoroutinefunction from unittest import IsolatedAsyncioTestCase From 2face9714bfd95506ee9d2fc9c6acecec26a6ff1 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 19 Mar 2022 10:25:12 +0100 Subject: [PATCH 09/13] blurb --- Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst diff --git a/Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst b/Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst new file mode 100644 index 00000000000000..c10c0e5ff48ecf --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst @@ -0,0 +1,2 @@ +The test suite is now passing on Emscripten platform. All fork, socket, +subprocess-based tests are skipped. From c6c41f36be1afcd8a7d9ee22d68f4e758873f406 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 19 Mar 2022 10:47:25 +0100 Subject: [PATCH 10/13] Fix doctest line number --- Lib/test/test_doctest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 49347626a61241..8616aeddc1d5d5 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -460,7 +460,7 @@ def basics(): r""" >>> tests = finder.find(sample_func) >>> print(tests) # doctest: +ELLIPSIS - [] + [] The exact name depends on how test_doctest was invoked, so allow for leading path components. From 475c127a83ded38a1f621728731caa439c70762b Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 21 Mar 2022 16:23:21 +0100 Subject: [PATCH 11/13] Fix LTO build, prepare for dlopen() side modules --- Makefile.pre.in | 2 +- configure | 41 +++++++++++++++++++++++++++++++++++++++-- configure.ac | 42 ++++++++++++++++++++++++++++++++++++++++-- setup.py | 5 +++++ 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index c4034dc248c65b..4b9aab0a284ced 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2352,7 +2352,7 @@ clean-retain-profile: pycremoval -rm -f pybuilddir.txt -rm -f Lib/lib2to3/*Grammar*.pickle -rm -f _bootstrap_python - -rm -f python.html python*.js python.data + -rm -f python.html python*.js python.data python*.symbols python*.map -rm -rf $(WASM_STDLIB) -rm -f Programs/_testembed Programs/_freeze_module -rm -f Python/deepfreeze/*.[co] diff --git a/configure b/configure index 5fa6efaab4fb7c..5ebcadd64239d9 100755 --- a/configure +++ b/configure @@ -7396,6 +7396,13 @@ $as_echo "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;} ;; esac ;; + *emcc*) + if test "$Py_LTO_POLICY" != "default"; then + as_fn_error $? "emcc supports only default lto." "$LINENO" 5 + fi + LTOFLAGS="-flto" + LTOCFLAGS="-flto" + ;; *gcc*) if test $Py_LTO_POLICY = thin then @@ -7717,17 +7724,34 @@ then fi # WASM flags +# TODO: Add -s MAIN_MODULE=2 for dlopen() support. +# The option disables code elimination, which increases code size of main +# binary. All objects must be built with -fPIC. case $ac_sys_system/$ac_sys_emscripten_target in #( Emscripten/browser) : - LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1 -s ALLOW_MEMORY_GROWTH=1 --preload-file \$(WASM_ASSETS_DIR)" + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ALLOW_MEMORY_GROWTH=1" + LINKFORSHARED="--preload-file \$(WASM_ASSETS_DIR)" WASM_ASSETS_DIR=".\$(prefix)" WASM_STDLIB="\$(WASM_ASSETS_DIR)/local/lib/python\$(VERSION)/os.py" + if test "$Py_DEBUG" = 'true'; then + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1" + LINKFORSHARED="$LINKFORSHARED -gsource-map --emit-symbol-map" + else + LINKFORSHARED="$LINKFORSHARED -O2 -g0" + fi ;; #( Emscripten/node) : - LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1 -s ALLOW_MEMORY_GROWTH=1 -s NODERAWFS=1 -s EXIT_RUNTIME=1 -s USE_PTHREADS -s PROXY_TO_PTHREAD" + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ALLOW_MEMORY_GROWTH=1 -s NODERAWFS=1 -s USE_PTHREADS=1" + LINKFORSHARED="-s PROXY_TO_PTHREAD=1 -s EXIT_RUNTIME=1" CFLAGS_NODIST="$CFLAGS_NODIST -pthread" + if test "$Py_DEBUG" = 'true'; then + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1" + LINKFORSHARED="$LINKFORSHARED -gseparate-dwarf --emit-symbol-map" + else + LINKFORSHARED="$LINKFORSHARED -O2 -gseparate-dwarf" + fi ;; #( WASI/*) : @@ -10403,6 +10427,10 @@ then Linux*|GNU*|QNX*|VxWorks*|Haiku*) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; + Emscripten*) + LDSHARED='$(CC) -shared -s SIDE_MODULE=1' + LDCXXSHARED='$(CXX) -shared -s SIDE_MODULE=1' + ;; FreeBSD*) if [ "`$CC -dM -E - &6; } fi +if test "$have_zlib" = "yes" -a "$ac_sys_system" = "Emscripten" -a "$ZLIB_LIBS" = "-lz"; then + ZLIB_LIBS="-s USE_ZLIB=1" +fi + if test "x$have_zlib" = xyes; then : BINASCII_CFLAGS="-DUSE_ZLIB_CRC32 $ZLIB_CFLAGS" @@ -15292,6 +15324,11 @@ $as_echo "yes" >&6; } have_bzip2=yes fi +if test "$have_bzip2" = "yes" -a "$ac_sys_system" = "Emscripten" -a "$BZIP2_LIBS" = "-lbz2"; then + BZIP2_LIBS="-s USE_BZIP2=1" +fi + + pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBLZMA" >&5 diff --git a/configure.ac b/configure.ac index 7a37ad279d0fcb..4afc898e81d503 100644 --- a/configure.ac +++ b/configure.ac @@ -1659,6 +1659,13 @@ if test "$Py_LTO" = 'true' ; then ;; esac ;; + *emcc*) + if test "$Py_LTO_POLICY" != "default"; then + AC_MSG_ERROR([emcc supports only default lto.]) + fi + LTOFLAGS="-flto" + LTOCFLAGS="-flto" + ;; *gcc*) if test $Py_LTO_POLICY = thin then @@ -1861,15 +1868,33 @@ then fi # WASM flags +# TODO: Add -s MAIN_MODULE=2 for dlopen() support. +# The option disables code elimination, which increases code size of main +# binary. All objects must be built with -fPIC. AS_CASE([$ac_sys_system/$ac_sys_emscripten_target], [Emscripten/browser], [ - LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1 -s ALLOW_MEMORY_GROWTH=1 --preload-file \$(WASM_ASSETS_DIR)" + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ALLOW_MEMORY_GROWTH=1" + LINKFORSHARED="--preload-file \$(WASM_ASSETS_DIR)" WASM_ASSETS_DIR=".\$(prefix)" WASM_STDLIB="\$(WASM_ASSETS_DIR)/local/lib/python\$(VERSION)/os.py" + dnl separate-dwarf does not seem to work in Chrome DevTools Support. + if test "$Py_DEBUG" = 'true'; then + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1" + LINKFORSHARED="$LINKFORSHARED -gsource-map --emit-symbol-map" + else + LINKFORSHARED="$LINKFORSHARED -O2 -g0" + fi ], [Emscripten/node], [ - LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1 -s ALLOW_MEMORY_GROWTH=1 -s NODERAWFS=1 -s EXIT_RUNTIME=1 -s USE_PTHREADS -s PROXY_TO_PTHREAD" + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ALLOW_MEMORY_GROWTH=1 -s NODERAWFS=1 -s USE_PTHREADS=1" + LINKFORSHARED="-s PROXY_TO_PTHREAD=1 -s EXIT_RUNTIME=1" CFLAGS_NODIST="$CFLAGS_NODIST -pthread" + if test "$Py_DEBUG" = 'true'; then + LDFLAGS_NODIST="$LDFLAGS_NODIST -s ASSERTIONS=1" + LINKFORSHARED="$LINKFORSHARED -gseparate-dwarf --emit-symbol-map" + else + LINKFORSHARED="$LINKFORSHARED -O2 -gseparate-dwarf" + fi ], [WASI/*], [ AC_DEFINE([_WASI_EMULATED_SIGNAL], [1], [Define to 1 if you want to emulate signals on WASI]) @@ -2880,6 +2905,10 @@ then Linux*|GNU*|QNX*|VxWorks*|Haiku*) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; + Emscripten*) + LDSHARED='$(CC) -shared -s SIDE_MODULE=1' + LDCXXSHARED='$(CXX) -shared -s SIDE_MODULE=1' + ;; FreeBSD*) if [[ "`$CC -dM -E - = 1.2.0], [ ], [have_zlib=no]) ]) +if test "$have_zlib" = "yes" -a "$ac_sys_system" = "Emscripten" -a "$ZLIB_LIBS" = "-lz"; then + ZLIB_LIBS="-s USE_ZLIB=1" +fi + dnl binascii can use zlib for optimized crc32. AS_VAR_IF([have_zlib], [yes], [ BINASCII_CFLAGS="-DUSE_ZLIB_CRC32 $ZLIB_CFLAGS" @@ -4372,6 +4405,11 @@ PKG_CHECK_MODULES([BZIP2], [bzip2], [have_bzip2=yes], [ ], [have_bzip2=no]) ]) +if test "$have_bzip2" = "yes" -a "$ac_sys_system" = "Emscripten" -a "$BZIP2_LIBS" = "-lbz2"; then + BZIP2_LIBS="-s USE_BZIP2=1" +fi + + PKG_CHECK_MODULES([LIBLZMA], [liblzma], [have_liblzma=yes], [ AC_CHECK_HEADERS([lzma.h], [ WITH_SAVE_ENV([ diff --git a/setup.py b/setup.py index c3cf2417bc429d..070ae9822bd5eb 100644 --- a/setup.py +++ b/setup.py @@ -84,10 +84,15 @@ def get_platform(): MACOS = (HOST_PLATFORM == 'darwin') AIX = (HOST_PLATFORM.startswith('aix')) VXWORKS = ('vxworks' in HOST_PLATFORM) +EMSCRIPTEN = HOST_PLATFORM == 'emscripten-wasm32' CC = os.environ.get("CC") if not CC: CC = sysconfig.get_config_var("CC") +if EMSCRIPTEN: + # emcc is a Python script from a different Python interpreter. + os.environ.pop("PYTHONPATH", None) + SUMMARY = """ Python is an interpreted, interactive, object-oriented programming From b14c9da120f03b91509017981e885fca853b555b Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 22 Mar 2022 08:33:56 +0100 Subject: [PATCH 12/13] Apply suggestions from code review Co-authored-by: Brett Cannon --- .../next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst b/Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst index c10c0e5ff48ecf..2572c27a8211ad 100644 --- a/Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst +++ b/Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst @@ -1,2 +1,2 @@ -The test suite is now passing on Emscripten platform. All fork, socket, -subprocess-based tests are skipped. +The test suite is now passing on the Emscripten platform. All fork, socket, +and subprocess-based tests are skipped. From 3db0a4879e8e405b59728c8ab41adeedad5eca33 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 22 Mar 2022 10:23:06 +0100 Subject: [PATCH 13/13] Document requires_working_socket --- Lib/test/support/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index cdf4a1b8f110e1..c5666d66f47825 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -525,6 +525,10 @@ def requires_subprocess(): has_socket_support = not is_emscripten and not is_wasi def requires_working_socket(*, module=False): + """Skip tests or modules that require working sockets + + Can be used as a function/class decorator or to skip an entire module. + """ msg = "requires socket support" if module: if not has_socket_support: