diff --git a/.github/workflows/run-crt-test.yml b/.github/workflows/run-crt-test.yml index e168631c..c4681f95 100644 --- a/.github/workflows/run-crt-test.yml +++ b/.github/workflows/run-crt-test.yml @@ -11,7 +11,7 @@ permissions: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 86fa09a1..e6116b3a 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -11,7 +11,7 @@ permissions: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: diff --git a/requirements-dev-lock.txt b/requirements-dev-lock.txt index 32d9eeb5..83d4de3a 100644 --- a/requirements-dev-lock.txt +++ b/requirements-dev-lock.txt @@ -86,21 +86,35 @@ iniconfig==2.0.0 \ packaging==24.1 \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 - # via pytest + # via + # pytest + # wheel pluggy==1.5.0 \ --hash=sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1 \ --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 # via pytest -psutil==4.4.2 \ - --hash=sha256:10fbb631142a3200623f4ab49f8bf82c32b79b8fe179f6056d01da3dfc589da1 \ - --hash=sha256:15aba78f0262d7839702913f5d2ce1e97c89e31456bb26da1a5f9f7d7fe6d336 \ - --hash=sha256:1c37e6428f7fe3aeea607f9249986d9bb933bb98133c7919837fd9aac4996b07 \ - --hash=sha256:69e30d789c495b781f7cd47c13ee64452c58abfc7132d6dd1b389af312a78239 \ - --hash=sha256:7481f299ae0e966a10cb8dd93a327efd8f51995d9bdc8810dcc65d3b12d856ee \ - --hash=sha256:c2b0d8d1d8b5669b9884d0dd49ccb4094d163858d672d3d13a3fa817bc8a3197 \ - --hash=sha256:d96d31d83781c7f3d0df8ccb1cc50650ca84d4722c5070b71ce8f1cc112e02e0 \ - --hash=sha256:e423dd9cb12256c742d1d56ec38bc7d2a7fa09287c82c41e475e68b9f932c2af \ - --hash=sha256:e44d6b758a96539e3e02336430d3f85263d43c470c5bad93572e9b6a86c67f76 +psutil==7.2.2 \ + --hash=sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372 \ + --hash=sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9 \ + --hash=sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841 \ + --hash=sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63 \ + --hash=sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979 \ + --hash=sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a \ + --hash=sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b \ + --hash=sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9 \ + --hash=sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee \ + --hash=sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312 \ + --hash=sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b \ + --hash=sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9 \ + --hash=sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e \ + --hash=sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc \ + --hash=sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1 \ + --hash=sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf \ + --hash=sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea \ + --hash=sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988 \ + --hash=sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486 \ + --hash=sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00 \ + --hash=sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8 # via -r requirements-dev.txt pytest==8.1.1 \ --hash=sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7 \ @@ -121,7 +135,7 @@ tomli==2.0.1 \ # via # coverage # pytest -wheel==0.43.0 \ - --hash=sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85 \ - --hash=sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81 +wheel==0.46.3 \ + --hash=sha256:4b399d56c9d9338230118d705d9737a2a468ccca63d5e813e2a4fc7815d8bc4d \ + --hash=sha256:e3e79874b07d776c40bd6033f8ddf76a7dad46a7b8aa1b2787a83083519a1803 # via -r requirements-dev.txt diff --git a/requirements-dev.txt b/requirements-dev.txt index 0fba7747..eca5ef24 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,8 +1,8 @@ -psutil>=4.1.0,<5.0.0 +psutil>=4.1.0,<8.0.0 tabulate==0.7.5 coverage==7.2.7 -wheel==0.43.0 -setuptools==71.1.0;python_version>="3.12" +wheel==0.46.3 +setuptools==80.10.2;python_version>="3.12" packaging==24.1;python_version>="3.12" # Requirement for setuptools>=71 # Pytest specific deps diff --git a/scripts/ci/install b/scripts/ci/install index 8b4e8b0f..ec27a26b 100755 --- a/scripts/ci/install +++ b/scripts/ci/install @@ -2,6 +2,7 @@ import argparse import os import shutil +import sys from contextlib import contextmanager from subprocess import check_call @@ -21,8 +22,8 @@ def cd(path): os.chdir(cwd) -def run(command): - return check_call(command, shell=True) +def run(args): + return check_call(args) if __name__ == "__main__": @@ -35,13 +36,13 @@ if __name__ == "__main__": ) args = parser.parse_args() with cd(REPO_ROOT): - run("pip install -r requirements.txt") - run('python scripts/ci/install-dev-deps') + run([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"]) + run([sys.executable, "scripts/ci/install-dev-deps"]) if os.path.isdir('dist') and os.listdir('dist'): shutil.rmtree('dist') - run('python setup.py bdist_wheel') + run([sys.executable, "setup.py", "bdist_wheel"]) wheel_dist = os.listdir('dist')[0] package = os.path.join('dist', wheel_dist) if args.extras: - package = f"'{package}[{args.extras}]'" - run(f'pip install {package}') + package = f"{package}[{args.extras}]" + run([sys.executable, "-m", "pip", "install", package]) diff --git a/scripts/ci/install-dev-deps b/scripts/ci/install-dev-deps index 71e9badc..463ea207 100755 --- a/scripts/ci/install-dev-deps +++ b/scripts/ci/install-dev-deps @@ -20,8 +20,8 @@ def cd(path): os.chdir(cwd) -def run(command): - return check_call(command, shell=True) +def run(args): + return check_call(args) if __name__ == "__main__": @@ -32,6 +32,24 @@ if __name__ == "__main__": # Setuptools 71+ now prefers already installed versions # of packaging _and_ broke the API for packaging<22.0. # We'll pin to match what's in requirements-dev.txt. - run("pip install setuptools==71.1.0 packaging==24.1") - - run("pip install -r requirements-dev-lock.txt") + run( + [ + sys.executable, + "-m", + "pip", + "install", + "setuptools==71.1.0", + "packaging==24.1", + ] + ) + + run( + [ + sys.executable, + "-m", + "pip", + "install", + "-r", + "requirements-dev-lock.txt", + ] + ) diff --git a/scripts/ci/run-crt-tests b/scripts/ci/run-crt-tests index f823aa4a..82b50396 100755 --- a/scripts/ci/run-crt-tests +++ b/scripts/ci/run-crt-tests @@ -24,8 +24,8 @@ def cd(path): os.chdir(cwd) -def run(command, env=None): - return check_call(command, shell=True, env=env) +def run(args, env=None): + return check_call(args, env=env) try: @@ -37,4 +37,11 @@ except ImportError: if __name__ == "__main__": with cd(os.path.join(REPO_ROOT, "tests")): - run(f"{REPO_ROOT}/scripts/ci/run-tests unit/ functional/") + run( + [ + sys.executable, + os.path.join(REPO_ROOT, "scripts/ci/run-tests"), + "unit/", + "functional/", + ] + ) diff --git a/tests/unit/test_compat.py b/tests/unit/test_compat.py index a50ad10a..6f474749 100644 --- a/tests/unit/test_compat.py +++ b/tests/unit/test_compat.py @@ -14,6 +14,7 @@ import os import shutil import signal +import socket import tempfile from io import BytesIO @@ -79,13 +80,28 @@ def test_non_file_like_obj(self): class TestBaseManager(unittest.TestCase): + def _can_bind_socket(self): + sock = socket.socket() + try: + sock.bind(('127.0.0.1', 0)) + return True + except PermissionError: + return False + finally: + sock.close() + def create_pid_manager(self): class PIDManager(BaseManager): def __init__(self): # Python 3.14 changed the non-macOS POSIX default to forkserver - # but the code in this module does not work with it + # and macOS defaults to spawn. This test uses a local manager + # class which is not picklable under spawn/forkserver, so force + # fork for the test. # See https://github.com/python/cpython/issues/125714 - if multiprocessing.get_start_method() == 'forkserver': + if multiprocessing.get_start_method() in ( + 'forkserver', + 'spawn', + ): ctx = multiprocessing.get_context(method='fork') else: ctx = multiprocessing.get_context() @@ -102,6 +118,8 @@ def get_pid(self, pid_manager): @skip_if_windows('os.kill() with SIGINT not supported on Windows') def test_can_provide_signal_handler_initializers_to_start(self): + if not self._can_bind_socket(): + self.skipTest('socket bind is not permitted in this environment') manager = self.create_pid_manager() manager.start(signal.signal, (signal.SIGINT, signal.SIG_IGN)) pid = self.get_pid(manager)