PHP 8.2.30
Preview: threadexception.py Size: 2.85 KB
//opt/cloudlinux/venv/lib/python3.11/site-packages/_pytest/threadexception.py

import threading
import traceback
import warnings
from types import TracebackType
from typing import Any
from typing import Callable
from typing import Generator
from typing import Optional
from typing import Type

import pytest


# Copied from cpython/Lib/test/support/threading_helper.py, with modifications.
class catch_threading_exception:
    """Context manager catching threading.Thread exception using
    threading.excepthook.

    Storing exc_value using a custom hook can create a reference cycle. The
    reference cycle is broken explicitly when the context manager exits.

    Storing thread using a custom hook can resurrect it if it is set to an
    object which is being finalized. Exiting the context manager clears the
    stored object.

    Usage:
        with threading_helper.catch_threading_exception() as cm:
            # code spawning a thread which raises an exception
            ...
            # check the thread exception: use cm.args
            ...
        # cm.args attribute no longer exists at this point
        # (to break a reference cycle)
    """

    def __init__(self) -> None:
        self.args: Optional["threading.ExceptHookArgs"] = None
        self._old_hook: Optional[Callable[["threading.ExceptHookArgs"], Any]] = None

    def _hook(self, args: "threading.ExceptHookArgs") -> None:
        self.args = args

    def __enter__(self) -> "catch_threading_exception":
        self._old_hook = threading.excepthook
        threading.excepthook = self._hook
        return self

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_val: Optional[BaseException],
        exc_tb: Optional[TracebackType],
    ) -> None:
        assert self._old_hook is not None
        threading.excepthook = self._old_hook
        self._old_hook = None
        del self.args


def thread_exception_runtest_hook() -> Generator[None, None, None]:
    with catch_threading_exception() as cm:
        yield
        if cm.args:
            thread_name = "<unknown>" if cm.args.thread is None else cm.args.thread.name
            msg = f"Exception in thread {thread_name}\n\n"
            msg += "".join(
                traceback.format_exception(
                    cm.args.exc_type,
                    cm.args.exc_value,
                    cm.args.exc_traceback,
                )
            )
            warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg))


@pytest.hookimpl(hookwrapper=True, trylast=True)
def pytest_runtest_setup() -> Generator[None, None, None]:
    yield from thread_exception_runtest_hook()


@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_call() -> Generator[None, None, None]:
    yield from thread_exception_runtest_hook()


@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_teardown() -> Generator[None, None, None]:
    yield from thread_exception_runtest_hook()

Directory Contents

Dirs: 7 × Files: 47

Name Size Perms Modified Actions
assertion DIR
- drwxr-xr-x 2026-02-06 08:01:08
Edit Download
config DIR
- drwxr-xr-x 2026-02-06 08:01:08
Edit Download
mark DIR
- drwxr-xr-x 2026-02-06 08:01:08
Edit Download
_code DIR
- drwxr-xr-x 2026-02-06 08:01:08
Edit Download
_io DIR
- drwxr-xr-x 2026-02-06 08:01:08
Edit Download
_py DIR
- drwxr-xr-x 2026-02-06 08:01:08
Edit Download
- drwxr-xr-x 2026-02-06 08:01:08
Edit Download
20.89 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
33.92 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
12.89 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
13.18 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
5.36 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
25.35 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.04 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
65.51 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
1.31 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
8.34 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
31.79 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
25.11 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
16.53 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
33.23 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
31.73 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
14.51 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
25.94 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
1.65 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
10.02 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.86 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
25.22 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
0 B lrw-r--r-- 2026-01-20 13:01:48
Edit Download
60.52 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
2.27 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
69.49 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
37.50 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
709 B lrw-r--r-- 2026-01-20 13:01:48
Edit Download
10.67 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
20.35 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
18.01 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
2.81 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.18 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
1.19 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
9.96 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
2.98 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
4.60 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
52.25 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
2.85 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
375 B lrw-r--r-- 2026-01-20 13:01:48
Edit Download
11.43 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
14.46 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.12 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
4.95 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
4.37 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.71 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
160 B lrw-r--r-- 2026-01-20 13:01:48
Edit Download
356 B lrw-r--r-- 2026-01-20 13:01:48
Edit Download

If ZipArchive is unavailable, a .tar will be created (no compression).