Skip to main content

pytest-reraise

PyPI GitHub Workflow Status codecov PyPI pyversions PyPI - Downloads Code style: black semantic-release

Let's assume you write a pytest test case that includes assertions in another thread, like so:

from threading import Thread

def test_assert():

    def run():
        assert False

    Thread(target=run).start()

This test will pass, as the AssertionError is not raised in the main thread. pytest-reraise is here to help you capture the exception and raise it in the main thread:

pip install pytest-reraise
from threading import Thread

def test_assert(reraise):

    def run():
        with reraise:
            assert False

    Thread(target=run).start()

The above test will fail, as pytest-reraise captures the exception and raises it at the end of the test case.

Advanced Usage and Special Cases

Wrapping Functions

Instead of using the reraise context manager in a function, you can also wrap the entire function with it via the reraise.wrap() method. Hence, the example

def run():
    with reraise:
        assert False

Thread(target=run).start()

can also be written as

def run():
    assert False

Thread(target=reraise.wrap(run)).start()

or even

@reraise.wrap
def run():
    assert False

Thread(target=run).start()

Manual Re-raising

By default, the captured exception (if any) is raised at the end of the test case. If you want to raise it before then, call reraise() in your test case. If an exception has been raised within a with reraise block by then, reraise() will raise it right away:

def test_assert(reraise):

    def run():
        with reraise:
            assert False

    reraise() # This will not raise anything yet

    t = Thread(target=run)
    t.start()
    t.join()

    reraise() # This will raise the assertion error

As seen in the example above, reraise() can be called multiple times during a test case. Whenever an exception has been raised in a with reraise block since the last call, it will be raised on the next call.

Multiple Exceptions

When the reraise context manager is used multiple times in a single test case, only the first-raised exception will be re-raised in the end. In the below example, both threads raise an exception but only one of these exceptions will be re-raised.

def test_assert(reraise):

    def run():
        with reraise:
            assert False

    for _ in range(2):
        Thread(target=run).start()

Catching Exceptions

By default, the reraise context manager does not catch exceptions, so they will not be hidden from the thread in which they are raised. If you want to change this, use reraise(catch=True) instead of reraise:

def test_assert(reraise):

    def run():
        with reraise(catch=True):
            assert False
        print("I'm alive!")

    Thread(target=run).start()

Note that you cannot use reraise() (without the catch argument) as a context manager, as it is used to raise exceptions.

Exception Priority

If reraise captures an exception and the main thread raises an exception as well, the exception captured by reraise will mask the main thread's exception unless that exception was already re-raised. The objective behind this is that the outcome of the main thread often depends on the work performed in other threads. Thus, failures in in other threads are likely to cause failures in the main thread, and other threads' exceptions (if any) are of greater importance for the developer than main thread exceptions.

The example below will report assert False, not assert "foo" == "bar".

def test_assert(reraise):

    def run():
        with reraise:
            assert False # This will be reported

    t = Thread(target=run)
    t.start()
    t.join()

    assert "foo" == "bar" # This won't

Accessing and Modifying Exceptions

reraise provides an exception property to retrieve the exception that was captured, if any. reraise.exception can also be used to assign an exception if no exception has been captured yet. In addition to that, reraise.reset() returns the value of reraise.exception and resets it to None so that the exception will not be raised anymore.

Here's a quick demonstration test case that passes:

def test_assert(reraise):

    def run():
        with reraise:
            assert False

    t = Thread(target=run)
    t.start()
    t.join()

    # Return the captured exception:
    assert type(reraise.exception) is AssertionError

    # This won't do anything, since an exception has already been captured:
    reraise.exception = Exception()

    # Return the exception and set `reraise.exception` to None:
    assert type(reraise.reset()) is AssertionError

    # `Reraise` will not fail the test case because
    assert reraise.exception is None

Release files for pytest-reraise 2.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytest-reraise 2.1.2
File Size Uploaded
pytest-reraise-2.1.2.tar.gz 5.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pytest-reraise 2.1.2
File Interpreter ABI Platform
pytest_reraise-2.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 10.4 kB

Release files / pytest-reraise-2.1.2.tar.gz

Download URL pytest-reraise-2.1.2.tar.gz
Size 5.2 kB
Tags Source
SHA-256 checksum
How to use checksums
5ab59bd0e2028be095289e6dfc9e36cc0b56936465278f3223e81bea0f2d1c70
BLAKE2b-256 checksum
How to use checksums
379befba721806e9018eee657dda66ffeaca7b5e6de26718b5e5aa7e62f60b03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.2.1 CPython/3.10.6 Linux/5.15.0-1019-azure

Release files / pytest_reraise-2.1.2-py3-none-any.whl

Download URL pytest_reraise-2.1.2-py3-none-any.whl
Size 5.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c22430d33b2cc18905959d7af28978e371113fcc6ef67b5fec95efcd80b88c16
BLAKE2b-256 checksum
How to use checksums
003515734aa39373983adf25cd43a1d76305befe763e45880d3a9dfe4b7a2410
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.2.1 CPython/3.10.6 Linux/5.15.0-1019-azure

Release history Release notifications | RSS feed

This release

2.1.2 This release

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page