mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
resolve issues with uninstall.
This commit is contained in:
+31
-36
@@ -30,6 +30,7 @@ from pipenv.utils.dependencies import (
|
||||
get_canonical_names,
|
||||
get_constraints_from_deps,
|
||||
get_lockfile_section_using_pipfile_category,
|
||||
get_pipfile_category_using_lockfile_section,
|
||||
is_pinned,
|
||||
is_required_version,
|
||||
is_star,
|
||||
@@ -1065,11 +1066,7 @@ def do_lock(
|
||||
|
||||
# Resolve package to generate constraints before resolving other categories
|
||||
for category in lockfile_categories:
|
||||
pipfile_category = category
|
||||
if pipfile_category == "develop":
|
||||
pipfile_category = "dev-packages"
|
||||
if pipfile_category == "default":
|
||||
pipfile_category = "packages"
|
||||
pipfile_category = get_pipfile_category_using_lockfile_section(category)
|
||||
if project.pipfile_exists:
|
||||
packages = project.parsed_pipfile.get(pipfile_category, {})
|
||||
else:
|
||||
@@ -2426,13 +2423,13 @@ def do_uninstall(
|
||||
# Automatically use an activated virtualenv.
|
||||
if project.s.PIPENV_USE_SYSTEM:
|
||||
system = True
|
||||
if categories is None:
|
||||
categories = project.get_package_categories()
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(project, three=three, python=python, pypi_mirror=pypi_mirror)
|
||||
# Uninstall all dependencies, if --all was provided.
|
||||
if not any([packages, editable_packages, all_dev, all, categories]):
|
||||
if not any([packages, editable_packages, all_dev, all]):
|
||||
raise exceptions.PipenvUsageError("No package provided!", ctx=ctx)
|
||||
if not categories:
|
||||
categories = project.get_package_categories(for_lockfile=True)
|
||||
editable_pkgs = [
|
||||
Requirement.from_line(f"-e {p}").name for p in editable_packages if p
|
||||
]
|
||||
@@ -2440,8 +2437,6 @@ def do_uninstall(
|
||||
package_names = {p for p in packages if p}
|
||||
package_map = {canonicalize_name(p): p for p in packages if p}
|
||||
installed_package_names = project.installed_package_names
|
||||
# Intelligently detect if --dev should be used or not.
|
||||
lockfile_packages = set()
|
||||
if project.lockfile_exists:
|
||||
project_pkg_names = project.lockfile_package_names
|
||||
else:
|
||||
@@ -2472,16 +2467,19 @@ def do_uninstall(
|
||||
)
|
||||
)
|
||||
preserve_packages = set()
|
||||
dev_packages = set()
|
||||
for category in project.get_package_categories(for_lockfile=True):
|
||||
if category == "develop":
|
||||
continue
|
||||
preserve_packages &= set(project_pkg_names[category])
|
||||
package_names = set(project_pkg_names["develop"]) - preserve_packages
|
||||
dev_packages |= set(project_pkg_names[category])
|
||||
else:
|
||||
preserve_packages |= set(project_pkg_names[category])
|
||||
|
||||
package_names = dev_packages - preserve_packages
|
||||
|
||||
# Remove known "bad packages" from the list.
|
||||
bad_pkgs = get_canonical_names(BAD_PACKAGES)
|
||||
ignored_packages = bad_pkgs & set(list(package_map.keys()))
|
||||
for ignored_pkg in ignored_packages:
|
||||
for ignored_pkg in get_canonical_names(ignored_packages):
|
||||
if project.s.is_verbose():
|
||||
click.echo(f"Ignoring {ignored_pkg}.", err=True)
|
||||
package_names.discard(package_map[ignored_pkg])
|
||||
@@ -2509,15 +2507,10 @@ def do_uninstall(
|
||||
for normalized, package_name in selected_pkg_map.items()
|
||||
if normalized in (used_packages - bad_pkgs)
|
||||
]
|
||||
for normalized_name, package_name in selected_pkg_map.items():
|
||||
click.secho(
|
||||
fix_utf8(f"Uninstalling {click.style(package_name)}..."),
|
||||
fg="green",
|
||||
bold=True,
|
||||
)
|
||||
found_package = False
|
||||
for category in categories:
|
||||
if normalized_name in lockfile_packages:
|
||||
for category in categories:
|
||||
category = get_lockfile_section_using_pipfile_category(category)
|
||||
for normalized_name, package_name in selected_pkg_map.items():
|
||||
if normalized_name in project.lockfile_content[category]:
|
||||
click.echo(
|
||||
"{} {} {} {}".format(
|
||||
click.style("Removing", fg="cyan"),
|
||||
@@ -2527,25 +2520,22 @@ def do_uninstall(
|
||||
)
|
||||
)
|
||||
lockfile = project.get_or_create_lockfile()
|
||||
if normalized_name in lockfile.default:
|
||||
del lockfile.default[normalized_name]
|
||||
if normalized_name in lockfile.develop:
|
||||
del lockfile.develop[normalized_name]
|
||||
if normalized_name in lockfile[category]:
|
||||
del lockfile[category][normalized_name]
|
||||
lockfile.write()
|
||||
|
||||
if project.remove_package_from_pipfile(package_name, category=category):
|
||||
pipfile_category = get_pipfile_category_using_lockfile_section(category)
|
||||
if project.remove_package_from_pipfile(
|
||||
package_name, category=pipfile_category
|
||||
):
|
||||
click.secho(
|
||||
fix_utf8(f"Removed {package_name} from Pipfile category {category}"),
|
||||
fix_utf8(
|
||||
f"Removed {package_name} from Pipfile category {pipfile_category}"
|
||||
),
|
||||
fg="green",
|
||||
)
|
||||
found_package = True
|
||||
|
||||
if not found_package:
|
||||
click.echo(
|
||||
"No package {} to remove from Pipfile.".format(
|
||||
click.style(package_name, fg="green")
|
||||
)
|
||||
)
|
||||
for normalized_name, package_name in selected_pkg_map.items():
|
||||
still_remains = False
|
||||
for category in project.get_package_categories():
|
||||
if project.get_package_name_in_pipfile(normalized_name, category=category):
|
||||
@@ -2553,6 +2543,11 @@ def do_uninstall(
|
||||
if not still_remains:
|
||||
# Uninstall the package.
|
||||
if package_name in packages_to_remove:
|
||||
click.secho(
|
||||
fix_utf8(f"Uninstalling {click.style(package_name)}..."),
|
||||
fg="green",
|
||||
bold=True,
|
||||
)
|
||||
with project.environment.activated():
|
||||
cmd = [
|
||||
project_python(project, system=system),
|
||||
|
||||
+14
-15
@@ -20,7 +20,6 @@ from pipenv.patched.pip._vendor import pkg_resources
|
||||
from pipenv.utils.constants import is_type_checking
|
||||
from pipenv.utils.dependencies import (
|
||||
get_canonical_names,
|
||||
get_lockfile_section_using_pipfile_category,
|
||||
is_editable,
|
||||
is_star,
|
||||
pep423_name,
|
||||
@@ -278,7 +277,7 @@ class Project:
|
||||
category_packages = get_canonical_names(
|
||||
self.lockfile_content[category].keys()
|
||||
)
|
||||
results[category] = category_packages
|
||||
results[category] = set(category_packages)
|
||||
results["combined"] = results["combined"] | category_packages
|
||||
return results
|
||||
|
||||
@@ -287,11 +286,10 @@ class Project:
|
||||
result = {}
|
||||
combined = set()
|
||||
for category in self.get_package_categories():
|
||||
lockfile_section = get_lockfile_section_using_pipfile_category(category)
|
||||
packages = self.get_pipfile_section(category)
|
||||
keys = get_canonical_names(packages.keys())
|
||||
combined |= keys
|
||||
result[lockfile_section] = keys
|
||||
result[category] = keys
|
||||
result["combined"] = combined
|
||||
return result
|
||||
|
||||
@@ -624,9 +622,10 @@ class Project:
|
||||
@property
|
||||
def all_packages(self):
|
||||
"""Returns a list of all packages."""
|
||||
p = dict(self.parsed_pipfile.get("dev-packages", {}))
|
||||
p.update(self.parsed_pipfile.get("packages", {}))
|
||||
return p
|
||||
packages = {}
|
||||
for category in self.get_package_categories():
|
||||
packages.update(self.parsed_pipfile.get(category, {}))
|
||||
return packages
|
||||
|
||||
@property
|
||||
def packages(self):
|
||||
@@ -761,17 +760,17 @@ class Project:
|
||||
formatted_data = tomlkit.dumps(data).rstrip()
|
||||
except Exception:
|
||||
document = tomlkit.document()
|
||||
for section in ("packages", "dev-packages"):
|
||||
document[section] = tomlkit.table()
|
||||
for category in self.get_package_categories():
|
||||
document[category] = tomlkit.table()
|
||||
# Convert things to inline tables — fancy :)
|
||||
for package in data.get(section, {}):
|
||||
if hasattr(data[section][package], "keys"):
|
||||
for package in data.get(category, {}):
|
||||
if hasattr(data[category][package], "keys"):
|
||||
table = tomlkit.inline_table()
|
||||
table.update(data[section][package])
|
||||
document[section][package] = table
|
||||
table.update(data[category][package])
|
||||
document[category][package] = table
|
||||
else:
|
||||
document[section][package] = tomlkit.string(
|
||||
data[section][package]
|
||||
document[category][package] = tomlkit.string(
|
||||
data[category][package]
|
||||
)
|
||||
formatted_data = tomlkit.dumps(document).rstrip()
|
||||
|
||||
|
||||
+1
-6
@@ -293,12 +293,7 @@ class Entry:
|
||||
|
||||
@property
|
||||
def pipfile_packages(self):
|
||||
from pipenv.utils.dependencies import (
|
||||
get_lockfile_section_using_pipfile_category,
|
||||
)
|
||||
|
||||
lockfile_section = get_lockfile_section_using_pipfile_category(self.category)
|
||||
return self.project.pipfile_package_names[lockfile_section]
|
||||
return self.project.pipfile_package_names[self.category]
|
||||
|
||||
def create_parent(self, name, specifier="*"):
|
||||
parent = self.create(
|
||||
|
||||
@@ -40,6 +40,16 @@ def get_lockfile_section_using_pipfile_category(category):
|
||||
return lockfile_section
|
||||
|
||||
|
||||
def get_pipfile_category_using_lockfile_section(category):
|
||||
if category == "develop":
|
||||
lockfile_section = "dev-packages"
|
||||
elif category == "default":
|
||||
lockfile_section = "packages"
|
||||
else:
|
||||
lockfile_section = category
|
||||
return lockfile_section
|
||||
|
||||
|
||||
class HackedPythonVersion:
|
||||
"""A Beautiful hack, which allows us to tell pip which version of Python we're using."""
|
||||
|
||||
|
||||
@@ -200,11 +200,34 @@ def test_uninstall_all_dev_with_shared_dependencies(pipenv_instance_pypi):
|
||||
|
||||
|
||||
@pytest.mark.uninstall
|
||||
def test_uninstall_missing_parameters(pipenv_instance_pypi):
|
||||
with pipenv_instance_pypi() as p:
|
||||
c = p.pipenv("install dataclasses-json")
|
||||
def test_uninstall_missing_parameters(pipenv_instance_private_pypi):
|
||||
with pipenv_instance_private_pypi() as p:
|
||||
c = p.pipenv("install six")
|
||||
assert c.returncode == 0
|
||||
|
||||
c = p.pipenv("uninstall")
|
||||
assert c.returncode != 0
|
||||
assert "No package provided!" in c.stderr
|
||||
|
||||
|
||||
@pytest.mark.install
|
||||
@pytest.mark.uninstall
|
||||
def test_uninstall_category_with_shared_requirement(pipenv_instance_pypi):
|
||||
with pipenv_instance_pypi() as p:
|
||||
with open(p.pipfile_path, "w") as f:
|
||||
contents = """
|
||||
[packages]
|
||||
six = "*"
|
||||
|
||||
[prereq]
|
||||
six = "*"
|
||||
"""
|
||||
f.write(contents)
|
||||
c = p.pipenv("install")
|
||||
assert c.returncode == 0
|
||||
|
||||
c = p.pipenv("uninstall six --categories packages")
|
||||
assert c.returncode == 0
|
||||
|
||||
assert "six" in p.lockfile["prereq"]
|
||||
assert "six" not in p.lockfile["default"]
|
||||
|
||||
Reference in New Issue
Block a user