From dc8ac38b1b596a54f5f019a6b49c36e673a5a886 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Wed, 20 Apr 2022 21:21:38 -0400 Subject: [PATCH] Allow pipenv option to consider all listed package sources when syncing the Pipfile.lock (#5039) * Allow option to search all sources during installation. * Add documentation for new Pipenv option ``install_search_all_sources``. --- docs/advanced.rst | 15 ++++++++++++++- news/5041.feature.rst | 2 ++ pipenv/core.py | 28 +++++++++++++++------------- 3 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 news/5041.feature.rst diff --git a/docs/advanced.rst b/docs/advanced.rst index cafa190deb..6d071b2b6b 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -62,6 +62,19 @@ as sub-dependencies must be mirrored onto your private index or they will not re standard recommendation of ``pip`` maintainers: "To correctly make a private project installable is to point --index-url to an index that contains both PyPI and their private projects—which is our recommended best practice." +The above documentation holds true for both ``lock`` resolution and ``sync`` of packages. It was suggested that +once the resolution and the lock file are updated, it is theoretically possible to safely scan multiple indexes +for these packages when running ``pipenv sync`` or ``pipenv install --deploy`` since it will verify the package +hashes match the allowed hashes that were already captured from a safe locking cycle. +To enable this non-default behavior, add ``install_search_all_sources = true`` option +to your ``Pipfile`` in the ``pipenv`` section:: + + [pipenv] + install_search_all_sources = true + +**Note:** The locking cycle will still requires that each package be resolved from a single index. This feature was +requested as a workaround in order to support organizations where not everyone has access to the package sources. + ☤ Using a PyPI Mirror ---------------------------- @@ -119,7 +132,7 @@ If you want to work with private registries that use the keychain for authentica can disable the "enforcement of no input". **Note:** Please be sure that the keychain will really not ask for -input. Otherwise the process will hang forever! +input. Otherwise the process will hang forever!:: [[source]] url = "https://pypi.org/simple" diff --git a/news/5041.feature.rst b/news/5041.feature.rst new file mode 100644 index 0000000000..2da1f6a28d --- /dev/null +++ b/news/5041.feature.rst @@ -0,0 +1,2 @@ +Added new Pipenv option ``install_search_all_sources`` that allows installation of packages from an +existing ``Pipfile.lock`` to search all defined indexes for the constrained package version and hash signatures. diff --git a/pipenv/core.py b/pipenv/core.py index 011ce24356..b62eae460e 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -1466,10 +1466,8 @@ def pip_install( use_pep517=True, ): piplogger = logging.getLogger("pipenv.patched.notpip._internal.commands.install") - src_dir = None if not trusted_hosts: trusted_hosts = [] - trusted_hosts.extend(os.environ.get("PIP_TRUSTED_HOSTS", [])) if not allow_global: src_dir = os.getenv( @@ -1484,22 +1482,26 @@ def pip_install( ignore_hashes = False line = None # Try installing for each source in project.sources. + search_all_sources = project.settings.get("install_search_all_sources", False) if not index and requirement.index: index = requirement.index if index and not extra_indexes: - extra_indexes = [] - if requirement.index: - extra_indexes = list( - filter(lambda d: d.get("name") == requirement.index, project.sources) - ) - if not extra_indexes: + if search_all_sources: extra_indexes = list(project.sources) + else: # Default: index restrictions apply during installation + extra_indexes = [] + if requirement.index: + extra_indexes = list( + filter(lambda d: d.get("name") == requirement.index, project.sources) + ) + if not extra_indexes: + extra_indexes = list(project.sources) if requirement and requirement.vcs or requirement.editable: requirement.index = None # Install dependencies when a package is a non-editable VCS dependency. # Don't specify a source directory when using --system. if not requirement.editable and no_deps is not True: - # Leave this off becauase old lockfiles don't have all deps included + # Leave this off because old Pipfile.lock don't have all deps included # TODO: When can it be turned back on? no_deps = False elif requirement.editable and no_deps is None: @@ -1519,7 +1521,7 @@ def pip_install( trusted_hosts=trusted_hosts, pypi_mirror=pypi_mirror, ) - if requirement.index in sources: + if not search_all_sources and requirement.index in sources: sources = list(filter(lambda d: d.get("name") == requirement.index, sources)) if r: with open(r, "r") as fh: @@ -1558,10 +1560,10 @@ def pip_install( if project.s.is_verbose(): click.echo(f"$ {cmd_list_to_shell(pip_command)}", err=True) cache_dir = Path(project.s.PIPENV_CACHE_DIR) - DEFAULT_EXISTS_ACTION = "w" + default_exists_action = "w" if selective_upgrade: - DEFAULT_EXISTS_ACTION = "i" - exists_action = project.s.PIP_EXISTS_ACTION or DEFAULT_EXISTS_ACTION + default_exists_action = "i" + exists_action = project.s.PIP_EXISTS_ACTION or default_exists_action pip_config = { "PIP_CACHE_DIR": cache_dir.as_posix(), "PIP_WHEEL_DIR": cache_dir.joinpath("wheels").as_posix(),