TS008: TestTimeout
Overview
| Property | Value |
|---|---|
| ID | TS008 |
| Name | TestTimeout |
| Group | tests |
| Severity | NOTE |
Description
Checks if test timeout configuration is present to prevent hanging tests from blocking CI/CD pipelines.
Tests without timeouts can:
- Block CI indefinitely: A single hanging test can prevent deployments
- Waste resources: Hung tests consume CI runner time
- Hide issues: Deadlocks and infinite loops go undetected
- Frustrate developers: Waiting for tests that never complete
What it checks
The check looks for timeout configuration in several places:
- pytest-timeout in dev dependencies:
pyproject.tomloptional-dependencies - Timeout decorators in test files:
@pytest.mark.timeout(...)decorators - Timeout configuration in conftest.py: Global timeout settings
Result states
- PASSED: Timeout configuration found
- FAILED: No timeout configuration detected
- NOT_APPLICABLE: No tests directory found
# Detected patterns
@pytest.mark.timeout(60) # Per-test timeout
def test_slow_operation():
pass
# In conftest.py
def pytest_configure(config):
config.addinivalue_line("timeout", "300")How to fix
Install pytest-timeout
The simplest approach is to add pytest-timeout to your dev dependencies:
# pyproject.toml
[project.optional-dependencies]
dev = [
"pytest>=7.0",
"pytest-timeout>=2.0", # Add this
]Then configure a default timeout:
# pyproject.toml
[tool.pytest.ini_options]
timeout = 300 # 5 minute default timeoutUse timeout decorators for specific tests
import pytest
@pytest.mark.timeout(10) # 10 second timeout
def test_quick_operation():
result = quick_function()
assert result is not None
@pytest.mark.timeout(60) # 1 minute for slower tests
def test_slow_operation():
result = slow_function()
assert result is not None
@pytest.mark.timeout(0) # Disable timeout for specific test
def test_known_slow():
result = very_slow_but_necessary()
assert result is not NoneConfigure timeout in conftest.py
# conftest.py
import pytest
def pytest_configure(config):
"""Configure default timeout for all tests."""
config.addinivalue_line(
"markers",
"timeout(seconds): Set test timeout"
)
@pytest.fixture(autouse=True)
def default_timeout(request):
"""Apply default timeout if not specified."""
if not request.node.get_closest_marker("timeout"):
request.node.add_marker(pytest.mark.timeout(60))Use pytest.ini or pyproject.toml
# pytest.ini
[pytest]
timeout = 300
timeout_method = threadOr in pyproject.toml:
[tool.pytest.ini_options]
timeout = 300
timeout_method = "thread"Set timeout via CLI
# Run with 60 second timeout
pytest --timeout=60
# Run with timeout and method
pytest --timeout=60 --timeout-method=threadTimeout methods
pytest-timeout supports different timeout methods:
- thread (default): Uses a separate thread to monitor timeout
- signal: Uses SIGALRM (Unix only, more reliable)
[tool.pytest.ini_options]
timeout = 300
timeout_method = "signal" # More reliable on UnixHandling legitimate slow tests
Some tests genuinely need more time:
import pytest
# Mark with longer timeout
@pytest.mark.timeout(600) # 10 minutes
def test_integration_suite():
pass
# Or disable timeout for specific test
@pytest.mark.timeout(0)
def test_known_slow():
pass
# Group slow tests for separate runs
@pytest.mark.slow
@pytest.mark.timeout(300)
def test_performance():
passRun slow tests separately:
# Skip slow tests in regular runs
pytest -m "not slow" --timeout=60
# Run slow tests with longer timeout
pytest -m slow --timeout=600Configuration
Skip this check
[tool.pycmdcheck]
skip = ["TS008"]CLI
pycmdcheck --skip TS008Why NOTE severity?
This check is a NOTE because:
- Small projects may not need timeouts
- Local development often doesn’t require timeout enforcement
- Some test suites have custom timeout handling
However, timeouts are strongly recommended for:
- CI/CD pipelines
- Large test suites
- Integration tests
- Any tests involving I/O or network