A Pytest Plugin for Mypy static type checking integration
—
Specialized pytest test items that handle mypy type checking integration. These items execute mypy checks and integrate results into pytest's test execution and reporting framework.
Foundation class for all mypy-related test items with shared functionality.
class MypyItem(pytest.Item):
"""
Base class for mypy-related test items.
Automatically adds the 'mypy' marker to enable filtering with -m mypy.
Provides custom error representation for mypy-specific exceptions.
"""
def __init__(self, *args: Any, **kwargs: Any): ...
def repr_failure(
self,
excinfo: pytest.ExceptionInfo[BaseException],
style: Optional[str] = None
) -> Union[str, TerminalRepr]:
"""
Custom failure representation for mypy errors.
Parameters:
- excinfo: Exception information from pytest
- style: Optional styling preference
Returns:
Clean error message string or terminal representation
"""Test item that performs mypy type checking on individual Python files.
class MypyFileItem(MypyItem):
"""
Test item for mypy type checking of a specific file.
Executes mypy on the associated file and reports any type errors
found. Integrates with pytest's xfail mechanism when configured.
"""
def runtest(self) -> None:
"""
Execute mypy check on the associated file.
Raises MypyError if type checking violations are found,
unless all errors are informational notes. Supports xfail
mode when --mypy-xfail option is used.
Raises:
- MypyError: When type checking violations are found
"""
def reportinfo(self) -> Tuple[Path, None, str]:
"""
Generate test report heading for this mypy check.
Returns:
Tuple containing file path, line number (None), and formatted test name
"""Test item that validates mypy's overall exit status across all checked files.
class MypyStatusItem(MypyItem):
"""
Test item for validating mypy's overall exit status.
Ensures mypy exited successfully across all checked files.
Prevents tests from passing when mypy failed globally but
individual file checks appeared successful.
"""
def runtest(self) -> None:
"""
Validate mypy's exit status from the cached results.
Raises MypyError if mypy exited with non-zero status,
indicating type checking failures that may not have been
captured by individual file items.
Raises:
- MypyError: When mypy exit status is non-zero
"""Plugin responsible for creating mypy test items during pytest's collection phase.
class MypyCollectionPlugin:
"""
Pytest plugin that creates MypyFile instances during collection.
Automatically registered when mypy options are detected.
Creates test items for .py and .pyi files while avoiding
duplicate collection when both file types exist.
"""
def pytest_collect_file(
self,
file_path: Path,
parent: pytest.Collector
) -> Optional[MypyFile]:
"""
Create MypyFile for Python source files.
Parameters:
- file_path: Path to potential Python file
- parent: Parent collector in pytest hierarchy
Returns:
MypyFile instance for .py/.pyi files, None otherwise
Note:
Skips .py files when corresponding .pyi stub exists
to avoid duplicate module errors.
"""Pytest File subclass that generates mypy test items.
class MypyFile(pytest.File):
"""
File collector that generates mypy test items.
Creates both file-specific checking items and optional
status validation items for comprehensive type checking.
"""
def collect(self) -> Iterator[MypyItem]:
"""
Generate mypy test items for this file.
Yields:
- MypyFileItem: Type checking for this specific file
- MypyStatusItem: Global mypy status check (when enabled)
The status item is only created once per session and
only when --mypy-no-status-check is not specified.
"""# In conftest.py - customize mypy test items
import pytest_mypy
def pytest_configure(config):
# Custom error handling for MypyFileItem
original_runtest = pytest_mypy.MypyFileItem.runtest
def custom_runtest(self):
try:
original_runtest(self)
except pytest_mypy.MypyError as e:
# Custom error processing
print(f"Type error in {self.path}: {e}")
raise
pytest_mypy.MypyFileItem.runtest = custom_runtest# Example of processing mypy errors in test items
def pytest_runtest_call(pyfuncitem):
if hasattr(pyfuncitem, 'path') and isinstance(pyfuncitem, pytest_mypy.MypyFileItem):
# Access mypy results for this item
results = pytest_mypy.MypyResults.from_session(pyfuncitem.session)
file_errors = results.path_lines.get(pyfuncitem.path.resolve(), [])
# Filter by error severity
error_lines = [line for line in file_errors
if pytest_mypy._error_severity(line) == "error"]
warning_lines = [line for line in file_errors
if pytest_mypy._error_severity(line) == "warning"]
print(f"Found {len(error_lines)} errors and {len(warning_lines)} warnings")# Run only mypy checks, excluding regular tests
pytest --mypy -m mypy src/
# Run mypy checks alongside specific test markers
pytest --mypy -m "mypy or unit" src/The test items integrate with pytest's standard reporting:
[mypy] path/to/file.py[mypy] mypy-statusInstall with Tessl CLI
npx tessl i tessl/pypi-pytest-mypy