Repository: pypa/pipenv

Issue:
2018.11.14 regression: KeyError: verify_ssl
### Issue description

Pipenv (2018.11.14) errors when being called to install deps from a project with a `Pipfile` without a `verify_ssl` key.

### Expected result

`pipenv install --dev` works and exits `0`

### Actual result

Trace:
```
New python executable in /home/ginkgo/.local/share/virtualenvs/servicely-workflows-YJPopuIU/bin/python3
Also creating executable in /home/ginkgo/.local/share/virtualenvs/servicely-workflows-YJPopuIU/bin/python
Installing setuptools, pip, wheel...
done.
Running virtualenv with interpreter /usr/bin/python3
Virtualenv location: /home/ginkgo/.local/share/virtualenvs/servicely-workflows-YJPopuIU
Traceback (most recent call last):
  File "/usr/local/bin/pipenv", line 11, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/pipenv/vendor/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/pipenv/cli/command.py", line 249, in install
    editable_packages=state.installstate.editables,
  File "/usr/local/lib/python3.6/dist-packages/pipenv/core.py", line 1872, in do_install
    keep_outdated=keep_outdated
  File "/usr/local/lib/python3.6/dist-packages/pipenv/core.py", line 1232, in do_init
    pypi_mirror=pypi_mirror,
  File "/usr/local/lib/python3.6/dist-packages/pipenv/core.py", line 781, in do_install_dependencies
    lockfile = project.get_or_create_lockfile()
  File "/usr/local/lib/python3.6/dist-packages/pipenv/project.py", line 758, in get_or_create_lockfile
    } for s in sources
  File "/usr/local/lib/python3.6/dist-packages/pipenv/project.py", line 758, in <listcomp>
    } for s in sources
KeyError: 'verify_ssl'
The command '/bin/sh -c pipenv install --dev' returned a non-zero code: 1
```

### Steps to replicate

With the following `Pipfile`:

```ini
[[source]]
url = 'https://pypi.example.com/simple/'

[requires]
python_version = '3'

[packages]
celery = '>=4.2'
Django = '>=2.0'
ginkgo-common = '*'
ginkgo-log = '*'
gappy = '==1.6.0'
gunicorn = '==19.9.0'
lims_api_client = '==1.9.0'
pygments = '*'
requests = '*'
six = '*'
Sphinx = '*'
sphinx-rtd-theme = '*'
pre-commit = "==1.9.0"
whitenoise = '==3.3.1'

[dev-packages]
coverage = '*'
flake8 = '*'
flake8-diff = '*'
ipython = '*'
mock = '*'
pytest = '*'
nose = '*'
tox = '*'
yapf = '*'
```

Run `pipenv install --dev` 

Commit that introduced the error was 2b90c89d1f518a543f775cb811ee8b5565ee1366 

Fix may just be as simple as using `.get`


Discussion:
Hey @myw,

We did a quick check and this issue looks very darn similar to

* [#3232 - 2018.11.14 regression: cannot create virtualenv](3232)
* [#3231 - &#39;pipenv clean&#39; fails when running in an existing virtualenv](3231)
* [#3230 - 2018.11.14 regression: pipenv fails to install editable extras](3230)

This could be a coincidence, but if any of these issues solves your problem then I did a good job :smile:

If not, the maintainers will get to this issue shortly.

Cheers,
Your Friendly Neighborhood ProBot

The pipenv should provide default value ```true``` for ```verify_ssl``` when locking Pipfile, which does not contain ```verify_ssl``` field, to Pipfile.lock.

Resolving patch:
diff --git a/pipenv/project.py b/pipenv/project.py
--- a/pipenv/project.py
+++ b/pipenv/project.py
@@ -727,6 +727,18 @@ def create_pipfile(self, python=None):
             data[u"requires"] = {"python_version": version[: len("2.7")]}
         self.write_toml(data)
 
+    @classmethod
+    def populate_source(cls, source):
+        """Derive missing values of source from the existing fields."""
+        # Only URL pararemter is mandatory, let the KeyError be thrown.
+        if "name" not in source:
+            source["name"] = get_url_name(source["url"])
+        if "verify_ssl" not in source:
+            source["verify_ssl"] = "https://" in source["url"]
+        if not isinstance(source["verify_ssl"], bool):
+            source["verify_ssl"] = source["verify_ssl"].lower() == "true"
+        return source
+
     def get_or_create_lockfile(self):
         from pipenv.vendor.requirementslib.models.lockfile import Lockfile as Req_Lockfile
         lockfile = None
@@ -747,15 +759,7 @@ def get_or_create_lockfile(self):
             elif not isinstance(sources, list):
                 sources = [sources,]
             lockfile_dict["_meta"]["sources"] = [
-                {
-                    "name": s.get("name", get_url_name(s.get("url"))),
-                    "url": s["url"],
-                    "verify_ssl": (
-                        s["verify_ssl"] if isinstance(s["verify_ssl"], bool) else (
-                            True if s["verify_ssl"].lower() == "true" else False
-                        )
-                    )
-                } for s in sources
+                self.populate_source(s) for s in sources
             ]
             _created_lockfile = Req_Lockfile.from_data(
                 path=self.lockfile_location, data=lockfile_dict, meta_from_project=False


Test patch:
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
@@ -486,3 +486,20 @@ def test_lockfile_with_empty_dict(PipenvInstance):
         assert c.return_code == 0
         assert 'Pipfile.lock is corrupted' in c.err
         assert p.lockfile['_meta']
+
+
+@pytest.mark.lock
+@pytest.mark.install
+def test_lock_with_incomplete_source(PipenvInstance, pypi):
+    with PipenvInstance(pypi=pypi, chdir=True) as p:
+        with open(p.pipfile_path, 'w') as f:
+            f.write("""
+[[source]]
+url = "https://test.pypi.org/simple"
+
+[packages]
+requests = "*"
+            """)
+        c = p.pipenv('install')
+        assert c.return_code == 0
+        assert p.lockfile['_meta']['sources']