Repository: pypa/pipenv

Issue:
Unexpected VCS dependencies added to the Pipfile.lock
When a VCS dependency is present in the Pipfile, any VCS dependency in the virtualenv will be added to the Pipfile.lock. This can include packages installed with `pip install -e <path>`, as it's represented in the `pip freeze` as `-e git+ssh://...` if the path corresponds to a git repo.

In my case this wasn't an issue before #835 as git dependencies where not parsed correctly, but since this PR I'm seeing unexpected git repositories showing up in my Pipfile.lock.

I think that the culprit is in this loop, which adds any VCS dependency present in the `pip freeze` to the Pipfile.lock without checking if they are in the Pipfile:
https://github.com/kennethreitz/pipenv/blob/8685ba80d75c6489bbb4dce19861c9e91c2636ed/pipenv/cli.py#L1050-L1061

I'm working on a fix.




Discussion:
I’m pretty sure that is the intended behavior and anything that alters it will be breaking the functionality instead of fixing it.  Pipenv by default is built to treat whichever virtualenv it manages as a representation of a dependency state. Pipfiles are a basis for installation (so you dont have to feed in the output of pip freeze anymore), while lockfiles are a more detailed representation of the present state of the environment (I.e. if it appears in pip freeze it should appear in the lockfile).

#835 actually FIXED an issue preventing vcs dependencies from showing up correctly in the lockfile. 

Out of curiosity, what problem is this causing for you?

> On Oct 12, 2017, at 6:58 AM, Yannick PÉROUX <notifications@github.com> wrote:
> 
> When a VCS dependency is present in the Pipfile, any VCS dependency in the virtualenv will be added to the Pipfile.lock. This can include packages installed with pip install -e <path>, as it's represented in the pip freeze as -e git+ssh://... if the path corresponds to a git repo.
> 
> In my case this wasn't an issue before #835 as git dependencies where not parsed correctly, but since this PR I'm seeing unexpected git repositories showing up in my Pipfile.lock.
> 
> I think that the culprit is in this loop, which adds any VCS dependency present in the pip freeze to the Pipfile.lock without checking if they are in the Pipfile:
> https://github.com/kennethreitz/pipenv/blob/8685ba80d75c6489bbb4dce19861c9e91c2636ed/pipenv/cli.py#L1050-L1061
> 
> I'm working on a fix.
> 
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub, or mute the thread.
> 

In my project if I do a `pipenv install -e .`, and I have another VCS dependency in my Pipfile, every time I run `pipenv lock` the Pipfile.lock will be edited with the following:
```json
        "e1839a8": {
            "git": "ssh://git@github.com/<orga>/<repo>.git",
            "ref": "<commit>",
            "editable": "."
        },
```

Instead of:
```json
        "e1839a8": {
            "path": ".",
            "editable": "."
        },
```

Also if I happen to install locally a VCS dependency which is not present in my Pipfile, it will be added to the Pipfile.lock. This is not true for non-VCS dependencies, and I'm pretty sure this is not an expected behavior.

Resolving patch:
diff --git a/pipenv/cli.py b/pipenv/cli.py
--- a/pipenv/cli.py
+++ b/pipenv/cli.py
@@ -1047,8 +1047,13 @@ def do_lock(verbose=False, system=False, clear=False, pre=False):
     vcs_deps = convert_deps_to_pip(project.vcs_dev_packages, project, r=False)
     pip_freeze = delegator.run('{0} freeze'.format(which_pip())).out
 
-    for dep in vcs_deps:
+    if vcs_deps:
         for line in pip_freeze.strip().split('\n'):
+            # if the line doesn't match a vcs dependency in the Pipfile,
+            # ignore it
+            if not any(dep in line for dep in vcs_deps):
+                continue
+
             try:
                 installed = convert_deps_from_pip(line)
                 name = list(installed.keys())[0]


Test patch:
diff --git a/tests/test_pipenv.py b/tests/test_pipenv.py
--- a/tests/test_pipenv.py
+++ b/tests/test_pipenv.py
@@ -586,6 +586,38 @@ def test_lock_requirements_file(self):
             for req in req_list:
                 assert req in c.out
 
+    @pytest.mark.lock
+    @pytest.mark.complex
+    def test_complex_lock_with_vcs_deps(self):
+
+        with PipenvInstance() as p:
+            with open(p.pipfile_path, 'w') as f:
+                contents = """
+[packages]
+click = "==6.7"
+
+[dev-packages]
+requests = {git = "https://github.com/requests/requests", egg = "requests"}
+                """.strip()
+                f.write(contents)
+
+            c = p.pipenv('install')
+            assert c.return_code == 0
+            lock = p.lockfile
+            assert 'requests' in lock['develop']
+            assert 'click' in lock['default']
+
+            c = p.pipenv('run pip install -e git+https://github.com/dateutil/dateutil#egg=python_dateutil')
+            assert c.return_code == 0
+
+            c = p.pipenv('lock')
+            assert c.return_code == 0
+            lock = p.lockfile
+            assert 'requests' in lock['develop']
+            assert 'click' in lock['default']
+            assert 'python_dateutil' not in lock['default']
+            assert 'python_dateutil' not in lock['develop']
+
     @pytest.mark.lock
     @pytest.mark.requirements
     @pytest.mark.complex