mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Invoke the resolver in the same process as pipenv rather than utilzing subprocess. Restore accidentally commented out part of pip validations.
This commit is contained in:
@@ -95,13 +95,13 @@ def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]:
|
||||
|
||||
link = Link(url)
|
||||
|
||||
# if not link.is_vcs:
|
||||
# backends = ", ".join(vcs.all_schemes)
|
||||
# raise InstallationError(
|
||||
# f"{editable_req} is not a valid editable requirement. "
|
||||
# f"It should either be a path to a local project or a VCS URL "
|
||||
# f"(beginning with {backends})."
|
||||
# )
|
||||
if not link.is_vcs:
|
||||
backends = ", ".join(vcs.all_schemes)
|
||||
raise InstallationError(
|
||||
f"{editable_req} is not a valid editable requirement. "
|
||||
f"It should either be a path to a local project or a VCS URL "
|
||||
f"(beginning with {backends})."
|
||||
)
|
||||
|
||||
package_name = link.egg_fragment
|
||||
if not package_name:
|
||||
|
||||
+8
-93
@@ -446,58 +446,6 @@ class Entry:
|
||||
parents.extend(parent.flattened_parents)
|
||||
return parents
|
||||
|
||||
def ensure_least_updates_possible(self):
|
||||
"""
|
||||
Mutate the current entry to ensure that we are making the smallest amount of
|
||||
changes possible to the existing lockfile -- this will keep the old locked
|
||||
versions of packages if they satisfy new constraints.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
constraints = self.get_constraints()
|
||||
can_use_original = True
|
||||
can_use_updated = True
|
||||
satisfied_by_versions = set()
|
||||
for constraint in constraints:
|
||||
if not constraint.specifier.contains(self.original_version):
|
||||
self.can_use_original = False
|
||||
if not constraint.specifier.contains(self.updated_version):
|
||||
self.can_use_updated = False
|
||||
satisfied_by_value = getattr(constraint, "satisfied_by", None)
|
||||
if satisfied_by_value:
|
||||
satisfied_by = "{}".format(
|
||||
self.clean_specifier(str(satisfied_by_value.version))
|
||||
)
|
||||
satisfied_by_versions.add(satisfied_by)
|
||||
if can_use_original:
|
||||
self.entry_dict = self.lockfile_dict.copy()
|
||||
elif can_use_updated:
|
||||
if len(satisfied_by_versions) == 1:
|
||||
self.entry_dict["version"] = next(
|
||||
iter(sat_by for sat_by in satisfied_by_versions if sat_by), None
|
||||
)
|
||||
hashes = None
|
||||
if self.lockfile_entry.specifiers == satisfied_by:
|
||||
ireq = self.lockfile_entry.as_ireq
|
||||
if (
|
||||
not self.lockfile_entry.hashes
|
||||
and self.resolver._should_include_hash(ireq)
|
||||
):
|
||||
hashes = self.resolver.get_hash(ireq)
|
||||
else:
|
||||
hashes = self.lockfile_entry.hashes
|
||||
else:
|
||||
if self.resolver._should_include_hash(constraint):
|
||||
hashes = self.resolver.get_hash(constraint)
|
||||
if hashes:
|
||||
self.entry_dict["hashes"] = list(hashes)
|
||||
self._entry.hashes = frozenset(hashes)
|
||||
else:
|
||||
# check for any parents, since they depend on this and the current
|
||||
# installed versions are not compatible with the new version, so
|
||||
# we will need to update the top level dependency if possible
|
||||
self.check_flattened_parents()
|
||||
|
||||
def get_constraints(self):
|
||||
"""
|
||||
Retrieve all of the relevant constraints, aggregated from the pipfile, resolver,
|
||||
@@ -668,7 +616,7 @@ def parse_packages(packages, pre, clear, system, requirements_dir=None):
|
||||
|
||||
|
||||
def resolve_packages(
|
||||
pre, clear, verbose, system, write, requirements_dir, packages, category
|
||||
pre, clear, verbose, system, requirements_dir, packages, category, constraints=None
|
||||
):
|
||||
from pipenv.utils.internet import create_mirror_source, replace_pypi_sources
|
||||
from pipenv.utils.resolver import resolve_deps
|
||||
@@ -679,6 +627,9 @@ def resolve_packages(
|
||||
else None
|
||||
)
|
||||
|
||||
if constraints:
|
||||
packages += constraints
|
||||
|
||||
def resolve(
|
||||
packages, pre, project, sources, clear, system, category, requirements_dir=None
|
||||
):
|
||||
@@ -713,43 +664,9 @@ def resolve_packages(
|
||||
requirements_dir=requirements_dir,
|
||||
)
|
||||
results = clean_results(results, resolver, project, category)
|
||||
if write:
|
||||
with open(write, "w") as fh:
|
||||
if not results:
|
||||
json.dump([], fh)
|
||||
else:
|
||||
json.dump(results, fh)
|
||||
else:
|
||||
print("RESULTS:")
|
||||
if results:
|
||||
print(json.dumps(results))
|
||||
else:
|
||||
print(json.dumps([]))
|
||||
|
||||
|
||||
def _main(
|
||||
pre,
|
||||
clear,
|
||||
verbose,
|
||||
system,
|
||||
write,
|
||||
requirements_dir,
|
||||
packages,
|
||||
parse_only=False,
|
||||
category=None,
|
||||
):
|
||||
if parse_only:
|
||||
parse_packages(
|
||||
packages,
|
||||
pre=pre,
|
||||
clear=clear,
|
||||
system=system,
|
||||
requirements_dir=requirements_dir,
|
||||
)
|
||||
else:
|
||||
resolve_packages(
|
||||
pre, clear, verbose, system, write, requirements_dir, packages, category
|
||||
)
|
||||
if results:
|
||||
return results
|
||||
return []
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
@@ -767,15 +684,13 @@ def main(argv=None):
|
||||
os.environ["PYTHONIOENCODING"] = "utf-8"
|
||||
os.environ["PYTHONUNBUFFERED"] = "1"
|
||||
parsed = handle_parsed_args(parsed)
|
||||
_main(
|
||||
resolve_packages(
|
||||
parsed.pre,
|
||||
parsed.clear,
|
||||
parsed.verbose,
|
||||
parsed.system,
|
||||
parsed.write,
|
||||
parsed.requirements_dir,
|
||||
parsed.packages,
|
||||
parse_only=parsed.parse_only,
|
||||
category=parsed.category,
|
||||
)
|
||||
|
||||
|
||||
+24
-58
@@ -1,14 +1,11 @@
|
||||
import contextlib
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import warnings
|
||||
from functools import lru_cache
|
||||
from html.parser import HTMLParser
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Set, Tuple, Union
|
||||
from urllib import parse
|
||||
|
||||
@@ -30,6 +27,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.patched.pip._vendor import pkg_resources, rich
|
||||
from pipenv.project import Project
|
||||
from pipenv.resolver import resolve_packages
|
||||
from pipenv.vendor import click
|
||||
from pipenv.vendor.requirementslib.fileutils import create_tracked_tempdir, open_file
|
||||
from pipenv.vendor.requirementslib.models.requirements import Line, Requirement
|
||||
@@ -57,7 +55,7 @@ from .dependencies import (
|
||||
from .indexes import parse_indexes, prepare_pip_source_args
|
||||
from .internet import _get_requests_session, is_pypi_url
|
||||
from .locking import format_requirement_for_lockfile, prepare_lockfile
|
||||
from .shell import make_posix, subprocess_run, temp_environ
|
||||
from .shell import subprocess_run, temp_environ
|
||||
|
||||
console = rich.console.Console()
|
||||
err = rich.console.Console(stderr=True)
|
||||
@@ -288,7 +286,8 @@ class Resolver:
|
||||
except ValueError:
|
||||
direct_url = DIRECT_URL_RE.match(line)
|
||||
if direct_url:
|
||||
line = "{}#egg={}".format(line, direct_url.groupdict()["name"])
|
||||
name = direct_url.groupdict()["name"]
|
||||
line = f"{name}@ {line}"
|
||||
try:
|
||||
req = Requirement.from_line(line)
|
||||
except ValueError:
|
||||
@@ -952,11 +951,8 @@ def actually_resolve_deps(
|
||||
clear,
|
||||
pre,
|
||||
category,
|
||||
req_dir=None,
|
||||
req_dir,
|
||||
):
|
||||
if not req_dir:
|
||||
req_dir = create_tracked_tempdir(suffix="-requirements", prefix="pipenv-")
|
||||
|
||||
with warnings.catch_warnings(record=True) as warning_list:
|
||||
resolver = Resolver.create(
|
||||
deps,
|
||||
@@ -1047,8 +1043,6 @@ def venv_resolve_deps(
|
||||
:return: The lock data
|
||||
:rtype: dict
|
||||
"""
|
||||
from pipenv import resolver
|
||||
|
||||
lockfile_section = get_lockfile_section_using_pipfile_category(category)
|
||||
|
||||
if not deps:
|
||||
@@ -1063,30 +1057,11 @@ def venv_resolve_deps(
|
||||
if lockfile is None:
|
||||
lockfile = project.lockfile(categories=[category])
|
||||
req_dir = create_tracked_tempdir(prefix="pipenv", suffix="requirements")
|
||||
cmd = [
|
||||
which("python", allow_global=allow_global),
|
||||
Path(resolver.__file__.rstrip("co")).as_posix(),
|
||||
]
|
||||
if pre:
|
||||
cmd.append("--pre")
|
||||
if clear:
|
||||
cmd.append("--clear")
|
||||
if allow_global:
|
||||
cmd.append("--system")
|
||||
if category:
|
||||
cmd.append("--category")
|
||||
cmd.append(category)
|
||||
target_file = tempfile.NamedTemporaryFile(
|
||||
prefix="resolver", suffix=".json", delete=False
|
||||
)
|
||||
target_file.close()
|
||||
cmd.extend(["--write", make_posix(target_file.name)])
|
||||
results = []
|
||||
with temp_environ():
|
||||
os.environ.update({k: str(val) for k, val in os.environ.items()})
|
||||
if pypi_mirror:
|
||||
os.environ["PIPENV_PYPI_MIRROR"] = str(pypi_mirror)
|
||||
os.environ["PIPENV_VERBOSITY"] = str(project.s.PIPENV_VERBOSITY)
|
||||
os.environ["PIPENV_REQ_DIR"] = req_dir
|
||||
os.environ["PIP_NO_INPUT"] = "1"
|
||||
pipenv_site_dir = get_pipenv_sitedir()
|
||||
if pipenv_site_dir is not None:
|
||||
@@ -1099,37 +1074,29 @@ def venv_resolve_deps(
|
||||
# dependency resolution on them, so we are including this step inside the
|
||||
# spinner context manager for the UX improvement
|
||||
st.console.print("Building requirements...")
|
||||
deps = convert_deps_to_pip(deps, project, include_index=True)
|
||||
deps = convert_deps_to_pip(deps, project)
|
||||
constraints = set(deps)
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w+", prefix="pipenv", suffix="constraints.txt", delete=False
|
||||
) as constraints_file:
|
||||
constraints_file.write(str("\n".join(constraints)))
|
||||
cmd.append("--constraints-file")
|
||||
cmd.append(constraints_file.name)
|
||||
st.console.print("Resolving dependencies...")
|
||||
c = resolve(cmd, st, project=project)
|
||||
if c.returncode == 0:
|
||||
st.console.print(environments.PIPENV_SPINNER_OK_TEXT.format("Success!"))
|
||||
if not project.s.is_verbose() and c.stderr.strip():
|
||||
click.echo(click.style(f"Warning: {c.stderr.strip()}"), err=True)
|
||||
else:
|
||||
try:
|
||||
results = resolve_packages(
|
||||
pre,
|
||||
clear,
|
||||
project.s.is_verbose(),
|
||||
allow_global,
|
||||
req_dir,
|
||||
deps,
|
||||
category=category,
|
||||
constraints=constraints,
|
||||
)
|
||||
if results:
|
||||
st.console.print(
|
||||
environments.PIPENV_SPINNER_OK_TEXT.format("Success!")
|
||||
)
|
||||
except Exception:
|
||||
st.console.print(
|
||||
environments.PIPENV_SPINNER_FAIL_TEXT.format("Locking Failed!")
|
||||
)
|
||||
click.echo(f"Output: {c.stdout.strip()}", err=True)
|
||||
click.echo(f"Error: {c.stderr.strip()}", err=True)
|
||||
try:
|
||||
with open(target_file.name) as fh:
|
||||
results = json.load(fh)
|
||||
except (IndexError, json.JSONDecodeError):
|
||||
click.echo(c.stdout.strip(), err=True)
|
||||
click.echo(c.stderr.strip(), err=True)
|
||||
if os.path.exists(target_file.name):
|
||||
os.unlink(target_file.name)
|
||||
raise RuntimeError("There was a problem with locking.")
|
||||
if os.path.exists(target_file.name):
|
||||
os.unlink(target_file.name)
|
||||
raise RuntimeError("There was a problem with locking.")
|
||||
if lockfile_section not in lockfile:
|
||||
lockfile[lockfile_section] = {}
|
||||
return prepare_lockfile(results, pipfile, lockfile[lockfile_section])
|
||||
@@ -1159,7 +1126,6 @@ def resolve_deps(
|
||||
if not deps:
|
||||
return results, resolver
|
||||
# First (proper) attempt:
|
||||
req_dir = req_dir if req_dir else os.environ.get("req_dir", None)
|
||||
if not req_dir:
|
||||
req_dir = create_tracked_tempdir(prefix="pipenv-", suffix="-requirements")
|
||||
with HackedPythonVersion(python_path=project.python(system=allow_global)):
|
||||
|
||||
@@ -243,17 +243,6 @@ class Lockfile(ReqLibBaseModel):
|
||||
]
|
||||
return []
|
||||
|
||||
def as_requirements(self, category: str, include_hashes: bool = False) -> List[str]:
|
||||
lines = []
|
||||
section = list(self.get_requirements(categories=[category]))
|
||||
for req in section:
|
||||
kwargs = {"include_hashes": include_hashes}
|
||||
if req.editable:
|
||||
kwargs["include_markers"] = False
|
||||
r = req.as_line(**kwargs)
|
||||
lines.append(r.strip())
|
||||
return lines
|
||||
|
||||
def write(self) -> None:
|
||||
self.projectfile.model = copy.deepcopy(self.lockfile)
|
||||
self.projectfile.write()
|
||||
|
||||
@@ -1386,12 +1386,6 @@ class SetupInfo(ReqLibBaseModel):
|
||||
self.populate_metadata(dist)
|
||||
self._ran_setup = True
|
||||
|
||||
@property
|
||||
def pep517_config(self) -> Dict[str, Any]:
|
||||
config = {}
|
||||
config.setdefault("--global-option", [])
|
||||
return config
|
||||
|
||||
def build_wheel(self) -> str:
|
||||
need_delete = False
|
||||
if not self.pyproject.exists():
|
||||
@@ -1422,7 +1416,6 @@ build-backend = "{1}"
|
||||
result = build_pep517(
|
||||
directory,
|
||||
self.extra_kwargs["build_dir"],
|
||||
config_settings=self.pep517_config,
|
||||
dist_type="wheel",
|
||||
)
|
||||
if need_delete:
|
||||
@@ -1454,7 +1447,6 @@ build-backend = "{1}"
|
||||
result = build_pep517(
|
||||
self.base_dir,
|
||||
self.extra_kwargs["build_dir"],
|
||||
config_settings=self.pep517_config,
|
||||
dist_type="sdist",
|
||||
)
|
||||
if need_delete:
|
||||
|
||||
@@ -92,18 +92,18 @@ tablib = "*"
|
||||
|
||||
@pytest.mark.basic
|
||||
@pytest.mark.install
|
||||
def test_install_with_version_req_default_operator(pipenv_instance_pypi):
|
||||
def test_install_with_version_req_default_operator(pipenv_instance_private_pypi):
|
||||
"""Ensure that running `pipenv install` work when spec is package = "X.Y.Z". """
|
||||
with pipenv_instance_pypi(chdir=True) as p:
|
||||
with pipenv_instance_private_pypi(chdir=True) as p:
|
||||
with open(p.pipfile_path, "w") as f:
|
||||
contents = """
|
||||
[packages]
|
||||
fastapi = "0.95.0"
|
||||
six = "1.12.0"
|
||||
""".strip()
|
||||
f.write(contents)
|
||||
c = p.pipenv("install")
|
||||
assert c.returncode == 0
|
||||
assert "fastapi" in p.pipfile["packages"]
|
||||
assert "six" in p.pipfile["packages"]
|
||||
|
||||
|
||||
@pytest.mark.basic
|
||||
|
||||
Reference in New Issue
Block a user