From e648b5c7934e101d3e5b89854ae594867a42b8de Mon Sep 17 00:00:00 2001 From: Thomas Dresselhaus Date: Wed, 8 Jul 2026 16:16:24 +0200 Subject: [PATCH] fix(pypi): preserve real version for URL-pinned pip deps on re-lock `get_package` reconstructs an already-locked dependency into a Poetry package during the reconcile solve (`--update`, or a changed input under `--check-input-hash`). For URL-sourced deps it hard-coded `version="0.0.0"`, discarding the real version in `locked.version`. When another package constrains the URL-pinned dep by version, holding it at `0.0.0` corrupts the reconcile: the solver either silently downgrades the constraining packages to ancient versions (emitting the URL dep as `0.0.0`), or fails with a `SolverProblemError` when no downgrade is possible. A first-time lock is unaffected because the URL dep is resolved fresh. Use `locked.version`, matching the non-URL `else` branch, while keeping the URL pin intact. A LockedDependency's source is always a URL source (`DependencySource.type` is `Literal["url"]`), so no gating is needed. Adds a deterministic regression test. Co-Authored-By: Claude Opus 4.8 (1M context) --- conda_lock/pypi_solver.py | 2 +- tests/test_conda_lock.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/conda_lock/pypi_solver.py b/conda_lock/pypi_solver.py index 8dba0f55f..91de57f8c 100644 --- a/conda_lock/pypi_solver.py +++ b/conda_lock/pypi_solver.py @@ -351,7 +351,7 @@ def get_package(locked: LockedDependency) -> PoetryPackage: locked.name, source_type="url", source_url=locked.source.url, - version="0.0.0", + version=locked.version, ) else: return PoetryPackage(locked.name, version=locked.version) diff --git a/tests/test_conda_lock.py b/tests/test_conda_lock.py index d4f053c8e..e2995c429 100644 --- a/tests/test_conda_lock.py +++ b/tests/test_conda_lock.py @@ -78,6 +78,7 @@ from conda_lock.invoke_conda import is_micromamba, reset_conda_pkgs_dir from conda_lock.lockfile import parse_conda_lock_file from conda_lock.lockfile.v2prelim.models import ( + DependencySource, HashModel, LockedDependency, MetadataOption, @@ -94,6 +95,7 @@ MANYLINUX_TAGS, PlatformEnv, _strip_auth, + get_package, parse_pip_requirement, solve_pypi, ) @@ -3480,6 +3482,28 @@ def test_pip_full_whl_url( ) +def test_get_package_preserves_version_for_url_source(): + """A URL-sourced locked dep must reconcile with its real version, not a 0.0.0 placeholder.""" + url = "https://example.com/foo-1.2.3-py3-none-any.whl" + locked = LockedDependency( + name="foo", + version="1.2.3", + manager="pip", + platform="linux-64", + dependencies={}, + url=url, + hash=HashModel(), + source=DependencySource(type="url", url=url), + ) + + package = get_package(locked) + + assert str(package.version) == "1.2.3" + # The dependency stays URL-pinned. + assert package.source_type == "url" + assert package.source_url == url + + def test_when_merging_lockfiles_content_hashes_are_updated( conda_exe: str, monkeypatch: "pytest.MonkeyPatch",