Description
Description
It seems that you can't install a package in editable mode, while simultaneously installing a package that depends on that package via a direct reference.
I came across this issue when splitting a project into 2 packages that both live in the same repository. Package A now depends on Package B via a direct reference. Since both are in the same repository, I tried installing both in editable mode, but pip came back with:
# pip install --use-feature=in-tree-build -e package_a/ -e package_b/
Obtaining file:///home/austin/workspace/pypa/test_project/package_a
Obtaining file:///home/austin/workspace/pypa/test_project/package_b
Processing ./package_b
ERROR: Cannot install package-a==1.0.0 and package-b 1.0.0 (from /home/austin/workspace/pypa/test_project/package_b) because these package versions have conflicting dependencies.
The conflict is caused by:
The user requested package-b 1.0.0 (from /home/austin/workspace/pypa/test_project/package_b)
package-a 1.0.0 depends on package-b 1.0.0 (from /home/austin/workspace/pypa/test_project/package_b)
To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip attempt to solve the dependency conflict
ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/user_guide/#fixing-conflicting-dependencies
It seems that this action should be allowed taking the wording of the error message at face value.
I did some debugging and found that Resolution._add_to_criteria
from src/pip/_vendor/resolvelib/resolvers.py
raises a RequirementsConflicted
exception. The resolver cannot resolve the 2 requirements below. The resolver fails to generate any candidates apparently because both requirements are instances of ExplicitRequirement
.
RequirementInformation(requirement=ExplicitRequirement(EditableCandidate('file:///home/austin/workspace/pypa/test_project/project_b')), parent=None)
RequirementInformation(requirement=ExplicitRequirement(LinkCandidate('file:///home/austin/workspace/pypa/test_project/project_b')), parent=EditableCandidate('file:///home/austin/workspace/pypa/test_project/project_a'))
We have 2 workarounds for this:
- Remove the direct reference from
package_a
, and just havepackage_a
depend on any package namedpackage_b
. This is an issue because Package A won't know where to get Package B unless you install them both at the same time withpip install -e ./package_a/ -e ./package_b/
. More worrying is if someone registers a package on PyPI that matches the name of our "Package B". - Install "Package A" first, then install "Package B" later. This is the solution we went with, since Pip now takes previously installed packages into consideration when solving an environment, and we keep the versions of dependencies of both packages relatively in sync. This does feel like it could cause problems down the road.
Expected behavior
I'm not sure what should be expected in this situation? It seems like one of these should be true:
- Pip should allow
pip install -e A -e B
when A depends on B via a direct reference - Pip's error message for Point 1 should indicate why you can't do that
- Setuptools should allow you to install a direct-reference package in editable mode
Point 3 doesn't feel right, but just wanted to throw that out there.
pip version
21.3.dev0 (commit: a53f888)
Python version
3.9.5
OS
Ubuntu 21.04 hirsute
How to Reproduce
Create a directory named "package_b". Create a setup.py
in that directory with the contents:
from setuptools import setup
setup(name="package_b", version="1.0.0")
Create a directory named "package_a" in the same directory that contains the "package_b" directory. Create a setup.py
in that directory with the contents:
from setuptools import setup
import os
package_b_dir = os.path.dirname(__file__).replace("package_a", "package_b")
setup(
name="package_a",
version="1.0.0",
install_requires=[
"package_b @ file://%s" % package_b_dir,
],
)
You should now have:
.
├── package_a
│ └── setup.py
└── package_b
└── setup.py
Now run pip install -e ./package_a/ -e ./package_b/
.
Output
The output is above in the description section, but pasting it here as well:
# pip install --use-feature=in-tree-build -e package_a/ -e package_b/
Obtaining file:///home/austin/workspace/pypa/test_project/package_a
Obtaining file:///home/austin/workspace/pypa/test_project/package_b
Processing ./package_b
ERROR: Cannot install package-a==1.0.0 and package-b 1.0.0 (from /home/austin/workspace/pypa/test_project/package_b) because these package versions have conflicting dependencies.
The conflict is caused by:
The user requested package-b 1.0.0 (from /home/austin/workspace/pypa/test_project/package_b)
package-a 1.0.0 depends on package-b 1.0.0 (from /home/austin/workspace/pypa/test_project/package_b)
To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip attempt to solve the dependency conflict
ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/user_guide/#fixing-conflicting-dependencies
Code of Conduct
- I agree to follow the PSF Code of Conduct.