Skip to content

Commit

Permalink
[pypa#3722] Exclude shared packages for all-dev opt
Browse files Browse the repository at this point in the history
Filters list of packages to uninstall for shared dependencies when
uninstall is used with the --all-dev option. This prevents shared
dependencies from being uninstalled or removed from the default section
of the lockfile.

Adds a test to ensure that shared dependencies are not uninstalled and
not removed from the pipfile or lockfile.
  • Loading branch information
ianpittwood committed Sep 7, 2019
1 parent bfbe130 commit 2c2189c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 4 deletions.
12 changes: 8 additions & 4 deletions pipenv/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2230,8 +2230,6 @@ def do_uninstall(
click.echo("Ignoring {0}.".format(ignored_pkg), err=True)
pkg_name_index = package_names.index(package_map[ignored_pkg])
del package_names[pkg_name_index]

used_packages = project_pkg_names["combined"] & installed_package_names
failure = False
packages_to_remove = set()
if all:
Expand All @@ -2245,10 +2243,14 @@ def do_uninstall(
)
do_purge(bare=False, allow_global=system)
sys.exit(0)
overlapping_package_names = set()
if all_dev:
package_names = project_pkg_names["dev"]
used_packages = (project_pkg_names["combined"] & installed_package_names) - project_pkg_names["default"]
else:
package_names = set([pkg_name for pkg_name in package_names])
used_packages = project_pkg_names["combined"] & installed_package_names

selected_pkg_map = {
canonicalize_name(p): p for p in package_names
}
Expand All @@ -2264,6 +2266,7 @@ def do_uninstall(
)
)
# Uninstall the package.
# If uninstall --all-dev, skip any common packages between default and dev from pip uninstall
if package_name in packages_to_remove:
with project.environment.activated():
if pip_path is None:
Expand All @@ -2286,7 +2289,8 @@ def do_uninstall(
crayons.white(fix_utf8("Pipfile.lock…")))
)
lockfile = project.get_or_create_lockfile()
if normalized in lockfile.default:
# Uninstall with --all-dev should not modify the default packages
if normalized in lockfile.default and not all_dev:
del lockfile.default[normalized]
if normalized in lockfile.develop:
del lockfile.develop[normalized]
Expand All @@ -2307,7 +2311,7 @@ def do_uninstall(
# Remove package from both packages and dev-packages.
if in_dev_packages:
project.remove_package_from_pipfile(package_name, dev=True)
if in_packages:
if in_packages and not all_dev:
project.remove_package_from_pipfile(package_name, dev=False)
if lock:
do_lock(system=system, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
Expand Down
35 changes: 35 additions & 0 deletions tests/integration/test_uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,41 @@ def test_uninstall_all_dev(PipenvInstance):
assert c.return_code == 0


@pytest.mark.run
@pytest.mark.uninstall
@pytest.mark.install
def test_uninstall_all_dev_leave_prod_packages(PipenvInstance):
with PipenvInstance() as p:
c = p.pipenv("install --dev --pre black")
assert c.return_code == 0

c = p.pipenv("install flask")
assert c.return_code == 0

assert "flask" in p.pipfile["packages"]
assert "black" in p.pipfile["dev-packages"]
assert "flask" in p.lockfile["default"]
assert "black" in p.lockfile["develop"]
assert "click" in p.lockfile["default"]
assert "click" in p.lockfile["develop"]

c = p.pipenv('run python -c "import click"')
assert c.return_code == 0

c = p.pipenv("uninstall --all-dev")
assert c.return_code == 0

assert p.pipfile["dev-packages"] == {}
assert "black" not in p.lockfile["develop"]
assert "click" not in p.lockfile["develop"]
assert "flask" in p.pipfile["packages"]
assert "flask" in p.lockfile["default"]
assert "click" in p.lockfile["default"]

c = p.pipenv('run python -c "import click"')
assert c.return_code == 0


@pytest.mark.uninstall
@pytest.mark.run
def test_normalize_name_uninstall(PipenvInstance):
Expand Down

0 comments on commit 2c2189c

Please sign in to comment.