list.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. from __future__ import absolute_import
  2. import logging
  3. import warnings
  4. from pip.basecommand import Command
  5. from pip.exceptions import DistributionNotFound
  6. from pip.index import PackageFinder
  7. from pip.req import InstallRequirement
  8. from pip.utils import get_installed_distributions, dist_is_editable
  9. from pip.utils.deprecation import RemovedInPip7Warning
  10. from pip.cmdoptions import make_option_group, index_group
  11. logger = logging.getLogger(__name__)
  12. class ListCommand(Command):
  13. """
  14. List installed packages, including editables.
  15. Packages are listed in a case-insensitive sorted order.
  16. """
  17. name = 'list'
  18. usage = """
  19. %prog [options]"""
  20. summary = 'List installed packages.'
  21. def __init__(self, *args, **kw):
  22. super(ListCommand, self).__init__(*args, **kw)
  23. cmd_opts = self.cmd_opts
  24. cmd_opts.add_option(
  25. '-o', '--outdated',
  26. action='store_true',
  27. default=False,
  28. help='List outdated packages (excluding editables)')
  29. cmd_opts.add_option(
  30. '-u', '--uptodate',
  31. action='store_true',
  32. default=False,
  33. help='List uptodate packages (excluding editables)')
  34. cmd_opts.add_option(
  35. '-e', '--editable',
  36. action='store_true',
  37. default=False,
  38. help='List editable projects.')
  39. cmd_opts.add_option(
  40. '-l', '--local',
  41. action='store_true',
  42. default=False,
  43. help=('If in a virtualenv that has global access, do not list '
  44. 'globally-installed packages.'),
  45. )
  46. self.cmd_opts.add_option(
  47. '--user',
  48. dest='user',
  49. action='store_true',
  50. default=False,
  51. help='Only output packages installed in user-site.')
  52. cmd_opts.add_option(
  53. '--pre',
  54. action='store_true',
  55. default=False,
  56. help=("Include pre-release and development versions. By default, "
  57. "pip only finds stable versions."),
  58. )
  59. index_opts = make_option_group(index_group, self.parser)
  60. self.parser.insert_option_group(0, index_opts)
  61. self.parser.insert_option_group(0, cmd_opts)
  62. def _build_package_finder(self, options, index_urls, session):
  63. """
  64. Create a package finder appropriate to this list command.
  65. """
  66. return PackageFinder(
  67. find_links=options.find_links,
  68. index_urls=index_urls,
  69. allow_external=options.allow_external,
  70. allow_unverified=options.allow_unverified,
  71. allow_all_external=options.allow_all_external,
  72. allow_all_prereleases=options.pre,
  73. trusted_hosts=options.trusted_hosts,
  74. process_dependency_links=options.process_dependency_links,
  75. session=session,
  76. )
  77. def run(self, options, args):
  78. if options.outdated:
  79. self.run_outdated(options)
  80. elif options.uptodate:
  81. self.run_uptodate(options)
  82. elif options.editable:
  83. self.run_editables(options)
  84. else:
  85. self.run_listing(options)
  86. def run_outdated(self, options):
  87. for dist, version, typ in self.find_packages_latest_versions(options):
  88. if version > dist.parsed_version:
  89. logger.info(
  90. '%s (Current: %s Latest: %s [%s])',
  91. dist.project_name, dist.version, version, typ,
  92. )
  93. def find_packages_latest_versions(self, options):
  94. index_urls = [options.index_url] + options.extra_index_urls
  95. if options.no_index:
  96. logger.info('Ignoring indexes: %s', ','.join(index_urls))
  97. index_urls = []
  98. if options.use_mirrors:
  99. warnings.warn(
  100. "--use-mirrors has been deprecated and will be removed in the "
  101. "future. Explicit uses of --index-url and/or --extra-index-url"
  102. " is suggested.",
  103. RemovedInPip7Warning,
  104. )
  105. if options.mirrors:
  106. warnings.warn(
  107. "--mirrors has been deprecated and will be removed in the "
  108. "future. Explicit uses of --index-url and/or --extra-index-url"
  109. " is suggested.",
  110. RemovedInPip7Warning,
  111. )
  112. index_urls += options.mirrors
  113. dependency_links = []
  114. for dist in get_installed_distributions(local_only=options.local,
  115. user_only=options.user):
  116. if dist.has_metadata('dependency_links.txt'):
  117. dependency_links.extend(
  118. dist.get_metadata_lines('dependency_links.txt'),
  119. )
  120. with self._build_session(options) as session:
  121. finder = self._build_package_finder(options, index_urls, session)
  122. finder.add_dependency_links(dependency_links)
  123. installed_packages = get_installed_distributions(
  124. local_only=options.local,
  125. user_only=options.user,
  126. include_editables=False,
  127. )
  128. for dist in installed_packages:
  129. req = InstallRequirement.from_line(
  130. dist.key, None, isolated=options.isolated_mode,
  131. )
  132. typ = 'unknown'
  133. try:
  134. link = finder.find_requirement(req, True)
  135. # If link is None, means installed version is most
  136. # up-to-date
  137. if link is None:
  138. continue
  139. except DistributionNotFound:
  140. continue
  141. else:
  142. remote_version = finder._link_package_versions(
  143. link, req.name
  144. ).version
  145. if link.is_wheel:
  146. typ = 'wheel'
  147. else:
  148. typ = 'sdist'
  149. yield dist, remote_version, typ
  150. def run_listing(self, options):
  151. installed_packages = get_installed_distributions(
  152. local_only=options.local,
  153. user_only=options.user,
  154. )
  155. self.output_package_listing(installed_packages)
  156. def run_editables(self, options):
  157. installed_packages = get_installed_distributions(
  158. local_only=options.local,
  159. user_only=options.user,
  160. editables_only=True,
  161. )
  162. self.output_package_listing(installed_packages)
  163. def output_package_listing(self, installed_packages):
  164. installed_packages = sorted(
  165. installed_packages,
  166. key=lambda dist: dist.project_name.lower(),
  167. )
  168. for dist in installed_packages:
  169. if dist_is_editable(dist):
  170. line = '%s (%s, %s)' % (
  171. dist.project_name,
  172. dist.version,
  173. dist.location,
  174. )
  175. else:
  176. line = '%s (%s)' % (dist.project_name, dist.version)
  177. logger.info(line)
  178. def run_uptodate(self, options):
  179. uptodate = []
  180. for dist, version, typ in self.find_packages_latest_versions(options):
  181. if dist.parsed_version == version:
  182. uptodate.append(dist)
  183. self.output_package_listing(uptodate)