diff --git a/pipenv/patched/pip/_internal/req/constructors.py b/pipenv/patched/pip/_internal/req/constructors.py index 3240c6b3..2c0be028 100644 --- a/pipenv/patched/pip/_internal/req/constructors.py +++ b/pipenv/patched/pip/_internal/req/constructors.py @@ -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: diff --git a/pipenv/resolver.py b/pipenv/resolver.py index e14319e8..cceef599 100644 --- a/pipenv/resolver.py +++ b/pipenv/resolver.py @@ -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, ) diff --git a/pipenv/utils/resolver.py b/pipenv/utils/resolver.py index f84f9699..fe6ef834 100644 --- a/pipenv/utils/resolver.py +++ b/pipenv/utils/resolver.py @@ -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)): diff --git a/pipenv/vendor/requirementslib/models/lockfile.py b/pipenv/vendor/requirementslib/models/lockfile.py index 5681422d..88917006 100644 --- a/pipenv/vendor/requirementslib/models/lockfile.py +++ b/pipenv/vendor/requirementslib/models/lockfile.py @@ -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() diff --git a/pipenv/vendor/requirementslib/models/setup_info.py b/pipenv/vendor/requirementslib/models/setup_info.py index 58978b71..19cc0af6 100644 --- a/pipenv/vendor/requirementslib/models/setup_info.py +++ b/pipenv/vendor/requirementslib/models/setup_info.py @@ -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: diff --git a/tests/integration/test_install_basic.py b/tests/integration/test_install_basic.py index cbbf052c..a686a1bd 100644 --- a/tests/integration/test_install_basic.py +++ b/tests/integration/test_install_basic.py @@ -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