Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

base_command.py 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. """Base Command class, and related routines"""
  2. from __future__ import absolute_import
  3. import logging
  4. import logging.config
  5. import optparse
  6. import os
  7. import sys
  8. from pip._internal.cli import cmdoptions
  9. from pip._internal.cli.parser import (
  10. ConfigOptionParser, UpdatingDefaultsHelpFormatter,
  11. )
  12. from pip._internal.cli.status_codes import (
  13. ERROR, PREVIOUS_BUILD_DIR_ERROR, SUCCESS, UNKNOWN_ERROR,
  14. VIRTUALENV_NOT_FOUND,
  15. )
  16. from pip._internal.download import PipSession
  17. from pip._internal.exceptions import (
  18. BadCommand, CommandError, InstallationError, PreviousBuildDirError,
  19. UninstallationError,
  20. )
  21. from pip._internal.index import PackageFinder
  22. from pip._internal.locations import running_under_virtualenv
  23. from pip._internal.req.constructors import (
  24. install_req_from_editable, install_req_from_line,
  25. )
  26. from pip._internal.req.req_file import parse_requirements
  27. from pip._internal.utils.logging import setup_logging
  28. from pip._internal.utils.misc import get_prog, normalize_path
  29. from pip._internal.utils.outdated import pip_version_check
  30. from pip._internal.utils.typing import MYPY_CHECK_RUNNING
  31. if MYPY_CHECK_RUNNING:
  32. from typing import Optional # noqa: F401
  33. __all__ = ['Command']
  34. logger = logging.getLogger(__name__)
  35. class Command(object):
  36. name = None # type: Optional[str]
  37. usage = None # type: Optional[str]
  38. hidden = False # type: bool
  39. ignore_require_venv = False # type: bool
  40. def __init__(self, isolated=False):
  41. parser_kw = {
  42. 'usage': self.usage,
  43. 'prog': '%s %s' % (get_prog(), self.name),
  44. 'formatter': UpdatingDefaultsHelpFormatter(),
  45. 'add_help_option': False,
  46. 'name': self.name,
  47. 'description': self.__doc__,
  48. 'isolated': isolated,
  49. }
  50. self.parser = ConfigOptionParser(**parser_kw)
  51. # Commands should add options to this option group
  52. optgroup_name = '%s Options' % self.name.capitalize()
  53. self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)
  54. # Add the general options
  55. gen_opts = cmdoptions.make_option_group(
  56. cmdoptions.general_group,
  57. self.parser,
  58. )
  59. self.parser.add_option_group(gen_opts)
  60. def _build_session(self, options, retries=None, timeout=None):
  61. session = PipSession(
  62. cache=(
  63. normalize_path(os.path.join(options.cache_dir, "http"))
  64. if options.cache_dir else None
  65. ),
  66. retries=retries if retries is not None else options.retries,
  67. insecure_hosts=options.trusted_hosts,
  68. )
  69. # Handle custom ca-bundles from the user
  70. if options.cert:
  71. session.verify = options.cert
  72. # Handle SSL client certificate
  73. if options.client_cert:
  74. session.cert = options.client_cert
  75. # Handle timeouts
  76. if options.timeout or timeout:
  77. session.timeout = (
  78. timeout if timeout is not None else options.timeout
  79. )
  80. # Handle configured proxies
  81. if options.proxy:
  82. session.proxies = {
  83. "http": options.proxy,
  84. "https": options.proxy,
  85. }
  86. # Determine if we can prompt the user for authentication or not
  87. session.auth.prompting = not options.no_input
  88. return session
  89. def parse_args(self, args):
  90. # factored out for testability
  91. return self.parser.parse_args(args)
  92. def main(self, args):
  93. options, args = self.parse_args(args)
  94. # Set verbosity so that it can be used elsewhere.
  95. self.verbosity = options.verbose - options.quiet
  96. setup_logging(
  97. verbosity=self.verbosity,
  98. no_color=options.no_color,
  99. user_log_file=options.log,
  100. )
  101. # TODO: Try to get these passing down from the command?
  102. # without resorting to os.environ to hold these.
  103. # This also affects isolated builds and it should.
  104. if options.no_input:
  105. os.environ['PIP_NO_INPUT'] = '1'
  106. if options.exists_action:
  107. os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action)
  108. if options.require_venv and not self.ignore_require_venv:
  109. # If a venv is required check if it can really be found
  110. if not running_under_virtualenv():
  111. logger.critical(
  112. 'Could not find an activated virtualenv (required).'
  113. )
  114. sys.exit(VIRTUALENV_NOT_FOUND)
  115. try:
  116. status = self.run(options, args)
  117. # FIXME: all commands should return an exit status
  118. # and when it is done, isinstance is not needed anymore
  119. if isinstance(status, int):
  120. return status
  121. except PreviousBuildDirError as exc:
  122. logger.critical(str(exc))
  123. logger.debug('Exception information:', exc_info=True)
  124. return PREVIOUS_BUILD_DIR_ERROR
  125. except (InstallationError, UninstallationError, BadCommand) as exc:
  126. logger.critical(str(exc))
  127. logger.debug('Exception information:', exc_info=True)
  128. return ERROR
  129. except CommandError as exc:
  130. logger.critical('ERROR: %s', exc)
  131. logger.debug('Exception information:', exc_info=True)
  132. return ERROR
  133. except KeyboardInterrupt:
  134. logger.critical('Operation cancelled by user')
  135. logger.debug('Exception information:', exc_info=True)
  136. return ERROR
  137. except BaseException:
  138. logger.critical('Exception:', exc_info=True)
  139. return UNKNOWN_ERROR
  140. finally:
  141. allow_version_check = (
  142. # Does this command have the index_group options?
  143. hasattr(options, "no_index") and
  144. # Is this command allowed to perform this check?
  145. not (options.disable_pip_version_check or options.no_index)
  146. )
  147. # Check if we're using the latest version of pip available
  148. if allow_version_check:
  149. session = self._build_session(
  150. options,
  151. retries=0,
  152. timeout=min(5, options.timeout)
  153. )
  154. with session:
  155. pip_version_check(session, options)
  156. # Shutdown the logging module
  157. logging.shutdown()
  158. return SUCCESS
  159. class RequirementCommand(Command):
  160. @staticmethod
  161. def populate_requirement_set(requirement_set, args, options, finder,
  162. session, name, wheel_cache):
  163. """
  164. Marshal cmd line args into a requirement set.
  165. """
  166. # NOTE: As a side-effect, options.require_hashes and
  167. # requirement_set.require_hashes may be updated
  168. for filename in options.constraints:
  169. for req_to_add in parse_requirements(
  170. filename,
  171. constraint=True, finder=finder, options=options,
  172. session=session, wheel_cache=wheel_cache):
  173. req_to_add.is_direct = True
  174. requirement_set.add_requirement(req_to_add)
  175. for req in args:
  176. req_to_add = install_req_from_line(
  177. req, None, isolated=options.isolated_mode,
  178. wheel_cache=wheel_cache
  179. )
  180. req_to_add.is_direct = True
  181. requirement_set.add_requirement(req_to_add)
  182. for req in options.editables:
  183. req_to_add = install_req_from_editable(
  184. req,
  185. isolated=options.isolated_mode,
  186. wheel_cache=wheel_cache
  187. )
  188. req_to_add.is_direct = True
  189. requirement_set.add_requirement(req_to_add)
  190. for filename in options.requirements:
  191. for req_to_add in parse_requirements(
  192. filename,
  193. finder=finder, options=options, session=session,
  194. wheel_cache=wheel_cache):
  195. req_to_add.is_direct = True
  196. requirement_set.add_requirement(req_to_add)
  197. # If --require-hashes was a line in a requirements file, tell
  198. # RequirementSet about it:
  199. requirement_set.require_hashes = options.require_hashes
  200. if not (args or options.editables or options.requirements):
  201. opts = {'name': name}
  202. if options.find_links:
  203. raise CommandError(
  204. 'You must give at least one requirement to %(name)s '
  205. '(maybe you meant "pip %(name)s %(links)s"?)' %
  206. dict(opts, links=' '.join(options.find_links)))
  207. else:
  208. raise CommandError(
  209. 'You must give at least one requirement to %(name)s '
  210. '(see "pip help %(name)s")' % opts)
  211. def _build_package_finder(self, options, session,
  212. platform=None, python_versions=None,
  213. abi=None, implementation=None):
  214. """
  215. Create a package finder appropriate to this requirement command.
  216. """
  217. index_urls = [options.index_url] + options.extra_index_urls
  218. if options.no_index:
  219. logger.debug('Ignoring indexes: %s', ','.join(index_urls))
  220. index_urls = []
  221. return PackageFinder(
  222. find_links=options.find_links,
  223. format_control=options.format_control,
  224. index_urls=index_urls,
  225. trusted_hosts=options.trusted_hosts,
  226. allow_all_prereleases=options.pre,
  227. process_dependency_links=options.process_dependency_links,
  228. session=session,
  229. platform=platform,
  230. versions=python_versions,
  231. abi=abi,
  232. implementation=implementation,
  233. prefer_binary=options.prefer_binary,
  234. )