Repository navigation
fix(adapters): isolate imports when switching projects (MUT-021) - #119
Conversation
|
@BasilZafar11 is attempting to deploy a commit to the priyanshu's projects Team on Vercel. A member of the Team first needs to authorize it. |
CodewithJha
left a comment
There was a problem hiding this comment.
Thanks @BasilZafar11, this is close. The core of #69 is fixed, and the tests are strong. One real regression needs fixing before merge.
What is working
- On
8c5a474, sequential A → B → A loads return the right agent each time, including deferred imports, regular and namespace helper packages, andagent:support_agentrefs. - Mutation check: with
loader.pyreverted tomain, all 7 new tests fail. With your change they pass. Full offline suite: 663 passed, and CI is green. - The CLI path (
run_cmd/test_cmd) selects the same root twice, so nothing is purged. One-shot CLI behaviour is unchanged, and Hosted never reaches this code. test_missing_agent_does_not_fall_back_to_previous_projectis a nice catch. It covers the silent wrong-agent case that the issue is really about.
What still needs to change
The purge condition pops every module whose file lives anywhere under the previous root, not just modules imported from that root. When a project directory contains its own virtualenv (the default with uv / python -m venv .venv), switching projects also purges installed packages.
Reproduced on this branch:
- Project A has
.venv/lib/python3.12/site-packages/fakesdkonsys.path. Load A, then B, then re-importfakesdk: it is a new module object, andisinstance(old_obj, fakesdk.Agent)isFalse. - Select this repository checkout as a project, then switch to a temp project: 1,403 modules are purged, including
pydanticand all ofmutiny_core(its editable install lives under the repo root). Objects created before the switch no longer match their classes.
That is the in-process multi-project scenario #69 targets, so it trades one wrong-identity bug for another.
Important
Please keep the scope you already have: same-root reselect stays a no-op, sys.path ordering stays as is, and no change to Hosted.
Suggested direction
Only drop modules that were imported with the previous root as their sys.path entry, meaning the first path segment under the root is the module's own top-level name. I tried this locally: all 7 of your tests still pass, and both reproductions above purge nothing (fakesdk / pydantic / mutiny_core keep their identity):
top = name.partition(".")[0]
for path in paths:
resolved = Path(path).resolve()
if resolved.is_relative_to(_project_root):
first = resolved.relative_to(_project_root).parts[:1]
if first in ((top,), (f"{top}.py",)):
names.append(name)
breakPlease add one regression test: a project whose root contains a package directory that is on sys.path separately (for example .venv/.../site-packages/fakesdk). After switching to another project, sys.modules["fakesdk"] should still be the same object.
| module_file = getattr(module, "__file__", None) | ||
| if module_file: | ||
| paths.append(module_file) | ||
| if any(Path(path).resolve().is_relative_to(_project_root) for path in paths): |
There was a problem hiding this comment.
This matches any file under the previous root, including <root>/.venv/.../site-packages/* and editable installs such as <repo>/packages/*/src. Switching away from the repo checkout purges 1,403 modules here, including pydantic and mutiny_core. Narrow it to modules whose first path segment under the root is their own top-level name (agent.py, project_helpers/...); see the review summary for a snippet that keeps all 7 tests green.
|
Addressed the review in commit 3740c80. The purge now targets modules imported directly from the project root, preserving virtualenv and editable dependency identities. Added regression coverage for both dependency layouts and switching away from the repository checkout. All 666 tests pass; Ruff and offline CLI smoke also pass. PR #119 is updated and ready for another review. Thanks for catching this. |
CodewithJha
left a comment
There was a problem hiding this comment.
Thanks @BasilZafar11, great turnaround. The narrowing is exactly right, and the new tests cover the regression well. Approving and merging.
Re-review of 3740c80
- ✓
.venv/ editable repro: I selected this repository checkout as a project, then switched to a temp project. 0 modules are purged now, down from 1,403.pydanticandmutiny_corekeep their identity. - ✓ Original fix still holds: all 7 A → B → A tests pass.
- ✓ Mutation checks:
- Broadening the condition back to "anything under the root" fails all 3 new regression tests: both
fakesdklayouts and the checkout-switch test. - Reverting
loader.pytomainfails 9 of 10 tests in the file.
- Broadening the condition back to "anything under the root" fails all 3 new regression tests: both
- ✓ Scope is unchanged: same-root reselect is still a no-op, so one-shot CLI behaviour is untouched, and Hosted never reaches this code.
- ✓ Checks: full suite 666 passed, Ruff clean, the offline CLI sample
run/testworks, and GitHub Actions is green.
This closes #69.
If you'd like to keep going
Co-authored-by: Cursor <cursoragent@cursor.com>
Fixes #69
Summary
agent.pyorproject_helpers/). Virtualenv packages and editable installs on separate import paths retain module and class identity.Review follow-up
Addressed the dependency identity regression in commit
3740c80. Both new fake SDK cases failed before narrowing the purge and now pass. A checkout regression also verifiesmutiny_coreandpydanticremain the same modules after switching away. Merged latest upstreammainwithout rewriting branch history.Type of change
Checklist
Test plan
uv run ruff checkpassed afteruv sync --extra dev.MUTINY_SAMPLE_OFFLINE=1 uv run pytest -q --tb=short: 666 passed on local Python 3.13. CI covers Python 3.11 and 3.12.mutiny --help,mutiny init, andmutiny runsucceeded with empty API keys; a violation regression was saved.Previously verified sample
mutiny testcorrectly returns exit 1 for the deliberately vulnerable sample's refund violations, rather than a loader error. Branch has zero commits behind the fetched upstreammainat push time.