{"id":687,"library":"pytest-timeout","title":"pytest-timeout","description":"pytest-timeout is an actively maintained pytest plugin designed to automatically abort excessively long-running or hanging tests. It helps in maintaining efficient test suites by enforcing timeout limits at various levels (global, session, per-test) and provides different methods to terminate tests. The current version is 2.4.0 and it is part of the pytest-dev organization, implying regular updates and maintenance.","status":"active","version":"2.4.0","language":"python","source_language":"en","source_url":"https://github.com/pytest-dev/pytest-timeout","tags":["pytest","testing","timeout","plugin","performance"],"install":[{"cmd":"pip install pytest-timeout","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core testing framework that this plugin extends.","package":"pytest","optional":false}],"imports":[{"note":"pytest-timeout is a plugin and typically configured via pytest.ini, command-line options, or test markers, rather than direct Python imports of its internal classes.","symbol":"pytest.mark.timeout","correct":"import pytest\n@pytest.mark.timeout(300)\ndef test_example():\n    pass"}],"quickstart":{"code":"import pytest\nimport time\nimport os\n\n# Example pytest.ini content (can be placed in a file named pytest.ini)\n# [pytest]\n# timeout = 5\n\n# Or set via environment variable (e.g., in CI/CD)\n# export PYTEST_TIMEOUT=10\n\n# A test that should pass within the global timeout (if set to > 1)\ndef test_fast_operation():\n    time.sleep(1) # Simulates a quick operation\n    assert True\n\n# A test with a specific timeout marker, overriding global settings\n@pytest.mark.timeout(os.environ.get('PYTEST_LONG_TIMEOUT', 20))\ndef test_long_running_operation():\n    time.sleep(15) # Simulates a potentially long operation\n    assert True\n\n# A test designed to time out if default or global timeout is low\n@pytest.mark.timeout(2)\ndef test_should_timeout():\n    time.sleep(3) # This will exceed the 2-second mark\n    assert False, \"Should not reach here if timeout works\"\n\n# To run these tests:\n# 1. Save as a Python file (e.g., test_timeouts.py)\n# 2. Run from your terminal: pytest test_timeouts.py\n#    (or pytest test_timeouts.py --timeout=5 to set a global CLI timeout)","lang":"python","description":"This quickstart demonstrates how to apply timeouts using `pytest-timeout`. It shows setting a global timeout via `pytest.ini` (or `PYTEST_TIMEOUT` environment variable), and overriding it for specific tests using the `@pytest.mark.timeout` decorator. The example includes tests that should pass and one designed to explicitly time out."},"warnings":[{"fix":"Upgrade pytest to `pytest>=7.0.0` using `pip install --upgrade pytest` and ensure Python is 3.7 or newer.","message":"Minimum `pytest` version has increased. For `pytest-timeout` versions 2.2.0 and later, `pytest>=7.0.0` is required. Ensure your `pytest` installation is up-to-date to avoid compatibility issues. Python 3.7+ is required for version 2.4.0.","severity":"breaking","affected_versions":"2.2.0+"},{"fix":"If experiencing issues, explicitly set the method using `--timeout-method=thread` CLI option or `timeout_method = thread` in `pytest.ini`. Consider the implications of each method on your test suite's behavior.","message":"The plugin offers two timeout methods: 'signal' (default on supported systems) and 'thread'. The 'signal' method (using SIGALRM) is generally more efficient but can interfere with code under test that also uses SIGALRM. The 'thread' method is more portable and reliable but incurs more overhead and can prevent other `pytest` features (like JUnit XML or fixture teardown) from completing normally because it terminates the entire process.","severity":"gotcha","affected_versions":"All"},{"fix":"For hard limits on individual test execution, always combine `--session-timeout` with global or per-test `timeout` settings. E.g., `pytest --session-timeout=3600 --timeout=300`.","message":"Session timeouts (`--session-timeout`) are 'cooperative'. They check the session time at the end of each test function and stop *further* tests from running if the timeout is exceeded. They will *not* interrupt a test currently in progress. To ensure a test-in-progress is interrupted, a per-function timeout must also be set.","severity":"gotcha","affected_versions":"All"},{"fix":"If you only want to time the test function body, set `timeout_func_only = True` in your `pytest.ini` file, or increase the timeout duration to account for fixture overhead.","message":"By default, timeouts apply to the entire test lifecycle, including fixture setup and teardown. If your fixtures are long-running, they can cause tests to time out prematurely.","severity":"gotcha","affected_versions":"All"},{"fix":"If you need timeouts to function even when a debugger is attached (e.g., for automated debugging workflows), use the `--timeout-disable-debugger-detection` CLI option or `disable_debugger_detection = True` in `pytest.ini`.","message":"By default, `pytest-timeout` attempts to detect when a debugger (like pdb or PyCharm's debugger) is active and disables timeouts to prevent interruption during debugging sessions. This behavior can be explicitly disabled.","severity":"gotcha","affected_versions":"All"},{"fix":"To address the 'root' user warning, it is recommended to use a Python virtual environment (e.g., `python -m venv .venv` and `source .venv/bin/activate`). To update `pip`, run `pip install --upgrade pip`.","message":"The test execution environment generated warnings from `pip`. These typically include warnings about running `pip` as the 'root' user (which can cause permission issues) and notices about new `pip` versions being available. These are external to the tested library's functionality and do not indicate a failure of `pytest-timeout`.","severity":"gotcha","affected_versions":"pip: All versions when conditions (e.g., root user, outdated pip) are met."}],"env_vars":null,"last_verified":"2026-05-12T17:49:33.982Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"Install the plugin using `pip install pytest-timeout` and ensure your Python environment is correctly configured.","cause":"The `pytest-timeout` plugin is not installed or pytest cannot find it, so the `--timeout` command-line argument is not recognized.","error":"pytest: error: unrecognized arguments: --timeout=X"},{"fix":"Use a valid timeout method such as `thread`, `signal` (Unix-only), or `process` for `--timeout-method` or in `pytest.ini`.","cause":"An unrecognized or misspelled timeout method was specified in the configuration or command line.","error":"ValueError: Invalid timeout-method 'X'. Must be one of: 'thread', 'signal', 'process'."},{"fix":"Register the marker by adding `markers = timeout` under the `[pytest]` section in your `pytest.ini` file, or ensure `pytest-timeout` is correctly installed.","cause":"The `pytest.mark.timeout` marker is not explicitly registered in your `pytest.ini` file, leading to a warning or the timeout not being applied.","error":"pytest: warning: unknown pytest.mark.timeout marker (may require \"--strict-markers\" command line option)"},{"fix":"Use `timeout-method=thread` or `timeout-method=process` instead, as `signal` is only supported on Unix-like systems.","cause":"The `signal` timeout method was specified on a non-Unix operating system, such as Windows, where POSIX signals are not available.","error":"ValueError: signal timeout-method only available on Unix."}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":"2.4.0","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.43,"mem_mb":12.2,"disk_size":"30.7M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.46,"mem_mb":12.2,"disk_size":"30.5M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.8,"import_time_s":0.3,"mem_mb":12.2,"disk_size":"31M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.31,"mem_mb":12.2,"disk_size":"31M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.55,"mem_mb":12.9,"disk_size":"33.6M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.61,"mem_mb":12.9,"disk_size":"33.4M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.6,"import_time_s":0.53,"mem_mb":12.9,"disk_size":"34M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.48,"mem_mb":12.9,"disk_size":"34M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.52,"mem_mb":12.8,"disk_size":"25.2M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.53,"mem_mb":12.8,"disk_size":"25.0M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.5,"import_time_s":0.49,"mem_mb":12.8,"disk_size":"26M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.56,"mem_mb":12.8,"disk_size":"25M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.45,"mem_mb":11.8,"disk_size":"25.0M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":11.8,"disk_size":"24.7M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":2.5,"import_time_s":0.43,"mem_mb":11.8,"disk_size":"25M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.57,"mem_mb":11.8,"disk_size":"25M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.36,"mem_mb":11.2,"disk_size":"30.0M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.39,"mem_mb":11.2,"disk_size":"29.8M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":3.1,"import_time_s":0.35,"mem_mb":11.2,"disk_size":"31M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.32,"mem_mb":11.2,"disk_size":"30M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}