Skip to content

Commit

Permalink
Duplicate distributions with distinct extras
Browse files Browse the repository at this point in the history
Any duplicate distributions will currently raise an error, even if
their extras are different: for example, 'pip install bar bar[foo]'.
Detect this situation, and union the extras together.

Closes #3189
  • Loading branch information
s-t-e-v-e-n-k committed Oct 21, 2015
1 parent 829b6c2 commit 88af44d
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
9 changes: 9 additions & 0 deletions pip/req/req_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@ 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):
if existing_req.name == install_req.name:
# If the extras do not match, then union them together to
# support install bar bar[foo]. If they do match, the
# InstallationError will be raised as per normal.
if existing_req.extras != install_req.extras:
existing_req.extras = tuple(
set(existing_req.extras).union(
set(install_req.extras)))
return [existing_req]
raise InstallationError(
'Double requirement given: %s (already in %s, name=%r)'
% (install_req, existing_req, name))
Expand Down
2 changes: 1 addition & 1 deletion tests/data/packages/LocalExtras/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ def path_to_url(path):
name='LocalExtras',
version='0.0.1',
packages=find_packages(),
extras_require={ 'bar': ['simple'] },
extras_require={ 'bar': ['simple'], 'baz': ['singlemodule'] },
dependency_links=[DEP_URL]
)
17 changes: 17 additions & 0 deletions tests/functional/test_install_reqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,20 @@ def test_constrained_to_url_install_same_url(script, data):
'install', '--no-index', '-f', data.find_links, '-c',
script.scratch_path / 'constraints.txt', to_install)
assert 'Running setup.py install for singlemodule' in result.stdout


def test_install_distribution_full_union(script, data):
to_install = data.packages.join("LocalExtras")
result = script.pip_install_local(
to_install, to_install + "[bar]", to_install + "[baz]")
assert 'Running setup.py install for LocalExtras' in result.stdout
assert script.site_packages / 'simple' in result.files_created
assert script.site_packages / 'singlemodule.py' in result.files_created


def test_install_distribution_duplicate_extras(script, data):
to_install = data.packages.join("LocalExtras")
package_name = to_install + "[bar]"
with pytest.raises(AssertionError):
result = script.pip_install_local(package_name, package_name)
assert 'Double requirement given: %s' % package_name in result.stderr

0 comments on commit 88af44d

Please sign in to comment.