Skip to content

Commit

Permalink
Merge pull request #752 from qwcode/pip_list
Browse files Browse the repository at this point in the history
pip list
  • Loading branch information
qwcode committed Dec 20, 2012
2 parents 1b582ff + c49f7e0 commit ffad700
Show file tree
Hide file tree
Showing 10 changed files with 425 additions and 61 deletions.
2 changes: 2 additions & 0 deletions AUTHORS.txt
Expand Up @@ -14,6 +14,7 @@ Clay McClure
Cody Soyland
Daniel Holth
Dave Abrahams
Dmitry Gladkov
Donald Stufft
Francesco
Georgi Valkov
Expand All @@ -38,6 +39,7 @@ Marcus Smith
Markus Hametner
Matt Maker
Maxime R.
Miguel Araujo
Nick Stenning
Nowell Strite
Oliver Tonnhofer
Expand Down
3 changes: 3 additions & 0 deletions docs/news.txt
Expand Up @@ -14,6 +14,9 @@ Beta and final releases planned for the end of 2012.
develop (unreleased)
--------------------

* Added "pip list" for listing installed packages and the latest version
available. Thanks Rafael Caricio, Miguel Araujo, Dmitry Gladkov (Pull #752)

* Split help output into general vs command-specific option groups.
Thanks Georgi Valkov. (Pull #744; Pull #721 contains preceding refactor)

Expand Down
40 changes: 31 additions & 9 deletions docs/usage.txt
Expand Up @@ -134,8 +134,37 @@ old version of the package is automatically restored if the new version
fails to download or install.


Searching for packages
----------------------
List installed packages
--------------------------

To list installed packages::

$ pip list

To only list editables::

$ pip list --editable

To list outdated packages (excluding editables), and the latest version available::

$ pip list --outdated

To list uptodate packages (excluding editables)::

$ pip list --uptodate


Show package status
-------------------

To get info about an installed package, including its location and included
files::

$ pip show SomePackage


Search for packages
-------------------

pip can search :term:`PyPI` for packages using the ``pip search``
command::
Expand All @@ -147,13 +176,6 @@ packages. With the ``--index`` option you can search in a different
repository.


Checking installed package status
---------------------------------

To get info about an installed package, including its location and included
files, run ``pip show ProjectName``.


Bundles
-------

Expand Down
80 changes: 80 additions & 0 deletions pip/cmdoptions.py
@@ -0,0 +1,80 @@
"""shared options and groups"""

from optparse import make_option, OptionGroup

def make_option_group(group, parser):
"""
Return an OptionGroup object
group -- assumed to be dict with 'name' and 'options' keys
parser -- an optparse Parser
"""
option_group = OptionGroup(parser, group['name'])
for option in group['options']:
option_group.add_option(option)
return option_group

###########
# options #
###########

find_links = make_option(
'-f', '--find-links',
dest='find_links',
action='append',
default=[],
metavar='URL',
help='URL to look for packages at')

index_url = make_option(
'-i', '--index-url', '--pypi-url',
dest='index_url',
metavar='URL',
default='http://pypi.python.org/simple/',
help='Base URL of Python Package Index (default %default)')

extra_index_url = make_option(
'--extra-index-url',
dest='extra_index_urls',
metavar='URL',
action='append',
default=[],
help='Extra URLs of package indexes to use in addition to --index-url')

no_index = make_option(
'--no-index',
dest='no_index',
action='store_true',
default=False,
help='Ignore package index (only looking at --find-links URLs instead)')

use_mirrors = make_option(
'-M', '--use-mirrors',
dest='use_mirrors',
action='store_true',
default=False,
help='Use the PyPI mirrors as a fallback in case the main index is down.')

mirrors = make_option(
'--mirrors',
dest='mirrors',
metavar='URL',
action='append',
default=[],
help='Specific mirror URLs to query when --use-mirrors is used')


##########
# groups #
##########

index_group = {
'name': 'Package Index Options',
'options': [
find_links,
index_url,
extra_index_url,
no_index,
use_mirrors,
mirrors
]
}
2 changes: 2 additions & 0 deletions pip/commands/__init__.py
Expand Up @@ -7,6 +7,7 @@
from pip.commands.completion import CompletionCommand
from pip.commands.freeze import FreezeCommand
from pip.commands.help import HelpCommand
from pip.commands.list import ListCommand
from pip.commands.search import SearchCommand
from pip.commands.show import ShowCommand
from pip.commands.install import InstallCommand
Expand All @@ -26,6 +27,7 @@
UninstallCommand.name: UninstallCommand,
UnzipCommand.name: UnzipCommand,
ZipCommand.name: ZipCommand,
ListCommand.name: ListCommand,
}


Expand Down
51 changes: 4 additions & 47 deletions pip/commands/install.py
Expand Up @@ -11,6 +11,7 @@
from pip.index import PackageFinder
from pip.exceptions import InstallationError, CommandError
from pip.backwardcompat import home_lib
from pip.cmdoptions import make_option_group, index_group


class InstallCommand(Command):
Expand All @@ -22,54 +23,8 @@ class InstallCommand(Command):
def __init__(self, *args, **kw):
super(InstallCommand, self).__init__(*args, **kw)

pypi_opts = optparse.OptionGroup(self.parser, 'Package Index Options')
cmd_opts = self.cmd_opts

pypi_opts.add_option(
'-f', '--find-links',
dest='find_links',
action='append',
default=[],
metavar='URL',
help='URL to look for packages at')

pypi_opts.add_option(
'-i', '--index-url', '--pypi-url',
dest='index_url',
metavar='URL',
default='http://pypi.python.org/simple/',
help='Base URL of Python Package Index (default %default)')

pypi_opts.add_option(
'--extra-index-url',
dest='extra_index_urls',
metavar='URL',
action='append',
default=[],
help='Extra URLs of package indexes to use in addition to --index-url')

pypi_opts.add_option(
'--no-index',
dest='no_index',
action='store_true',
default=False,
help='Ignore package index (only looking at --find-links URLs instead)')

pypi_opts.add_option(
'-M', '--use-mirrors',
dest='use_mirrors',
action='store_true',
default=False,
help='Use the PyPI mirrors as a fallback in case the main index is down.')

pypi_opts.add_option(
'--mirrors',
dest='mirrors',
metavar='URL',
action='append',
default=[],
help='Specific mirror URLs to query when --use-mirrors is used')

cmd_opts.add_option(
'-e', '--editable',
dest='editables',
Expand Down Expand Up @@ -200,7 +155,9 @@ def __init__(self, *args, **kw):
default=None,
help="Install everything relative to this alternate root directory")

self.parser.insert_option_group(0, pypi_opts)
index_opts = make_option_group(index_group, self.parser)

self.parser.insert_option_group(0, index_opts)
self.parser.insert_option_group(0, cmd_opts)

def _build_package_finder(self, options, index_urls):
Expand Down
134 changes: 134 additions & 0 deletions pip/commands/list.py
@@ -0,0 +1,134 @@
import pkg_resources
from pip.basecommand import Command
from pip.exceptions import DistributionNotFound, BestVersionAlreadyInstalled
from pip.index import PackageFinder
from pip.log import logger
from pip.req import InstallRequirement
from pip.util import get_installed_distributions, dist_is_editable
from pip.cmdoptions import make_option_group, index_group


class ListCommand(Command):
name = 'list'
usage = '%prog [OPTIONS]'
summary = 'List installed packages (including editables).'

def __init__(self, *args, **kw):
super(ListCommand, self).__init__(*args, **kw)


cmd_opts = self.cmd_opts

cmd_opts.add_option(
'-o', '--outdated',
action='store_true',
default=False,
help='List outdated packages (excluding editables)')
cmd_opts.add_option(
'-u', '--uptodate',
action='store_true',
default=False,
help='List uptodate packages (excluding editables)')
cmd_opts.add_option(
'-e', '--editable',
action='store_true',
default=False,
help='List editable packages.')
cmd_opts.add_option(
'-l', '--local',
action='store_true',
default=False,
help='If in a virtualenv, do not list globally-installed packages')


index_opts = make_option_group(index_group, self.parser)

self.parser.insert_option_group(0, index_opts)
self.parser.insert_option_group(0, cmd_opts)


def _build_package_finder(self, options, index_urls):
"""
Create a package finder appropriate to this list command.
"""
return PackageFinder(find_links=options.find_links,
index_urls=index_urls,
use_mirrors=options.use_mirrors,
mirrors=options.mirrors)

def run(self, options, args):
if options.outdated:
self.run_outdated(options)
elif options.uptodate:
self.run_uptodate(options)
elif options.editable:
self.run_editables(options)
else:
self.run_listing(options)

def run_outdated(self, options):
for dist, remote_version_raw, remote_version_parsed in self.find_packages_latests_versions(options):
if remote_version_parsed > dist.parsed_version:
logger.notify('%s (Current: %s Latest: %s)' % (dist.project_name,
dist.version, remote_version_raw))

def find_packages_latests_versions(self, options):
index_urls = [options.index_url] + options.extra_index_urls
if options.no_index:
logger.notify('Ignoring indexes: %s' % ','.join(index_urls))
index_urls = []

dependency_links = []
for dist in get_installed_distributions(local_only=options.local):
if dist.has_metadata('dependency_links.txt'):
dependency_links.extend(
dist.get_metadata_lines('dependency_links.txt'),
)

finder = self._build_package_finder(options, index_urls)
finder.add_dependency_links(dependency_links)

installed_packages = get_installed_distributions(local_only=options.local, include_editables=False)
for dist in installed_packages:
req = InstallRequirement.from_line(dist.key, None)
try:
link = finder.find_requirement(req, True)

# If link is None, means installed version is most up-to-date
if link is None:
continue
except DistributionNotFound:
continue
except BestVersionAlreadyInstalled:
remote_version = req.installed_version
else:
# It might be a good idea that link or finder had a public method
# that returned version
remote_version = finder._link_package_versions(link, req.name)[0]
remote_version_raw = remote_version[2]
remote_version_parsed = remote_version[0]
yield dist, remote_version_raw, remote_version_parsed

def run_listing(self, options):
installed_packages = get_installed_distributions(local_only=options.local)
self.output_package_listing(installed_packages)

def run_editables(self, options):
installed_packages = get_installed_distributions(local_only=options.local, editables_only=True)
self.output_package_listing(installed_packages)

def output_package_listing(self, installed_packages):
for dist in installed_packages:
if dist_is_editable(dist):
line = '%s (%s, %s)' % (dist.project_name, dist.version, dist.location)
else:
line = '%s (%s)' % (dist.project_name, dist.version)
logger.notify(line)

def run_uptodate(self, options):
uptodate = []
for dist, remote_version_raw, remote_version_parsed in self.find_packages_latests_versions(options):
if dist.parsed_version == remote_version_parsed:
uptodate.append(dist)
self.output_package_listing(uptodate)

0 comments on commit ffad700

Please sign in to comment.