factor out get_installed_distributions utility function and add pip uninstall autocomplete; fixes #76

This commit is contained in:
Carl Meyer 2010-03-09 14:39:48 -05:00
parent 15d872ea6d
commit 107835ec99
5 changed files with 50 additions and 15 deletions

View File

@ -2,4 +2,3 @@ recursive-include docs *.txt
recursive-include docs *.html
recursive-exclude docs/_build *.txt
prune docs/_build/_sources
recursive-include scripts/completion *

View File

@ -9,6 +9,7 @@ from pip.baseparser import parser
from pip.exceptions import InstallationError
from pip.basecommand import command_dict, load_command, load_all_commands
from pip.vcs import vcs, get_src_requirement, import_vcs_support
from pip.util import get_installed_distributions
def autocomplete():
"""Command and option completion for the main option parser (and options)
@ -39,6 +40,18 @@ def autocomplete():
# subcommand options
# special case: the 'help' subcommand has no options
elif cwords[0] in subcommands and cwords[0] != 'help':
# special case: list locally installed dists for uninstall command
if cwords[0] == 'uninstall' and not current.startswith('-'):
installed = []
lc = current.lower()
for dist in get_installed_distributions(local_only=True):
if dist.key.startswith(lc) and dist.key not in cwords[1:]:
installed.append(dist.key)
# if there are no dists installed, fall back to option completion
if installed:
for dist in installed:
print dist
sys.exit(1)
subcommand = command_dict.get(cwords[0])
options += [(opt.get_opt_string(), opt.nargs)
for opt in subcommand.parser.option_list

View File

@ -5,7 +5,7 @@ import pip
from pip.req import InstallRequirement
from pip.log import logger
from pip.basecommand import Command
from pip.util import dist_location, is_local
from pip.util import get_installed_distributions
class FreezeCommand(Command):
name = 'freeze'
@ -61,12 +61,7 @@ class FreezeCommand(Command):
for link in find_links:
f.write('-f %s\n' % link)
installations = {}
for dist in pkg_resources.working_set:
if local_only and not is_local(dist_location(dist)):
continue
if dist.key in ('setuptools', 'pip', 'python'):
## FIXME: also skip virtualenv?
continue
for dist in get_installed_distributions(local_only=local_only):
req = pip.FrozenRequirement.from_dist(dist, dependency_links, find_tags=find_tags)
installations[req.name] = req
if requirement:

View File

@ -19,7 +19,7 @@ from pip.log import logger
from pip.util import display_path, rmtree, format_size
from pip.util import splitext, ask, backup_dir
from pip.util import url_to_filename, filename_to_url
from pip.util import is_url, is_filename, is_local
from pip.util import is_url, is_filename, is_local, dist_is_local
from pip.util import renames, normalize_path, egg_link_path
from pip.util import make_path_relative, is_svn_page, file_contents
from pip.util import has_leading_dir, split_leading_dir
@ -421,8 +421,6 @@ execfile(__file__)
easy_install_pth = os.path.join(os.path.dirname(develop_egg_link),
'easy-install.pth')
paths_to_remove.add_pth(easy_install_pth, dist.location)
# fix location (so we can uninstall links to sources outside venv)
paths_to_remove.location = normalize_path(develop_egg_link)
# find distutils scripts= scripts
if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'):
@ -1368,20 +1366,19 @@ class UninstallPathSet(object):
self._refuse = set()
self.pth = {}
self.dist = dist
self.location = normalize_path(dist.location)
self.save_dir = None
self._moved_paths = []
def _permitted(self, path):
"""
Return True if the given path is one we are permitted to remove,
False otherwise.
Return True if the given path is one we are permitted to
remove/modify, False otherwise.
"""
return is_local(path)
def _can_uninstall(self):
if not self._permitted(self.location):
if not dist_is_local(self.dist):
logger.notify("Not uninstalling %s at %s, outside environment %s"
% (self.dist.project_name, self.location, sys.prefix))
return False

View File

@ -6,6 +6,9 @@ import stat
import urllib
import urllib2
import re
import pkg_resources
from pip.backwardcompat import WindowsError
from pip.exceptions import InstallationError
from pip.locations import site_packages
@ -323,6 +326,34 @@ def is_local(path):
return True
return normalize_path(path).startswith(normalize_path(sys.prefix))
def dist_is_local(dist):
"""
Return True if given Distribution object is installed locally
(i.e. within current virtualenv).
Always True if we're not in a virtualenv.
"""
return is_local(dist_location(dist))
def get_installed_distributions(local_only=True, skip=('setuptools', 'pip', 'python')):
"""
Return a list of installed Distribution objects.
If ``local_only`` is True (default), only return installations
local to the current virtualenv, if in a virtualenv.
``skip`` argument is an iterable of lower-case project names to
ignore; defaults to ('setuptools', 'pip', 'python'). [FIXME also
skip virtualenv?]
"""
if local_only:
local_test = dist_is_local
else:
local_test = lambda d: True
return [d for d in pkg_resources.working_set if local_test(d) and d.key not in skip]
def egg_link_path(dist):
"""
Return the path where we'd expect to find a .egg-link file for