Exclude from resolver constraints the editable dependencies that will be installed. (#5271)

* Exclude from resolver constraints the editable dependencies that will be installed.
This commit is contained in:
Matt Davis
2022-08-18 18:14:40 -04:00
committed by GitHub
parent 697f1a9e9e
commit 4c393145cc
3 changed files with 36 additions and 72 deletions
+1
View File
@@ -0,0 +1 @@
Fix issue where resolver is provided with ``install_requires`` constraints from ``setup.py`` that depend on editable dependencies and could not resolve them.
+3 -3
View File
@@ -579,7 +579,7 @@ class Project:
def lockfile_content(self):
return self.load_lockfile()
def _get_editable_packages(self, dev=False):
def get_editable_packages(self, dev=False):
section = "dev-packages" if dev else "packages"
packages = {
k: v
@@ -601,11 +601,11 @@ class Project:
@property
def editable_packages(self):
return self._get_editable_packages(dev=False)
return self.get_editable_packages(dev=False)
@property
def editable_dev_packages(self):
return self._get_editable_packages(dev=True)
return self.get_editable_packages(dev=True)
@property
def vcs_packages(self):
+32 -69
View File
@@ -25,7 +25,7 @@ from pipenv.patched.pip._internal.utils.hashes import FAVORITE_HASH
from pipenv.patched.pip._internal.utils.temp_dir import global_tempdir_manager
from pipenv.project import Project
from pipenv.vendor import click
from pipenv.vendor.requirementslib import Pipfile, Requirement
from pipenv.vendor.requirementslib import Requirement
from pipenv.vendor.requirementslib.models.requirements import Line
from pipenv.vendor.requirementslib.models.utils import DIRECT_URL_RE
from pipenv.vendor.vistir import TemporaryDirectory, open_file
@@ -178,9 +178,8 @@ class Resolver:
)
return self._hash_cache
@classmethod
def get_metadata(
cls,
self,
deps: List[str],
index_lookup: Dict[str, str],
markers_lookup: Dict[str, str],
@@ -203,7 +202,7 @@ class Resolver:
markers_lookup = {}
if not req_dir:
req_dir = create_tracked_tempdir(prefix="pipenv-", suffix="-reqdir")
transient_resolver = cls(
transient_resolver = Resolver(
[],
req_dir,
project,
@@ -216,7 +215,7 @@ class Resolver:
for dep in deps:
if not dep:
continue
req, req_idx, markers_idx = cls.parse_line(
req, req_idx, markers_idx = self.parse_line(
dep,
index_lookup=index_lookup,
markers_lookup=markers_lookup,
@@ -235,7 +234,7 @@ class Resolver:
)
if not use_sources:
use_sources = sources
transient_resolver = cls(
transient_resolver = Resolver(
[],
req_dir,
project,
@@ -245,16 +244,15 @@ class Resolver:
clear=clear,
pre=pre,
)
constraint_update, lockfile_update = cls.get_deps_from_req(
constraint_update, lockfile_update = self.get_deps_from_req(
req, resolver=transient_resolver, resolve_vcs=project.s.PIPENV_RESOLVE_VCS
)
constraints |= constraint_update
skipped.update(lockfile_update)
return constraints, skipped, index_lookup, markers_lookup
@classmethod
def parse_line(
cls,
self,
line: str,
index_lookup: Dict[str, str] = None,
markers_lookup: Dict[str, str] = None,
@@ -306,9 +304,8 @@ class Resolver:
markers_lookup[req.normalized_name] = req.markers.replace('"', "'")
return req, index_lookup, markers_lookup
@classmethod
def get_deps_from_req(
cls,
self,
req: Requirement,
resolver: Optional["Resolver"] = None,
resolve_vcs: bool = True,
@@ -322,6 +319,7 @@ class Resolver:
# TODO: this is way too complex, refactor this
constraints: Set[str] = set()
locked_deps: Dict[str, Dict[str, Union[str, bool, List[str]]]] = {}
editable_packages = self.project.get_editable_packages(dev=self.dev)
if (req.is_file_or_url or req.is_vcs) and not req.is_wheel:
# for local packages with setup.py files and potential direct url deps:
if req.is_vcs:
@@ -357,21 +355,22 @@ class Resolver:
if not r.url:
continue
line = _requirement_to_str_lowercase_name(r)
new_req, _, _ = cls.parse_line(line)
new_req, _, _ = self.parse_line(line)
if r.marker and not r.marker.evaluate():
new_constraints = {}
_, new_entry = req.pipfile_entry
new_lock = {pep423_name(new_req.normalized_name): new_entry}
else:
new_constraints, new_lock = cls.get_deps_from_req(
new_constraints, new_lock = self.get_deps_from_req(
new_req, resolver
)
locked_deps.update(new_lock)
constraints |= new_constraints
# if there is no marker or there is a valid marker, add the constraint line
elif r and (not r.marker or (r.marker and r.marker.evaluate())):
line = _requirement_to_str_lowercase_name(r)
constraints.add(line)
if r.name not in editable_packages:
line = _requirement_to_str_lowercase_name(r)
constraints.add(line)
# ensure the top level entry remains as provided
# note that we shouldn't pin versions for editable vcs deps
if not req.is_vcs:
@@ -445,7 +444,18 @@ class Resolver:
markers_lookup = {}
if sources is None:
sources = project.sources
constraints, skipped, index_lookup, markers_lookup = cls.get_metadata(
resolver = Resolver(
[],
req_dir,
project,
sources,
index_lookup=index_lookup,
markers_lookup=markers_lookup,
clear=clear,
pre=pre,
dev=dev,
)
constraints, skipped, index_lookup, markers_lookup = resolver.get_metadata(
deps,
index_lookup,
markers_lookup,
@@ -454,59 +464,12 @@ class Resolver:
req_dir=req_dir,
pre=pre,
clear=clear,
)
return Resolver(
constraints,
req_dir,
project,
sources,
index_lookup=index_lookup,
markers_lookup=markers_lookup,
skipped=skipped,
clear=clear,
pre=pre,
dev=dev,
)
@classmethod
def from_pipfile(
cls,
project: Optional[Project],
pipfile: Optional[Pipfile] = None,
dev: bool = False,
pre: bool = False,
clear: bool = False,
) -> "Resolver":
if not pipfile:
pipfile = project._pipfile
req_dir = create_tracked_tempdir(suffix="-requirements", prefix="pipenv-")
index_lookup, markers_lookup = {}, {}
deps = set()
if dev:
deps.update({req.as_line() for req in pipfile.dev_packages})
deps.update({req.as_line() for req in pipfile.packages})
constraints, skipped, index_lookup, markers_lookup = cls.get_metadata(
list(deps),
index_lookup,
markers_lookup,
project,
project.sources,
req_dir=req_dir,
pre=pre,
clear=clear,
)
return Resolver(
constraints,
req_dir,
project,
project.sources,
index_lookup=index_lookup,
markers_lookup=markers_lookup,
skipped=skipped,
clear=clear,
pre=pre,
)
) # Workaround to the fact `get_metadata` instantiates a transient Resolver
resolver.initial_constraints = constraints
resolver.skipped = skipped
resolver.index_lookup = index_lookup
resolver.markers_lookup = markers_lookup
return resolver
@property
def pip_command(self):