Skip to content

Commit a224038

Browse files
committed
bpo-40280: Add requires_fork test helper
1 parent 5cd9a16 commit a224038

10 files changed

+34
-18
lines changed

Lib/test/support/__init__.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@
3939
"requires_gzip", "requires_bz2", "requires_lzma",
4040
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
4141
"requires_IEEE_754", "requires_zlib",
42+
"has_fork_support", "requires_fork",
4243
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
4344
"check__all__", "skip_if_buggy_ucrt_strfptime",
4445
"check_disallow_instantiation",
4546
# sys
46-
"is_jython", "is_android", "check_impl_detail", "unix_shell",
47-
"setswitchinterval",
47+
"is_jython", "is_android", "is_emscripten",
48+
"check_impl_detail", "unix_shell", "setswitchinterval",
4849
# network
4950
"open_urlresource",
5051
# processes
@@ -466,6 +467,15 @@ def requires_debug_ranges(reason='requires co_positions / debug_ranges'):
466467
else:
467468
unix_shell = None
468469

470+
# wasm32-emscripten is POSIX-like but does not provide a
471+
# working fork() or subprocess API.
472+
is_emscripten = sys.platform == "emscripten"
473+
474+
has_fork_support = hasattr(os, "fork") and not is_emscripten
475+
476+
def requires_fork():
477+
return unittest.skipUnless(has_fork_support, "requires working os.fork()")
478+
469479
# Define the URL of a dedicated HTTP server for the network tests.
470480
# The URL must use clear-text HTTP: no redirection to encrypted HTTPS.
471481
TEST_HTTP_URL = "http://www.pythontest.net"

Lib/test/test_fork1.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515

1616
# Skip test if fork does not exist.
17-
support.get_attribute(os, 'fork')
17+
if not support.has_fork_support:
18+
raise unittest.SkipTest("test module requires working os.fork")
19+
1820

1921
class ForkTest(ForkWait):
2022
def test_threaded_import_lock_fork(self):

Lib/test/test_random.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1293,7 +1293,7 @@ def test__all__(self):
12931293
# tests validity but not completeness of the __all__ list
12941294
self.assertTrue(set(random.__all__) <= set(dir(random)))
12951295

1296-
@unittest.skipUnless(hasattr(os, "fork"), "fork() required")
1296+
@test.support.requires_fork()
12971297
def test_after_fork(self):
12981298
# Test the global Random instance gets reseeded in child
12991299
r, w = os.pipe()

Lib/test/test_support.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def test_temp_dir__existing_dir__quiet_true(self):
198198
f'temporary directory {path!r}: '),
199199
warn)
200200

201-
@unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork")
201+
@support.requires_fork()
202202
def test_temp_dir__forked_child(self):
203203
"""Test that a forked child process does not remove the directory."""
204204
# See bpo-30028 for details.
@@ -447,6 +447,7 @@ def test_check__all__(self):
447447

448448
@unittest.skipUnless(hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG'),
449449
'need os.waitpid() and os.WNOHANG')
450+
@support.requires_fork()
450451
def test_reap_children(self):
451452
# Make sure that there is no other pending child process
452453
support.reap_children()

Lib/test/test_sysconfig.py

+2
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,8 @@ def test_SO_value(self):
412412
'EXT_SUFFIX required for this test')
413413
def test_EXT_SUFFIX_in_vars(self):
414414
import _imp
415+
if not _imp.extension_suffixes():
416+
self.skipTest("stub loader has no suffixes")
415417
vars = sysconfig.get_config_vars()
416418
self.assertIsNotNone(vars['SO'])
417419
self.assertEqual(vars['SO'], vars['EXT_SUFFIX'])

Lib/test/test_tempfile.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,7 @@ def supports_iter(self):
198198
if i == 20:
199199
break
200200

201-
@unittest.skipUnless(hasattr(os, 'fork'),
202-
"os.fork is required for this test")
201+
@support.requires_fork()
203202
def test_process_awareness(self):
204203
# ensure that the random source differs between
205204
# child and parent.

Lib/test/test_thread.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class TestForkInThread(unittest.TestCase):
224224
def setUp(self):
225225
self.read_fd, self.write_fd = os.pipe()
226226

227-
@unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
227+
@support.requires_fork()
228228
@threading_helper.reap_threads
229229
def test_forkinthread(self):
230230
pid = None

Lib/test/test_threading.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ def test_daemon_param(self):
505505
t = threading.Thread(daemon=True)
506506
self.assertTrue(t.daemon)
507507

508-
@unittest.skipUnless(hasattr(os, 'fork'), 'needs os.fork()')
508+
@support.requires_fork()
509509
def test_fork_at_exit(self):
510510
# bpo-42350: Calling os.fork() after threading._shutdown() must
511511
# not log an error.
@@ -533,7 +533,7 @@ def exit_handler():
533533
self.assertEqual(out, b'')
534534
self.assertEqual(err.rstrip(), b'child process ok')
535535

536-
@unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()')
536+
@support.requires_fork()
537537
def test_dummy_thread_after_fork(self):
538538
# Issue #14308: a dummy thread in the active list doesn't mess up
539539
# the after-fork mechanism.
@@ -560,7 +560,7 @@ def background_thread(evt):
560560
self.assertEqual(out, b'')
561561
self.assertEqual(err, b'')
562562

563-
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
563+
@support.requires_fork()
564564
def test_is_alive_after_fork(self):
565565
# Try hard to trigger #18418: is_alive() could sometimes be True on
566566
# threads that vanished after a fork.
@@ -594,7 +594,7 @@ def f():
594594
th.start()
595595
th.join()
596596

597-
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
597+
@support.requires_fork()
598598
@unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()")
599599
def test_main_thread_after_fork(self):
600600
code = """if 1:
@@ -616,7 +616,7 @@ def test_main_thread_after_fork(self):
616616
self.assertEqual(data, "MainThread\nTrue\nTrue\n")
617617

618618
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
619-
@unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
619+
@support.requires_fork()
620620
@unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()")
621621
def test_main_thread_after_fork_from_nonmain_thread(self):
622622
code = """if 1:
@@ -993,7 +993,7 @@ def test_1_join_on_shutdown(self):
993993
"""
994994
self._run_and_join(script)
995995

996-
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
996+
@support.requires_fork()
997997
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
998998
def test_2_join_in_forked_process(self):
999999
# Like the test above, but from a forked interpreter
@@ -1014,7 +1014,7 @@ def test_2_join_in_forked_process(self):
10141014
"""
10151015
self._run_and_join(script)
10161016

1017-
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
1017+
@support.requires_fork()
10181018
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
10191019
def test_3_join_in_forked_from_thread(self):
10201020
# Like the test above, but fork() was called from a worker thread
@@ -1085,7 +1085,7 @@ def main():
10851085
rc, out, err = assert_python_ok('-c', script)
10861086
self.assertFalse(err)
10871087

1088-
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
1088+
@support.requires_fork()
10891089
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
10901090
def test_reinit_tls_after_fork(self):
10911091
# Issue #13817: fork() would deadlock in a multithreaded program with
@@ -1109,7 +1109,7 @@ def do_fork_and_wait():
11091109
for t in threads:
11101110
t.join()
11111111

1112-
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
1112+
@support.requires_fork()
11131113
def test_clear_threads_states_after_fork(self):
11141114
# Issue #17094: check that threads states are cleared after fork()
11151115

Lib/test/test_uuid.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ def test_uuid5(self):
647647
equal(u, self.uuid.UUID(v))
648648
equal(str(u), v)
649649

650-
@unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
650+
@support.requires_fork()
651651
def testIssue8621(self):
652652
# On at least some versions of OSX self.uuid.uuid4 generates
653653
# the same sequence of UUIDs in the parent and any
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :func:`test.support.requires_fork` decorators to mark tests that require
2+
a working :func:`os.fork`.

0 commit comments

Comments
 (0)