Repository: pypa/pipenv

Issue:
Finish dropping --skip-lock so we can move forward with migrating away from Requirementslib
### Issue description

A simplified architecture for pipenv would be:

![image](https://github.com/pypa/pipenv/assets/479892/1447095d-d7c9-403a-a69e-c5c86037df03)

`--skip-lock` is problematic because it requires also being able to generate the install lines from the Pipfile.  Additionally given the other bugs around this flag, the recommendation is if you want to skip the lock and install something for testing just run `pipenv run pip install`  If you want to do this from the Pipfile run `pipenv requirements` to generate a requirements file and then run `pipenv run pip install -r requirements.txt`   

This will also improve the security of pipenv because some users may be using the `--skip-lock` flag in their CI builds.




Discussion:

Resolving patch:
diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py
--- a/pipenv/cli/command.py
+++ b/pipenv/cli/command.py
@@ -15,7 +15,6 @@
     pypi_mirror_option,
     python_option,
     site_packages_option,
-    skip_lock_option,
     sync_options,
     system_option,
     uninstall_options,
@@ -223,7 +222,6 @@ def cli(
 @system_option
 @deploy_option
 @site_packages_option
-@skip_lock_option
 @install_options
 @pass_state
 def install(state, **kwargs):
@@ -237,7 +235,6 @@ def install(state, **kwargs):
         pypi_mirror=state.pypi_mirror,
         system=state.system,
         ignore_pipfile=state.installstate.ignore_pipfile,
-        skip_lock=state.installstate.skip_lock,
         requirementstxt=state.installstate.requirementstxt,
         pre=state.installstate.pre,
         deploy=state.installstate.deploy,
@@ -314,7 +311,7 @@ def uninstall(ctx, state, all_dev=False, all=False, **kwargs):
         editable_packages=state.installstate.editables,
         python=state.python,
         system=state.system,
-        lock=not state.installstate.skip_lock,
+        lock=True,
         all_dev=all_dev,
         all=all,
         pypi_mirror=state.pypi_mirror,
diff --git a/pipenv/cli/options.py b/pipenv/cli/options.py
--- a/pipenv/cli/options.py
+++ b/pipenv/cli/options.py
@@ -3,7 +3,6 @@
 
 from pipenv.project import Project
 from pipenv.utils.internet import is_valid_url
-from pipenv.vendor import click
 from pipenv.vendor.click import (
     BadArgumentUsage,
     BadParameter,
@@ -77,7 +76,6 @@ class InstallState:
     def __init__(self):
         self.dev = False
         self.pre = False
-        self.skip_lock = False
         self.ignore_pipfile = False
         self.code = False
         self.requirementstxt = None
@@ -130,34 +128,6 @@ def callback(ctx, param, value):
     )(f)
 
 
-def skip_lock_option(f):
-    def callback(ctx, param, value):
-        state = ctx.ensure_object(State)
-        state.installstate.skip_lock = value
-        if value:
-            click.secho(
-                "The flag --skip-lock has been deprecated for removal.  "
-                "Without running the lock resolver it is not possible to manage multiple package indexes.  "
-                "Additionally it bypasses the build consistency guarantees provided by maintaining a lock file.",
-                fg="yellow",
-                bold=True,
-                err=True,
-            )
-        return value
-
-    return option(
-        "--skip-lock",
-        is_flag=True,
-        default=False,
-        expose_value=False,
-        help="Skip locking mechanisms and use the Pipfile instead during operation.",
-        envvar="PIPENV_SKIP_LOCK",
-        callback=callback,
-        type=click_types.BOOL,
-        show_envvar=True,
-    )(f)
-
-
 def ignore_pipfile_option(f):
     def callback(ctx, param, value):
         state = ctx.ensure_object(State)
@@ -533,7 +503,6 @@ def uninstall_options(f):
     f = install_base_options(f)
     f = categories_option(f)
     f = uninstall_dev_option(f)
-    f = skip_lock_option(f)
     f = editable_option(f)
     f = package_arg(f)
     return f
diff --git a/pipenv/routines/install.py b/pipenv/routines/install.py
--- a/pipenv/routines/install.py
+++ b/pipenv/routines/install.py
@@ -38,7 +38,6 @@ def do_install(
     pypi_mirror=None,
     system=False,
     ignore_pipfile=False,
-    skip_lock=False,
     requirementstxt=False,
     pre=False,
     deploy=False,
@@ -72,7 +71,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 ((skip_lock and deploy) or ignore_pipfile) and not project.lockfile_exists:
+        elif 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:
@@ -173,7 +172,6 @@ def do_install(
             allow_global=system,
             ignore_pipfile=ignore_pipfile,
             system=system,
-            skip_lock=skip_lock,
             deploy=deploy,
             pre=pre,
             requirements_dir=requirements_directory,
@@ -197,7 +195,6 @@ def do_install(
                 requirements_dir=requirements_directory,
                 deploy=deploy,
                 pypi_mirror=pypi_mirror,
-                skip_lock=skip_lock,
                 extra_pip_args=extra_pip_args,
                 categories=categories,
             )
@@ -300,7 +297,6 @@ def do_install(
                 requirements_dir=requirements_directory,
                 deploy=deploy,
                 pypi_mirror=pypi_mirror,
-                skip_lock=skip_lock,
                 extra_pip_args=extra_pip_args,
                 categories=categories,
             )
@@ -373,7 +369,6 @@ def do_install_dependencies(
     bare=False,
     allow_global=False,
     ignore_hashes=False,
-    skip_lock=False,
     requirements_dir=None,
     pypi_mirror=None,
     extra_pip_args=None,
@@ -395,20 +390,14 @@ def do_install_dependencies(
     lockfile = None
     pipfile = None
     for category in categories:
-        # Load the lockfile if it exists, or if dev_only is being used.
-        if skip_lock:
-            if not bare:
-                click.secho("Installing dependencies from Pipfile...", bold=True)
-            pipfile = project.get_pipfile_section(category)
-        else:
-            lockfile = project.get_or_create_lockfile(categories=categories)
-            if not bare:
-                click.secho(
-                    "Installing dependencies from Pipfile.lock ({})...".format(
-                        lockfile["_meta"].get("hash", {}).get("sha256")[-6:]
-                    ),
-                    bold=True,
-                )
+        lockfile = project.get_or_create_lockfile(categories=categories)
+        if not bare:
+            click.secho(
+                "Installing dependencies from Pipfile.lock ({})...".format(
+                    lockfile["_meta"].get("hash", {}).get("sha256")[-6:]
+                ),
+                bold=True,
+            )
         dev = dev or dev_only
         if lockfile:
             deps_list = list(
@@ -419,12 +408,11 @@ def do_install_dependencies(
             for req_name, specifier in pipfile.items():
                 deps_list.append(Requirement.from_pipfile(req_name, specifier))
         failed_deps_queue = queue.Queue()
-        if skip_lock:
-            ignore_hashes = True
+
         editable_or_vcs_deps = [dep for dep in deps_list if (dep.editable or dep.vcs)]
         normal_deps = [dep for dep in deps_list if not (dep.editable or dep.vcs)]
         install_kwargs = {
-            "no_deps": not skip_lock,
+            "no_deps": True,
             "ignore_hashes": ignore_hashes,
             "allow_global": allow_global,
             "pypi_mirror": pypi_mirror,
@@ -676,7 +664,6 @@ def do_init(
     dev_only=False,
     allow_global=False,
     ignore_pipfile=False,
-    skip_lock=False,
     system=False,
     deploy=False,
     pre=False,
@@ -709,7 +696,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) and not skip_lock:
+    if project.lockfile_exists and not ignore_pipfile:
         old_hash = project.get_lockfile_hash()
         new_hash = project.calculate_pipfile_hash()
         if new_hash != old_hash:
@@ -749,7 +736,7 @@ def do_init(
                     categories=categories,
                 )
     # Write out the lockfile if it doesn't exist.
-    if not project.lockfile_exists and not skip_lock:
+    if not project.lockfile_exists:
         # 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):
@@ -778,7 +765,6 @@ def do_init(
         dev=dev,
         dev_only=dev_only,
         allow_global=allow_global,
-        skip_lock=skip_lock,
         requirements_dir=requirements_dir,
         pypi_mirror=pypi_mirror,
         extra_pip_args=extra_pip_args,


Test patch:
diff --git a/tests/integration/test_install_twists.py b/tests/integration/test_install_twists.py
--- a/tests/integration/test_install_twists.py
+++ b/tests/integration/test_install_twists.py
@@ -275,25 +275,3 @@ def test_outdated_should_compare_postreleases_without_failing(pipenv_instance_pr
         c = p.pipenv("update --outdated")
         assert c.returncode != 0
         assert "out-of-date" in c.stdout
-
-
-@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
diff --git a/tests/integration/test_lock.py b/tests/integration/test_lock.py
--- a/tests/integration/test_lock.py
+++ b/tests/integration/test_lock.py
@@ -262,36 +262,6 @@ def test_lock_extras_without_install(pipenv_instance_private_pypi):
         assert "extra == 'socks'" not in c.stdout.strip()
 
 
-@pytest.mark.skip(reason="Skip lock does not support multiple indexes sources; flag is considered for deprecation.")
-@pytest.mark.index
-@pytest.mark.install  # private indexes need to be uncached for resolution
-@pytest.mark.skip_lock
-@pytest.mark.needs_internet
-def test_private_index_skip_lock(pipenv_instance_private_pypi):
-    with pipenv_instance_private_pypi() as p:
-        with open(p.pipfile_path, 'w') as f:
-            contents = """
-[[source]]
-url = "https://pypi.org/simple"
-verify_ssl = true
-name = "pypi"
-
-[[source]]
-url = "https://test.pypi.org/simple"
-verify_ssl = true
-name = "testpypi"
-
-[packages]
-pipenv-test-private-package = {version = "*", index = "testpypi"}
-
-[pipenv]
-install_search_all_sources = true
-            """.strip()
-            f.write(contents)
-        c = p.pipenv('install --skip-lock')
-        assert c.returncode == 0
-
-
 @pytest.mark.lock
 @pytest.mark.index
 @pytest.mark.install  # private indexes need to be uncached for resolution
diff --git a/tests/integration/test_project.py b/tests/integration/test_project.py
--- a/tests/integration/test_project.py
+++ b/tests/integration/test_project.py
@@ -162,17 +162,3 @@ 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