Add back --skip-lock flag using the new utilities. (#5847)

* Add back --skip-lock flag using the new utilities.
This commit is contained in:
Matt Davis
2023-08-22 06:17:14 -04:00
committed by GitHub
parent d43a7ae555
commit c8f446510e
7 changed files with 98 additions and 36 deletions
-6
View File
@@ -18,9 +18,6 @@ Vendored Libraries
2023.8.20 (2023-08-20)
======================
Pipenv 2023.8.20 (2023-08-20)
=============================
Bug Fixes
---------
@@ -30,9 +27,6 @@ Bug Fixes
2023.8.19 (2023-08-19)
======================
Pipenv 2023.8.19 (2023-08-19)
=============================
Features & Improvements
-----------------------
+1
View File
@@ -222,6 +222,7 @@ def install(state, **kwargs):
site_packages=state.site_packages,
extra_pip_args=state.installstate.extra_pip_args,
categories=state.installstate.categories,
skip_lock=state.installstate.skip_lock,
)
+8 -7
View File
@@ -85,6 +85,7 @@ class InstallState:
self.editables = []
self.extra_pip_args = []
self.categories = []
self.skip_lock = False
class LockOptions:
@@ -484,32 +485,32 @@ def validate_pypi_mirror(ctx, param, value):
return value
# OLD REMOVED COMMANDS THAT WE STILL DISPLAY HELP TEXT FOR #
def skip_lock_option(f):
def callback(ctx, param, value):
if value:
err.print(
"The flag --skip-lock has been functionally removed. "
"Without running the lock resolver it is not possible to manage multiple package indexes. "
"Additionally it bypassed the build consistency guarantees provided by maintaining a lock file.",
"The flag --skip-lock has been reintroduced (but is not recommended). "
"Without the lock resolver it is difficult to manage multiple package indexes, and hash checking is not provided. "
"However it can help manage installs with current deficiencies in locking across platforms.",
style="yellow bold",
)
raise ValueError("The flag --skip-lock flag has been removed.")
state = ctx.ensure_object(State)
state.installstate.skip_lock = value
return value
return option(
"--skip-lock",
is_flag=True,
default=False,
expose_value=False,
expose_value=True,
envvar="PIPENV_SKIP_LOCK",
callback=callback,
type=click_types.BOOL,
show_envvar=True,
hidden=True, # This hides the option from the help text.
)(f)
# OLD REMOVED COMMANDS THAT WE STILL DISPLAY HELP TEXT FOR WHEN USED #
def keep_outdated_option(f):
def callback(ctx, param, value):
state = ctx.ensure_object(State)
+53 -18
View File
@@ -12,6 +12,7 @@ from pipenv.utils import console, err, fileutils
from pipenv.utils.dependencies import (
expansive_install_req_from_line,
get_lockfile_section_using_pipfile_category,
install_req_from_pipfile,
)
from pipenv.utils.indexes import get_source_list
from pipenv.utils.internet import download_file, is_valid_url
@@ -42,6 +43,7 @@ def do_install(
site_packages=None,
extra_pip_args=None,
categories=None,
skip_lock=False,
):
requirements_directory = fileutils.create_tracked_tempdir(
suffix="-requirements", prefix="pipenv-"
@@ -70,7 +72,7 @@ def do_install(
if not project.pipfile_exists and not (package_args or dev):
if not (ignore_pipfile or deploy):
raise exceptions.PipfileNotFound(project.path_to("Pipfile"))
elif ignore_pipfile and not project.lockfile_exists:
elif ((skip_lock and deploy) or ignore_pipfile) and not project.lockfile_exists:
raise exceptions.LockfileNotFound(project.path_to("Pipfile.lock"))
# Load the --pre settings from the Pipfile.
if not pre:
@@ -171,6 +173,7 @@ def do_install(
pypi_mirror=pypi_mirror,
extra_pip_args=extra_pip_args,
categories=categories,
skip_lock=skip_lock,
)
# This is for if the user passed in dependencies, then we want to make sure we
@@ -188,6 +191,7 @@ def do_install(
pypi_mirror=pypi_mirror,
extra_pip_args=extra_pip_args,
categories=categories,
skip_lock=skip_lock,
)
for pkg_line in pkg_list:
@@ -284,6 +288,7 @@ def do_install(
pypi_mirror=pypi_mirror,
extra_pip_args=extra_pip_args,
categories=categories,
skip_lock=skip_lock,
)
except Exception as e:
# If we fail to install, remove the package from the Pipfile.
@@ -358,6 +363,7 @@ def do_install_dependencies(
pypi_mirror=None,
extra_pip_args=None,
categories=None,
skip_lock=False,
):
"""
Executes the installation functionality.
@@ -373,17 +379,39 @@ def do_install_dependencies(
categories = ["packages"]
for category in categories:
lockfile = project.get_or_create_lockfile(categories=categories)
if not bare:
console.print(
f"Installing dependencies from Pipfile.lock "
f"({lockfile['_meta'].get('hash', {}).get('sha256')[-6:]})...",
style="bold",
)
# Load the lockfile if it exists, or if dev_only is being used.
lockfile = None
pipfile = None
if skip_lock:
ignore_hashes = True
if not bare:
console.print("Installing dependencies from Pipfile...", style="bold")
pipfile = project.get_pipfile_section(category)
else:
lockfile = project.get_or_create_lockfile(categories=categories)
if not bare:
console.print(
f"Installing dependencies from Pipfile.lock "
f"({lockfile['_meta'].get('hash', {}).get('sha256')[-6:]})...",
style="bold",
)
dev = dev or dev_only
deps_list = list(
lockfile.get_requirements(dev=dev, only=dev_only, categories=[category])
)
if skip_lock:
deps_list = []
for req_name, pipfile_entry in pipfile.items():
install_req, markers, req_line = install_req_from_pipfile(
req_name, pipfile_entry
)
deps_list.append(
(
install_req,
req_line,
)
)
else:
deps_list = list(
lockfile.get_requirements(dev=dev, only=dev_only, categories=[category])
)
editable_or_vcs_deps = [
(dep, pip_line) for dep, pip_line in deps_list if (dep.link and dep.editable)
]
@@ -394,15 +422,18 @@ def do_install_dependencies(
]
install_kwargs = {
"no_deps": True,
"no_deps": not skip_lock,
"ignore_hashes": ignore_hashes,
"allow_global": allow_global,
"pypi_mirror": pypi_mirror,
"sequential_deps": editable_or_vcs_deps,
"extra_pip_args": extra_pip_args,
}
lockfile_category = get_lockfile_section_using_pipfile_category(category)
lockfile_section = lockfile[lockfile_category]
if skip_lock:
lockfile_section = pipfile
else:
lockfile_category = get_lockfile_section_using_pipfile_category(category)
lockfile_section = lockfile[lockfile_category]
batch_install(
project,
normal_deps,
@@ -499,8 +530,10 @@ def batch_install(
deps_by_index = defaultdict(list)
for dependency, pip_line in deps_to_install:
index = project.sources_default["name"]
if dependency.name and lockfile_section[dependency.name].get("index"):
index = lockfile_section[dependency.name]["index"]
if dependency.name and dependency.name in lockfile_section:
entry = lockfile_section[dependency.name]
if isinstance(entry, dict) and "index" in entry:
index = entry["index"]
deps_by_index[index].append(pip_line)
# Treat each index as its own pip install phase
for index_name, dependencies in deps_by_index.items():
@@ -560,6 +593,7 @@ def do_init(
pypi_mirror=None,
extra_pip_args=None,
categories=None,
skip_lock=False,
):
"""Executes the init functionality."""
python = None
@@ -585,7 +619,7 @@ def do_init(
suffix="-requirements", prefix="pipenv-"
)
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
if project.lockfile_exists and not ignore_pipfile:
if (project.lockfile_exists and not ignore_pipfile) and not skip_lock:
old_hash = project.get_lockfile_hash()
new_hash = project.calculate_pipfile_hash()
if new_hash != old_hash:
@@ -620,7 +654,7 @@ def do_init(
categories=categories,
)
# Write out the lockfile if it doesn't exist.
if not project.lockfile_exists:
if not project.lockfile_exists and not skip_lock:
# Unless we're in a virtualenv not managed by pipenv, abort if we're
# using the system's python.
if (system or allow_global) and not (project.s.PIPENV_VIRTUALENV):
@@ -652,6 +686,7 @@ def do_init(
pypi_mirror=pypi_mirror,
extra_pip_args=extra_pip_args,
categories=categories,
skip_lock=skip_lock,
)
# Hint the user what to do to activate the virtualenv.
+4 -5
View File
@@ -185,7 +185,7 @@ def unearth_hashes_for_dep(project, dep):
break
# 1 Try to get hashes directly form index
install_req, markers = install_req_from_pipfile(dep["name"], dep)
install_req, markers, _ = install_req_from_pipfile(dep["name"], dep)
if not install_req or not install_req.req:
return []
if "https://pypi.org/simple/" in index_url:
@@ -981,7 +981,7 @@ def install_req_from_pipfile(name, pipfile):
vcs_url_parts = vcs_url.rsplit("@", 1)
vcs_url = vcs_url_parts[0]
fallback_ref = vcs_url_parts[1]
req_str = f"{vcs_url}{_pipfile.get('ref', fallback_ref)}{extras_str}"
req_str = f"{vcs_url}@{_pipfile.get('ref', fallback_ref)}{extras_str}"
if not req_str.startswith(f"{vcs}+"):
req_str = f"{vcs}+{req_str}"
if f"{vcs}+file://" in req_str:
@@ -1011,12 +1011,11 @@ def install_req_from_pipfile(name, pipfile):
expand_env=True,
)
markers = PipenvMarkers.from_pipfile(name, _pipfile)
return install_req, markers
return install_req, markers, req_str
def from_pipfile(name, pipfile):
install_req, markers = install_req_from_pipfile(name, pipfile)
install_req, markers, req_str = install_req_from_pipfile(name, pipfile)
if markers:
markers = str(markers)
install_req.markers = Marker(markers)
+19
View File
@@ -286,3 +286,22 @@ def test_install_remote_wheel_file_with_extras(pipenv_instance_pypi):
assert "pre-commit" in p.lockfile["default"]
assert "uvicorn" in p.lockfile["default"]
@pytest.mark.install
@pytest.mark.skip_lock
@pytest.mark.needs_internet
def test_install_skip_lock(pipenv_instance_private_pypi):
with pipenv_instance_private_pypi() as p:
with open(p.pipfile_path, 'w') as f:
contents = """
[[source]]
url = "{}"
verify_ssl = true
name = "pypi"
[packages]
six = {}
""".format(p.index_url, '{version = "*", index = "pypi"}').strip()
f.write(contents)
c = p.pipenv('install --skip-lock')
assert c.returncode == 0
c = p.pipenv('run python -c "import six"')
assert c.returncode == 0
+13
View File
@@ -162,3 +162,16 @@ def test_run_in_virtualenv(pipenv_instance_pypi):
c = p.pipenv("clean --dry-run")
assert c.returncode == 0
assert "click" in c.stdout
@pytest.mark.project
@pytest.mark.sources
def test_no_sources_in_pipfile(pipenv_instance_pypi):
with pipenv_instance_pypi() as p:
with open(p.pipfile_path, 'w') as f:
contents = """
[packages]
pytest = "*"
""".strip()
f.write(contents)
c = p.pipenv('install --skip-lock')
assert c.returncode == 0