Repository: kennethreitz/pipenv (python)

Issue:
Fails if two conflicting "requires" sections are present.
I stumbled upon this since, at some point, an extra `requires` section was added to my `Pipifile`. I'm not able to reproduce the circumstances that lead to such a malformed configuration file, but still the reaction of `pipenv` is quite baffling. 

##### Describe you environment

1. OS Type: OS X 10.12.6 (16G29)
1. Python2 version: `$ python -V` 2.7.14
1. Python3 version: `$ python3 -V` 3.6.3
1. Pipenv version: `$ pipenv --version` 8.2.7

##### Expected result

Running `pipenv check` on

```
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[requires]
python_version = "3.6"

[requires]
python_version = "2.7"

[packages]

[dev-packages]

```

should return a more informative error about the presence of two conflicting `requires` sections than a stacktrace.

##### Actual result

The command crashes emitting a stacktrace (related to the `requires` section already defined, but not so readable).

```
$ pipenv check
Checking PEP 508 requirements…
Traceback (most recent call last):
  File "/usr/local/bin/pipenv", line 11, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/pipenv/cli.py", line 2208, in check
    p = pipfile.Pipfile.load(project.pipfile_location)
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/pipfile/api.py", line 126, in load
    pipfile.data = p.parse()
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/pipfile/api.py", line 82, in parse
    config.update(toml.loads(content))
  File "/usr/local/lib/python3.6/site-packages/pipenv/vendor/toml.py", line 344, in loads
    str(currentlevel))
toml.TomlDecodeError: What? requires already exists?{'source': [{'url': 'https://pypi.python.org/simple', 'verify_ssl': True, 'name': 'pypi'}], 'requires': {'python_version': '3.6'}}

```

##### Steps to replicate

Just run `pipenv check` in an empty directory containing just the above-mentioned `Pipfile`.

Pull request:
Fix #973 Fails if two conflicting "requires" sections are present.
Add a more explicit error message if a section of the Pipfile is duplicated

Patch:
diff --git a/pipenv/project.py b/pipenv/project.py
index 027da542..36a2bd42 100644
--- a/pipenv/project.py
+++ b/pipenv/project.py
@@ -227,6 +227,14 @@ class Project(object):
         with open(self.pipfile_location) as f:
             contents = f.read()
 
+        sections = re.findall("\[[a-zA-Z-]+\]", contents)
+        for section in set(sections):
+            section_count = sections.count(section)
+            if section_count > 1:
+                raise RuntimeError(
+                    "Your Pipfile contains section '{}' multiple times ({}x)".format(section, section_count)
+                )
+
         # If any outline tables are present...
         if ('[packages.' in contents) or ('[dev-packages.' in contents):
 


Test patch:
diff --git a/tests/test_project.py b/tests/test_project.py
index 3375415c..6436f58f 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -1,4 +1,5 @@
 import pipenv.project
+import pytest
 from pipenv.vendor import delegator
 
 
@@ -153,3 +154,22 @@ class TestProject():
         assert lockfile['_meta']['hash'] == {'sha256': 'ff0b0584610a7091156f32ca7d5adab8f29cb17263c6d63bcab42de2137c4787'}
 
         delegator.run('rm -fr test_internal_lockfile')
+
+    def test_duplicate_sections(self):
+        proj = pipenv.project.Project()
+
+        # Create test space.
+        delegator.run('mkdir test_duplicate_sections')
+
+        with open('test_duplicate_sections/Pipfile', 'w') as f:
+            f.write('[requires]\n'
+                    'python_version = "3.6"\n\n'
+                    '[requires]\n'
+                    'python_version = "2.7"\n')
+
+        proj._pipfile_location = 'test_duplicate_sections/Pipfile'
+
+        with pytest.raises(RuntimeError):
+            _ = proj.parsed_pipfile
+
+        delegator.run('rm -fr test_duplicate_sections')