__init__.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #!/usr/bin/env python
  2. from __future__ import absolute_import
  3. import locale
  4. import logging
  5. import os
  6. import optparse
  7. import warnings
  8. import sys
  9. import re
  10. # 2016-06-17 barry@debian.org: urllib3 1.14 added optional support for socks,
  11. # but if invoked (i.e. imported), it will issue a warning to stderr if socks
  12. # isn't available. requests unconditionally imports urllib3's socks contrib
  13. # module, triggering this warning. The warning breaks DEP-8 tests (because of
  14. # the stderr output) and is just plain annoying in normal usage. I don't want
  15. # to add socks as yet another dependency for pip, nor do I want to allow-stder
  16. # in the DEP-8 tests, so just suppress the warning. pdb tells me this has to
  17. # be done before the import of pip.vcs.
  18. from pip._vendor.requests.packages.urllib3.exceptions import DependencyWarning
  19. warnings.filterwarnings("ignore", category=DependencyWarning) # noqa
  20. from pip.exceptions import InstallationError, CommandError, PipError
  21. from pip.utils import get_installed_distributions, get_prog
  22. from pip.utils import deprecation, dist_is_editable
  23. from pip.vcs import git, mercurial, subversion, bazaar # noqa
  24. from pip.baseparser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
  25. from pip.commands import get_summaries, get_similar_commands
  26. from pip.commands import commands_dict
  27. from pip._vendor.requests.packages.urllib3.exceptions import (
  28. InsecureRequestWarning,
  29. )
  30. # assignment for flake8 to be happy
  31. # This fixes a peculiarity when importing via __import__ - as we are
  32. # initialising the pip module, "from pip import cmdoptions" is recursive
  33. # and appears not to work properly in that situation.
  34. import pip.cmdoptions
  35. cmdoptions = pip.cmdoptions
  36. # The version as used in the setup.py and the docs conf.py
  37. __version__ = "9.0.1"
  38. logger = logging.getLogger(__name__)
  39. # Hide the InsecureRequestWarning from urllib3
  40. warnings.filterwarnings("ignore", category=InsecureRequestWarning)
  41. def autocomplete():
  42. """Command and option completion for the main option parser (and options)
  43. and its subcommands (and options).
  44. Enable by sourcing one of the completion shell scripts (bash, zsh or fish).
  45. """
  46. # Don't complete if user hasn't sourced bash_completion file.
  47. if 'PIP_AUTO_COMPLETE' not in os.environ:
  48. return
  49. cwords = os.environ['COMP_WORDS'].split()[1:]
  50. cword = int(os.environ['COMP_CWORD'])
  51. try:
  52. current = cwords[cword - 1]
  53. except IndexError:
  54. current = ''
  55. subcommands = [cmd for cmd, summary in get_summaries()]
  56. options = []
  57. # subcommand
  58. try:
  59. subcommand_name = [w for w in cwords if w in subcommands][0]
  60. except IndexError:
  61. subcommand_name = None
  62. parser = create_main_parser()
  63. # subcommand options
  64. if subcommand_name:
  65. # special case: 'help' subcommand has no options
  66. if subcommand_name == 'help':
  67. sys.exit(1)
  68. # special case: list locally installed dists for uninstall command
  69. if subcommand_name == 'uninstall' and not current.startswith('-'):
  70. installed = []
  71. lc = current.lower()
  72. for dist in get_installed_distributions(local_only=True):
  73. if dist.key.startswith(lc) and dist.key not in cwords[1:]:
  74. installed.append(dist.key)
  75. # if there are no dists installed, fall back to option completion
  76. if installed:
  77. for dist in installed:
  78. print(dist)
  79. sys.exit(1)
  80. subcommand = commands_dict[subcommand_name]()
  81. options += [(opt.get_opt_string(), opt.nargs)
  82. for opt in subcommand.parser.option_list_all
  83. if opt.help != optparse.SUPPRESS_HELP]
  84. # filter out previously specified options from available options
  85. prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]]
  86. options = [(x, v) for (x, v) in options if x not in prev_opts]
  87. # filter options by current input
  88. options = [(k, v) for k, v in options if k.startswith(current)]
  89. for option in options:
  90. opt_label = option[0]
  91. # append '=' to options which require args
  92. if option[1]:
  93. opt_label += '='
  94. print(opt_label)
  95. else:
  96. # show main parser options only when necessary
  97. if current.startswith('-') or current.startswith('--'):
  98. opts = [i.option_list for i in parser.option_groups]
  99. opts.append(parser.option_list)
  100. opts = (o for it in opts for o in it)
  101. subcommands += [i.get_opt_string() for i in opts
  102. if i.help != optparse.SUPPRESS_HELP]
  103. print(' '.join([x for x in subcommands if x.startswith(current)]))
  104. sys.exit(1)
  105. def create_main_parser():
  106. parser_kw = {
  107. 'usage': '\n%prog <command> [options]',
  108. 'add_help_option': False,
  109. 'formatter': UpdatingDefaultsHelpFormatter(),
  110. 'name': 'global',
  111. 'prog': get_prog(),
  112. }
  113. parser = ConfigOptionParser(**parser_kw)
  114. parser.disable_interspersed_args()
  115. pip_pkg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  116. parser.version = 'pip %s from %s (python %s)' % (
  117. __version__, pip_pkg_dir, sys.version[:3])
  118. # add the general options
  119. gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser)
  120. parser.add_option_group(gen_opts)
  121. parser.main = True # so the help formatter knows
  122. # create command listing for description
  123. command_summaries = get_summaries()
  124. description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries]
  125. parser.description = '\n'.join(description)
  126. return parser
  127. def parseopts(args):
  128. parser = create_main_parser()
  129. # Note: parser calls disable_interspersed_args(), so the result of this
  130. # call is to split the initial args into the general options before the
  131. # subcommand and everything else.
  132. # For example:
  133. # args: ['--timeout=5', 'install', '--user', 'INITools']
  134. # general_options: ['--timeout==5']
  135. # args_else: ['install', '--user', 'INITools']
  136. general_options, args_else = parser.parse_args(args)
  137. # --version
  138. if general_options.version:
  139. sys.stdout.write(parser.version)
  140. sys.stdout.write(os.linesep)
  141. sys.exit()
  142. # pip || pip help -> print_help()
  143. if not args_else or (args_else[0] == 'help' and len(args_else) == 1):
  144. parser.print_help()
  145. sys.exit()
  146. # the subcommand name
  147. cmd_name = args_else[0]
  148. if cmd_name not in commands_dict:
  149. guess = get_similar_commands(cmd_name)
  150. msg = ['unknown command "%s"' % cmd_name]
  151. if guess:
  152. msg.append('maybe you meant "%s"' % guess)
  153. raise CommandError(' - '.join(msg))
  154. # all the args without the subcommand
  155. cmd_args = args[:]
  156. cmd_args.remove(cmd_name)
  157. return cmd_name, cmd_args
  158. def check_isolated(args):
  159. isolated = False
  160. if "--isolated" in args:
  161. isolated = True
  162. return isolated
  163. def main(args=None):
  164. if args is None:
  165. args = sys.argv[1:]
  166. # Configure our deprecation warnings to be sent through loggers
  167. deprecation.install_warning_logger()
  168. autocomplete()
  169. try:
  170. cmd_name, cmd_args = parseopts(args)
  171. except PipError as exc:
  172. sys.stderr.write("ERROR: %s" % exc)
  173. sys.stderr.write(os.linesep)
  174. sys.exit(1)
  175. # Needed for locale.getpreferredencoding(False) to work
  176. # in pip.utils.encoding.auto_decode
  177. try:
  178. locale.setlocale(locale.LC_ALL, '')
  179. except locale.Error as e:
  180. # setlocale can apparently crash if locale are uninitialized
  181. logger.debug("Ignoring error %s when setting locale", e)
  182. command = commands_dict[cmd_name](isolated=check_isolated(cmd_args))
  183. return command.main(cmd_args)
  184. # ###########################################################
  185. # # Writing freeze files
  186. class FrozenRequirement(object):
  187. def __init__(self, name, req, editable, comments=()):
  188. self.name = name
  189. self.req = req
  190. self.editable = editable
  191. self.comments = comments
  192. _rev_re = re.compile(r'-r(\d+)$')
  193. _date_re = re.compile(r'-(20\d\d\d\d\d\d)$')
  194. @classmethod
  195. def from_dist(cls, dist, dependency_links):
  196. location = os.path.normcase(os.path.abspath(dist.location))
  197. comments = []
  198. from pip.vcs import vcs, get_src_requirement
  199. if dist_is_editable(dist) and vcs.get_backend_name(location):
  200. editable = True
  201. try:
  202. req = get_src_requirement(dist, location)
  203. except InstallationError as exc:
  204. logger.warning(
  205. "Error when trying to get requirement for VCS system %s, "
  206. "falling back to uneditable format", exc
  207. )
  208. req = None
  209. if req is None:
  210. logger.warning(
  211. 'Could not determine repository location of %s', location
  212. )
  213. comments.append(
  214. '## !! Could not determine repository location'
  215. )
  216. req = dist.as_requirement()
  217. editable = False
  218. else:
  219. editable = False
  220. req = dist.as_requirement()
  221. specs = req.specs
  222. assert len(specs) == 1 and specs[0][0] in ["==", "==="], \
  223. 'Expected 1 spec with == or ===; specs = %r; dist = %r' % \
  224. (specs, dist)
  225. version = specs[0][1]
  226. ver_match = cls._rev_re.search(version)
  227. date_match = cls._date_re.search(version)
  228. if ver_match or date_match:
  229. svn_backend = vcs.get_backend('svn')
  230. if svn_backend:
  231. svn_location = svn_backend().get_location(
  232. dist,
  233. dependency_links,
  234. )
  235. if not svn_location:
  236. logger.warning(
  237. 'Warning: cannot find svn location for %s', req)
  238. comments.append(
  239. '## FIXME: could not find svn URL in dependency_links '
  240. 'for this package:'
  241. )
  242. else:
  243. comments.append(
  244. '# Installing as editable to satisfy requirement %s:' %
  245. req
  246. )
  247. if ver_match:
  248. rev = ver_match.group(1)
  249. else:
  250. rev = '{%s}' % date_match.group(1)
  251. editable = True
  252. req = '%s@%s#egg=%s' % (
  253. svn_location,
  254. rev,
  255. cls.egg_name(dist)
  256. )
  257. return cls(dist.project_name, req, editable, comments)
  258. @staticmethod
  259. def egg_name(dist):
  260. name = dist.egg_name()
  261. match = re.search(r'-py\d\.\d$', name)
  262. if match:
  263. name = name[:match.start()]
  264. return name
  265. def __str__(self):
  266. req = self.req
  267. if self.editable:
  268. req = '-e %s' % req
  269. return '\n'.join(list(self.comments) + [str(req)]) + '\n'
  270. if __name__ == '__main__':
  271. sys.exit(main())