From 65b8720a4af4bfed541f36a5b69a81326e285578 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 2 Jul 2026 11:06:23 -0700 Subject: [PATCH] fix(tests): root pytest run collects all 3 packages via importlib (TAP-4575) Cross-package ImportPathMismatchError from three identically-named `tests` trees broke the root `pytest` run, forcing per-package invocations. Switch to --import-mode=importlib + consider_namespace_packages, drop the colliding tests/__init__.py files, and pin docs-mcp on pythonpath so `from tests.helpers` still resolves. Collapse the prepush/regression per-package loops into a single root run. Root collection now: 10244 tests collected, 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/docs-mcp/tests/__init__.py | 0 packages/tapps-core/tests/__init__.py | 0 packages/tapps-mcp/tests/__init__.py | 0 pyproject.toml | 15 ++++++++++++++- scripts/prepush-smoke.sh | 6 ++++-- scripts/run-regression.sh | 17 ++++++----------- 6 files changed, 24 insertions(+), 14 deletions(-) delete mode 100644 packages/docs-mcp/tests/__init__.py delete mode 100644 packages/tapps-core/tests/__init__.py delete mode 100644 packages/tapps-mcp/tests/__init__.py diff --git a/packages/docs-mcp/tests/__init__.py b/packages/docs-mcp/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/tapps-core/tests/__init__.py b/packages/tapps-core/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/tapps-mcp/tests/__init__.py b/packages/tapps-mcp/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyproject.toml b/pyproject.toml index f953c143..0739818b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -187,6 +187,13 @@ testpaths = [ # passed positionally (e.g. ``pytest packages/tapps-mcp``), which overrides # testpaths. Excluding src/ keeps that invocation hermetic. norecursedirs = ["src", ".venv", "*.egg", "build", "dist", "node_modules"] +# TAP-4575: docs-mcp test modules import shared fixtures via ``from tests.helpers +# import ...``. With the tests/__init__.py files removed (so the three packages' +# identically named ``tests`` trees no longer collide under importlib), that +# import resolves only if docs-mcp's package root is on the path and ``tests`` is +# treated as a namespace package (consider_namespace_packages above). Only +# docs-mcp ships tests/helpers.py, so this is unambiguous. +pythonpath = ["packages/docs-mcp"] asyncio_mode = "auto" timeout = 60 markers = [ @@ -195,7 +202,13 @@ markers = [ "optional_deps: marks tests requiring optional dependencies (sentence-transformers, faiss-cpu, cohere)", "brain_contract: marks tests requiring a running tapps-brain HTTP server (3.18+)", ] -addopts = "-v --tb=short -p randomly --randomly-seed=last" +addopts = "-v --tb=short -p randomly --randomly-seed=last --import-mode=importlib" +# TAP-4575: importlib import mode lets the three packages' identically named +# ``tests`` trees (each ships tests/__init__.py) be collected together from the +# repo root without pytest's rootdir-based ImportPathMismatchError. Namespace +# packages must be considered so docs-mcp's ``from tests.helpers import ...`` +# still resolves under importlib mode. +consider_namespace_packages = true filterwarnings = [ "ignore:tapps_core\\.memory is deprecated:DeprecationWarning", "ignore:tapps_core\\.memory\\.gc is deprecated:DeprecationWarning", diff --git a/scripts/prepush-smoke.sh b/scripts/prepush-smoke.sh index 64a78b26..4d6fd2dc 100755 --- a/scripts/prepush-smoke.sh +++ b/scripts/prepush-smoke.sh @@ -5,8 +5,10 @@ # Intentionally avoids pytest-xdist (-n auto): parallel runs starve live Cursor # MCP child processes during push and can flake unrelated integration tests. # -# Each test path runs in its own pytest invocation to avoid conftest.py -# ImportPathMismatchError across packages. +# Each curated test path runs in its own serial pytest invocation for that +# xdist-avoidance reason. (The cross-package conftest.py ImportPathMismatchError +# that once forced separate invocations is fixed — TAP-4575 added +# --import-mode=importlib so a single root run collects all three packages.) set -euo pipefail diff --git a/scripts/run-regression.sh b/scripts/run-regression.sh index 87cad326..3a54ac69 100755 --- a/scripts/run-regression.sh +++ b/scripts/run-regression.sh @@ -15,17 +15,12 @@ if [[ "${1:-}" == "--serial" ]]; then XDIST=() fi -echo "[regression] Full non-slow suite (all packages). Not part of git push." >&2 -FAILED=0 -for PKG in packages/tapps-mcp packages/tapps-core packages/docs-mcp; do - echo "[regression] $PKG/tests/" >&2 - if ! uv run pytest "$PKG/tests/" -m "not slow" -q --tb=line --timeout=60 "${XDIST[@]}" --maxfail=3; then - FAILED=1 - fi -done - -if [[ "$FAILED" -ne 0 ]]; then - echo "[regression] FAILED — investigate with: uv run pytest /tests/ -m 'not slow' -v" >&2 +echo "[regression] Full non-slow suite (all packages, single invocation). Not part of git push." >&2 +# TAP-4575: the three packages' tests are collected in one root pytest run +# (testpaths + --import-mode=importlib in pyproject.toml). No more per-package +# loop — a single invocation restores cross-package xdist parallelism. +if ! uv run pytest -m "not slow" -q --tb=line --timeout=60 "${XDIST[@]}" --maxfail=3; then + echo "[regression] FAILED — investigate with: uv run pytest -m 'not slow' -v" >&2 exit 1 fi