mirror of https://github.com/pypa/pip
factor out get_installed_distributions utility function and add pip uninstall autocomplete; fixes #76
This commit is contained in:
parent
15d872ea6d
commit
107835ec99
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
11
pip/req.py
11
pip/req.py
|
@ -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
|
||||
|
|
31
pip/util.py
31
pip/util.py
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue