Repository: pypa/pip

Issue:
Ignore literal duplicates (includes and/or individual requirements)
pip's handling of requirements files does not support a scenario like this one:

```
# common.txt
somepackage==1.0

# testing.txt
- r common.txt
test-tool==1.0

# development.txt
-r common.txt
-r testing.txt
developer-tool==1.0
```

Here, `pip install -r development.txt` will complain about a double requirement `somepackage==1.0` and quit.

Because of that, I have to duplicate my testing requirements in my development.txt. Not a big deal, but it would be nice if pip could handle this. For this scenario, it seems that it would be sufficient to just ignore the duplicate `-r` line, so this would probably be easier to implement than #56.



Discussion:
Just ran into the exact same issue, same use case.

+1

closing as dupe of #56

reopening, this is not a duplicate of #56.  this issue is about literal duplicate includes, whereas #56 is about resolving non-conflicting (but not necessarily duplicate) top-level requirements.

+1

I looked at this from the angle of attempting to allow/ignore literal duplicate requirements.

One snag was with non-editable url requirements, e.g. pkg urls or vcs urls without `-e`.
currently, that code path does't store the full url in the `url` property of `InstallRequirement`, but rather just the url without the fragment.

e.g. so there could be 2 lines like this

```
git+http://project.git@branch#egg=project'
git+http://project.git@branch#egg=anotherproject'
```

I don't think these 2 should pass thru as literal duplicates, but we don't have enough information stored to distinguish them.   we should look into storing the full url I think, and understand why we're not.  I'm not sure atm

related issue: #1658

:+1:

Pip is more disappointing the more you try to do anything outside of tutorial material.

+1 same error similiar usecase.
Related issue: https://github.com/rackerlabs/mimic/issues/502


Resolving patch:
diff --git a/pip/req/req_set.py b/pip/req/req_set.py
--- a/pip/req/req_set.py
+++ b/pip/req/req_set.py
@@ -242,7 +242,8 @@ def add_requirement(self, install_req, parent_req_name=None):
                 existing_req = None
             if (parent_req_name is None and existing_req and not
                     existing_req.constraint and
-                    existing_req.extras == install_req.extras):
+                    existing_req.extras == install_req.extras and not
+                    existing_req.req.specs == install_req.req.specs):
                 raise InstallationError(
                     'Double requirement given: %s (already in %s, name=%r)'
                     % (install_req, existing_req, name))


Test patch:
diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py
--- a/tests/functional/test_install.py
+++ b/tests/functional/test_install.py
@@ -932,3 +932,22 @@ def test_install_tar_lzma(script, data):
         pytest.skip("No lzma support")
     res = script.pip('install', data.packages / 'singlemodule-0.0.1.tar.lzma')
     assert "Successfully installed singlemodule-0.0.1" in res.stdout, res
+
+
+def test_double_install(script, data):
+    """
+    Test double install passing with two same version requirements
+    """
+    result = script.pip('install', 'pip', 'pip', expect_error=False)
+    msg = "Double requirement given: pip (already in pip, name='pip')"
+    assert msg not in result.stderr
+
+
+def test_double_install_fail(script, data):
+    """
+    Test double install failing with two different version requirements
+    """
+    result = script.pip('install', 'pip==*', 'pip==7.1.2', expect_error=True)
+    msg = ("Double requirement given: pip==7.1.2 (already in pip==*, "
+           "name='pip')")
+    assert msg in result.stderr