Skip to content

fix: expand editable path dependencies under Poetry >= 2.3.0 - #163

Open
BrandonLWhite wants to merge 1 commit into
python-poetry:mainfrom
BrandonLWhite:fix/editable-path-deps-poetry-2-3
Open

fix: expand editable path dependencies under Poetry >= 2.3.0#163
BrandonLWhite wants to merge 1 commit into
python-poetry:mainfrom
BrandonLWhite:fix/editable-path-deps-poetry-2-3

Conversation

@BrandonLWhite

@BrandonLWhite BrandonLWhite commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #159

Problem

With Poetry >= 2.3.0, poetry bundle venv installs develop = true path dependencies as editable installs. The bundled venv gets a .pth file pointing back at the original source tree instead of a real copy of the package, so the bundle is no longer portable — it breaks as soon as it is shipped to another machine, a container, or a Lambda.

The failure is silent at bundle time: the command reports success and only the destination breaks.

Root cause

Poetry 2.3.0 changed the default of installer.re-resolve from true to false (python-poetry/poetry#10622).

VenvBundler.bundle() neutralizes develop mode with a CustomLocker subclass that overrides Locker.locked_repository() and forces package.develop = False. But Installer._do_install picks its package source based on that config flag:

  • installer.re-resolve = true (the pre-2.3.0 default) → self._locker.locked_repository() — the overridden method, so develop mode was cleared.
  • installer.re-resolve = false (the 2.3.0+ default) → self._locker.locked_packages()not overridden, so develop = true survives from the lock file and the executor performs an editable install.

The plugin was overriding only one of the two seams the installer reads from.

Fix

Override locked_packages() as well, sharing the develop-clearing loop between both overrides.

This leaves the user's installer.re-resolve setting in effect rather than overriding it. The alternative — forcing installer.re-resolve = true on the installer's config, which is the current user-facing workaround (POETRY_INSTALLER_RE_RESOLVE=true poetry bundle venv …) — was rejected because it would permanently opt the plugin out of the faster lockfile-direct install path, and it would stake correctness on a config default that has already changed once.

Why the existing test did not catch it

tests/fixtures/simple_project_with_editable_dep/poetry.lock was lock-version 1.0. Poetry forces re-resolution for lock files older than 2.1 (the is_locked_groups_and_markers() gate in _do_install), so test_bundler_editable_deps only ever exercised the old, working path and passed regardless of this bug.

This PR regenerates that fixture to lock-version 2.1 and parametrizes the test over both installer.re-resolve values, so the regression is pinned on both paths. The fixture's content-hash is unchanged, since its pyproject.toml is untouched. (The bar version in the lock moves 0.1.01.2.3; the old lock file was simply stale relative to bar/pyproject.toml.)

Verification

  • Unit: 26/26 tests pass; mypy --strict clean; all pre-commit hooks pass. Test-first: test_bundler_editable_deps[False] fails with assert 1 == 0 before the fix and passes after, while [True] passes throughout.
  • End to end, since the unit tests mock Executor._execute_operation and therefore assert on Install operations rather than files on disk — a real poetry bundle venv run against Poetry 2.4.1 with default config, on a project with a develop = true path dependency:
    • no .pth file in the bundle's site-packages
    • direct_url.json reads "dir_info": {} rather than "dir_info": {"editable": true}
    • a real, copied package directory is present in site-packages
  • Across the declared poetry>=2.1.0,<3.0.0 range: Locker.locked_packages() exists with an identical signature in Poetry 2.1.0, 2.2.1, 2.3.x and 2.4.x, and installer.re-resolve is in the config schema of all of them. On 2.1/2.2 defaults the new override is dormant but harmless, and it is correct if a user turns re-resolve off there. Lock-version 2.1 is natively readable by Poetry 2.1.0, so the regenerated fixture does not affect older supported versions.

Poetry 2.3.0 changed the default of installer.re-resolve from true to
false (python-poetry/poetry#10622). On that path,
Installer._do_install sources its install targets from
Locker.locked_packages() rather than Locker.locked_repository().
VenvBundler's CustomLocker only overrode locked_repository() to clear
develop mode, so develop = true path dependencies were bundled as
editable installs, leaving a .pth file pointing at the original source
tree and making the bundle non-portable.

Override locked_packages() as well, sharing the develop-clearing loop
between both overrides.

The existing test did not catch this because the
simple_project_with_editable_dep fixture's lock file was lock-version
1.0, and Poetry forces re-resolution for lock files older than 2.1, so
only the working path was ever exercised. Regenerate that fixture to
lock-version 2.1 (content-hash unchanged) and parametrize the test over
both installer.re-resolve values.
@BrandonLWhite
BrandonLWhite marked this pull request as ready for review August 13, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Bundle venv creates editable installs with Poetry 2.3.0+

1 participant