Multiple dev packages with hard pins cannot be resolved without override
Checks
-
[x] I have checked that this issue has not already been reported.
-
[x] I have confirmed this bug exists on the latest version of pixi, using
pixi --version.
Reproducible example
I am working on two Python packages which have a hard dependency on each other dask and distributed. These two packages are released in lock step and the pyproject.toml of each package is updated to depend on each other.
Currently the latest release is 2025.11.0, so dask depends on distributed==2025.11.0 and distributed depends on dask==2025.11.0. I usually develop these in a single conda environment with both packages installed via pip install -e .. After @lucascolley gave a neat EuroSciPy demo of using pixi to develop with multiple packages installed from source I've been meaning to give this a go.
However, with this hard pinning pixi doesn't seem to realise that both projects are installed from source, so it's failing to resolve. Both packages use setuptools-scm to dynamically set the version number from git, so once there are commits on main the versions look something like 2025.11.1.dev2+gc7d9c55e5.
mkdir pixidasktest && cd pixidasktest
git clone [email protected]:dask/dask.git
git clone [email protected]:dask/distributed.git
touch pixi.toml
# pixi.toml
[workspace]
channels = ["conda-forge"]
platforms = ["osx-arm64"]
[dependencies]
python = "==3.13"
[pypi-dependencies]
dask = { path = "./dask", editable = true }
distributed = { path = "./distributed", editable = true }
$ pixi shell
Error: × failed to solve the pypi requirements of 'default' 'osx-arm64'
├─▶ failed to resolve pypi dependencies
╰─▶ Because there is no version of dask==2025.11.0 and distributed==2025.11.1.dev2+gc7d9c55e5 depends on dask==2025.11.0, we can conclude that
distributed==2025.11.1.dev2+gc7d9c55e5 cannot be used.
And because only distributed==2025.11.1.dev2+gc7d9c55e5 is available and you require distributed, we can conclude that your requirements
are unsatisfiable.
$ pixi info took 3s
System
------------
Pixi version: 0.59.0
Platform: osx-arm64
Virtual packages: __unix=0=0
: __osx=26.0.1=0
: __archspec=1=m1
Cache dir: /Users/jtomlinson/Library/Caches/rattler/cache
Auth storage: /Users/jtomlinson/.rattler/credentials.json
Config locations: /Users/jtomlinson/.pixi/config.toml
Global
------------
Bin dir: /Users/jtomlinson/.pixi/bin
Environment dir: /Users/jtomlinson/.pixi/envs
Manifest dir: /Users/jtomlinson/.pixi/manifests/pixi-global.toml
Workspace
------------
Name: pixitest
Manifest file: /Users/jtomlinson/Scratch/pixidasktest/pixi.toml
Environments
------------
Environment: default
Features: default
Channels: conda-forge
Dependency count: 1
Dependencies: python
PyPI Dependencies: dask, distributed
Target platforms: osx-arm64
Prefix location: /Users/jtomlinson/Scratch/pixidasktest/.pixi/envs/default
Is there a way of telling pixi that the packages can relax their hard pins on each other because they are both installed from source?
Issue description
No response
Expected behavior
I would expect pixi to see that dask depends on distributed==2025.11.0, however in pixi.toml there is already distributed editable installed from source so that takes precedence.
cc @VeckoTheGecko I know you have been working with these packages in the xarray Pixi setup somewhat
probably there is some way along the lines of https://github.com/pydata/xarray/pull/10888/commits/8abc993be1519571a570a023d993a1084a5078ae to get around this using https://pixi.sh/latest/advanced/override/
probably there is some way along the lines of pydata/xarray@8abc993 to get around this using pixi.sh/latest/advanced/override
Exactly this - distributed pins the version of dask so you have to override it
Thanks @VeckoTheGecko @lucascolley. I found that specifying the packages again as overrides gets things working. It's a shame this doesn't happen automatically for packages installed from source like this, that's what I would've expected to happen.
[workspace]
channels = ["conda-forge"]
platforms = ["osx-arm64"]
[dependencies]
python = "==3.13"
[pypi-dependencies]
dask = { path = "./dask", editable = true }
distributed = { path = "./distributed", editable = true }
[pypi-options.dependency-overrides]
dask = { path = "./dask", editable = true }
distributed = { path = "./distributed", editable = true }
It's a shame this doesn't happen automatically for packages installed from source like this
Going out on a limb here - I disagree with this.
2025.11.1.dev2+gc7d9c55e5 should not satisfy the hard pin of ==2025.11.1 since its just not that version. It could, however, satisfy >=2025.11.1,<2025.11.2.
Explicitly overriding it is a feature I think - but if you want you can update your pyproject.toml to the above pin if you want to avoid explicitly specifying it (I haven't tested, but I think that should work)
Note that Pixi defers to UV for Pypi - so this is actually upstream.
UV reproducer https://github.com/pydata/xarray/pull/10888#issuecomment-3516452010
2025.11.1.dev2+gc7d9c55e5 should not satisfy the hard pin of ==2025.11.1 since its just not that version. It could, however, satisfy >=2025.11.1,<2025.11.2.
I hear what you're saying, but I've already explicitly put dask = { path = "./dask", editable = true }. So it doesn't really matter if another package depends on a hard pinned version of dask (or any other constraint for that matter), by installing as editable I'm implicitly overriding everything else. I can't imagine a situation where you would want something else to happen.
I appreciate that Python says explicit > implicit, but this seems like one of those situations where there's only one possible course of action so implicit is fine.
We follow uv in this case so I think we'll wait for a solution there. In the mean time the dependency overrides seem like a good solution that follows proper semantics.