Skip to content

Commit

Permalink
Skip satisfied dependencies during installation
Browse files Browse the repository at this point in the history
- Skip satisfied dependencies in the environment during install
  by checking whether the constraint of a specifier is satisfied
- If there is no specifier and a dependency is installed, assume it
  is satisfied
- For editable dependencies, if the dependency in the environment is
  an egg link and points at the same path as the given dep, assume
  it is satisfied
- Fixes #3057

Signed-off-by: Dan Ryan <dan.ryan@canonical.com>
  • Loading branch information
techalchemy committed Apr 29, 2020
1 parent 36a5a7c commit 2afa6ec
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 0 deletions.
1 change: 1 addition & 0 deletions news/3057.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``pipenv install`` and ``pipenv sync`` will no longer attempt to install satisfied dependencies during installation.
3 changes: 3 additions & 0 deletions pipenv/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,9 @@ def batch_install(deps_list, procs, failed_deps_queue,

deps_to_install = deps_list[:]
deps_to_install.extend(sequential_deps)
deps_to_install = [
dep for dep in deps_to_install if not project.environment.is_satisfied(dep)
]
sequential_dep_names = [d.name for d in sequential_deps]

deps_list_bar = progress.bar(
Expand Down
18 changes: 18 additions & 0 deletions pipenv/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import pipenv

from .vendor.cached_property import cached_property
from .vendor.packaging.utils import canonicalize_name
from .vendor import vistir

from .utils import normalize_path, make_posix
Expand Down Expand Up @@ -712,6 +713,23 @@ def is_installed(self, pkgname):

return any(d for d in self.get_distributions() if d.project_name == pkgname)

def is_satisfied(self, req):
match = next(
iter(
d for d in self.get_distributions()
if canonicalize_name(d.project_name) == req.normalized_name
), None
)
if match is not None:
if req.editable and self.find_egg(match):
return req.line_instance.path == match.location
elif req.line_instance.specifiers is not None:
return req.line_instance.specifiers.contains(
match.version, prereleases=True
)
return True
return False

def run(self, cmd, cwd=os.curdir):
"""Run a command with :class:`~subprocess.Popen` in the context of the environment
Expand Down

0 comments on commit 2afa6ec

Please sign in to comment.