comparison lib/python3.8/site-packages/pip/_internal/cli/base_command.py @ 0:9e54283cc701 draft

"planemo upload commit d12c32a45bcd441307e632fca6d9af7d60289d44"
author guerler
date Mon, 27 Jul 2020 03:47:31 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:9e54283cc701
1 """Base Command class, and related routines"""
2
3 from __future__ import absolute_import, print_function
4
5 import logging
6 import logging.config
7 import optparse
8 import os
9 import platform
10 import sys
11 import traceback
12
13 from pip._internal.cli import cmdoptions
14 from pip._internal.cli.command_context import CommandContextMixIn
15 from pip._internal.cli.parser import (
16 ConfigOptionParser,
17 UpdatingDefaultsHelpFormatter,
18 )
19 from pip._internal.cli.status_codes import (
20 ERROR,
21 PREVIOUS_BUILD_DIR_ERROR,
22 SUCCESS,
23 UNKNOWN_ERROR,
24 VIRTUALENV_NOT_FOUND,
25 )
26 from pip._internal.exceptions import (
27 BadCommand,
28 CommandError,
29 InstallationError,
30 PreviousBuildDirError,
31 UninstallationError,
32 )
33 from pip._internal.utils.deprecation import deprecated
34 from pip._internal.utils.filesystem import check_path_owner
35 from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
36 from pip._internal.utils.misc import get_prog, normalize_path
37 from pip._internal.utils.temp_dir import global_tempdir_manager
38 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
39 from pip._internal.utils.virtualenv import running_under_virtualenv
40
41 if MYPY_CHECK_RUNNING:
42 from typing import List, Tuple, Any
43 from optparse import Values
44
45 __all__ = ['Command']
46
47 logger = logging.getLogger(__name__)
48
49
50 class Command(CommandContextMixIn):
51 usage = None # type: str
52 ignore_require_venv = False # type: bool
53
54 def __init__(self, name, summary, isolated=False):
55 # type: (str, str, bool) -> None
56 super(Command, self).__init__()
57 parser_kw = {
58 'usage': self.usage,
59 'prog': '%s %s' % (get_prog(), name),
60 'formatter': UpdatingDefaultsHelpFormatter(),
61 'add_help_option': False,
62 'name': name,
63 'description': self.__doc__,
64 'isolated': isolated,
65 }
66
67 self.name = name
68 self.summary = summary
69 self.parser = ConfigOptionParser(**parser_kw)
70
71 # Commands should add options to this option group
72 optgroup_name = '%s Options' % self.name.capitalize()
73 self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)
74
75 # Add the general options
76 gen_opts = cmdoptions.make_option_group(
77 cmdoptions.general_group,
78 self.parser,
79 )
80 self.parser.add_option_group(gen_opts)
81
82 def handle_pip_version_check(self, options):
83 # type: (Values) -> None
84 """
85 This is a no-op so that commands by default do not do the pip version
86 check.
87 """
88 # Make sure we do the pip version check if the index_group options
89 # are present.
90 assert not hasattr(options, 'no_index')
91
92 def run(self, options, args):
93 # type: (Values, List[Any]) -> Any
94 raise NotImplementedError
95
96 def parse_args(self, args):
97 # type: (List[str]) -> Tuple[Any, Any]
98 # factored out for testability
99 return self.parser.parse_args(args)
100
101 def main(self, args):
102 # type: (List[str]) -> int
103 try:
104 with self.main_context():
105 return self._main(args)
106 finally:
107 logging.shutdown()
108
109 def _main(self, args):
110 # type: (List[str]) -> int
111 # Intentionally set as early as possible so globally-managed temporary
112 # directories are available to the rest of the code.
113 self.enter_context(global_tempdir_manager())
114
115 options, args = self.parse_args(args)
116
117 # Set verbosity so that it can be used elsewhere.
118 self.verbosity = options.verbose - options.quiet
119
120 level_number = setup_logging(
121 verbosity=self.verbosity,
122 no_color=options.no_color,
123 user_log_file=options.log,
124 )
125
126 if (
127 sys.version_info[:2] == (2, 7) and
128 not options.no_python_version_warning
129 ):
130 message = (
131 "A future version of pip will drop support for Python 2.7. "
132 "More details about Python 2 support in pip, can be found at "
133 "https://pip.pypa.io/en/latest/development/release-process/#python-2-support" # noqa
134 )
135 if platform.python_implementation() == "CPython":
136 message = (
137 "Python 2.7 reached the end of its life on January "
138 "1st, 2020. Please upgrade your Python as Python 2.7 "
139 "is no longer maintained. "
140 ) + message
141 deprecated(message, replacement=None, gone_in=None)
142
143 if options.skip_requirements_regex:
144 deprecated(
145 "--skip-requirements-regex is unsupported and will be removed",
146 replacement=(
147 "manage requirements/constraints files explicitly, "
148 "possibly generating them from metadata"
149 ),
150 gone_in="20.1",
151 issue=7297,
152 )
153
154 # TODO: Try to get these passing down from the command?
155 # without resorting to os.environ to hold these.
156 # This also affects isolated builds and it should.
157
158 if options.no_input:
159 os.environ['PIP_NO_INPUT'] = '1'
160
161 if options.exists_action:
162 os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action)
163
164 if options.require_venv and not self.ignore_require_venv:
165 # If a venv is required check if it can really be found
166 if not running_under_virtualenv():
167 logger.critical(
168 'Could not find an activated virtualenv (required).'
169 )
170 sys.exit(VIRTUALENV_NOT_FOUND)
171
172 if options.cache_dir:
173 options.cache_dir = normalize_path(options.cache_dir)
174 if not check_path_owner(options.cache_dir):
175 logger.warning(
176 "The directory '%s' or its parent directory is not owned "
177 "or is not writable by the current user. The cache "
178 "has been disabled. Check the permissions and owner of "
179 "that directory. If executing pip with sudo, you may want "
180 "sudo's -H flag.",
181 options.cache_dir,
182 )
183 options.cache_dir = None
184
185 try:
186 status = self.run(options, args)
187 # FIXME: all commands should return an exit status
188 # and when it is done, isinstance is not needed anymore
189 if isinstance(status, int):
190 return status
191 except PreviousBuildDirError as exc:
192 logger.critical(str(exc))
193 logger.debug('Exception information:', exc_info=True)
194
195 return PREVIOUS_BUILD_DIR_ERROR
196 except (InstallationError, UninstallationError, BadCommand) as exc:
197 logger.critical(str(exc))
198 logger.debug('Exception information:', exc_info=True)
199
200 return ERROR
201 except CommandError as exc:
202 logger.critical('%s', exc)
203 logger.debug('Exception information:', exc_info=True)
204
205 return ERROR
206 except BrokenStdoutLoggingError:
207 # Bypass our logger and write any remaining messages to stderr
208 # because stdout no longer works.
209 print('ERROR: Pipe to stdout was broken', file=sys.stderr)
210 if level_number <= logging.DEBUG:
211 traceback.print_exc(file=sys.stderr)
212
213 return ERROR
214 except KeyboardInterrupt:
215 logger.critical('Operation cancelled by user')
216 logger.debug('Exception information:', exc_info=True)
217
218 return ERROR
219 except BaseException:
220 logger.critical('Exception:', exc_info=True)
221
222 return UNKNOWN_ERROR
223 finally:
224 self.handle_pip_version_check(options)
225
226 return SUCCESS