From f49a1dd8735325639ecdc75a18de8e82feee3d76 Mon Sep 17 00:00:00 2001 From: frostming Date: Fri, 28 Aug 2020 14:21:52 +0800 Subject: [PATCH 1/5] Fix constraint validation --- news/4386.bugfix.rst | 1 + pipenv/cli/options.py | 1 + pipenv/core.py | 8 ++++---- pipenv/resolver.py | 12 +++++++----- 4 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 news/4386.bugfix.rst diff --git a/news/4386.bugfix.rst b/news/4386.bugfix.rst new file mode 100644 index 00000000..ff633fb9 --- /dev/null +++ b/news/4386.bugfix.rst @@ -0,0 +1 @@ +Fix a bug that non-wheel file requirements can be resolved successfully. diff --git a/pipenv/cli/options.py b/pipenv/cli/options.py index b96a03f6..35af39ca 100644 --- a/pipenv/cli/options.py +++ b/pipenv/cli/options.py @@ -440,6 +440,7 @@ def lock_options(f): f = install_base_options(f) f = lock_dev_option(f) f = emit_requirements_flag(f) + f = emit_requirements_header_flag(f) f = dev_only_flag(f) return f diff --git a/pipenv/core.py b/pipenv/core.py index 6e8639ee..a59ef9df 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -841,15 +841,15 @@ def do_install_dependencies( dev = dev or dev_only deps_list = list(lockfile.get_requirements(dev=dev, only=dev_only)) if emit_requirements: - index_args = prepare_pip_source_args(get_source_list(pypi_mirror=pypi_mirror, project=project)) + index_args = prepare_pip_source_args( + get_source_list(pypi_mirror=pypi_mirror, project=project) + ) index_args = " ".join(index_args).replace(" -", "\n-") deps = [ req.as_line(sources=False, include_hashes=False) for req in deps_list ] click.echo(index_args) - click.echo( - "\n".join(sorted(deps)) - ) + click.echo("\n".join(sorted(deps))) sys.exit(0) if concurrent: nprocs = PIPENV_MAX_SUBPROCESS diff --git a/pipenv/resolver.py b/pipenv/resolver.py index 733b28d5..697109d4 100644 --- a/pipenv/resolver.py +++ b/pipenv/resolver.py @@ -562,13 +562,15 @@ class Entry(object): :return: True if the constraints are satisfied by the resolution provided :raises: :exc:`pipenv.exceptions.DependencyConflict` if the constraints dont exist """ + from pipenv.exceptions import DependencyConflict + from pipenv.environments import is_verbose + constraints = self.get_constraints() + old_version = self.strip_version(self.old_specifiers) for constraint in constraints: - try: - constraint.check_if_exists(False) - except Exception: - from pipenv.exceptions import DependencyConflict - from pipenv.environments import is_verbose + if not constraint.req: + continue + if not constraint.req.specifier.contains(str(old_version), prereleases=True): if is_verbose(): print("Tried constraint: {0!r}".format(constraint), file=sys.stderr) msg = ( From 63d2360ee19d9b5e09a45dd95aa0b3c1c10990b9 Mon Sep 17 00:00:00 2001 From: frostming Date: Fri, 28 Aug 2020 15:31:26 +0800 Subject: [PATCH 2/5] clean implementation --- pipenv/resolver.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pipenv/resolver.py b/pipenv/resolver.py index 697109d4..dba100de 100644 --- a/pipenv/resolver.py +++ b/pipenv/resolver.py @@ -566,11 +566,13 @@ class Entry(object): from pipenv.environments import is_verbose constraints = self.get_constraints() - old_version = self.strip_version(self.old_specifiers) + old_version = self.original_version for constraint in constraints: if not constraint.req: continue - if not constraint.req.specifier.contains(str(old_version), prereleases=True): + if old_version and not constraint.req.specifier.contains( + str(old_version), prereleases=True + ): if is_verbose(): print("Tried constraint: {0!r}".format(constraint), file=sys.stderr) msg = ( From eac3a285791980775c5b21a334cb3672e206a2b1 Mon Sep 17 00:00:00 2001 From: frostming Date: Fri, 28 Aug 2020 15:38:38 +0800 Subject: [PATCH 3/5] add news --- news/4441.feature.rst | 1 + news/4443.feature.rst | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 news/4441.feature.rst create mode 100644 news/4443.feature.rst diff --git a/news/4441.feature.rst b/news/4441.feature.rst new file mode 100644 index 00000000..3836516c --- /dev/null +++ b/news/4441.feature.rst @@ -0,0 +1 @@ +Add the missing ``--system`` option to ``pipenv sync``. diff --git a/news/4443.feature.rst b/news/4443.feature.rst new file mode 100644 index 00000000..ea4a0c06 --- /dev/null +++ b/news/4443.feature.rst @@ -0,0 +1,2 @@ +Add a new option pair ``--header/--no-header`` to ``pipenv lock`` command, +which adds a header to the generated requirements.txt From fd98b384103addb394856a61c137a32ea67a2d12 Mon Sep 17 00:00:00 2001 From: frostming Date: Fri, 28 Aug 2020 16:53:57 +0800 Subject: [PATCH 4/5] fix validation logic --- pipenv/resolver.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pipenv/resolver.py b/pipenv/resolver.py index dba100de..53820b27 100644 --- a/pipenv/resolver.py +++ b/pipenv/resolver.py @@ -566,19 +566,19 @@ class Entry(object): from pipenv.environments import is_verbose constraints = self.get_constraints() - old_version = self.original_version + pinned_version = self.updated_version for constraint in constraints: if not constraint.req: continue - if old_version and not constraint.req.specifier.contains( - str(old_version), prereleases=True + if pinned_version and not constraint.req.specifier.contains( + str(pinned_version), prereleases=True ): if is_verbose(): print("Tried constraint: {0!r}".format(constraint), file=sys.stderr) msg = ( "Cannot resolve conflicting version {0}{1} while {2}{3} is " "locked.".format( - self.name, self.updated_specifier, self.old_name, self.old_specifiers + self.name, self.updated_specifier, self.name, pinned_version ) ) raise DependencyConflict(msg) From 9fd8e39e6b1d06ecf172440b3f7861ab3cb69636 Mon Sep 17 00:00:00 2001 From: frostming Date: Fri, 28 Aug 2020 17:25:39 +0800 Subject: [PATCH 5/5] don't check against old lock entry --- pipenv/resolver.py | 52 ++-------------------------------------------- 1 file changed, 2 insertions(+), 50 deletions(-) diff --git a/pipenv/resolver.py b/pipenv/resolver.py index 53820b27..b06deca6 100644 --- a/pipenv/resolver.py +++ b/pipenv/resolver.py @@ -504,55 +504,6 @@ class Entry(object): """ if self.is_in_pipfile: return self.pipfile_entry.as_ireq() - return self.constraint_from_parent_conflicts() - - def constraint_from_parent_conflicts(self): - """ - Given a resolved entry with multiple parent dependencies with different - constraints, searches for the resolution that satisfies all of the parent - constraints. - - :return: A new **InstallRequirement** satisfying all parent constraints - :raises: :exc:`~pipenv.exceptions.DependencyConflict` if resolution is impossible - """ - # ensure that we satisfy the parent dependencies of this dep - parent_dependencies = set() - has_mismatch = False - can_use_original = True - for p in self.parent_deps: - # updated dependencies should be satisfied since they were resolved already - if p.is_updated: - continue - # parents with no requirements can't conflict - if not p.requirements: - continue - entry_ref = p.get_dependency(self.name) - required = entry_ref.get("required_version", "*") - required = self.clean_specifier(required) - parent_requires = self.make_requirement(self.name, required) - parent_dependencies.add("{0} => {1} ({2})".format(p.name, self.name, required)) - # use pre=True here or else prereleases dont satisfy constraints - if parent_requires.requirement.specifier and ( - not parent_requires.requirement.specifier.contains(self.original_version, prereleases=True) - ): - can_use_original = False - if parent_requires.requirement.specifier and ( - not parent_requires.requirement.specifier.contains(self.updated_version, prereleases=True) - ): - if not self.entry.editable and self.updated_version != self.original_version: - has_mismatch = True - if has_mismatch and not can_use_original: - from pipenv.exceptions import DependencyConflict - msg = ( - "Cannot resolve {0} ({1}) due to conflicting parent dependencies: " - "\n\t{2}".format( - self.name, self.updated_version, "\n\t".join(parent_dependencies) - ) - ) - raise DependencyConflict(msg) - elif can_use_original: - return self.lockfile_entry.as_ireq() - return self.entry.as_ireq() def validate_constraints(self): """ @@ -578,7 +529,8 @@ class Entry(object): msg = ( "Cannot resolve conflicting version {0}{1} while {2}{3} is " "locked.".format( - self.name, self.updated_specifier, self.name, pinned_version + self.name, constraint.req.specifier, + self.name, self.updated_specifier ) ) raise DependencyConflict(msg)