From e255c71cac0b41bf0c75cde5aec78d5f4adfbcb9 Mon Sep 17 00:00:00 2001 From: Chris Rosales Date: Fri, 19 Dec 2025 21:08:33 -0500 Subject: [PATCH] speed up pytest collection - pre-warm heavy imports (numpy, hypothesis, cereal, opendbc.car, etc) - lazy-load fixture modules (OpenpilotPrefix, manager, HARDWARE) - use norecursedirs instead of --ignore flags --- conftest.py | 111 +++++++++++++++++++++++++++++++++++++++++++++++-- pyproject.toml | 30 ++++++++++++- 2 files changed, 136 insertions(+), 5 deletions(-) diff --git a/conftest.py b/conftest.py index 7e40ec3ed7a9d5..4ecf3434a262b2 100644 --- a/conftest.py +++ b/conftest.py @@ -1,11 +1,109 @@ import contextlib import gc import os + +# Pre-warm heavy imports before pytest collection +try: + import numpy # noqa: F401 +except ImportError: + pass + +try: + import hypothesis # noqa: F401 +except ImportError: + pass + +try: + import cereal +except ImportError: + pass + +try: + from opendbc import car # noqa: F401 +except ImportError: + pass + +try: + from openpilot.tools.lib.logreader import LogReader # noqa: F401 +except ImportError: + pass + +try: + import casadi # noqa: F401 +except ImportError: + pass + +try: + from openpilot.common.params import Params # noqa: F401 +except ImportError: + pass + +try: + from openpilot.selfdrive.test import helpers # noqa: F401 +except ImportError: + pass + +try: + import parameterized # noqa: F401 +except ImportError: + pass + +try: + import cereal.messaging # noqa: F401 +except ImportError: + pass + +try: + from cereal import log # noqa: F401 +except ImportError: + pass + +try: + from panda import Panda # noqa: F401 +except ImportError: + pass + +try: + from openpilot.system.manager.process_config import managed_processes # noqa: F401 +except ImportError: + pass + import pytest +from typing import Any + +# Lazy-loaded modules for fixtures +_OpenpilotPrefix: Any = None +_manager: Any = None +_HARDWARE: Any = None + + +def _get_openpilot_prefix(): + global _OpenpilotPrefix + if _OpenpilotPrefix is None: + from openpilot.common.prefix import OpenpilotPrefix + _OpenpilotPrefix = OpenpilotPrefix + return _OpenpilotPrefix + + +def _get_manager(): + global _manager + if _manager is None: + from openpilot.system.manager import manager + _manager = manager + return _manager + + +def _get_hardware(): + global _HARDWARE + if _HARDWARE is None: + from openpilot.system.hardware import HARDWARE + _HARDWARE = HARDWARE + return _HARDWARE + + +def _is_tici(): + return os.path.isfile('/TICI') -from openpilot.common.prefix import OpenpilotPrefix -from openpilot.system.manager import manager -from openpilot.system.hardware import TICI, HARDWARE # TODO: pytest-cpp doesn't support FAIL, and we need to create test translations in sessionstart # pending https://github.com/pytest-dev/pytest-cpp/pull/147 @@ -47,6 +145,9 @@ def clean_env(): @pytest.fixture(scope="function", autouse=True) def openpilot_function_fixture(request): + OpenpilotPrefix = _get_openpilot_prefix() + manager = _get_manager() + with clean_env(): # setup a clean environment for each test with OpenpilotPrefix(shared_download_cache=request.node.get_closest_marker("shared_download_cache") is not None) as prefix: @@ -78,6 +179,7 @@ def tici_setup_fixture(request, openpilot_function_fixture): """Ensure a consistent state for tests on-device. Needs the openpilot function fixture to run first.""" if 'skip_tici_setup' in request.keywords: return + HARDWARE = _get_hardware() HARDWARE.initialize_hardware() HARDWARE.set_power_save(False) os.system("pkill -9 -f athena") @@ -86,9 +188,10 @@ def tici_setup_fixture(request, openpilot_function_fixture): @pytest.hookimpl(tryfirst=True) def pytest_collection_modifyitems(config, items): skipper = pytest.mark.skip(reason="Skipping tici test on PC") + is_tici = _is_tici() for item in items: if "tici" in item.keywords: - if not TICI: + if not is_tici: item.add_marker(skipper) else: item.fixturenames.append('tici_setup_fixture') diff --git a/pyproject.toml b/pyproject.toml index d5dc95e1b1a7b1..98616476e67496 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -144,7 +144,35 @@ allow-direct-references = true [tool.pytest.ini_options] minversion = "6.0" -addopts = "--ignore=openpilot/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ --ignore=msgq/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" +addopts = "-Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup" +norecursedirs = [ + ".git", + ".github", + ".venv", + ".vscode", + ".pytest_cache", + "__pycache__", + "*.egg-info", + "build", + "dist", + "openpilot", + "opendbc", + "opendbc_repo", + "panda", + "rednose", + "rednose_repo", + "tinygrad", + "tinygrad_repo", + "teleoprtc", + "teleoprtc_repo", + "msgq", + "msgq_repo", + "third_party", + "site_scons", + "release", + "scripts", + "docs", +] cpp_files = "test_*" cpp_harness = "selfdrive/test/cpp_harness.py" python_files = "test_*.py"