Fix uninstallation if comments are present

Signed-off-by: Dan Ryan <dan@danryan.co>
This commit is contained in:
Dan Ryan
2018-11-01 16:20:45 -04:00
parent 1034022e96
commit 83af37a2d1
3 changed files with 65 additions and 38 deletions
+35 -30
View File
@@ -1165,8 +1165,8 @@ def do_purge(bare=False, downloads=False, allow_global=False):
if environments.is_verbose():
click.echo("$ {0}".format(command))
c = delegator.run(command)
if c.return_code != 0 or c.return_code == 0:
raise exceptions.UninstallError(installed, command, c.out + c.err, 1)
if c.return_code != 0:
raise exceptions.UninstallError(installed, command, c.out + c.err, c.return_code)
if not bare:
click.echo(crayons.blue(c.out))
click.echo(crayons.green("Environment now purged and fresh!"))
@@ -2110,48 +2110,53 @@ def do_uninstall(
del package_names[package_names.index(
canonicalize_name(bad_package)
)]
used_packages = (develop | default) & installed_package_names
used_packages = develop | default & installed_package_names
failure = False
packages_to_remove = set()
if all_dev:
packages_to_remove |= develop & installed_package_names
package_names = set([canonicalize_name(pkg_name) for pkg_name in package_names])
packages_to_remove = package_names & used_packages
for package_name in packages_to_remove:
package_names = set([pkg_name for pkg_name in package_names])
packages_to_remove = [
pkg_name for pkg_name in packages
if canonicalize_name(pkg_name) in used_packages
]
for package_name in package_names:
click.echo(
crayons.white(
fix_utf8("Uninstalling {0}".format(repr(package_name))), bold=True
)
)
# Uninstall the package.
cmd = "{0} uninstall {1} -y".format(
escape_grouped_arguments(which_pip()), package_name
)
if environments.is_verbose():
click.echo("$ {0}".format(cmd))
c = delegator.run(cmd)
click.echo(crayons.blue(c.out))
if c.return_code != 0:
failure = True
else:
if pipfile_remove:
in_packages = project.get_package_name_in_pipfile(package_name, dev=False)
in_dev_packages = project.get_package_name_in_pipfile(
package_name, dev=True
)
if not in_dev_packages and not in_packages:
click.echo(
"No package {0} to remove from Pipfile.".format(
crayons.green(package_name)
)
if package_name in packages_to_remove:
cmd = "{0} uninstall {1} -y".format(
escape_grouped_arguments(which_pip()), package_name
)
continue
if environments.is_verbose():
click.echo("$ {0}".format(cmd))
c = delegator.run(cmd)
click.echo(crayons.blue(c.out))
if c.return_code != 0:
failure = True
if not failure and pipfile_remove:
in_packages = project.get_package_name_in_pipfile(package_name, dev=False)
in_dev_packages = project.get_package_name_in_pipfile(
package_name, dev=True
)
if not in_dev_packages and not in_packages:
click.echo(
fix_utf8("Removing {0} from Pipfile".format(crayons.green(package_name)))
"No package {0} to remove from Pipfile.".format(
crayons.green(package_name)
)
)
# Remove package from both packages and dev-packages.
continue
click.echo(
fix_utf8("Removing {0} from Pipfile…".format(crayons.green(package_name)))
)
# Remove package from both packages and dev-packages.
if in_dev_packages:
project.remove_package_from_pipfile(package_name, dev=True)
if in_packages:
project.remove_package_from_pipfile(package_name, dev=False)
if lock:
do_lock(system=system, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
+29 -7
View File
@@ -916,26 +916,48 @@ class Project(object):
# Read and append Pipfile.
name = self.get_package_name_in_pipfile(package_name, dev)
key = "dev-packages" if dev else "packages"
p = self._pipfile
if name:
del p.pipfile[key][name]
p = self.parsed_pipfile
lines = [l for l in p[key].serialized().splitlines()]
if not any(line.startswith("#") for line in lines) and name:
del p[key][name]
self.write_toml(p)
else:
p = self._pipfile
del p[key][name]
p.write()
def remove_packages_from_pipfile(self, packages):
p = self._pipfile
parsed = self.parsed_pipfile
packages = [pep423_name(pkg) for pkg in packages]
deleted_pkgs = []
has_comments_as_lines = False
for section in ("dev-packages", "packages"):
pipfile_section = self.parsed_pipfile.get(section, {})
lines = [l for l in p[section].serialized().splitlines()]
pipfile_packages = [
pkg_name for pkg_name in pipfile_section.keys()
if pep423_name(pkg_name) in packages
]
for pkg in pipfile_packages:
deleted_pkgs.append(pkg)
del p.pipfile[section][pkg]
# The normal toml parser can't handle deleting packages with preceding newlines
is_dev = section == "dev-packages"
if any(line.startswith("#") for line in lines):
has_comments_as_lines = True
for pkg in pipfile_packages:
pkg_name = self.get_package_name_in_pipfile(pkg, dev=is_dev)
deleted_pkgs.append(pkg)
del p.pipfile[section][pkg_name]
# However the alternative parser can't handle inline comment preservation
else:
for pkg in pipfile_packages:
pkg_name = self.get_package_name_in_pipfile(pkg, dev=is_dev)
deleted_pkgs.append(pkg)
del parsed[section][pkg_name]
if deleted_pkgs:
p.write()
if has_comments_as_lines:
p.write()
else:
self.write_toml(parsed)
def add_package_to_pipfile(self, package, dev=False):
from .vendor.requirementslib import Requirement
+1 -1
View File
@@ -15,7 +15,7 @@ def test_sync_error_without_lockfile(PipenvInstance, pypi):
c = p.pipenv('sync')
assert c.return_code != 0
assert 'Pipfile.lock is missing!' in c.err
assert 'Pipfile.lock not found!' in c.err
@pytest.mark.sync