Skip to main content

A pytest plugin for executing tests in parallel with MPI

Project description

mpi-pytest

Pytest plugin that lets you run tests in parallel with MPI.

mpi-pytest provides:

  • A parallel marker indicating that the test must be run under MPI.
  • A parallel_assert function for evaluating assertions in a deadlock-safe way.

parallel marker

Writing a parallel test simply requires marking the test with the parallel marker:

@pytest.mark.parallel(nprocs=5)  # run in parallel with 5 processes
def test_my_code_on_5_procs():
    ...

@pytest.mark.parallel(5)  # the "nprocs" kwarg is optional
def test_my_code_on_5_procs_again():
    ...

@pytest.mark.parallel  # run in parallel with the default number of processes (3)
def test_my_code_on_3_procs():
    ...

@pytest.mark.parallel()  # the brackets are optional
def test_my_code_on_3_procs_again():
    ...

One can also mark a test with a sequence of values for nprocs:

@pytest.mark.parallel(nprocs=[1, 2, 3])  # run in parallel on 1, 2 and 3 processes
def test_my_code_on_variable_nprocs():
    ...

@pytest.mark.parallel([1, 2, 3])  # again the "nprocs" kwarg is optional
def test_my_code_on_variable_nprocs_again():
    ...

If multiple numbers of processes are requested then the tests are parametrised and renamed to, in this case, test_my_code_on_variable_nprocs[nprocs=1], test_my_code_on_variable_nprocs[nprocs=2] and test_my_code_on_variable_nprocs[nprocs=3].

When running the code with these parallel markers, mpi-pytest adds extra markers to each test to allow one to select all tests with a particular number of processors. For example, to select all parallel tests on 3 processors, one should run:

$ mpiexec -n 3 pytest -m parallel[3]

Serial tests - those either unmarked or marked @pytest.mark.parallel(1) - can be selected by running:

$ pytest -m "not parallel or parallel[1]"

Forking mode

mpi-pytest can be used in one of two modes: forking or non-forking. The former works as follows:

  1. The user calls pytest (not mpiexec -n <# proc> pytest). This launches the "parent" pytest process.
  2. This parent pytest process collects all the tests and begins to run them.
  3. When a test is found with the parallel marker, rather than executing the function as before, a subprocess is forked calling mpiexec -n <# proc> pytest this_specific_test_file.py::this_specific_test. This produces <# proc> 'child' pytest processes that execute the test together.
  4. If this terminates successfully then the test is considered to have passed.

This is convenient for development for a number of reasons:

  • The plugin composes better with other pytest plugins like pytest-xdist.
  • It is not necessary to wrap pytest invocations with mpiexec calls, and all parallel and serial tests can be run at once.

There are however a number of downsides:

  • Only one mainstream MPI distribution (MPICH) supports nested calls to MPI_Init. If your 'parent' pytest process initialises MPI (for instance by executing from mpi4py import MPI) then this will cause non-MPICH MPI distributions to crash.
  • Forking a subprocess can be expensive since a completely fresh Python interpreter is launched each time.
  • Sandboxing each test means that polluted global state at the end of a test cannot be detected.

Non-forking mode

With these significant limitations in mind, mpi-pytest therefore also supports a non-forking mode. To use it, one simply needs to wrap the pytest invocation with mpiexec, no additional configuration is necessary. For example, to run all of the parallel tests on 2 ranks one needs to execute:

$ mpiexec -n 2 pytest -m parallel[2]

parallel_assert

Using regular assert statements can be unsafe in parallel codes. Consider the code:

@pytest.mark.parallel(2)
def test_something():
    # this will only fail on *some* ranks
    assert COMM_WORLD.rank == 0

    # this will hang
    COMM_WORLD.barrier()

One can see that failing assertions on some ranks but not others will violate SPMD and lead to deadlocks. To avoid this, mpi-pytest provides a parallel_assert function used as follows:

from pytest_mpi import parallel_assert

@pytest.mark.parallel(2)
def test_something():
    # this will fail on *all* ranks
    parallel_assert(lambda: COMM_WORLD.rank == 0)
    ...

Configuration

mpi-pytest respects the environment variable PYTEST_MPI_MAX_NPROCS, which defines the maximum number of processes that can be requested by a parallel marker. If this value is exceeded an error will be raised.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mpi_pytest-2025.2.0.tar.gz (44.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mpi_pytest-2025.2.0-py3-none-any.whl (32.4 kB view details)

Uploaded Python 3

File details

Details for the file mpi_pytest-2025.2.0.tar.gz.

File metadata

  • Download URL: mpi_pytest-2025.2.0.tar.gz
  • Upload date:
  • Size: 44.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for mpi_pytest-2025.2.0.tar.gz
Algorithm Hash digest
SHA256 561cfe0d044071d88fca2e6125de127fbfd44e6a0df1c23f74b65d0bae5bfed0
MD5 308d0f450ebe29424d19e4294836547f
BLAKE2b-256 4ae1b35933ec9dae652e0f80d0ebb6178990435b843a734026bc99398ed88226

See more details on using hashes here.

Provenance

The following attestation bundles were made for mpi_pytest-2025.2.0.tar.gz:

Publisher: release.yml on firedrakeproject/mpi-pytest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mpi_pytest-2025.2.0-py3-none-any.whl.

File metadata

  • Download URL: mpi_pytest-2025.2.0-py3-none-any.whl
  • Upload date:
  • Size: 32.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for mpi_pytest-2025.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5e258f1bac13c2d14d87b244f5a63d5a5e0609cfc5e302b67ea221d1782d1846
MD5 2e4298ce07809319a78432d923a3b41a
BLAKE2b-256 511c621d9af95a06f8975f344868ff2a85e17cda531e869f4b2f3b821686f70d

See more details on using hashes here.

Provenance

The following attestation bundles were made for mpi_pytest-2025.2.0-py3-none-any.whl:

Publisher: release.yml on firedrakeproject/mpi-pytest

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page