Skip to content

Commit ddbeb2f

Browse files
authored
bpo-38377: Add support.skip_if_broken_multiprocessing_synchronize() (GH-20944)
On Linux, skip tests using multiprocessing if the current user cannot create a file in /dev/shm/ directory. Add the skip_if_broken_multiprocessing_synchronize() function to the test.support module.
1 parent 2c2a4f3 commit ddbeb2f

File tree

9 files changed

+48
-12
lines changed

9 files changed

+48
-12
lines changed

Doc/library/test.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,14 @@ The :mod:`test.support` module defines the following functions:
919919

920920
.. versionadded:: 3.6
921921

922+
.. function:: skip_if_broken_multiprocessing_synchronize()
923+
924+
Skip tests if the :mod:`multiprocessing.synchronize` module is missing, if
925+
there is no available semaphore implementation, or if creating a lock raises
926+
an :exc:`OSError`.
927+
928+
.. versionadded:: 3.10
929+
922930

923931
The :mod:`test.support` module defines the following classes:
924932

Lib/test/_test_multiprocessing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
# Skip tests if _multiprocessing wasn't built.
3535
_multiprocessing = test.support.import_module('_multiprocessing')
3636
# Skip tests if sem_open implementation is broken.
37-
test.support.import_module('multiprocessing.synchronize')
37+
support.skip_if_broken_multiprocessing_synchronize()
3838
import threading
3939

4040
import multiprocessing.connection

Lib/test/support/__init__.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,3 +1957,25 @@ def wait_process(pid, *, exitcode, timeout=None):
19571957
# sanity check: it should not fail in practice
19581958
if pid2 != pid:
19591959
raise AssertionError(f"pid {pid2} != pid {pid}")
1960+
1961+
def skip_if_broken_multiprocessing_synchronize():
1962+
"""
1963+
Skip tests if the multiprocessing.synchronize module is missing, if there
1964+
is no available semaphore implementation, or if creating a lock raises an
1965+
OSError.
1966+
"""
1967+
1968+
# Skip tests if the _multiprocessing extension is missing.
1969+
import_module('_multiprocessing')
1970+
1971+
# Skip tests if there is no available semaphore implementation:
1972+
# multiprocessing.synchronize requires _multiprocessing.SemLock.
1973+
synchronize = import_module('multiprocessing.synchronize')
1974+
1975+
try:
1976+
# bpo-38377: On Linux, creating a semaphore is the current user
1977+
# does not have the permission to create a file in /dev/shm.
1978+
# Create a semaphore to check permissions.
1979+
synchronize.Lock(ctx=None)
1980+
except OSError as exc:
1981+
raise unittest.SkipTest(f"broken multiprocessing SemLock: {exc!r}")

Lib/test/test_asyncio/test_events.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2673,10 +2673,10 @@ def tearDown(self):
26732673
if sys.platform != 'win32':
26742674

26752675
def test_get_event_loop_new_process(self):
2676-
# Issue bpo-32126: The multiprocessing module used by
2676+
# bpo-32126: The multiprocessing module used by
26772677
# ProcessPoolExecutor is not functional when the
26782678
# multiprocessing.synchronize module cannot be imported.
2679-
support.import_module('multiprocessing.synchronize')
2679+
support.skip_if_broken_multiprocessing_synchronize()
26802680

26812681
async def main():
26822682
pool = concurrent.futures.ProcessPoolExecutor()

Lib/test/test_concurrent_futures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Skip tests if _multiprocessing wasn't built.
55
support.import_module('_multiprocessing')
66
# Skip tests if sem_open implementation is broken.
7-
support.import_module('multiprocessing.synchronize')
7+
support.skip_if_broken_multiprocessing_synchronize()
88

99
from test.support import hashlib_helper
1010
from test.support.script_helper import assert_python_ok

Lib/test/test_logging.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3630,9 +3630,9 @@ def test_handle_called_with_queue_queue(self, mock_handle):
36303630

36313631
@patch.object(logging.handlers.QueueListener, 'handle')
36323632
def test_handle_called_with_mp_queue(self, mock_handle):
3633-
# Issue 28668: The multiprocessing (mp) module is not functional
3633+
# bpo-28668: The multiprocessing (mp) module is not functional
36343634
# when the mp.synchronize module cannot be imported.
3635-
support.import_module('multiprocessing.synchronize')
3635+
support.skip_if_broken_multiprocessing_synchronize()
36363636
for i in range(self.repeat):
36373637
log_queue = multiprocessing.Queue()
36383638
self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
@@ -3656,9 +3656,9 @@ def test_no_messages_in_queue_after_stop(self):
36563656
indicates that messages were not registered on the queue until
36573657
_after_ the QueueListener stopped.
36583658
"""
3659-
# Issue 28668: The multiprocessing (mp) module is not functional
3659+
# bpo-28668: The multiprocessing (mp) module is not functional
36603660
# when the mp.synchronize module cannot be imported.
3661-
support.import_module('multiprocessing.synchronize')
3661+
support.skip_if_broken_multiprocessing_synchronize()
36623662
for i in range(self.repeat):
36633663
queue = multiprocessing.Queue()
36643664
self.setup_and_log(queue, '%s_%s' %(self.id(), i))

Lib/test/test_multiprocessing_main_handling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
AVAILABLE_START_METHODS = set(multiprocessing.get_all_start_methods())
2424

2525
# Issue #22332: Skip tests if sem_open implementation is broken.
26-
support.import_module('multiprocessing.synchronize')
26+
support.skip_if_broken_multiprocessing_synchronize()
2727

2828
verbose = support.verbose
2929

Lib/test/test_venv.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
import tempfile
1717
from test.support import (captured_stdout, captured_stderr, requires_zlib,
1818
can_symlink, EnvironmentVarGuard, rmtree,
19-
import_module)
19+
import_module,
20+
skip_if_broken_multiprocessing_synchronize)
2021
import unittest
2122
import venv
2223
from unittest.mock import patch
@@ -357,10 +358,11 @@ def test_multiprocessing(self):
357358
"""
358359
Test that the multiprocessing is able to spawn.
359360
"""
360-
# Issue bpo-36342: Instantiation of a Pool object imports the
361+
# bpo-36342: Instantiation of a Pool object imports the
361362
# multiprocessing.synchronize module. Skip the test if this module
362363
# cannot be imported.
363-
import_module('multiprocessing.synchronize')
364+
skip_if_broken_multiprocessing_synchronize()
365+
364366
rmtree(self.env_dir)
365367
self.run_with_capture(venv.create, self.env_dir)
366368
envpy = os.path.join(os.path.realpath(self.env_dir),
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
On Linux, skip tests using multiprocessing if the current user cannot create
2+
a file in ``/dev/shm/`` directory. Add the
3+
:func:`~test.support.skip_if_broken_multiprocessing_synchronize` function to
4+
the :mod:`test.support` module.

0 commit comments

Comments
 (0)