| # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
| # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt |
| |
| """ |
| Pytest auto configuration. |
| |
| This module is run automatically by pytest, to define and enable fixtures. |
| """ |
| |
| from __future__ import annotations |
| |
| import os |
| import sys |
| import sysconfig |
| import warnings |
| |
| from pathlib import Path |
| from typing import Iterator |
| |
| import pytest |
| |
| from coverage import env |
| from coverage.files import set_relative_directory |
| |
| # Pytest will rewrite assertions in test modules, but not elsewhere. |
| # This tells pytest to also rewrite assertions in these files: |
| pytest.register_assert_rewrite("tests.coveragetest") |
| pytest.register_assert_rewrite("tests.helpers") |
| |
| # Pytest can take additional options: |
| # $set_env.py: PYTEST_ADDOPTS - Extra arguments to pytest. |
| |
| pytest_plugins = [ |
| "tests.balance_xdist_plugin", |
| "tests.select_plugin", |
| ] |
| |
| |
| @pytest.fixture(autouse=True) |
| def set_warnings() -> None: |
| """Configure warnings to show while running tests.""" |
| warnings.simplefilter("default") |
| warnings.simplefilter("once", DeprecationWarning) |
| |
| # Warnings to suppress: |
| # How come these warnings are successfully suppressed here, but not in pyproject.toml?? |
| |
| if env.PYPY: |
| # pypy3 warns about unclosed files a lot. |
| warnings.filterwarnings("ignore", r".*unclosed file", category=ResourceWarning) |
| |
| # Don't warn about unclosed SQLite connections. |
| # We don't close ":memory:" databases because we don't have a way to connect |
| # to them more than once if we close them. In real coverage.py uses, there |
| # are only a couple of them, but our test suite makes many and we get warned |
| # about them all. |
| # Python3.13 added this warning, but the behavior has been the same all along, |
| # without any reported problems, so just quiet the warning. |
| # https://github.com/python/cpython/issues/105539 |
| warnings.filterwarnings("ignore", r"unclosed database", category=ResourceWarning) |
| |
| |
| @pytest.fixture(autouse=True) |
| def reset_sys_path() -> Iterator[None]: |
| """Clean up sys.path changes around every test.""" |
| sys_path = list(sys.path) |
| yield |
| sys.path[:] = sys_path |
| |
| |
| @pytest.fixture(autouse=True) |
| def reset_environment() -> Iterator[None]: |
| """Make sure a test setting an envvar doesn't leak into another test.""" |
| old_environ = os.environ.copy() |
| yield |
| os.environ.clear() |
| os.environ.update(old_environ) |
| |
| |
| @pytest.fixture(autouse=True) |
| def reset_filesdotpy_globals() -> Iterator[None]: |
| """coverage/files.py has some unfortunate globals. Reset them every test.""" |
| set_relative_directory() |
| yield |
| |
| WORKER = os.getenv("PYTEST_XDIST_WORKER", "none") |
| |
| def pytest_sessionstart() -> None: |
| """Run once at the start of the test session.""" |
| # Only in the main process... |
| if WORKER == "none": |
| # Create a .pth file for measuring subprocess coverage. |
| pth_dir = find_writable_pth_directory() |
| assert pth_dir |
| (pth_dir / "subcover.pth").write_text("import coverage; coverage.process_startup()\n") |
| # subcover.pth is deleted by pytest_sessionfinish below. |
| |
| |
| def pytest_sessionfinish() -> None: |
| """Hook the end of a test session, to clean up.""" |
| # This is called by each of the workers and by the main process. |
| if WORKER == "none": |
| for pth_dir in possible_pth_dirs(): # pragma: part covered |
| pth_file = pth_dir / "subcover.pth" |
| if pth_file.exists(): |
| pth_file.unlink() |
| |
| |
| def possible_pth_dirs() -> Iterator[Path]: |
| """Produce a sequence of directories for trying to write .pth files.""" |
| # First look through sys.path, and if we find a .pth file, then it's a good |
| # place to put ours. |
| for pth_dir in map(Path, sys.path): # pragma: part covered |
| pth_files = list(pth_dir.glob("*.pth")) |
| if pth_files: |
| yield pth_dir |
| |
| # If we're still looking, then try the Python library directory. |
| # https://github.com/nedbat/coveragepy/issues/339 |
| yield Path(sysconfig.get_path("purelib")) # pragma: cant happen |
| |
| |
| def find_writable_pth_directory() -> Path | None: |
| """Find a place to write a .pth file.""" |
| for pth_dir in possible_pth_dirs(): # pragma: part covered |
| try_it = pth_dir / f"touch_{WORKER}.it" |
| try: |
| try_it.write_text("foo") |
| except OSError: # pragma: cant happen |
| continue |
| |
| os.remove(try_it) |
| return pth_dir |
| |
| return None # pragma: cant happen |