]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40280: Skip socket, fork, subprocess tests on Emscripten (GH-31986)
authorChristian Heimes <christian@python.org>
Tue, 22 Mar 2022 10:04:36 +0000 (12:04 +0200)
committerGitHub <noreply@github.com>
Tue, 22 Mar 2022 10:04:36 +0000 (03:04 -0700)
- Add requires_fork and requires_subprocess to more tests
- Skip extension import tests if dlopen is not available
- Don't assume that _testcapi is a shared extension
- Skip a lot of socket tests that don't work on Emscripten
- Skip mmap tests, mmap emulation is incomplete
- venv does not work yet
- Cannot get libc from executable

The "entire" test suite is now passing on Emscripten with EMSDK from git head (91 suites are skipped).

52 files changed:
Lib/test/lock_tests.py
Lib/test/pythoninfo.py
Lib/test/support/__init__.py
Lib/test/test_asyncgen.py
Lib/test/test_asynchat.py
Lib/test/test_asyncio/__init__.py
Lib/test/test_asyncore.py
Lib/test/test_contextlib_async.py
Lib/test/test_doctest.py
Lib/test/test_docxmlrpc.py
Lib/test/test_ftplib.py
Lib/test/test_httplib.py
Lib/test/test_httpservers.py
Lib/test/test_imaplib.py
Lib/test/test_import/__init__.py
Lib/test/test_importlib/extension/test_finder.py
Lib/test/test_importlib/extension/test_loader.py
Lib/test/test_json/test_tool.py
Lib/test/test_logging.py
Lib/test/test_mailbox.py
Lib/test/test_mmap.py
Lib/test/test_pdb.py
Lib/test/test_peg_generator/test_c_parser.py
Lib/test/test_platform.py
Lib/test/test_poll.py
Lib/test/test_poplib.py
Lib/test/test_pydoc.py
Lib/test/test_robotparser.py
Lib/test/test_select.py
Lib/test/test_selectors.py
Lib/test/test_smtplib.py
Lib/test/test_socket.py
Lib/test/test_socketserver.py
Lib/test/test_sys_settrace.py
Lib/test/test_telnetlib.py
Lib/test/test_tools/__init__.py
Lib/test/test_urllib2.py
Lib/test/test_urllib2_localnet.py
Lib/test/test_venv.py
Lib/test/test_wait3.py
Lib/test/test_wait4.py
Lib/test/test_xmlrpc.py
Lib/unittest/test/__init__.py
Lib/unittest/test/test_async_case.py
Lib/unittest/test/test_program.py
Lib/unittest/test/test_runner.py
Lib/unittest/test/testmock/testasync.py
Makefile.pre.in
Misc/NEWS.d/next/Tests/2022-03-19-10-25-04.bpo-40280.wBRSel.rst [new file with mode: 0644]
configure
configure.ac
setup.py

index d82629368dff8a5f10cc5e85b1f9a586de5b8818..f16c7ed952cf55379d74c2ef19d7aa7b9278e21f 100644 (file)
@@ -15,7 +15,7 @@ from test import support
 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)")
 
index d15a11c80b649af4890bcc1afe472ecb6b981f57..b00830c279e8763af53dc6289bdacfc0083e75c2 100644 (file)
@@ -6,6 +6,7 @@ import errno
 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
index fc1b86bebcd1aec373c145a97e4424ceef132452..c5666d66f4782520ebdce5a09bae99856fb1c209 100644 (file)
@@ -42,6 +42,7 @@ __all__ = [
     "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,21 @@ 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):
+    """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:
+            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":
index 473bce484b47b022f06a2d15f5f8c1e81766e940..fb22f411c2e2967f7674759c52cdbe176c897e29 100644 (file)
@@ -4,10 +4,12 @@ import unittest
 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()
 
 
index 973ac1f7d97c9b083aca6c0b98c4ee524f210009..d28d67732e7886f31cf50ff9461d4984b2a4c4c8 100644 (file)
@@ -18,6 +18,8 @@ with warnings.catch_warnings():
     import asynchat
     import asyncore
 
+support.requires_working_socket(module=True)
+
 HOST = socket_helper.HOST
 SERVER_QUIT = b'QUIT\n'
 
index 5d415044d7dc6629de0b24f4bc865423ecea2c05..ab0b5aa9489257cd0e7de66296eb61aa8a7f434f 100644 (file)
@@ -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')
index ecd1e120ecb515c53ff315206c36d16b98c5fb37..e3f31bd06d0c3aa335798a80a80646b19098502e 100644 (file)
@@ -18,6 +18,8 @@ from io import BytesIO
 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)
index c16c7ecd19a2592b5a40db45e0324a812e874c0a..462e05cc79aec80818fe45666211c1c4a74afb14 100644 (file)
@@ -8,6 +8,7 @@ import unittest
 
 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."""
index 407a14c7ddf67e2e06806a97cc34bcd33bc4062e..8616aeddc1d5d54c8da4ef430b5fec27c92f0744 100644 (file)
@@ -18,6 +18,11 @@ import shutil
 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.
 
@@ -455,7 +460,7 @@ We'll simulate a __file__ attr that ends in pyc:
     >>> tests = finder.find(sample_func)
 
     >>> print(tests)  # doctest: +ELLIPSIS
-    [<DocTest sample_func from test_doctest.py:28 (1 example)>]
+    [<DocTest sample_func from test_doctest.py:33 (1 example)>]
 
 The exact name depends on how test_doctest was invoked, so allow for
 leading path components.
index 9a06be458550215137b9410c4485f99608a2d8d0..89d80091850f5e6bfec022fc6a71d71320774f70 100644 (file)
@@ -4,6 +4,9 @@ import re
 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
index 2f5cc06ca4b9a56b57a9a6f227c71bf62fb8b858..2794fccfe7c72d10a32768128c7e50b03953c54d 100644 (file)
@@ -29,6 +29,7 @@ with warnings.catch_warnings():
     import asyncore
     import asynchat
 
+support.requires_working_socket(module=True)
 
 TIMEOUT = support.LOOPBACK_TIMEOUT
 DEFAULT_ENCODING = 'utf-8'
index 8265b8d1d6d2dd77c2977525325d2e75c56277de..15dab0356f5e35e759ea2c5c8800dea564baf87f 100644 (file)
@@ -19,6 +19,7 @@ from test.support import os_helper
 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'
index 1cc020f63539decafddf10df24ccab0715cad4f7..d20b45e8e02f88a2f151ada78fd93212adb9db69 100644 (file)
@@ -33,6 +33,7 @@ from test import support
 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):
index 30b553746af11a1180f90d41cfb2fae3b39ab0fe..ff13edea2d1e4aae97e3f43655d32db0386b7a20 100644 (file)
@@ -11,7 +11,8 @@ import threading
 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 @@ try:
 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")
 
index 8857fd5000bb145c0a37b5ee28d166430d508760..7cca9f9d60ab6ab827028bbdc3e5d141af08a63d 100644 (file)
@@ -20,7 +20,7 @@ from unittest import mock
 
 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 @@ class ImportTests(unittest.TestCase):
         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):
index 140f20657f73637d1d4935db119830359c6fe231..b6663a4484550237d6e8274b438bcdebb3359dc2 100644 (file)
@@ -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,
index e7a88a8f5e3218e9eb208d07d7c62a5c35eb9519..5080009bee32ee0942940a17288586873bf7aba1 100644 (file)
@@ -12,11 +12,14 @@ import importlib.util
 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)
index 1d7fca6efb1cc725aae787fe4a0df421d598eb85..2b63810d53981e97fdc13d83942d5bfef719e0ff 100644 (file)
@@ -10,6 +10,7 @@ from test.support import os_helper
 from test.support.script_helper import assert_python_ok
 
 
+@support.requires_subprocess()
 class TestTool(unittest.TestCase):
     data = """
 
index be193dcdacf4f0fa36d1f1c51d89d0133880aa1c..5f72a6dd5871ae5f06333868941553e7cd518a24 100644 (file)
@@ -75,6 +75,7 @@ try:
 except ImportError:
     pass
 
+
 class BaseTest(unittest.TestCase):
 
     """Base class for logging tests."""
@@ -626,6 +627,9 @@ class HandlerTest(BaseTest):
             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 +1062,7 @@ if hasattr(socket, "AF_UNIX"):
 
 # - end of server_helper section
 
+@support.requires_working_socket()
 class SMTPHandlerTest(BaseTest):
     # bpo-14314, bpo-19665, bpo-34092: don't wait forever
     TIMEOUT = support.LONG_TIMEOUT
@@ -1681,6 +1686,7 @@ class ConfigFileTest(BaseTest):
             os.unlink(fn)
 
 
+@support.requires_working_socket()
 class SocketHandlerTest(BaseTest):
 
     """Test for SocketHandler objects."""
@@ -1795,6 +1801,7 @@ class UnixSocketHandlerTest(SocketHandlerTest):
         SocketHandlerTest.tearDown(self)
         os_helper.unlink(self.address)
 
+@support.requires_working_socket()
 class DatagramHandlerTest(BaseTest):
 
     """Test for DatagramHandler."""
@@ -1876,6 +1883,7 @@ class UnixDatagramHandlerTest(DatagramHandlerTest):
         DatagramHandlerTest.tearDown(self)
         os_helper.unlink(self.address)
 
+@support.requires_working_socket()
 class SysLogHandlerTest(BaseTest):
 
     """Test for SysLogHandler using UDP."""
@@ -1985,6 +1993,7 @@ class IPv6SysLogHandlerTest(SysLogHandlerTest):
         self.server_class.address_family = socket.AF_INET
         super(IPv6SysLogHandlerTest, self).tearDown()
 
+@support.requires_working_socket()
 class HTTPHandlerTest(BaseTest):
     """Test for HTTPHandler."""
 
@@ -3261,6 +3270,7 @@ class ConfigDictTest(BaseTest):
             logging.config.stopListening()
             threading_helper.join_thread(t)
 
+    @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))
@@ -3280,6 +3290,7 @@ class ConfigDictTest(BaseTest):
                 ('ERROR', '4'),
             ], stream=output)
 
+    @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))
@@ -3294,6 +3305,7 @@ class ConfigDictTest(BaseTest):
             # Original logger output is empty.
             self.assert_log_lines([])
 
+    @support.requires_working_socket()
     def test_listen_verify(self):
 
         def verify_fail(stuff):
index 604fc4525f53e9f3ddae4de6f1ff21956628328f..20c460e300cc9de39e13bafc0b42f6a4f4e026a8 100644 (file)
@@ -1061,7 +1061,7 @@ class _TestMboxMMDF(_TestSingleFile):
             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,
index 014171cbb4911bc6a2a3f8abc6ef9cd7d59a9533..213a44d56f37b3a2acb84811963baba81e16afa5 100644 (file)
@@ -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):
index d2bf3dc90ed239e38e2f0892e6ab5dba687104af..bfa2cc92d25147f875be5ab13b1c6e23299e79b3 100644 (file)
@@ -13,6 +13,7 @@ import linecache
 
 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)
index b761bd493f52c7d581504fa1cc6d04fa4ec7afcf..51a4f7d7c07a081b37ca49159a402529b3f2e064 100644 (file)
@@ -70,6 +70,7 @@ unittest.main()
 """
 
 
+@support.requires_subprocess()
 class TestCParser(unittest.TestCase):
     def setUp(self):
         self._backup_config_vars = dict(sysconfig._CONFIG_VARS)
index d70ef155271f51e613d10e290f9c2210444bdcac..9b2cd201f3c2fe69bb9faa8958644d05d370b7bb 100644 (file)
@@ -364,6 +364,7 @@ class PlatformTest(unittest.TestCase):
             # 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 \
index ae3ffc77e9924ae9318859602004b2e19f8327b5..7d542b5cfd783ddc3ee554f8582c78746b6c3254 100644 (file)
@@ -7,7 +7,9 @@ import select
 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 @@ try:
 except AttributeError:
     raise unittest.SkipTest("select.poll not defined")
 
+requires_working_socket(module=True)
 
 def find_ready_matching(ready, flag):
     match = []
index 1220ca32ef82e8fb760cd6aac6779ece879a514d..57ccc541b81fe1babe27af41366c4f078283519b 100644 (file)
@@ -22,6 +22,8 @@ with warnings.catch_warnings():
     import asynchat
     import asyncore
 
+test_support.requires_working_socket(module=True)
+
 HOST = socket_helper.HOST
 PORT = 0
 
index 7cedf76fb3af425d1d303749b559f159ac555366..e2dab1207172d78ff5cae3fbe38a62f95920ad2d 100644 (file)
@@ -27,7 +27,7 @@ from test.support import os_helper
 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 @@ foo
         )
 
 
+@unittest.skipIf(is_emscripten, "Socket server not available on Emscripten.")
 class PydocServerTest(unittest.TestCase):
     """Tests for pydoc._start_server"""
 
index b0bed431d4b059f6e4e5d24de9ebdf43b9389247..08bdf59d333d4e8fa4bb7effe1e4367189471f93 100644 (file)
@@ -308,6 +308,9 @@ class RobotHandler(BaseHTTPRequestHandler):
         pass
 
 
+@unittest.skipIf(
+    support.is_emscripten, "Socket server not available on Emscripten."
+)
 class PasswordProtectedSiteTestCase(unittest.TestCase):
 
     def setUp(self):
index 8b59321121e49454cba266f15a8553f33ed3d9e7..ca2a9d9d24dabc710d29c6039c46d002ca58804a 100644 (file)
@@ -7,6 +7,8 @@ import textwrap
 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):
index fe6b725a4bd05065eaf2386b16aa8ac68b14424f..c927331d438b0cb5599def38afb24fd2c677ea30 100644 (file)
@@ -19,6 +19,10 @@ except ImportError:
     resource = None
 
 
+if support.is_emscripten:
+    raise unittest.SkipTest("Cannot create socketpair on Emscripten.")
+
+
 if hasattr(socket, 'socketpair'):
     socketpair = socket.socketpair
 else:
index 1a60fef8a428b75854f120e30144060c4f4a262f..e798645a5ca66923f399cba9a03d24d31ad06566 100644 (file)
@@ -29,6 +29,8 @@ with warnings.catch_warnings():
     import asyncore
     import smtpd
 
+support.requires_working_socket(module=True)
+
 HOST = socket_helper.HOST
 
 if sys.platform == 'darwin':
index 53aa5e90fa25cbcc5cd9f2a1c3cf029b5d4afa27..97cc6260c3c2a51ec210349c72d327673a2096a9 100755 (executable)
@@ -37,6 +37,8 @@ try:
 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')
index 211321f37617e9a7b61af67d7e947e96e88dc1a2..c498d3d12e24a78c3e688a71d5f6a4b54b84b3a4 100644 (file)
@@ -28,7 +28,7 @@ HOST = socket_helper.HOST
 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):
index fe6f7da0fd75810d7a55f3ee06a54758f05b6691..85d6bdf7221e39427470e32cb816228d2e291ab7 100644 (file)
@@ -8,6 +8,7 @@ import gc
 from functools import wraps
 import asyncio
 
+support.requires_working_socket(module=True)
 
 class tracecontext:
     """Context manager that traces its enter and exit."""
index 41c4fcd4195e3aada7a8cf15da790d2a336c6e70..b50df1459d1f4c3d11f248b5901b3cfabfa3f206 100644 (file)
@@ -8,6 +8,8 @@ from test import support
 from test.support import socket_helper
 import unittest
 
+support.requires_working_socket(module=True)
+
 HOST = socket_helper.HOST
 
 def server(evt, serv):
index 34b0d3b8fb3eb08dc505ad66f00af7b73d33931c..2102b9fceff568c0bb2e8d0a567f30b28c103faf 100644 (file)
@@ -13,6 +13,10 @@ if support.check_sanitizer(address=True, memory=True):
     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(                 # <src/install dir>
             os.path.dirname(                # Lib
index a4772a5b1d94401709fd461aaea6840663293016..46a0ab1d83e60eaaa049f16f665b8c0a1e2857d4 100644 (file)
@@ -24,6 +24,8 @@ from urllib.parse import urlparse
 import urllib.error
 import http.client
 
+support.requires_working_socket(module=True)
+
 # XXX
 # Request
 # CacheFTPHandler (hard to write)
index 1b2baf2f366b560067317a7e94adc3d85835199c..36314312ac0eba6ef70254e404b0f817b004d16f 100644 (file)
@@ -8,6 +8,7 @@ import threading
 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 @@ try:
 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')
index db812f21dbc56276c61e6e3f7324ede686ccaa26..c91b75493841be3a1be8c36605783354811a8075 100644 (file)
@@ -16,7 +16,7 @@ import sys
 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 @@ requireVenvCreate = unittest.skipUnless(
     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,
index aa166baa400bc7c82fccd7d9127cf0b58ff6bba7..4ec7690ac19bbf3d6ce503426e1c938a1d517279 100644 (file)
@@ -9,8 +9,8 @@ import unittest
 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")
index f8d5e13014f0c13b050b540f63ee34f0b79df7b3..24f1aaec60c56beeffeb968fcca3f99c11f8dc3c 100644 (file)
@@ -9,7 +9,9 @@ from test.fork_wait import ForkWait
 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')
 
 
index 1f06f5fdf483e9d2722cb0e523eb23076a4b33c0..6c4601ddaddcbdee53882e0541f0dd367517aa9e 100644 (file)
@@ -25,6 +25,8 @@ try:
 except ImportError:
     gzip = None
 
+support.requires_working_socket(module=True)
+
 alist = [{'astring': 'foo@bar.baz.spam',
           'afloat': 7283.43,
           'anint': 2**20,
index cdae8a7442785aec74de286883b716173bed18d6..143f4ab5a3d87819a7d74ea40e10553a88ef0db9 100644 (file)
@@ -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'))
index 7dc8a6bffa019e7af35d9c63d0f2e578a4334558..a48140829cc219d5fea329b7d0e2f6fba0599ba9 100644 (file)
@@ -3,6 +3,8 @@ import contextvars
 import unittest
 from test import support
 
+support.requires_working_socket(module=True)
+
 
 class MyException(Exception):
     pass
index fa9e6291caaf56e029a44705e401d7ab1c758579..126497aa56656d33b6597a234fbebe81eb4f6624 100644 (file)
@@ -196,6 +196,7 @@ class FakeRunner(object):
         return RESULT
 
 
+@support.requires_subprocess()
 class TestCommandLineArgs(unittest.TestCase):
 
     def setUp(self):
index c487e9ec4efcbff02fe0c14dc5ea722281ae59e4..18062ae5a58710d3c670ca1e37f8b1f3781347ac 100644 (file)
@@ -3,6 +3,7 @@ import os
 import sys
 import pickle
 import subprocess
+from test import support
 
 import unittest
 from unittest.case import _Outcome
@@ -1139,6 +1140,7 @@ class Test_TextTestRunner(unittest.TestCase):
         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
index 122e6956635d579f4f41ada0562b769ae55ace48..1bab671acdef182f5536c82b47804e981456e6f7 100644 (file)
@@ -4,6 +4,9 @@ import inspect
 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
index c4034dc248c65b9ccfa474b50c35a6ecb47d5883..4b9aab0a284ced217357eb5aa3ec81fe530ecb87 100644 (file)
@@ -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/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 (file)
index 0000000..2572c27
--- /dev/null
@@ -0,0 +1,2 @@
+The test suite is now passing on the Emscripten platform. All fork, socket,
+and subprocess-based tests are skipped.
index 5fa6efaab4fb7c16df6d23a12d3acac19e7936e7..5ebcadd64239d9eac4b99b562a09a77b9ab6671a 100755 (executable)
--- 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 - </dev/null | grep __ELF__`" != "" ]
                then
@@ -15063,6 +15091,10 @@ $as_echo "yes" >&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
index 7a37ad279d0fcba129da389877afe989bf7e4fa6..4afc898e81d503942fe3aa82de0a8885ed3265f5 100644 (file)
@@ -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 - </dev/null | grep __ELF__`" != "" ]]
                then
@@ -4354,6 +4383,10 @@ PKG_CHECK_MODULES([ZLIB], [zlib >= 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([
index c3cf2417bc429d1f70c55f03daa5796645a57556..070ae9822bd5ebe35b78ef6fc87fa088d64d4bd4 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -84,10 +84,15 @@ CYGWIN = (HOST_PLATFORM == 'cygwin')
 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