verify-pytest-imports-worktree-not-primary-checkout · v1.0.0 · 2026-08-12 · sha256 648bb4ac30fe5379
verify-pytest-imports-worktree-not-primary-checkout v1.0.0A
Immutable. This exact content is served forever at /api/v1/blob/648bb4ac30fe5379.
---
name: verify-pytest-imports-worktree-not-primary-checkout
description: |
When you run pytest (or any `python -c "import <pkg>"`) from a git WORKTREE
but the venv has an editable install (`pip install -e .`) made from the
PRIMARY checkout, `import <pkg>` silently resolves to the PRIMARY checkout's
source, NOT the worktree code you think you're testing. Use when: (1) you
edited code in a worktree, ran the suite, it passed/failed — but you're
unsure it exercised the worktree's edits, (2) tests pass on changes that
"shouldn't" pass (or fail on changes you reverted), (3) a `src/`-layout
project with absolute `import src.*` / `import <pkg>.*` imports, one shared
`.venv`, and multiple worktrees. Fix: prepend the worktree root to
`PYTHONPATH` and VERIFY resolution with `print(<pkg>.__file__)`.
author: Claude Code
version: 1.0.0
date: 2026-05-29
disable-model-invocation: true
---
# Pytest editable-install resolves to primary checkout, not the worktree
## Problem
You have one virtualenv with an **editable install** (`pip install -e .`) created
from the **primary** repo checkout. You then create a git **worktree** to do
isolated feature work, edit code there, and run the test suite from the worktree
directory. The suite runs against the **primary checkout's** source, not your
worktree edits — silently. Green tests "prove" nothing about your branch; a fix
you only made in the worktree looks like it had no effect, or a bug you only
reverted in the worktree still appears.
## Context / Trigger Conditions
- A `src/`-layout project whose code uses **absolute** imports (`import src.app`,
`from mypkg.x import y`) — so the package is resolved via `sys.path`, not via
the cwd.
- ONE shared venv with `pip install -e .` (or `pip install -e ".[dev]"`) run from
the **primary** checkout. The editable install drops a `__editable__.<pkg>.pth`
/ finder into site-packages that **hardcodes the primary checkout's path**.
- You run `pytest` / `python -m pytest` / `python -c "import <pkg>"` from a
**git worktree** directory (e.g. `.../.claude/worktrees/feature-x`).
- Symptom: tests pass on a change you believe is incomplete, OR fail on code you
already fixed in the worktree, OR you simply can't be sure which tree ran.
## Why it happens
`sys.path` precedence at import time is roughly: the script/cwd entry, then
`PYTHONPATH` entries, then site-packages (where the editable `.pth` lives).
pytest does **not** reliably put the worktree's project root first (it only adds
`rootdir`/cwd under specific `pythonpath`/`conftest`/`rootdir` conditions, and a
`src/` layout usually means `src`'s parent isn't auto-added). So `import <pkg>`
falls through to the editable install's hardcoded **primary** path. Nothing
errors — it's just the wrong tree.
## Solution
Prepend the **worktree root** to `PYTHONPATH` so it wins over the editable
`.pth`, and **verify resolution** before trusting any result:
```bash
WT=/abs/path/to/worktree # the worktree you edited
VENV=/abs/path/to/primary/.venv # the shared venv with the editable install
# 1. VERIFY which tree import resolves to — do this FIRST, every time:
PYTHONPATH="$WT" "$VENV/bin/python" -c \
"import src.app, pathlib; print('src from:', pathlib.Path(src.app.__file__))"
# want: src from: /abs/path/to/worktree/src/app.py (NOT the primary checkout)
# 2. Run the suite with the same override:
cd "$WT" && PYTHONPATH="$WT" "$VENV/bin/python" -m pytest tests/ -q
```
Alternatives (heavier): create a fresh venv inside the worktree and
`pip install -e .` there; or use `tox`/`uv run` with per-tree environments. The
`PYTHONPATH` prepend is the fastest and needs no install.
## Verification
The `print(<pkg>.__file__)` line resolves to a path **under the worktree**, not
the primary checkout. A quick negative control: run the same one-liner WITHOUT
`PYTHONPATH` — it should print the primary path, confirming the trap is real and
the override is doing the work.
## Example
brief-runner S26: fixing a template/CSS bug in worktree
`.claude/worktrees/s26-configure-fix`, the venv lived at the primary checkout
(`/Users/.../the-handover-repo/.venv`) with `pip install -e .`. Before running the
wizard tests I checked:
```
$ PYTHONPATH="$PWD" /…/the-handover-repo/.venv/bin/python -c \
"import src.app, pathlib; print('src from:', pathlib.Path(src.app.__file__))"
src from: /Users/.../the-handover-repo/.claude/worktrees/s26-configure-fix/src/app.py ✓
```
Confirmed the worktree's `src` won; the 17-test wizard suite then genuinely
exercised the worktree edits. Without the check, a green run would have been
meaningless.
## Notes
- This is distinct from cwd/edit-staleness worktree traps
(`flask-debug-cross-worktree-edit-stale`, `multi-worktree-file-url-stale-content`,
`main-bash-cwd-persists-nested-worktree`): here the *files* are fine in the
worktree, but the Python *import machinery* points elsewhere because of the
editable install's hardcoded path. Same family ("am I really running the tree I
think I am?"), different mechanism.
- The Bash tool's cwd is reset between calls in some harnesses, so don't rely on a
prior `cd` — pass `PYTHONPATH` (and an absolute venv python) on the same command
line every time.
- If the project ever switches to a flat layout or a non-editable install, the
trap changes shape — re-verify with `__file__` rather than assuming.
- Same reasoning applies to `ruff`/`mypy`/coverage that import the package: verify
the resolved path, not just that the tool ran.
## References
- PEP 660 (editable installs via build backends) — explains the hardcoded-path
finder/`.pth` that site-packages installs.
- pytest `pythonpath` / import-mode docs — why `src/` roots aren't auto-added.