diff options
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal')
61 files changed, 0 insertions, 15110 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/__init__.py deleted file mode 100644 index d713b0d..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/__init__.py +++ /dev/null | |||
| @@ -1,246 +0,0 @@ | |||
| 1 | #!/usr/bin/env python | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import locale | ||
| 5 | import logging | ||
| 6 | import os | ||
| 7 | import optparse | ||
| 8 | import warnings | ||
| 9 | |||
| 10 | import sys | ||
| 11 | |||
| 12 | # 2016-06-17 barry@debian.org: urllib3 1.14 added optional support for socks, | ||
| 13 | # but if invoked (i.e. imported), it will issue a warning to stderr if socks | ||
| 14 | # isn't available. requests unconditionally imports urllib3's socks contrib | ||
| 15 | # module, triggering this warning. The warning breaks DEP-8 tests (because of | ||
| 16 | # the stderr output) and is just plain annoying in normal usage. I don't want | ||
| 17 | # to add socks as yet another dependency for pip, nor do I want to allow-stder | ||
| 18 | # in the DEP-8 tests, so just suppress the warning. pdb tells me this has to | ||
| 19 | # be done before the import of pip.vcs. | ||
| 20 | from pip._vendor.urllib3.exceptions import DependencyWarning | ||
| 21 | warnings.filterwarnings("ignore", category=DependencyWarning) # noqa | ||
| 22 | |||
| 23 | # We want to inject the use of SecureTransport as early as possible so that any | ||
| 24 | # references or sessions or what have you are ensured to have it, however we | ||
| 25 | # only want to do this in the case that we're running on macOS and the linked | ||
| 26 | # OpenSSL is too old to handle TLSv1.2 | ||
| 27 | try: | ||
| 28 | import ssl | ||
| 29 | except ImportError: | ||
| 30 | pass | ||
| 31 | else: | ||
| 32 | # Checks for OpenSSL 1.0.1 on MacOS | ||
| 33 | if sys.platform == "darwin" and ssl.OPENSSL_VERSION_NUMBER < 0x1000100f: | ||
| 34 | try: | ||
| 35 | from pip._vendor.urllib3.contrib import securetransport | ||
| 36 | except (ImportError, OSError): | ||
| 37 | pass | ||
| 38 | else: | ||
| 39 | securetransport.inject_into_urllib3() | ||
| 40 | |||
| 41 | from pip import __version__ | ||
| 42 | from pip._internal import cmdoptions | ||
| 43 | from pip._internal.exceptions import CommandError, PipError | ||
| 44 | from pip._internal.utils.misc import get_installed_distributions, get_prog | ||
| 45 | from pip._internal.utils import deprecation | ||
| 46 | from pip._internal.vcs import git, mercurial, subversion, bazaar # noqa | ||
| 47 | from pip._internal.baseparser import ( | ||
| 48 | ConfigOptionParser, UpdatingDefaultsHelpFormatter, | ||
| 49 | ) | ||
| 50 | from pip._internal.commands import get_summaries, get_similar_commands | ||
| 51 | from pip._internal.commands import commands_dict | ||
| 52 | from pip._vendor.urllib3.exceptions import InsecureRequestWarning | ||
| 53 | |||
| 54 | logger = logging.getLogger(__name__) | ||
| 55 | |||
| 56 | # Hide the InsecureRequestWarning from urllib3 | ||
| 57 | warnings.filterwarnings("ignore", category=InsecureRequestWarning) | ||
| 58 | |||
| 59 | |||
| 60 | def autocomplete(): | ||
| 61 | """Command and option completion for the main option parser (and options) | ||
| 62 | and its subcommands (and options). | ||
| 63 | |||
| 64 | Enable by sourcing one of the completion shell scripts (bash, zsh or fish). | ||
| 65 | """ | ||
| 66 | # Don't complete if user hasn't sourced bash_completion file. | ||
| 67 | if 'PIP_AUTO_COMPLETE' not in os.environ: | ||
| 68 | return | ||
| 69 | cwords = os.environ['COMP_WORDS'].split()[1:] | ||
| 70 | cword = int(os.environ['COMP_CWORD']) | ||
| 71 | try: | ||
| 72 | current = cwords[cword - 1] | ||
| 73 | except IndexError: | ||
| 74 | current = '' | ||
| 75 | |||
| 76 | subcommands = [cmd for cmd, summary in get_summaries()] | ||
| 77 | options = [] | ||
| 78 | # subcommand | ||
| 79 | try: | ||
| 80 | subcommand_name = [w for w in cwords if w in subcommands][0] | ||
| 81 | except IndexError: | ||
| 82 | subcommand_name = None | ||
| 83 | |||
| 84 | parser = create_main_parser() | ||
| 85 | # subcommand options | ||
| 86 | if subcommand_name: | ||
| 87 | # special case: 'help' subcommand has no options | ||
| 88 | if subcommand_name == 'help': | ||
| 89 | sys.exit(1) | ||
| 90 | # special case: list locally installed dists for show and uninstall | ||
| 91 | should_list_installed = ( | ||
| 92 | subcommand_name in ['show', 'uninstall'] and | ||
| 93 | not current.startswith('-') | ||
| 94 | ) | ||
| 95 | if should_list_installed: | ||
| 96 | installed = [] | ||
| 97 | lc = current.lower() | ||
| 98 | for dist in get_installed_distributions(local_only=True): | ||
| 99 | if dist.key.startswith(lc) and dist.key not in cwords[1:]: | ||
| 100 | installed.append(dist.key) | ||
| 101 | # if there are no dists installed, fall back to option completion | ||
| 102 | if installed: | ||
| 103 | for dist in installed: | ||
| 104 | print(dist) | ||
| 105 | sys.exit(1) | ||
| 106 | |||
| 107 | subcommand = commands_dict[subcommand_name]() | ||
| 108 | |||
| 109 | for opt in subcommand.parser.option_list_all: | ||
| 110 | if opt.help != optparse.SUPPRESS_HELP: | ||
| 111 | for opt_str in opt._long_opts + opt._short_opts: | ||
| 112 | options.append((opt_str, opt.nargs)) | ||
| 113 | |||
| 114 | # filter out previously specified options from available options | ||
| 115 | prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] | ||
| 116 | options = [(x, v) for (x, v) in options if x not in prev_opts] | ||
| 117 | # filter options by current input | ||
| 118 | options = [(k, v) for k, v in options if k.startswith(current)] | ||
| 119 | for option in options: | ||
| 120 | opt_label = option[0] | ||
| 121 | # append '=' to options which require args | ||
| 122 | if option[1] and option[0][:2] == "--": | ||
| 123 | opt_label += '=' | ||
| 124 | print(opt_label) | ||
| 125 | else: | ||
| 126 | # show main parser options only when necessary | ||
| 127 | if current.startswith('-') or current.startswith('--'): | ||
| 128 | opts = [i.option_list for i in parser.option_groups] | ||
| 129 | opts.append(parser.option_list) | ||
| 130 | opts = (o for it in opts for o in it) | ||
| 131 | |||
| 132 | for opt in opts: | ||
| 133 | if opt.help != optparse.SUPPRESS_HELP: | ||
| 134 | subcommands += opt._long_opts + opt._short_opts | ||
| 135 | |||
| 136 | print(' '.join([x for x in subcommands if x.startswith(current)])) | ||
| 137 | sys.exit(1) | ||
| 138 | |||
| 139 | |||
| 140 | def create_main_parser(): | ||
| 141 | parser_kw = { | ||
| 142 | 'usage': '\n%prog <command> [options]', | ||
| 143 | 'add_help_option': False, | ||
| 144 | 'formatter': UpdatingDefaultsHelpFormatter(), | ||
| 145 | 'name': 'global', | ||
| 146 | 'prog': get_prog(), | ||
| 147 | } | ||
| 148 | |||
| 149 | parser = ConfigOptionParser(**parser_kw) | ||
| 150 | parser.disable_interspersed_args() | ||
| 151 | |||
| 152 | pip_pkg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
| 153 | parser.version = 'pip %s from %s (python %s)' % ( | ||
| 154 | __version__, pip_pkg_dir, sys.version[:3], | ||
| 155 | ) | ||
| 156 | |||
| 157 | # add the general options | ||
| 158 | gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) | ||
| 159 | parser.add_option_group(gen_opts) | ||
| 160 | |||
| 161 | parser.main = True # so the help formatter knows | ||
| 162 | |||
| 163 | # create command listing for description | ||
| 164 | command_summaries = get_summaries() | ||
| 165 | description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries] | ||
| 166 | parser.description = '\n'.join(description) | ||
| 167 | |||
| 168 | return parser | ||
| 169 | |||
| 170 | |||
| 171 | def parseopts(args): | ||
| 172 | parser = create_main_parser() | ||
| 173 | |||
| 174 | # Note: parser calls disable_interspersed_args(), so the result of this | ||
| 175 | # call is to split the initial args into the general options before the | ||
| 176 | # subcommand and everything else. | ||
| 177 | # For example: | ||
| 178 | # args: ['--timeout=5', 'install', '--user', 'INITools'] | ||
| 179 | # general_options: ['--timeout==5'] | ||
| 180 | # args_else: ['install', '--user', 'INITools'] | ||
| 181 | general_options, args_else = parser.parse_args(args) | ||
| 182 | |||
| 183 | # --version | ||
| 184 | if general_options.version: | ||
| 185 | sys.stdout.write(parser.version) | ||
| 186 | sys.stdout.write(os.linesep) | ||
| 187 | sys.exit() | ||
| 188 | |||
| 189 | # pip || pip help -> print_help() | ||
| 190 | if not args_else or (args_else[0] == 'help' and len(args_else) == 1): | ||
| 191 | parser.print_help() | ||
| 192 | sys.exit() | ||
| 193 | |||
| 194 | # the subcommand name | ||
| 195 | cmd_name = args_else[0] | ||
| 196 | |||
| 197 | if cmd_name not in commands_dict: | ||
| 198 | guess = get_similar_commands(cmd_name) | ||
| 199 | |||
| 200 | msg = ['unknown command "%s"' % cmd_name] | ||
| 201 | if guess: | ||
| 202 | msg.append('maybe you meant "%s"' % guess) | ||
| 203 | |||
| 204 | raise CommandError(' - '.join(msg)) | ||
| 205 | |||
| 206 | # all the args without the subcommand | ||
| 207 | cmd_args = args[:] | ||
| 208 | cmd_args.remove(cmd_name) | ||
| 209 | |||
| 210 | return cmd_name, cmd_args | ||
| 211 | |||
| 212 | |||
| 213 | def check_isolated(args): | ||
| 214 | isolated = False | ||
| 215 | |||
| 216 | if "--isolated" in args: | ||
| 217 | isolated = True | ||
| 218 | |||
| 219 | return isolated | ||
| 220 | |||
| 221 | |||
| 222 | def main(args=None): | ||
| 223 | if args is None: | ||
| 224 | args = sys.argv[1:] | ||
| 225 | |||
| 226 | # Configure our deprecation warnings to be sent through loggers | ||
| 227 | deprecation.install_warning_logger() | ||
| 228 | |||
| 229 | autocomplete() | ||
| 230 | |||
| 231 | try: | ||
| 232 | cmd_name, cmd_args = parseopts(args) | ||
| 233 | except PipError as exc: | ||
| 234 | sys.stderr.write("ERROR: %s" % exc) | ||
| 235 | sys.stderr.write(os.linesep) | ||
| 236 | sys.exit(1) | ||
| 237 | |||
| 238 | # Needed for locale.getpreferredencoding(False) to work | ||
| 239 | # in pip._internal.utils.encoding.auto_decode | ||
| 240 | try: | ||
| 241 | locale.setlocale(locale.LC_ALL, '') | ||
| 242 | except locale.Error as e: | ||
| 243 | # setlocale can apparently crash if locale are uninitialized | ||
| 244 | logger.debug("Ignoring error %s when setting locale", e) | ||
| 245 | command = commands_dict[cmd_name](isolated=check_isolated(cmd_args)) | ||
| 246 | return command.main(cmd_args) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/basecommand.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/basecommand.py deleted file mode 100644 index e900928..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/basecommand.py +++ /dev/null | |||
| @@ -1,373 +0,0 @@ | |||
| 1 | """Base Command class, and related routines""" | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import logging | ||
| 5 | import logging.config | ||
| 6 | import optparse | ||
| 7 | import os | ||
| 8 | import sys | ||
| 9 | import warnings | ||
| 10 | |||
| 11 | from pip._internal import cmdoptions | ||
| 12 | from pip._internal.baseparser import ( | ||
| 13 | ConfigOptionParser, UpdatingDefaultsHelpFormatter, | ||
| 14 | ) | ||
| 15 | from pip._internal.compat import WINDOWS | ||
| 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.req_file import parse_requirements | ||
| 24 | from pip._internal.req.req_install import InstallRequirement | ||
| 25 | from pip._internal.status_codes import ( | ||
| 26 | ERROR, PREVIOUS_BUILD_DIR_ERROR, SUCCESS, UNKNOWN_ERROR, | ||
| 27 | VIRTUALENV_NOT_FOUND, | ||
| 28 | ) | ||
| 29 | from pip._internal.utils import deprecation | ||
| 30 | from pip._internal.utils.logging import IndentingFormatter | ||
| 31 | from pip._internal.utils.misc import get_prog, normalize_path | ||
| 32 | from pip._internal.utils.outdated import pip_version_check | ||
| 33 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 34 | |||
| 35 | if MYPY_CHECK_RUNNING: | ||
| 36 | from typing import Optional | ||
| 37 | |||
| 38 | __all__ = ['Command'] | ||
| 39 | |||
| 40 | logger = logging.getLogger(__name__) | ||
| 41 | |||
| 42 | |||
| 43 | class Command(object): | ||
| 44 | name = None # type: Optional[str] | ||
| 45 | usage = None # type: Optional[str] | ||
| 46 | hidden = False # type: bool | ||
| 47 | ignore_require_venv = False # type: bool | ||
| 48 | log_streams = ("ext://sys.stdout", "ext://sys.stderr") | ||
| 49 | |||
| 50 | def __init__(self, isolated=False): | ||
| 51 | parser_kw = { | ||
| 52 | 'usage': self.usage, | ||
| 53 | 'prog': '%s %s' % (get_prog(), self.name), | ||
| 54 | 'formatter': UpdatingDefaultsHelpFormatter(), | ||
| 55 | 'add_help_option': False, | ||
| 56 | 'name': self.name, | ||
| 57 | 'description': self.__doc__, | ||
| 58 | 'isolated': isolated, | ||
| 59 | } | ||
| 60 | |||
| 61 | self.parser = ConfigOptionParser(**parser_kw) | ||
| 62 | |||
| 63 | # Commands should add options to this option group | ||
| 64 | optgroup_name = '%s Options' % self.name.capitalize() | ||
| 65 | self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) | ||
| 66 | |||
| 67 | # Add the general options | ||
| 68 | gen_opts = cmdoptions.make_option_group( | ||
| 69 | cmdoptions.general_group, | ||
| 70 | self.parser, | ||
| 71 | ) | ||
| 72 | self.parser.add_option_group(gen_opts) | ||
| 73 | |||
| 74 | def _build_session(self, options, retries=None, timeout=None): | ||
| 75 | session = PipSession( | ||
| 76 | cache=( | ||
| 77 | normalize_path(os.path.join(options.cache_dir, "http")) | ||
| 78 | if options.cache_dir else None | ||
| 79 | ), | ||
| 80 | retries=retries if retries is not None else options.retries, | ||
| 81 | insecure_hosts=options.trusted_hosts, | ||
| 82 | ) | ||
| 83 | |||
| 84 | # Handle custom ca-bundles from the user | ||
| 85 | if options.cert: | ||
| 86 | session.verify = options.cert | ||
| 87 | |||
| 88 | # Handle SSL client certificate | ||
| 89 | if options.client_cert: | ||
| 90 | session.cert = options.client_cert | ||
| 91 | |||
| 92 | # Handle timeouts | ||
| 93 | if options.timeout or timeout: | ||
| 94 | session.timeout = ( | ||
| 95 | timeout if timeout is not None else options.timeout | ||
| 96 | ) | ||
| 97 | |||
| 98 | # Handle configured proxies | ||
| 99 | if options.proxy: | ||
| 100 | session.proxies = { | ||
| 101 | "http": options.proxy, | ||
| 102 | "https": options.proxy, | ||
| 103 | } | ||
| 104 | |||
| 105 | # Determine if we can prompt the user for authentication or not | ||
| 106 | session.auth.prompting = not options.no_input | ||
| 107 | |||
| 108 | return session | ||
| 109 | |||
| 110 | def parse_args(self, args): | ||
| 111 | # factored out for testability | ||
| 112 | return self.parser.parse_args(args) | ||
| 113 | |||
| 114 | def main(self, args): | ||
| 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 | if self.verbosity >= 1: | ||
| 121 | level = "DEBUG" | ||
| 122 | elif self.verbosity == -1: | ||
| 123 | level = "WARNING" | ||
| 124 | elif self.verbosity == -2: | ||
| 125 | level = "ERROR" | ||
| 126 | elif self.verbosity <= -3: | ||
| 127 | level = "CRITICAL" | ||
| 128 | else: | ||
| 129 | level = "INFO" | ||
| 130 | |||
| 131 | # The root logger should match the "console" level *unless* we | ||
| 132 | # specified "--log" to send debug logs to a file. | ||
| 133 | root_level = level | ||
| 134 | if options.log: | ||
| 135 | root_level = "DEBUG" | ||
| 136 | |||
| 137 | logger_class = "pip._internal.utils.logging.ColorizedStreamHandler" | ||
| 138 | handler_class = "pip._internal.utils.logging.BetterRotatingFileHandler" | ||
| 139 | |||
| 140 | logging.config.dictConfig({ | ||
| 141 | "version": 1, | ||
| 142 | "disable_existing_loggers": False, | ||
| 143 | "filters": { | ||
| 144 | "exclude_warnings": { | ||
| 145 | "()": "pip._internal.utils.logging.MaxLevelFilter", | ||
| 146 | "level": logging.WARNING, | ||
| 147 | }, | ||
| 148 | }, | ||
| 149 | "formatters": { | ||
| 150 | "indent": { | ||
| 151 | "()": IndentingFormatter, | ||
| 152 | "format": "%(message)s", | ||
| 153 | }, | ||
| 154 | }, | ||
| 155 | "handlers": { | ||
| 156 | "console": { | ||
| 157 | "level": level, | ||
| 158 | "class": logger_class, | ||
| 159 | "no_color": options.no_color, | ||
| 160 | "stream": self.log_streams[0], | ||
| 161 | "filters": ["exclude_warnings"], | ||
| 162 | "formatter": "indent", | ||
| 163 | }, | ||
| 164 | "console_errors": { | ||
| 165 | "level": "WARNING", | ||
| 166 | "class": logger_class, | ||
| 167 | "no_color": options.no_color, | ||
| 168 | "stream": self.log_streams[1], | ||
| 169 | "formatter": "indent", | ||
| 170 | }, | ||
| 171 | "user_log": { | ||
| 172 | "level": "DEBUG", | ||
| 173 | "class": handler_class, | ||
| 174 | "filename": options.log or "/dev/null", | ||
| 175 | "delay": True, | ||
| 176 | "formatter": "indent", | ||
| 177 | }, | ||
| 178 | }, | ||
| 179 | "root": { | ||
| 180 | "level": root_level, | ||
| 181 | "handlers": list(filter(None, [ | ||
| 182 | "console", | ||
| 183 | "console_errors", | ||
| 184 | "user_log" if options.log else None, | ||
| 185 | ])), | ||
| 186 | }, | ||
| 187 | # Disable any logging besides WARNING unless we have DEBUG level | ||
| 188 | # logging enabled. These use both pip._vendor and the bare names | ||
| 189 | # for the case where someone unbundles our libraries. | ||
| 190 | "loggers": { | ||
| 191 | name: { | ||
| 192 | "level": ( | ||
| 193 | "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" | ||
| 194 | ) | ||
| 195 | } for name in [ | ||
| 196 | "pip._vendor", "distlib", "requests", "urllib3" | ||
| 197 | ] | ||
| 198 | }, | ||
| 199 | }) | ||
| 200 | |||
| 201 | if sys.version_info[:2] == (3, 3): | ||
| 202 | warnings.warn( | ||
| 203 | "Python 3.3 supported has been deprecated and support for it " | ||
| 204 | "will be dropped in the future. Please upgrade your Python.", | ||
| 205 | deprecation.RemovedInPip11Warning, | ||
| 206 | ) | ||
| 207 | |||
| 208 | # TODO: try to get these passing down from the command? | ||
| 209 | # without resorting to os.environ to hold these. | ||
| 210 | |||
| 211 | if options.no_input: | ||
| 212 | os.environ['PIP_NO_INPUT'] = '1' | ||
| 213 | |||
| 214 | if options.exists_action: | ||
| 215 | os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) | ||
| 216 | |||
| 217 | if options.require_venv and not self.ignore_require_venv: | ||
| 218 | # If a venv is required check if it can really be found | ||
| 219 | if not running_under_virtualenv(): | ||
| 220 | logger.critical( | ||
| 221 | 'Could not find an activated virtualenv (required).' | ||
| 222 | ) | ||
| 223 | sys.exit(VIRTUALENV_NOT_FOUND) | ||
| 224 | |||
| 225 | original_root_handlers = set(logging.root.handlers) | ||
| 226 | |||
| 227 | try: | ||
| 228 | status = self.run(options, args) | ||
| 229 | # FIXME: all commands should return an exit status | ||
| 230 | # and when it is done, isinstance is not needed anymore | ||
| 231 | if isinstance(status, int): | ||
| 232 | return status | ||
| 233 | except PreviousBuildDirError as exc: | ||
| 234 | logger.critical(str(exc)) | ||
| 235 | logger.debug('Exception information:', exc_info=True) | ||
| 236 | |||
| 237 | return PREVIOUS_BUILD_DIR_ERROR | ||
| 238 | except (InstallationError, UninstallationError, BadCommand) as exc: | ||
| 239 | logger.critical(str(exc)) | ||
| 240 | logger.debug('Exception information:', exc_info=True) | ||
| 241 | |||
| 242 | return ERROR | ||
| 243 | except CommandError as exc: | ||
| 244 | logger.critical('ERROR: %s', exc) | ||
| 245 | logger.debug('Exception information:', exc_info=True) | ||
| 246 | |||
| 247 | return ERROR | ||
| 248 | except KeyboardInterrupt: | ||
| 249 | logger.critical('Operation cancelled by user') | ||
| 250 | logger.debug('Exception information:', exc_info=True) | ||
| 251 | |||
| 252 | return ERROR | ||
| 253 | except: | ||
| 254 | logger.critical('Exception:', exc_info=True) | ||
| 255 | |||
| 256 | return UNKNOWN_ERROR | ||
| 257 | finally: | ||
| 258 | # Check if we're using the latest version of pip available | ||
| 259 | if (not options.disable_pip_version_check and not | ||
| 260 | getattr(options, "no_index", False)): | ||
| 261 | with self._build_session( | ||
| 262 | options, | ||
| 263 | retries=0, | ||
| 264 | timeout=min(5, options.timeout)) as session: | ||
| 265 | pip_version_check(session, options) | ||
| 266 | # Avoid leaking loggers | ||
| 267 | for handler in set(logging.root.handlers) - original_root_handlers: | ||
| 268 | # this method benefit from the Logger class internal lock | ||
| 269 | logging.root.removeHandler(handler) | ||
| 270 | |||
| 271 | return SUCCESS | ||
| 272 | |||
| 273 | |||
| 274 | class RequirementCommand(Command): | ||
| 275 | |||
| 276 | @staticmethod | ||
| 277 | def populate_requirement_set(requirement_set, args, options, finder, | ||
| 278 | session, name, wheel_cache): | ||
| 279 | """ | ||
| 280 | Marshal cmd line args into a requirement set. | ||
| 281 | """ | ||
| 282 | # NOTE: As a side-effect, options.require_hashes and | ||
| 283 | # requirement_set.require_hashes may be updated | ||
| 284 | |||
| 285 | for filename in options.constraints: | ||
| 286 | for req_to_add in parse_requirements( | ||
| 287 | filename, | ||
| 288 | constraint=True, finder=finder, options=options, | ||
| 289 | session=session, wheel_cache=wheel_cache): | ||
| 290 | req_to_add.is_direct = True | ||
| 291 | requirement_set.add_requirement(req_to_add) | ||
| 292 | |||
| 293 | for req in args: | ||
| 294 | req_to_add = InstallRequirement.from_line( | ||
| 295 | req, None, isolated=options.isolated_mode, | ||
| 296 | wheel_cache=wheel_cache | ||
| 297 | ) | ||
| 298 | req_to_add.is_direct = True | ||
| 299 | requirement_set.add_requirement(req_to_add) | ||
| 300 | |||
| 301 | for req in options.editables: | ||
| 302 | req_to_add = InstallRequirement.from_editable( | ||
| 303 | req, | ||
| 304 | isolated=options.isolated_mode, | ||
| 305 | wheel_cache=wheel_cache | ||
| 306 | ) | ||
| 307 | req_to_add.is_direct = True | ||
| 308 | requirement_set.add_requirement(req_to_add) | ||
| 309 | |||
| 310 | for filename in options.requirements: | ||
| 311 | for req_to_add in parse_requirements( | ||
| 312 | filename, | ||
| 313 | finder=finder, options=options, session=session, | ||
| 314 | wheel_cache=wheel_cache): | ||
| 315 | req_to_add.is_direct = True | ||
| 316 | requirement_set.add_requirement(req_to_add) | ||
| 317 | # If --require-hashes was a line in a requirements file, tell | ||
| 318 | # RequirementSet about it: | ||
| 319 | requirement_set.require_hashes = options.require_hashes | ||
| 320 | |||
| 321 | if not (args or options.editables or options.requirements): | ||
| 322 | opts = {'name': name} | ||
| 323 | if options.find_links: | ||
| 324 | raise CommandError( | ||
| 325 | 'You must give at least one requirement to %(name)s ' | ||
| 326 | '(maybe you meant "pip %(name)s %(links)s"?)' % | ||
| 327 | dict(opts, links=' '.join(options.find_links))) | ||
| 328 | else: | ||
| 329 | raise CommandError( | ||
| 330 | 'You must give at least one requirement to %(name)s ' | ||
| 331 | '(see "pip help %(name)s")' % opts) | ||
| 332 | |||
| 333 | # On Windows, any operation modifying pip should be run as: | ||
| 334 | # python -m pip ... | ||
| 335 | # See https://github.com/pypa/pip/issues/1299 for more discussion | ||
| 336 | should_show_use_python_msg = ( | ||
| 337 | WINDOWS and | ||
| 338 | requirement_set.has_requirement("pip") and | ||
| 339 | os.path.basename(sys.argv[0]).startswith("pip") | ||
| 340 | ) | ||
| 341 | if should_show_use_python_msg: | ||
| 342 | new_command = [ | ||
| 343 | sys.executable, "-m", "pip" | ||
| 344 | ] + sys.argv[1:] | ||
| 345 | raise CommandError( | ||
| 346 | 'To modify pip, please run the following command:\n{}' | ||
| 347 | .format(" ".join(new_command)) | ||
| 348 | ) | ||
| 349 | |||
| 350 | def _build_package_finder(self, options, session, | ||
| 351 | platform=None, python_versions=None, | ||
| 352 | abi=None, implementation=None): | ||
| 353 | """ | ||
| 354 | Create a package finder appropriate to this requirement command. | ||
| 355 | """ | ||
| 356 | index_urls = [options.index_url] + options.extra_index_urls | ||
| 357 | if options.no_index: | ||
| 358 | logger.debug('Ignoring indexes: %s', ','.join(index_urls)) | ||
| 359 | index_urls = [] | ||
| 360 | |||
| 361 | return PackageFinder( | ||
| 362 | find_links=options.find_links, | ||
| 363 | format_control=options.format_control, | ||
| 364 | index_urls=index_urls, | ||
| 365 | trusted_hosts=options.trusted_hosts, | ||
| 366 | allow_all_prereleases=options.pre, | ||
| 367 | process_dependency_links=options.process_dependency_links, | ||
| 368 | session=session, | ||
| 369 | platform=platform, | ||
| 370 | versions=python_versions, | ||
| 371 | abi=abi, | ||
| 372 | implementation=implementation, | ||
| 373 | ) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/baseparser.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/baseparser.py deleted file mode 100644 index ed28a1b..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/baseparser.py +++ /dev/null | |||
| @@ -1,240 +0,0 @@ | |||
| 1 | """Base option parser setup""" | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import logging | ||
| 5 | import optparse | ||
| 6 | import sys | ||
| 7 | import textwrap | ||
| 8 | from distutils.util import strtobool | ||
| 9 | |||
| 10 | from pip._vendor.six import string_types | ||
| 11 | |||
| 12 | from pip._internal.compat import get_terminal_size | ||
| 13 | from pip._internal.configuration import Configuration, ConfigurationError | ||
| 14 | |||
| 15 | logger = logging.getLogger(__name__) | ||
| 16 | |||
| 17 | |||
| 18 | class PrettyHelpFormatter(optparse.IndentedHelpFormatter): | ||
| 19 | """A prettier/less verbose help formatter for optparse.""" | ||
| 20 | |||
| 21 | def __init__(self, *args, **kwargs): | ||
| 22 | # help position must be aligned with __init__.parseopts.description | ||
| 23 | kwargs['max_help_position'] = 30 | ||
| 24 | kwargs['indent_increment'] = 1 | ||
| 25 | kwargs['width'] = get_terminal_size()[0] - 2 | ||
| 26 | optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs) | ||
| 27 | |||
| 28 | def format_option_strings(self, option): | ||
| 29 | return self._format_option_strings(option, ' <%s>', ', ') | ||
| 30 | |||
| 31 | def _format_option_strings(self, option, mvarfmt=' <%s>', optsep=', '): | ||
| 32 | """ | ||
| 33 | Return a comma-separated list of option strings and metavars. | ||
| 34 | |||
| 35 | :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') | ||
| 36 | :param mvarfmt: metavar format string - evaluated as mvarfmt % metavar | ||
| 37 | :param optsep: separator | ||
| 38 | """ | ||
| 39 | opts = [] | ||
| 40 | |||
| 41 | if option._short_opts: | ||
| 42 | opts.append(option._short_opts[0]) | ||
| 43 | if option._long_opts: | ||
| 44 | opts.append(option._long_opts[0]) | ||
| 45 | if len(opts) > 1: | ||
| 46 | opts.insert(1, optsep) | ||
| 47 | |||
| 48 | if option.takes_value(): | ||
| 49 | metavar = option.metavar or option.dest.lower() | ||
| 50 | opts.append(mvarfmt % metavar.lower()) | ||
| 51 | |||
| 52 | return ''.join(opts) | ||
| 53 | |||
| 54 | def format_heading(self, heading): | ||
| 55 | if heading == 'Options': | ||
| 56 | return '' | ||
| 57 | return heading + ':\n' | ||
| 58 | |||
| 59 | def format_usage(self, usage): | ||
| 60 | """ | ||
| 61 | Ensure there is only one newline between usage and the first heading | ||
| 62 | if there is no description. | ||
| 63 | """ | ||
| 64 | msg = '\nUsage: %s\n' % self.indent_lines(textwrap.dedent(usage), " ") | ||
| 65 | return msg | ||
| 66 | |||
| 67 | def format_description(self, description): | ||
| 68 | # leave full control over description to us | ||
| 69 | if description: | ||
| 70 | if hasattr(self.parser, 'main'): | ||
| 71 | label = 'Commands' | ||
| 72 | else: | ||
| 73 | label = 'Description' | ||
| 74 | # some doc strings have initial newlines, some don't | ||
| 75 | description = description.lstrip('\n') | ||
| 76 | # some doc strings have final newlines and spaces, some don't | ||
| 77 | description = description.rstrip() | ||
| 78 | # dedent, then reindent | ||
| 79 | description = self.indent_lines(textwrap.dedent(description), " ") | ||
| 80 | description = '%s:\n%s\n' % (label, description) | ||
| 81 | return description | ||
| 82 | else: | ||
| 83 | return '' | ||
| 84 | |||
| 85 | def format_epilog(self, epilog): | ||
| 86 | # leave full control over epilog to us | ||
| 87 | if epilog: | ||
| 88 | return epilog | ||
| 89 | else: | ||
| 90 | return '' | ||
| 91 | |||
| 92 | def indent_lines(self, text, indent): | ||
| 93 | new_lines = [indent + line for line in text.split('\n')] | ||
| 94 | return "\n".join(new_lines) | ||
| 95 | |||
| 96 | |||
| 97 | class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): | ||
| 98 | """Custom help formatter for use in ConfigOptionParser. | ||
| 99 | |||
| 100 | This is updates the defaults before expanding them, allowing | ||
| 101 | them to show up correctly in the help listing. | ||
| 102 | """ | ||
| 103 | |||
| 104 | def expand_default(self, option): | ||
| 105 | if self.parser is not None: | ||
| 106 | self.parser._update_defaults(self.parser.defaults) | ||
| 107 | return optparse.IndentedHelpFormatter.expand_default(self, option) | ||
| 108 | |||
| 109 | |||
| 110 | class CustomOptionParser(optparse.OptionParser): | ||
| 111 | |||
| 112 | def insert_option_group(self, idx, *args, **kwargs): | ||
| 113 | """Insert an OptionGroup at a given position.""" | ||
| 114 | group = self.add_option_group(*args, **kwargs) | ||
| 115 | |||
| 116 | self.option_groups.pop() | ||
| 117 | self.option_groups.insert(idx, group) | ||
| 118 | |||
| 119 | return group | ||
| 120 | |||
| 121 | @property | ||
| 122 | def option_list_all(self): | ||
| 123 | """Get a list of all options, including those in option groups.""" | ||
| 124 | res = self.option_list[:] | ||
| 125 | for i in self.option_groups: | ||
| 126 | res.extend(i.option_list) | ||
| 127 | |||
| 128 | return res | ||
| 129 | |||
| 130 | |||
| 131 | class ConfigOptionParser(CustomOptionParser): | ||
| 132 | """Custom option parser which updates its defaults by checking the | ||
| 133 | configuration files and environmental variables""" | ||
| 134 | |||
| 135 | def __init__(self, *args, **kwargs): | ||
| 136 | self.name = kwargs.pop('name') | ||
| 137 | |||
| 138 | isolated = kwargs.pop("isolated", False) | ||
| 139 | self.config = Configuration(isolated) | ||
| 140 | |||
| 141 | assert self.name | ||
| 142 | optparse.OptionParser.__init__(self, *args, **kwargs) | ||
| 143 | |||
| 144 | def check_default(self, option, key, val): | ||
| 145 | try: | ||
| 146 | return option.check_value(key, val) | ||
| 147 | except optparse.OptionValueError as exc: | ||
| 148 | print("An error occurred during configuration: %s" % exc) | ||
| 149 | sys.exit(3) | ||
| 150 | |||
| 151 | def _get_ordered_configuration_items(self): | ||
| 152 | # Configuration gives keys in an unordered manner. Order them. | ||
| 153 | override_order = ["global", self.name, ":env:"] | ||
| 154 | |||
| 155 | # Pool the options into different groups | ||
| 156 | section_items = {name: [] for name in override_order} | ||
| 157 | for section_key, val in self.config.items(): | ||
| 158 | # ignore empty values | ||
| 159 | if not val: | ||
| 160 | logger.debug( | ||
| 161 | "Ignoring configuration key '%s' as it's value is empty.", | ||
| 162 | section_key | ||
| 163 | ) | ||
| 164 | continue | ||
| 165 | |||
| 166 | section, key = section_key.split(".", 1) | ||
| 167 | if section in override_order: | ||
| 168 | section_items[section].append((key, val)) | ||
| 169 | |||
| 170 | # Yield each group in their override order | ||
| 171 | for section in override_order: | ||
| 172 | for key, val in section_items[section]: | ||
| 173 | yield key, val | ||
| 174 | |||
| 175 | def _update_defaults(self, defaults): | ||
| 176 | """Updates the given defaults with values from the config files and | ||
| 177 | the environ. Does a little special handling for certain types of | ||
| 178 | options (lists).""" | ||
| 179 | |||
| 180 | # Accumulate complex default state. | ||
| 181 | self.values = optparse.Values(self.defaults) | ||
| 182 | late_eval = set() | ||
| 183 | # Then set the options with those values | ||
| 184 | for key, val in self._get_ordered_configuration_items(): | ||
| 185 | # '--' because configuration supports only long names | ||
| 186 | option = self.get_option('--' + key) | ||
| 187 | |||
| 188 | # Ignore options not present in this parser. E.g. non-globals put | ||
| 189 | # in [global] by users that want them to apply to all applicable | ||
| 190 | # commands. | ||
| 191 | if option is None: | ||
| 192 | continue | ||
| 193 | |||
| 194 | if option.action in ('store_true', 'store_false', 'count'): | ||
| 195 | val = strtobool(val) | ||
| 196 | elif option.action == 'append': | ||
| 197 | val = val.split() | ||
| 198 | val = [self.check_default(option, key, v) for v in val] | ||
| 199 | elif option.action == 'callback': | ||
| 200 | late_eval.add(option.dest) | ||
| 201 | opt_str = option.get_opt_string() | ||
| 202 | val = option.convert_value(opt_str, val) | ||
| 203 | # From take_action | ||
| 204 | args = option.callback_args or () | ||
| 205 | kwargs = option.callback_kwargs or {} | ||
| 206 | option.callback(option, opt_str, val, self, *args, **kwargs) | ||
| 207 | else: | ||
| 208 | val = self.check_default(option, key, val) | ||
| 209 | |||
| 210 | defaults[option.dest] = val | ||
| 211 | |||
| 212 | for key in late_eval: | ||
| 213 | defaults[key] = getattr(self.values, key) | ||
| 214 | self.values = None | ||
| 215 | return defaults | ||
| 216 | |||
| 217 | def get_default_values(self): | ||
| 218 | """Overriding to make updating the defaults after instantiation of | ||
| 219 | the option parser possible, _update_defaults() does the dirty work.""" | ||
| 220 | if not self.process_default_values: | ||
| 221 | # Old, pre-Optik 1.5 behaviour. | ||
| 222 | return optparse.Values(self.defaults) | ||
| 223 | |||
| 224 | # Load the configuration, or error out in case of an error | ||
| 225 | try: | ||
| 226 | self.config.load() | ||
| 227 | except ConfigurationError as err: | ||
| 228 | self.exit(2, err.args[0]) | ||
| 229 | |||
| 230 | defaults = self._update_defaults(self.defaults.copy()) # ours | ||
| 231 | for option in self._get_all_options(): | ||
| 232 | default = defaults.get(option.dest) | ||
| 233 | if isinstance(default, string_types): | ||
| 234 | opt_str = option.get_opt_string() | ||
| 235 | defaults[option.dest] = option.check_value(opt_str, default) | ||
| 236 | return optparse.Values(defaults) | ||
| 237 | |||
| 238 | def error(self, msg): | ||
| 239 | self.print_usage(sys.stderr) | ||
| 240 | self.exit(2, "%s\n" % msg) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/build_env.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/build_env.py deleted file mode 100644 index 8ad7735..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/build_env.py +++ /dev/null | |||
| @@ -1,92 +0,0 @@ | |||
| 1 | """Build Environment used for isolation during sdist building | ||
| 2 | """ | ||
| 3 | |||
| 4 | import os | ||
| 5 | from distutils.sysconfig import get_python_lib | ||
| 6 | from sysconfig import get_paths | ||
| 7 | |||
| 8 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 9 | |||
| 10 | |||
| 11 | class BuildEnvironment(object): | ||
| 12 | """Creates and manages an isolated environment to install build deps | ||
| 13 | """ | ||
| 14 | |||
| 15 | def __init__(self, no_clean): | ||
| 16 | self._temp_dir = TempDirectory(kind="build-env") | ||
| 17 | self._no_clean = no_clean | ||
| 18 | |||
| 19 | @property | ||
| 20 | def path(self): | ||
| 21 | return self._temp_dir.path | ||
| 22 | |||
| 23 | def __enter__(self): | ||
| 24 | self._temp_dir.create() | ||
| 25 | |||
| 26 | self.save_path = os.environ.get('PATH', None) | ||
| 27 | self.save_pythonpath = os.environ.get('PYTHONPATH', None) | ||
| 28 | self.save_nousersite = os.environ.get('PYTHONNOUSERSITE', None) | ||
| 29 | |||
| 30 | install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix' | ||
| 31 | install_dirs = get_paths(install_scheme, vars={ | ||
| 32 | 'base': self.path, | ||
| 33 | 'platbase': self.path, | ||
| 34 | }) | ||
| 35 | |||
| 36 | scripts = install_dirs['scripts'] | ||
| 37 | if self.save_path: | ||
| 38 | os.environ['PATH'] = scripts + os.pathsep + self.save_path | ||
| 39 | else: | ||
| 40 | os.environ['PATH'] = scripts + os.pathsep + os.defpath | ||
| 41 | |||
| 42 | # Note: prefer distutils' sysconfig to get the | ||
| 43 | # library paths so PyPy is correctly supported. | ||
| 44 | purelib = get_python_lib(plat_specific=0, prefix=self.path) | ||
| 45 | platlib = get_python_lib(plat_specific=1, prefix=self.path) | ||
| 46 | if purelib == platlib: | ||
| 47 | lib_dirs = purelib | ||
| 48 | else: | ||
| 49 | lib_dirs = purelib + os.pathsep + platlib | ||
| 50 | if self.save_pythonpath: | ||
| 51 | os.environ['PYTHONPATH'] = lib_dirs + os.pathsep + \ | ||
| 52 | self.save_pythonpath | ||
| 53 | else: | ||
| 54 | os.environ['PYTHONPATH'] = lib_dirs | ||
| 55 | |||
| 56 | os.environ['PYTHONNOUSERSITE'] = '1' | ||
| 57 | |||
| 58 | return self.path | ||
| 59 | |||
| 60 | def __exit__(self, exc_type, exc_val, exc_tb): | ||
| 61 | if not self._no_clean: | ||
| 62 | self._temp_dir.cleanup() | ||
| 63 | |||
| 64 | def restore_var(varname, old_value): | ||
| 65 | if old_value is None: | ||
| 66 | os.environ.pop(varname, None) | ||
| 67 | else: | ||
| 68 | os.environ[varname] = old_value | ||
| 69 | |||
| 70 | restore_var('PATH', self.save_path) | ||
| 71 | restore_var('PYTHONPATH', self.save_pythonpath) | ||
| 72 | restore_var('PYTHONNOUSERSITE', self.save_nousersite) | ||
| 73 | |||
| 74 | def cleanup(self): | ||
| 75 | self._temp_dir.cleanup() | ||
| 76 | |||
| 77 | |||
| 78 | class NoOpBuildEnvironment(BuildEnvironment): | ||
| 79 | """A no-op drop-in replacement for BuildEnvironment | ||
| 80 | """ | ||
| 81 | |||
| 82 | def __init__(self, no_clean): | ||
| 83 | pass | ||
| 84 | |||
| 85 | def __enter__(self): | ||
| 86 | pass | ||
| 87 | |||
| 88 | def __exit__(self, exc_type, exc_val, exc_tb): | ||
| 89 | pass | ||
| 90 | |||
| 91 | def cleanup(self): | ||
| 92 | pass | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/cache.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/cache.py deleted file mode 100644 index 5547d73..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/cache.py +++ /dev/null | |||
| @@ -1,202 +0,0 @@ | |||
| 1 | """Cache Management | ||
| 2 | """ | ||
| 3 | |||
| 4 | import errno | ||
| 5 | import hashlib | ||
| 6 | import logging | ||
| 7 | import os | ||
| 8 | |||
| 9 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 10 | |||
| 11 | from pip._internal import index | ||
| 12 | from pip._internal.compat import expanduser | ||
| 13 | from pip._internal.download import path_to_url | ||
| 14 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 15 | from pip._internal.wheel import InvalidWheelFilename, Wheel | ||
| 16 | |||
| 17 | logger = logging.getLogger(__name__) | ||
| 18 | |||
| 19 | |||
| 20 | class Cache(object): | ||
| 21 | """An abstract class - provides cache directories for data from links | ||
| 22 | |||
| 23 | |||
| 24 | :param cache_dir: The root of the cache. | ||
| 25 | :param format_control: A pip.index.FormatControl object to limit | ||
| 26 | binaries being read from the cache. | ||
| 27 | :param allowed_formats: which formats of files the cache should store. | ||
| 28 | ('binary' and 'source' are the only allowed values) | ||
| 29 | """ | ||
| 30 | |||
| 31 | def __init__(self, cache_dir, format_control, allowed_formats): | ||
| 32 | super(Cache, self).__init__() | ||
| 33 | self.cache_dir = expanduser(cache_dir) if cache_dir else None | ||
| 34 | self.format_control = format_control | ||
| 35 | self.allowed_formats = allowed_formats | ||
| 36 | |||
| 37 | _valid_formats = {"source", "binary"} | ||
| 38 | assert self.allowed_formats.union(_valid_formats) == _valid_formats | ||
| 39 | |||
| 40 | def _get_cache_path_parts(self, link): | ||
| 41 | """Get parts of part that must be os.path.joined with cache_dir | ||
| 42 | """ | ||
| 43 | |||
| 44 | # We want to generate an url to use as our cache key, we don't want to | ||
| 45 | # just re-use the URL because it might have other items in the fragment | ||
| 46 | # and we don't care about those. | ||
| 47 | key_parts = [link.url_without_fragment] | ||
| 48 | if link.hash_name is not None and link.hash is not None: | ||
| 49 | key_parts.append("=".join([link.hash_name, link.hash])) | ||
| 50 | key_url = "#".join(key_parts) | ||
| 51 | |||
| 52 | # Encode our key url with sha224, we'll use this because it has similar | ||
| 53 | # security properties to sha256, but with a shorter total output (and | ||
| 54 | # thus less secure). However the differences don't make a lot of | ||
| 55 | # difference for our use case here. | ||
| 56 | hashed = hashlib.sha224(key_url.encode()).hexdigest() | ||
| 57 | |||
| 58 | # We want to nest the directories some to prevent having a ton of top | ||
| 59 | # level directories where we might run out of sub directories on some | ||
| 60 | # FS. | ||
| 61 | parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] | ||
| 62 | |||
| 63 | return parts | ||
| 64 | |||
| 65 | def _get_candidates(self, link, package_name): | ||
| 66 | can_not_cache = ( | ||
| 67 | not self.cache_dir or | ||
| 68 | not package_name or | ||
| 69 | not link | ||
| 70 | ) | ||
| 71 | if can_not_cache: | ||
| 72 | return [] | ||
| 73 | |||
| 74 | canonical_name = canonicalize_name(package_name) | ||
| 75 | formats = index.fmt_ctl_formats( | ||
| 76 | self.format_control, canonical_name | ||
| 77 | ) | ||
| 78 | if not self.allowed_formats.intersection(formats): | ||
| 79 | return [] | ||
| 80 | |||
| 81 | root = self.get_path_for_link(link) | ||
| 82 | try: | ||
| 83 | return os.listdir(root) | ||
| 84 | except OSError as err: | ||
| 85 | if err.errno in {errno.ENOENT, errno.ENOTDIR}: | ||
| 86 | return [] | ||
| 87 | raise | ||
| 88 | |||
| 89 | def get_path_for_link(self, link): | ||
| 90 | """Return a directory to store cached items in for link. | ||
| 91 | """ | ||
| 92 | raise NotImplementedError() | ||
| 93 | |||
| 94 | def get(self, link, package_name): | ||
| 95 | """Returns a link to a cached item if it exists, otherwise returns the | ||
| 96 | passed link. | ||
| 97 | """ | ||
| 98 | raise NotImplementedError() | ||
| 99 | |||
| 100 | def _link_for_candidate(self, link, candidate): | ||
| 101 | root = self.get_path_for_link(link) | ||
| 102 | path = os.path.join(root, candidate) | ||
| 103 | |||
| 104 | return index.Link(path_to_url(path)) | ||
| 105 | |||
| 106 | def cleanup(self): | ||
| 107 | pass | ||
| 108 | |||
| 109 | |||
| 110 | class SimpleWheelCache(Cache): | ||
| 111 | """A cache of wheels for future installs. | ||
| 112 | """ | ||
| 113 | |||
| 114 | def __init__(self, cache_dir, format_control): | ||
| 115 | super(SimpleWheelCache, self).__init__( | ||
| 116 | cache_dir, format_control, {"binary"} | ||
| 117 | ) | ||
| 118 | |||
| 119 | def get_path_for_link(self, link): | ||
| 120 | """Return a directory to store cached wheels for link | ||
| 121 | |||
| 122 | Because there are M wheels for any one sdist, we provide a directory | ||
| 123 | to cache them in, and then consult that directory when looking up | ||
| 124 | cache hits. | ||
| 125 | |||
| 126 | We only insert things into the cache if they have plausible version | ||
| 127 | numbers, so that we don't contaminate the cache with things that were | ||
| 128 | not unique. E.g. ./package might have dozens of installs done for it | ||
| 129 | and build a version of 0.0...and if we built and cached a wheel, we'd | ||
| 130 | end up using the same wheel even if the source has been edited. | ||
| 131 | |||
| 132 | :param link: The link of the sdist for which this will cache wheels. | ||
| 133 | """ | ||
| 134 | parts = self._get_cache_path_parts(link) | ||
| 135 | |||
| 136 | # Store wheels within the root cache_dir | ||
| 137 | return os.path.join(self.cache_dir, "wheels", *parts) | ||
| 138 | |||
| 139 | def get(self, link, package_name): | ||
| 140 | candidates = [] | ||
| 141 | |||
| 142 | for wheel_name in self._get_candidates(link, package_name): | ||
| 143 | try: | ||
| 144 | wheel = Wheel(wheel_name) | ||
| 145 | except InvalidWheelFilename: | ||
| 146 | continue | ||
| 147 | if not wheel.supported(): | ||
| 148 | # Built for a different python/arch/etc | ||
| 149 | continue | ||
| 150 | candidates.append((wheel.support_index_min(), wheel_name)) | ||
| 151 | |||
| 152 | if not candidates: | ||
| 153 | return link | ||
| 154 | |||
| 155 | return self._link_for_candidate(link, min(candidates)[1]) | ||
| 156 | |||
| 157 | |||
| 158 | class EphemWheelCache(SimpleWheelCache): | ||
| 159 | """A SimpleWheelCache that creates it's own temporary cache directory | ||
| 160 | """ | ||
| 161 | |||
| 162 | def __init__(self, format_control): | ||
| 163 | self._temp_dir = TempDirectory(kind="ephem-wheel-cache") | ||
| 164 | self._temp_dir.create() | ||
| 165 | |||
| 166 | super(EphemWheelCache, self).__init__( | ||
| 167 | self._temp_dir.path, format_control | ||
| 168 | ) | ||
| 169 | |||
| 170 | def cleanup(self): | ||
| 171 | self._temp_dir.cleanup() | ||
| 172 | |||
| 173 | |||
| 174 | class WheelCache(Cache): | ||
| 175 | """Wraps EphemWheelCache and SimpleWheelCache into a single Cache | ||
| 176 | |||
| 177 | This Cache allows for gracefully degradation, using the ephem wheel cache | ||
| 178 | when a certain link is not found in the simple wheel cache first. | ||
| 179 | """ | ||
| 180 | |||
| 181 | def __init__(self, cache_dir, format_control): | ||
| 182 | super(WheelCache, self).__init__( | ||
| 183 | cache_dir, format_control, {'binary'} | ||
| 184 | ) | ||
| 185 | self._wheel_cache = SimpleWheelCache(cache_dir, format_control) | ||
| 186 | self._ephem_cache = EphemWheelCache(format_control) | ||
| 187 | |||
| 188 | def get_path_for_link(self, link): | ||
| 189 | return self._wheel_cache.get_path_for_link(link) | ||
| 190 | |||
| 191 | def get_ephem_path_for_link(self, link): | ||
| 192 | return self._ephem_cache.get_path_for_link(link) | ||
| 193 | |||
| 194 | def get(self, link, package_name): | ||
| 195 | retval = self._wheel_cache.get(link, package_name) | ||
| 196 | if retval is link: | ||
| 197 | retval = self._ephem_cache.get(link, package_name) | ||
| 198 | return retval | ||
| 199 | |||
| 200 | def cleanup(self): | ||
| 201 | self._wheel_cache.cleanup() | ||
| 202 | self._ephem_cache.cleanup() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/cmdoptions.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/cmdoptions.py deleted file mode 100644 index 58854e3..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/cmdoptions.py +++ /dev/null | |||
| @@ -1,609 +0,0 @@ | |||
| 1 | """ | ||
| 2 | shared options and groups | ||
| 3 | |||
| 4 | The principle here is to define options once, but *not* instantiate them | ||
| 5 | globally. One reason being that options with action='append' can carry state | ||
| 6 | between parses. pip parses general options twice internally, and shouldn't | ||
| 7 | pass on state. To be consistent, all options will follow this design. | ||
| 8 | |||
| 9 | """ | ||
| 10 | from __future__ import absolute_import | ||
| 11 | |||
| 12 | import warnings | ||
| 13 | from functools import partial | ||
| 14 | from optparse import SUPPRESS_HELP, Option, OptionGroup | ||
| 15 | |||
| 16 | from pip._internal.index import ( | ||
| 17 | FormatControl, fmt_ctl_handle_mutual_exclude, fmt_ctl_no_binary, | ||
| 18 | ) | ||
| 19 | from pip._internal.locations import USER_CACHE_DIR, src_prefix | ||
| 20 | from pip._internal.models import PyPI | ||
| 21 | from pip._internal.utils.hashes import STRONG_HASHES | ||
| 22 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 23 | from pip._internal.utils.ui import BAR_TYPES | ||
| 24 | |||
| 25 | if MYPY_CHECK_RUNNING: | ||
| 26 | from typing import Any | ||
| 27 | |||
| 28 | |||
| 29 | def make_option_group(group, parser): | ||
| 30 | """ | ||
| 31 | Return an OptionGroup object | ||
| 32 | group -- assumed to be dict with 'name' and 'options' keys | ||
| 33 | parser -- an optparse Parser | ||
| 34 | """ | ||
| 35 | option_group = OptionGroup(parser, group['name']) | ||
| 36 | for option in group['options']: | ||
| 37 | option_group.add_option(option()) | ||
| 38 | return option_group | ||
| 39 | |||
| 40 | |||
| 41 | def check_install_build_global(options, check_options=None): | ||
| 42 | """Disable wheels if per-setup.py call options are set. | ||
| 43 | |||
| 44 | :param options: The OptionParser options to update. | ||
| 45 | :param check_options: The options to check, if not supplied defaults to | ||
| 46 | options. | ||
| 47 | """ | ||
| 48 | if check_options is None: | ||
| 49 | check_options = options | ||
| 50 | |||
| 51 | def getname(n): | ||
| 52 | return getattr(check_options, n, None) | ||
| 53 | names = ["build_options", "global_options", "install_options"] | ||
| 54 | if any(map(getname, names)): | ||
| 55 | control = options.format_control | ||
| 56 | fmt_ctl_no_binary(control) | ||
| 57 | warnings.warn( | ||
| 58 | 'Disabling all use of wheels due to the use of --build-options ' | ||
| 59 | '/ --global-options / --install-options.', stacklevel=2, | ||
| 60 | ) | ||
| 61 | |||
| 62 | |||
| 63 | ########### | ||
| 64 | # options # | ||
| 65 | ########### | ||
| 66 | |||
| 67 | help_ = partial( | ||
| 68 | Option, | ||
| 69 | '-h', '--help', | ||
| 70 | dest='help', | ||
| 71 | action='help', | ||
| 72 | help='Show help.', | ||
| 73 | ) # type: Any | ||
| 74 | |||
| 75 | isolated_mode = partial( | ||
| 76 | Option, | ||
| 77 | "--isolated", | ||
| 78 | dest="isolated_mode", | ||
| 79 | action="store_true", | ||
| 80 | default=False, | ||
| 81 | help=( | ||
| 82 | "Run pip in an isolated mode, ignoring environment variables and user " | ||
| 83 | "configuration." | ||
| 84 | ), | ||
| 85 | ) | ||
| 86 | |||
| 87 | require_virtualenv = partial( | ||
| 88 | Option, | ||
| 89 | # Run only if inside a virtualenv, bail if not. | ||
| 90 | '--require-virtualenv', '--require-venv', | ||
| 91 | dest='require_venv', | ||
| 92 | action='store_true', | ||
| 93 | default=False, | ||
| 94 | help=SUPPRESS_HELP | ||
| 95 | ) # type: Any | ||
| 96 | |||
| 97 | verbose = partial( | ||
| 98 | Option, | ||
| 99 | '-v', '--verbose', | ||
| 100 | dest='verbose', | ||
| 101 | action='count', | ||
| 102 | default=0, | ||
| 103 | help='Give more output. Option is additive, and can be used up to 3 times.' | ||
| 104 | ) | ||
| 105 | |||
| 106 | no_color = partial( | ||
| 107 | Option, | ||
| 108 | '--no-color', | ||
| 109 | dest='no_color', | ||
| 110 | action='store_true', | ||
| 111 | default=False, | ||
| 112 | help="Suppress colored output", | ||
| 113 | ) | ||
| 114 | |||
| 115 | version = partial( | ||
| 116 | Option, | ||
| 117 | '-V', '--version', | ||
| 118 | dest='version', | ||
| 119 | action='store_true', | ||
| 120 | help='Show version and exit.', | ||
| 121 | ) # type: Any | ||
| 122 | |||
| 123 | quiet = partial( | ||
| 124 | Option, | ||
| 125 | '-q', '--quiet', | ||
| 126 | dest='quiet', | ||
| 127 | action='count', | ||
| 128 | default=0, | ||
| 129 | help=( | ||
| 130 | 'Give less output. Option is additive, and can be used up to 3' | ||
| 131 | ' times (corresponding to WARNING, ERROR, and CRITICAL logging' | ||
| 132 | ' levels).' | ||
| 133 | ), | ||
| 134 | ) # type: Any | ||
| 135 | |||
| 136 | progress_bar = partial( | ||
| 137 | Option, | ||
| 138 | '--progress-bar', | ||
| 139 | dest='progress_bar', | ||
| 140 | type='choice', | ||
| 141 | choices=list(BAR_TYPES.keys()), | ||
| 142 | default='on', | ||
| 143 | help=( | ||
| 144 | 'Specify type of progress to be displayed [' + | ||
| 145 | '|'.join(BAR_TYPES.keys()) + '] (default: %default)' | ||
| 146 | ), | ||
| 147 | ) # type: Any | ||
| 148 | |||
| 149 | log = partial( | ||
| 150 | Option, | ||
| 151 | "--log", "--log-file", "--local-log", | ||
| 152 | dest="log", | ||
| 153 | metavar="path", | ||
| 154 | help="Path to a verbose appending log." | ||
| 155 | ) # type: Any | ||
| 156 | |||
| 157 | no_input = partial( | ||
| 158 | Option, | ||
| 159 | # Don't ask for input | ||
| 160 | '--no-input', | ||
| 161 | dest='no_input', | ||
| 162 | action='store_true', | ||
| 163 | default=False, | ||
| 164 | help=SUPPRESS_HELP | ||
| 165 | ) # type: Any | ||
| 166 | |||
| 167 | proxy = partial( | ||
| 168 | Option, | ||
| 169 | '--proxy', | ||
| 170 | dest='proxy', | ||
| 171 | type='str', | ||
| 172 | default='', | ||
| 173 | help="Specify a proxy in the form [user:passwd@]proxy.server:port." | ||
| 174 | ) # type: Any | ||
| 175 | |||
| 176 | retries = partial( | ||
| 177 | Option, | ||
| 178 | '--retries', | ||
| 179 | dest='retries', | ||
| 180 | type='int', | ||
| 181 | default=5, | ||
| 182 | help="Maximum number of retries each connection should attempt " | ||
| 183 | "(default %default times).", | ||
| 184 | ) # type: Any | ||
| 185 | |||
| 186 | timeout = partial( | ||
| 187 | Option, | ||
| 188 | '--timeout', '--default-timeout', | ||
| 189 | metavar='sec', | ||
| 190 | dest='timeout', | ||
| 191 | type='float', | ||
| 192 | default=15, | ||
| 193 | help='Set the socket timeout (default %default seconds).', | ||
| 194 | ) # type: Any | ||
| 195 | |||
| 196 | skip_requirements_regex = partial( | ||
| 197 | Option, | ||
| 198 | # A regex to be used to skip requirements | ||
| 199 | '--skip-requirements-regex', | ||
| 200 | dest='skip_requirements_regex', | ||
| 201 | type='str', | ||
| 202 | default='', | ||
| 203 | help=SUPPRESS_HELP, | ||
| 204 | ) # type: Any | ||
| 205 | |||
| 206 | |||
| 207 | def exists_action(): | ||
| 208 | return Option( | ||
| 209 | # Option when path already exist | ||
| 210 | '--exists-action', | ||
| 211 | dest='exists_action', | ||
| 212 | type='choice', | ||
| 213 | choices=['s', 'i', 'w', 'b', 'a'], | ||
| 214 | default=[], | ||
| 215 | action='append', | ||
| 216 | metavar='action', | ||
| 217 | help="Default action when a path already exists: " | ||
| 218 | "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort).", | ||
| 219 | ) | ||
| 220 | |||
| 221 | |||
| 222 | cert = partial( | ||
| 223 | Option, | ||
| 224 | '--cert', | ||
| 225 | dest='cert', | ||
| 226 | type='str', | ||
| 227 | metavar='path', | ||
| 228 | help="Path to alternate CA bundle.", | ||
| 229 | ) # type: Any | ||
| 230 | |||
| 231 | client_cert = partial( | ||
| 232 | Option, | ||
| 233 | '--client-cert', | ||
| 234 | dest='client_cert', | ||
| 235 | type='str', | ||
| 236 | default=None, | ||
| 237 | metavar='path', | ||
| 238 | help="Path to SSL client certificate, a single file containing the " | ||
| 239 | "private key and the certificate in PEM format.", | ||
| 240 | ) # type: Any | ||
| 241 | |||
| 242 | index_url = partial( | ||
| 243 | Option, | ||
| 244 | '-i', '--index-url', '--pypi-url', | ||
| 245 | dest='index_url', | ||
| 246 | metavar='URL', | ||
| 247 | default=PyPI.simple_url, | ||
| 248 | help="Base URL of Python Package Index (default %default). " | ||
| 249 | "This should point to a repository compliant with PEP 503 " | ||
| 250 | "(the simple repository API) or a local directory laid out " | ||
| 251 | "in the same format.", | ||
| 252 | ) # type: Any | ||
| 253 | |||
| 254 | |||
| 255 | def extra_index_url(): | ||
| 256 | return Option( | ||
| 257 | '--extra-index-url', | ||
| 258 | dest='extra_index_urls', | ||
| 259 | metavar='URL', | ||
| 260 | action='append', | ||
| 261 | default=[], | ||
| 262 | help="Extra URLs of package indexes to use in addition to " | ||
| 263 | "--index-url. Should follow the same rules as " | ||
| 264 | "--index-url.", | ||
| 265 | ) | ||
| 266 | |||
| 267 | |||
| 268 | no_index = partial( | ||
| 269 | Option, | ||
| 270 | '--no-index', | ||
| 271 | dest='no_index', | ||
| 272 | action='store_true', | ||
| 273 | default=False, | ||
| 274 | help='Ignore package index (only looking at --find-links URLs instead).', | ||
| 275 | ) # type: Any | ||
| 276 | |||
| 277 | |||
| 278 | def find_links(): | ||
| 279 | return Option( | ||
| 280 | '-f', '--find-links', | ||
| 281 | dest='find_links', | ||
| 282 | action='append', | ||
| 283 | default=[], | ||
| 284 | metavar='url', | ||
| 285 | help="If a url or path to an html file, then parse for links to " | ||
| 286 | "archives. If a local path or file:// url that's a directory, " | ||
| 287 | "then look for archives in the directory listing.", | ||
| 288 | ) | ||
| 289 | |||
| 290 | |||
| 291 | def trusted_host(): | ||
| 292 | return Option( | ||
| 293 | "--trusted-host", | ||
| 294 | dest="trusted_hosts", | ||
| 295 | action="append", | ||
| 296 | metavar="HOSTNAME", | ||
| 297 | default=[], | ||
| 298 | help="Mark this host as trusted, even though it does not have valid " | ||
| 299 | "or any HTTPS.", | ||
| 300 | ) | ||
| 301 | |||
| 302 | |||
| 303 | # Remove after 1.5 | ||
| 304 | process_dependency_links = partial( | ||
| 305 | Option, | ||
| 306 | "--process-dependency-links", | ||
| 307 | dest="process_dependency_links", | ||
| 308 | action="store_true", | ||
| 309 | default=False, | ||
| 310 | help="Enable the processing of dependency links.", | ||
| 311 | ) # type: Any | ||
| 312 | |||
| 313 | |||
| 314 | def constraints(): | ||
| 315 | return Option( | ||
| 316 | '-c', '--constraint', | ||
| 317 | dest='constraints', | ||
| 318 | action='append', | ||
| 319 | default=[], | ||
| 320 | metavar='file', | ||
| 321 | help='Constrain versions using the given constraints file. ' | ||
| 322 | 'This option can be used multiple times.' | ||
| 323 | ) | ||
| 324 | |||
| 325 | |||
| 326 | def requirements(): | ||
| 327 | return Option( | ||
| 328 | '-r', '--requirement', | ||
| 329 | dest='requirements', | ||
| 330 | action='append', | ||
| 331 | default=[], | ||
| 332 | metavar='file', | ||
| 333 | help='Install from the given requirements file. ' | ||
| 334 | 'This option can be used multiple times.' | ||
| 335 | ) | ||
| 336 | |||
| 337 | |||
| 338 | def editable(): | ||
| 339 | return Option( | ||
| 340 | '-e', '--editable', | ||
| 341 | dest='editables', | ||
| 342 | action='append', | ||
| 343 | default=[], | ||
| 344 | metavar='path/url', | ||
| 345 | help=('Install a project in editable mode (i.e. setuptools ' | ||
| 346 | '"develop mode") from a local project path or a VCS url.'), | ||
| 347 | ) | ||
| 348 | |||
| 349 | |||
| 350 | src = partial( | ||
| 351 | Option, | ||
| 352 | '--src', '--source', '--source-dir', '--source-directory', | ||
| 353 | dest='src_dir', | ||
| 354 | metavar='dir', | ||
| 355 | default=src_prefix, | ||
| 356 | help='Directory to check out editable projects into. ' | ||
| 357 | 'The default in a virtualenv is "<venv path>/src". ' | ||
| 358 | 'The default for global installs is "<current dir>/src".' | ||
| 359 | ) # type: Any | ||
| 360 | |||
| 361 | |||
| 362 | def _get_format_control(values, option): | ||
| 363 | """Get a format_control object.""" | ||
| 364 | return getattr(values, option.dest) | ||
| 365 | |||
| 366 | |||
| 367 | def _handle_no_binary(option, opt_str, value, parser): | ||
| 368 | existing = getattr(parser.values, option.dest) | ||
| 369 | fmt_ctl_handle_mutual_exclude( | ||
| 370 | value, existing.no_binary, existing.only_binary, | ||
| 371 | ) | ||
| 372 | |||
| 373 | |||
| 374 | def _handle_only_binary(option, opt_str, value, parser): | ||
| 375 | existing = getattr(parser.values, option.dest) | ||
| 376 | fmt_ctl_handle_mutual_exclude( | ||
| 377 | value, existing.only_binary, existing.no_binary, | ||
| 378 | ) | ||
| 379 | |||
| 380 | |||
| 381 | def no_binary(): | ||
| 382 | return Option( | ||
| 383 | "--no-binary", dest="format_control", action="callback", | ||
| 384 | callback=_handle_no_binary, type="str", | ||
| 385 | default=FormatControl(set(), set()), | ||
| 386 | help="Do not use binary packages. Can be supplied multiple times, and " | ||
| 387 | "each time adds to the existing value. Accepts either :all: to " | ||
| 388 | "disable all binary packages, :none: to empty the set, or one or " | ||
| 389 | "more package names with commas between them. Note that some " | ||
| 390 | "packages are tricky to compile and may fail to install when " | ||
| 391 | "this option is used on them.", | ||
| 392 | ) | ||
| 393 | |||
| 394 | |||
| 395 | def only_binary(): | ||
| 396 | return Option( | ||
| 397 | "--only-binary", dest="format_control", action="callback", | ||
| 398 | callback=_handle_only_binary, type="str", | ||
| 399 | default=FormatControl(set(), set()), | ||
| 400 | help="Do not use source packages. Can be supplied multiple times, and " | ||
| 401 | "each time adds to the existing value. Accepts either :all: to " | ||
| 402 | "disable all source packages, :none: to empty the set, or one or " | ||
| 403 | "more package names with commas between them. Packages without " | ||
| 404 | "binary distributions will fail to install when this option is " | ||
| 405 | "used on them.", | ||
| 406 | ) | ||
| 407 | |||
| 408 | |||
| 409 | cache_dir = partial( | ||
| 410 | Option, | ||
| 411 | "--cache-dir", | ||
| 412 | dest="cache_dir", | ||
| 413 | default=USER_CACHE_DIR, | ||
| 414 | metavar="dir", | ||
| 415 | help="Store the cache data in <dir>." | ||
| 416 | ) | ||
| 417 | |||
| 418 | no_cache = partial( | ||
| 419 | Option, | ||
| 420 | "--no-cache-dir", | ||
| 421 | dest="cache_dir", | ||
| 422 | action="store_false", | ||
| 423 | help="Disable the cache.", | ||
| 424 | ) | ||
| 425 | |||
| 426 | no_deps = partial( | ||
| 427 | Option, | ||
| 428 | '--no-deps', '--no-dependencies', | ||
| 429 | dest='ignore_dependencies', | ||
| 430 | action='store_true', | ||
| 431 | default=False, | ||
| 432 | help="Don't install package dependencies.", | ||
| 433 | ) # type: Any | ||
| 434 | |||
| 435 | build_dir = partial( | ||
| 436 | Option, | ||
| 437 | '-b', '--build', '--build-dir', '--build-directory', | ||
| 438 | dest='build_dir', | ||
| 439 | metavar='dir', | ||
| 440 | help='Directory to unpack packages into and build in. Note that ' | ||
| 441 | 'an initial build still takes place in a temporary directory. ' | ||
| 442 | 'The location of temporary directories can be controlled by setting ' | ||
| 443 | 'the TMPDIR environment variable (TEMP on Windows) appropriately. ' | ||
| 444 | 'When passed, build directories are not cleaned in case of failures.' | ||
| 445 | ) # type: Any | ||
| 446 | |||
| 447 | ignore_requires_python = partial( | ||
| 448 | Option, | ||
| 449 | '--ignore-requires-python', | ||
| 450 | dest='ignore_requires_python', | ||
| 451 | action='store_true', | ||
| 452 | help='Ignore the Requires-Python information.' | ||
| 453 | ) # type: Any | ||
| 454 | |||
| 455 | no_build_isolation = partial( | ||
| 456 | Option, | ||
| 457 | '--no-build-isolation', | ||
| 458 | dest='build_isolation', | ||
| 459 | action='store_false', | ||
| 460 | default=True, | ||
| 461 | help='Disable isolation when building a modern source distribution. ' | ||
| 462 | 'Build dependencies specified by PEP 518 must be already installed ' | ||
| 463 | 'if this option is used.' | ||
| 464 | ) # type: Any | ||
| 465 | |||
| 466 | install_options = partial( | ||
| 467 | Option, | ||
| 468 | '--install-option', | ||
| 469 | dest='install_options', | ||
| 470 | action='append', | ||
| 471 | metavar='options', | ||
| 472 | help="Extra arguments to be supplied to the setup.py install " | ||
| 473 | "command (use like --install-option=\"--install-scripts=/usr/local/" | ||
| 474 | "bin\"). Use multiple --install-option options to pass multiple " | ||
| 475 | "options to setup.py install. If you are using an option with a " | ||
| 476 | "directory path, be sure to use absolute path.", | ||
| 477 | ) # type: Any | ||
| 478 | |||
| 479 | global_options = partial( | ||
| 480 | Option, | ||
| 481 | '--global-option', | ||
| 482 | dest='global_options', | ||
| 483 | action='append', | ||
| 484 | metavar='options', | ||
| 485 | help="Extra global options to be supplied to the setup.py " | ||
| 486 | "call before the install command.", | ||
| 487 | ) # type: Any | ||
| 488 | |||
| 489 | no_clean = partial( | ||
| 490 | Option, | ||
| 491 | '--no-clean', | ||
| 492 | action='store_true', | ||
| 493 | default=False, | ||
| 494 | help="Don't clean up build directories)." | ||
| 495 | ) # type: Any | ||
| 496 | |||
| 497 | pre = partial( | ||
| 498 | Option, | ||
| 499 | '--pre', | ||
| 500 | action='store_true', | ||
| 501 | default=False, | ||
| 502 | help="Include pre-release and development versions. By default, " | ||
| 503 | "pip only finds stable versions.", | ||
| 504 | ) # type: Any | ||
| 505 | |||
| 506 | disable_pip_version_check = partial( | ||
| 507 | Option, | ||
| 508 | "--disable-pip-version-check", | ||
| 509 | dest="disable_pip_version_check", | ||
| 510 | action="store_true", | ||
| 511 | default=False, | ||
| 512 | help="Don't periodically check PyPI to determine whether a new version " | ||
| 513 | "of pip is available for download. Implied with --no-index.", | ||
| 514 | ) # type: Any | ||
| 515 | |||
| 516 | |||
| 517 | # Deprecated, Remove later | ||
| 518 | always_unzip = partial( | ||
| 519 | Option, | ||
| 520 | '-Z', '--always-unzip', | ||
| 521 | dest='always_unzip', | ||
| 522 | action='store_true', | ||
| 523 | help=SUPPRESS_HELP, | ||
| 524 | ) # type: Any | ||
| 525 | |||
| 526 | |||
| 527 | def _merge_hash(option, opt_str, value, parser): | ||
| 528 | """Given a value spelled "algo:digest", append the digest to a list | ||
| 529 | pointed to in a dict by the algo name.""" | ||
| 530 | if not parser.values.hashes: | ||
| 531 | parser.values.hashes = {} | ||
| 532 | try: | ||
| 533 | algo, digest = value.split(':', 1) | ||
| 534 | except ValueError: | ||
| 535 | parser.error('Arguments to %s must be a hash name ' | ||
| 536 | 'followed by a value, like --hash=sha256:abcde...' % | ||
| 537 | opt_str) | ||
| 538 | if algo not in STRONG_HASHES: | ||
| 539 | parser.error('Allowed hash algorithms for %s are %s.' % | ||
| 540 | (opt_str, ', '.join(STRONG_HASHES))) | ||
| 541 | parser.values.hashes.setdefault(algo, []).append(digest) | ||
| 542 | |||
| 543 | |||
| 544 | hash = partial( | ||
| 545 | Option, | ||
| 546 | '--hash', | ||
| 547 | # Hash values eventually end up in InstallRequirement.hashes due to | ||
| 548 | # __dict__ copying in process_line(). | ||
| 549 | dest='hashes', | ||
| 550 | action='callback', | ||
| 551 | callback=_merge_hash, | ||
| 552 | type='string', | ||
| 553 | help="Verify that the package's archive matches this " | ||
| 554 | 'hash before installing. Example: --hash=sha256:abcdef...', | ||
| 555 | ) # type: Any | ||
| 556 | |||
| 557 | |||
| 558 | require_hashes = partial( | ||
| 559 | Option, | ||
| 560 | '--require-hashes', | ||
| 561 | dest='require_hashes', | ||
| 562 | action='store_true', | ||
| 563 | default=False, | ||
| 564 | help='Require a hash to check each requirement against, for ' | ||
| 565 | 'repeatable installs. This option is implied when any package in a ' | ||
| 566 | 'requirements file has a --hash option.', | ||
| 567 | ) # type: Any | ||
| 568 | |||
| 569 | |||
| 570 | ########## | ||
| 571 | # groups # | ||
| 572 | ########## | ||
| 573 | |||
| 574 | general_group = { | ||
| 575 | 'name': 'General Options', | ||
| 576 | 'options': [ | ||
| 577 | help_, | ||
| 578 | isolated_mode, | ||
| 579 | require_virtualenv, | ||
| 580 | verbose, | ||
| 581 | version, | ||
| 582 | quiet, | ||
| 583 | log, | ||
| 584 | no_input, | ||
| 585 | proxy, | ||
| 586 | retries, | ||
| 587 | timeout, | ||
| 588 | skip_requirements_regex, | ||
| 589 | exists_action, | ||
| 590 | trusted_host, | ||
| 591 | cert, | ||
| 592 | client_cert, | ||
| 593 | cache_dir, | ||
| 594 | no_cache, | ||
| 595 | disable_pip_version_check, | ||
| 596 | no_color, | ||
| 597 | ] | ||
| 598 | } | ||
| 599 | |||
| 600 | index_group = { | ||
| 601 | 'name': 'Package Index Options', | ||
| 602 | 'options': [ | ||
| 603 | index_url, | ||
| 604 | extra_index_url, | ||
| 605 | no_index, | ||
| 606 | find_links, | ||
| 607 | process_dependency_links, | ||
| 608 | ] | ||
| 609 | } | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/__init__.py deleted file mode 100644 index d44e6f1..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/__init__.py +++ /dev/null | |||
| @@ -1,79 +0,0 @@ | |||
| 1 | """ | ||
| 2 | Package containing all pip commands | ||
| 3 | """ | ||
| 4 | from __future__ import absolute_import | ||
| 5 | |||
| 6 | from pip._internal.commands.completion import CompletionCommand | ||
| 7 | from pip._internal.commands.configuration import ConfigurationCommand | ||
| 8 | from pip._internal.commands.download import DownloadCommand | ||
| 9 | from pip._internal.commands.freeze import FreezeCommand | ||
| 10 | from pip._internal.commands.hash import HashCommand | ||
| 11 | from pip._internal.commands.help import HelpCommand | ||
| 12 | from pip._internal.commands.list import ListCommand | ||
| 13 | from pip._internal.commands.check import CheckCommand | ||
| 14 | from pip._internal.commands.search import SearchCommand | ||
| 15 | from pip._internal.commands.show import ShowCommand | ||
| 16 | from pip._internal.commands.install import InstallCommand | ||
| 17 | from pip._internal.commands.uninstall import UninstallCommand | ||
| 18 | from pip._internal.commands.wheel import WheelCommand | ||
| 19 | |||
| 20 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 21 | |||
| 22 | if MYPY_CHECK_RUNNING: | ||
| 23 | from typing import List, Type | ||
| 24 | from pip._internal.basecommand import Command | ||
| 25 | |||
| 26 | commands_order = [ | ||
| 27 | InstallCommand, | ||
| 28 | DownloadCommand, | ||
| 29 | UninstallCommand, | ||
| 30 | FreezeCommand, | ||
| 31 | ListCommand, | ||
| 32 | ShowCommand, | ||
| 33 | CheckCommand, | ||
| 34 | ConfigurationCommand, | ||
| 35 | SearchCommand, | ||
| 36 | WheelCommand, | ||
| 37 | HashCommand, | ||
| 38 | CompletionCommand, | ||
| 39 | HelpCommand, | ||
| 40 | ] # type: List[Type[Command]] | ||
| 41 | |||
| 42 | commands_dict = {c.name: c for c in commands_order} | ||
| 43 | |||
| 44 | |||
| 45 | def get_summaries(ordered=True): | ||
| 46 | """Yields sorted (command name, command summary) tuples.""" | ||
| 47 | |||
| 48 | if ordered: | ||
| 49 | cmditems = _sort_commands(commands_dict, commands_order) | ||
| 50 | else: | ||
| 51 | cmditems = commands_dict.items() | ||
| 52 | |||
| 53 | for name, command_class in cmditems: | ||
| 54 | yield (name, command_class.summary) | ||
| 55 | |||
| 56 | |||
| 57 | def get_similar_commands(name): | ||
| 58 | """Command name auto-correct.""" | ||
| 59 | from difflib import get_close_matches | ||
| 60 | |||
| 61 | name = name.lower() | ||
| 62 | |||
| 63 | close_commands = get_close_matches(name, commands_dict.keys()) | ||
| 64 | |||
| 65 | if close_commands: | ||
| 66 | return close_commands[0] | ||
| 67 | else: | ||
| 68 | return False | ||
| 69 | |||
| 70 | |||
| 71 | def _sort_commands(cmddict, order): | ||
| 72 | def keyfn(key): | ||
| 73 | try: | ||
| 74 | return order.index(key[1]) | ||
| 75 | except ValueError: | ||
| 76 | # unordered items should come last | ||
| 77 | return 0xff | ||
| 78 | |||
| 79 | return sorted(cmddict.items(), key=keyfn) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/check.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/check.py deleted file mode 100644 index b1bf38a..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/check.py +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | import logging | ||
| 2 | |||
| 3 | from pip._internal.basecommand import Command | ||
| 4 | from pip._internal.operations.check import ( | ||
| 5 | check_package_set, create_package_set_from_installed, | ||
| 6 | ) | ||
| 7 | from pip._internal.utils.misc import get_installed_distributions | ||
| 8 | |||
| 9 | logger = logging.getLogger(__name__) | ||
| 10 | |||
| 11 | |||
| 12 | class CheckCommand(Command): | ||
| 13 | """Verify installed packages have compatible dependencies.""" | ||
| 14 | name = 'check' | ||
| 15 | usage = """ | ||
| 16 | %prog [options]""" | ||
| 17 | summary = 'Verify installed packages have compatible dependencies.' | ||
| 18 | |||
| 19 | def run(self, options, args): | ||
| 20 | package_set = create_package_set_from_installed() | ||
| 21 | missing, conflicting = check_package_set(package_set) | ||
| 22 | |||
| 23 | for project_name in missing: | ||
| 24 | version = package_set[project_name].version | ||
| 25 | for dependency in missing[project_name]: | ||
| 26 | logger.info( | ||
| 27 | "%s %s requires %s, which is not installed.", | ||
| 28 | project_name, version, dependency[0], | ||
| 29 | ) | ||
| 30 | |||
| 31 | for project_name in conflicting: | ||
| 32 | version = package_set[project_name].version | ||
| 33 | for dep_name, dep_version, req in conflicting[project_name]: | ||
| 34 | logger.info( | ||
| 35 | "%s %s has requirement %s, but you have %s %s.", | ||
| 36 | project_name, version, req, dep_name, dep_version, | ||
| 37 | ) | ||
| 38 | |||
| 39 | if missing or conflicting: | ||
| 40 | return 1 | ||
| 41 | else: | ||
| 42 | logger.info("No broken requirements found.") | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/completion.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/completion.py deleted file mode 100644 index 8da1e83..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/completion.py +++ /dev/null | |||
| @@ -1,94 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import sys | ||
| 4 | import textwrap | ||
| 5 | |||
| 6 | from pip._internal.basecommand import Command | ||
| 7 | from pip._internal.utils.misc import get_prog | ||
| 8 | |||
| 9 | BASE_COMPLETION = """ | ||
| 10 | # pip %(shell)s completion start%(script)s# pip %(shell)s completion end | ||
| 11 | """ | ||
| 12 | |||
| 13 | COMPLETION_SCRIPTS = { | ||
| 14 | 'bash': """ | ||
| 15 | _pip_completion() | ||
| 16 | { | ||
| 17 | COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ | ||
| 18 | COMP_CWORD=$COMP_CWORD \\ | ||
| 19 | PIP_AUTO_COMPLETE=1 $1 ) ) | ||
| 20 | } | ||
| 21 | complete -o default -F _pip_completion %(prog)s | ||
| 22 | """, | ||
| 23 | 'zsh': """ | ||
| 24 | function _pip_completion { | ||
| 25 | local words cword | ||
| 26 | read -Ac words | ||
| 27 | read -cn cword | ||
| 28 | reply=( $( COMP_WORDS="$words[*]" \\ | ||
| 29 | COMP_CWORD=$(( cword-1 )) \\ | ||
| 30 | PIP_AUTO_COMPLETE=1 $words[1] ) ) | ||
| 31 | } | ||
| 32 | compctl -K _pip_completion %(prog)s | ||
| 33 | """, | ||
| 34 | 'fish': """ | ||
| 35 | function __fish_complete_pip | ||
| 36 | set -lx COMP_WORDS (commandline -o) "" | ||
| 37 | set -lx COMP_CWORD ( \\ | ||
| 38 | math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ | ||
| 39 | ) | ||
| 40 | set -lx PIP_AUTO_COMPLETE 1 | ||
| 41 | string split \\ -- (eval $COMP_WORDS[1]) | ||
| 42 | end | ||
| 43 | complete -fa "(__fish_complete_pip)" -c %(prog)s | ||
| 44 | """, | ||
| 45 | } | ||
| 46 | |||
| 47 | |||
| 48 | class CompletionCommand(Command): | ||
| 49 | """A helper command to be used for command completion.""" | ||
| 50 | name = 'completion' | ||
| 51 | summary = 'A helper command used for command completion.' | ||
| 52 | ignore_require_venv = True | ||
| 53 | |||
| 54 | def __init__(self, *args, **kw): | ||
| 55 | super(CompletionCommand, self).__init__(*args, **kw) | ||
| 56 | |||
| 57 | cmd_opts = self.cmd_opts | ||
| 58 | |||
| 59 | cmd_opts.add_option( | ||
| 60 | '--bash', '-b', | ||
| 61 | action='store_const', | ||
| 62 | const='bash', | ||
| 63 | dest='shell', | ||
| 64 | help='Emit completion code for bash') | ||
| 65 | cmd_opts.add_option( | ||
| 66 | '--zsh', '-z', | ||
| 67 | action='store_const', | ||
| 68 | const='zsh', | ||
| 69 | dest='shell', | ||
| 70 | help='Emit completion code for zsh') | ||
| 71 | cmd_opts.add_option( | ||
| 72 | '--fish', '-f', | ||
| 73 | action='store_const', | ||
| 74 | const='fish', | ||
| 75 | dest='shell', | ||
| 76 | help='Emit completion code for fish') | ||
| 77 | |||
| 78 | self.parser.insert_option_group(0, cmd_opts) | ||
| 79 | |||
| 80 | def run(self, options, args): | ||
| 81 | """Prints the completion code of the given shell""" | ||
| 82 | shells = COMPLETION_SCRIPTS.keys() | ||
| 83 | shell_options = ['--' + shell for shell in sorted(shells)] | ||
| 84 | if options.shell in shells: | ||
| 85 | script = textwrap.dedent( | ||
| 86 | COMPLETION_SCRIPTS.get(options.shell, '') % { | ||
| 87 | 'prog': get_prog(), | ||
| 88 | } | ||
| 89 | ) | ||
| 90 | print(BASE_COMPLETION % {'script': script, 'shell': options.shell}) | ||
| 91 | else: | ||
| 92 | sys.stderr.write( | ||
| 93 | 'ERROR: You must pass %s\n' % ' or '.join(shell_options) | ||
| 94 | ) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/configuration.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/configuration.py deleted file mode 100644 index e10d9a9..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/configuration.py +++ /dev/null | |||
| @@ -1,227 +0,0 @@ | |||
| 1 | import logging | ||
| 2 | import os | ||
| 3 | import subprocess | ||
| 4 | |||
| 5 | from pip._internal.basecommand import Command | ||
| 6 | from pip._internal.configuration import Configuration, kinds | ||
| 7 | from pip._internal.exceptions import PipError | ||
| 8 | from pip._internal.locations import venv_config_file | ||
| 9 | from pip._internal.status_codes import ERROR, SUCCESS | ||
| 10 | from pip._internal.utils.misc import get_prog | ||
| 11 | |||
| 12 | logger = logging.getLogger(__name__) | ||
| 13 | |||
| 14 | |||
| 15 | class ConfigurationCommand(Command): | ||
| 16 | """Manage local and global configuration. | ||
| 17 | |||
| 18 | Subcommands: | ||
| 19 | |||
| 20 | list: List the active configuration (or from the file specified) | ||
| 21 | edit: Edit the configuration file in an editor | ||
| 22 | get: Get the value associated with name | ||
| 23 | set: Set the name=value | ||
| 24 | unset: Unset the value associated with name | ||
| 25 | |||
| 26 | If none of --user, --global and --venv are passed, a virtual | ||
| 27 | environment configuration file is used if one is active and the file | ||
| 28 | exists. Otherwise, all modifications happen on the to the user file by | ||
| 29 | default. | ||
| 30 | """ | ||
| 31 | |||
| 32 | name = 'config' | ||
| 33 | usage = """ | ||
| 34 | %prog [<file-option>] list | ||
| 35 | %prog [<file-option>] [--editor <editor-path>] edit | ||
| 36 | |||
| 37 | %prog [<file-option>] get name | ||
| 38 | %prog [<file-option>] set name value | ||
| 39 | %prog [<file-option>] unset name | ||
| 40 | """ | ||
| 41 | |||
| 42 | summary = "Manage local and global configuration." | ||
| 43 | |||
| 44 | def __init__(self, *args, **kwargs): | ||
| 45 | super(ConfigurationCommand, self).__init__(*args, **kwargs) | ||
| 46 | |||
| 47 | self.configuration = None | ||
| 48 | |||
| 49 | self.cmd_opts.add_option( | ||
| 50 | '--editor', | ||
| 51 | dest='editor', | ||
| 52 | action='store', | ||
| 53 | default=None, | ||
| 54 | help=( | ||
| 55 | 'Editor to use to edit the file. Uses VISUAL or EDITOR ' | ||
| 56 | 'environment variables if not provided.' | ||
| 57 | ) | ||
| 58 | ) | ||
| 59 | |||
| 60 | self.cmd_opts.add_option( | ||
| 61 | '--global', | ||
| 62 | dest='global_file', | ||
| 63 | action='store_true', | ||
| 64 | default=False, | ||
| 65 | help='Use the system-wide configuration file only' | ||
| 66 | ) | ||
| 67 | |||
| 68 | self.cmd_opts.add_option( | ||
| 69 | '--user', | ||
| 70 | dest='user_file', | ||
| 71 | action='store_true', | ||
| 72 | default=False, | ||
| 73 | help='Use the user configuration file only' | ||
| 74 | ) | ||
| 75 | |||
| 76 | self.cmd_opts.add_option( | ||
| 77 | '--venv', | ||
| 78 | dest='venv_file', | ||
| 79 | action='store_true', | ||
| 80 | default=False, | ||
| 81 | help='Use the virtualenv configuration file only' | ||
| 82 | ) | ||
| 83 | |||
| 84 | self.parser.insert_option_group(0, self.cmd_opts) | ||
| 85 | |||
| 86 | def run(self, options, args): | ||
| 87 | handlers = { | ||
| 88 | "list": self.list_values, | ||
| 89 | "edit": self.open_in_editor, | ||
| 90 | "get": self.get_name, | ||
| 91 | "set": self.set_name_value, | ||
| 92 | "unset": self.unset_name | ||
| 93 | } | ||
| 94 | |||
| 95 | # Determine action | ||
| 96 | if not args or args[0] not in handlers: | ||
| 97 | logger.error("Need an action ({}) to perform.".format( | ||
| 98 | ", ".join(sorted(handlers))) | ||
| 99 | ) | ||
| 100 | return ERROR | ||
| 101 | |||
| 102 | action = args[0] | ||
| 103 | |||
| 104 | # Determine which configuration files are to be loaded | ||
| 105 | # Depends on whether the command is modifying. | ||
| 106 | try: | ||
| 107 | load_only = self._determine_file( | ||
| 108 | options, need_value=(action in ["get", "set", "unset", "edit"]) | ||
| 109 | ) | ||
| 110 | except PipError as e: | ||
| 111 | logger.error(e.args[0]) | ||
| 112 | return ERROR | ||
| 113 | |||
| 114 | # Load a new configuration | ||
| 115 | self.configuration = Configuration( | ||
| 116 | isolated=options.isolated_mode, load_only=load_only | ||
| 117 | ) | ||
| 118 | self.configuration.load() | ||
| 119 | |||
| 120 | # Error handling happens here, not in the action-handlers. | ||
| 121 | try: | ||
| 122 | handlers[action](options, args[1:]) | ||
| 123 | except PipError as e: | ||
| 124 | logger.error(e.args[0]) | ||
| 125 | return ERROR | ||
| 126 | |||
| 127 | return SUCCESS | ||
| 128 | |||
| 129 | def _determine_file(self, options, need_value): | ||
| 130 | file_options = { | ||
| 131 | kinds.USER: options.user_file, | ||
| 132 | kinds.GLOBAL: options.global_file, | ||
| 133 | kinds.VENV: options.venv_file | ||
| 134 | } | ||
| 135 | |||
| 136 | if sum(file_options.values()) == 0: | ||
| 137 | if not need_value: | ||
| 138 | return None | ||
| 139 | # Default to user, unless there's a virtualenv file. | ||
| 140 | elif os.path.exists(venv_config_file): | ||
| 141 | return kinds.VENV | ||
| 142 | else: | ||
| 143 | return kinds.USER | ||
| 144 | elif sum(file_options.values()) == 1: | ||
| 145 | # There's probably a better expression for this. | ||
| 146 | return [key for key in file_options if file_options[key]][0] | ||
| 147 | |||
| 148 | raise PipError( | ||
| 149 | "Need exactly one file to operate upon " | ||
| 150 | "(--user, --venv, --global) to perform." | ||
| 151 | ) | ||
| 152 | |||
| 153 | def list_values(self, options, args): | ||
| 154 | self._get_n_args(args, "list", n=0) | ||
| 155 | |||
| 156 | for key, value in sorted(self.configuration.items()): | ||
| 157 | logger.info("%s=%r", key, value) | ||
| 158 | |||
| 159 | def get_name(self, options, args): | ||
| 160 | key = self._get_n_args(args, "get [name]", n=1) | ||
| 161 | value = self.configuration.get_value(key) | ||
| 162 | |||
| 163 | logger.info("%s", value) | ||
| 164 | |||
| 165 | def set_name_value(self, options, args): | ||
| 166 | key, value = self._get_n_args(args, "set [name] [value]", n=2) | ||
| 167 | self.configuration.set_value(key, value) | ||
| 168 | |||
| 169 | self._save_configuration() | ||
| 170 | |||
| 171 | def unset_name(self, options, args): | ||
| 172 | key = self._get_n_args(args, "unset [name]", n=1) | ||
| 173 | self.configuration.unset_value(key) | ||
| 174 | |||
| 175 | self._save_configuration() | ||
| 176 | |||
| 177 | def open_in_editor(self, options, args): | ||
| 178 | editor = self._determine_editor(options) | ||
| 179 | |||
| 180 | fname = self.configuration.get_file_to_edit() | ||
| 181 | if fname is None: | ||
| 182 | raise PipError("Could not determine appropriate file.") | ||
| 183 | |||
| 184 | try: | ||
| 185 | subprocess.check_call([editor, fname]) | ||
| 186 | except subprocess.CalledProcessError as e: | ||
| 187 | raise PipError( | ||
| 188 | "Editor Subprocess exited with exit code {}" | ||
| 189 | .format(e.returncode) | ||
| 190 | ) | ||
| 191 | |||
| 192 | def _get_n_args(self, args, example, n): | ||
| 193 | """Helper to make sure the command got the right number of arguments | ||
| 194 | """ | ||
| 195 | if len(args) != n: | ||
| 196 | msg = ( | ||
| 197 | 'Got unexpected number of arguments, expected {}. ' | ||
| 198 | '(example: "{} config {}")' | ||
| 199 | ).format(n, get_prog(), example) | ||
| 200 | raise PipError(msg) | ||
| 201 | |||
| 202 | if n == 1: | ||
| 203 | return args[0] | ||
| 204 | else: | ||
| 205 | return args | ||
| 206 | |||
| 207 | def _save_configuration(self): | ||
| 208 | # We successfully ran a modifying command. Need to save the | ||
| 209 | # configuration. | ||
| 210 | try: | ||
| 211 | self.configuration.save() | ||
| 212 | except Exception: | ||
| 213 | logger.error( | ||
| 214 | "Unable to save configuration. Please report this as a bug.", | ||
| 215 | exc_info=1 | ||
| 216 | ) | ||
| 217 | raise PipError("Internal Error.") | ||
| 218 | |||
| 219 | def _determine_editor(self, options): | ||
| 220 | if options.editor is not None: | ||
| 221 | return options.editor | ||
| 222 | elif "VISUAL" in os.environ: | ||
| 223 | return os.environ["VISUAL"] | ||
| 224 | elif "EDITOR" in os.environ: | ||
| 225 | return os.environ["EDITOR"] | ||
| 226 | else: | ||
| 227 | raise PipError("Could not determine editor to use.") | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/download.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/download.py deleted file mode 100644 index 916a470..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/download.py +++ /dev/null | |||
| @@ -1,233 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os | ||
| 5 | |||
| 6 | from pip._internal import cmdoptions | ||
| 7 | from pip._internal.basecommand import RequirementCommand | ||
| 8 | from pip._internal.exceptions import CommandError | ||
| 9 | from pip._internal.index import FormatControl | ||
| 10 | from pip._internal.operations.prepare import RequirementPreparer | ||
| 11 | from pip._internal.req import RequirementSet | ||
| 12 | from pip._internal.resolve import Resolver | ||
| 13 | from pip._internal.utils.filesystem import check_path_owner | ||
| 14 | from pip._internal.utils.misc import ensure_dir, normalize_path | ||
| 15 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 16 | |||
| 17 | logger = logging.getLogger(__name__) | ||
| 18 | |||
| 19 | |||
| 20 | class DownloadCommand(RequirementCommand): | ||
| 21 | """ | ||
| 22 | Download packages from: | ||
| 23 | |||
| 24 | - PyPI (and other indexes) using requirement specifiers. | ||
| 25 | - VCS project urls. | ||
| 26 | - Local project directories. | ||
| 27 | - Local or remote source archives. | ||
| 28 | |||
| 29 | pip also supports downloading from "requirements files", which provide | ||
| 30 | an easy way to specify a whole environment to be downloaded. | ||
| 31 | """ | ||
| 32 | name = 'download' | ||
| 33 | |||
| 34 | usage = """ | ||
| 35 | %prog [options] <requirement specifier> [package-index-options] ... | ||
| 36 | %prog [options] -r <requirements file> [package-index-options] ... | ||
| 37 | %prog [options] <vcs project url> ... | ||
| 38 | %prog [options] <local project path> ... | ||
| 39 | %prog [options] <archive url/path> ...""" | ||
| 40 | |||
| 41 | summary = 'Download packages.' | ||
| 42 | |||
| 43 | def __init__(self, *args, **kw): | ||
| 44 | super(DownloadCommand, self).__init__(*args, **kw) | ||
| 45 | |||
| 46 | cmd_opts = self.cmd_opts | ||
| 47 | |||
| 48 | cmd_opts.add_option(cmdoptions.constraints()) | ||
| 49 | cmd_opts.add_option(cmdoptions.requirements()) | ||
| 50 | cmd_opts.add_option(cmdoptions.build_dir()) | ||
| 51 | cmd_opts.add_option(cmdoptions.no_deps()) | ||
| 52 | cmd_opts.add_option(cmdoptions.global_options()) | ||
| 53 | cmd_opts.add_option(cmdoptions.no_binary()) | ||
| 54 | cmd_opts.add_option(cmdoptions.only_binary()) | ||
| 55 | cmd_opts.add_option(cmdoptions.src()) | ||
| 56 | cmd_opts.add_option(cmdoptions.pre()) | ||
| 57 | cmd_opts.add_option(cmdoptions.no_clean()) | ||
| 58 | cmd_opts.add_option(cmdoptions.require_hashes()) | ||
| 59 | cmd_opts.add_option(cmdoptions.progress_bar()) | ||
| 60 | cmd_opts.add_option(cmdoptions.no_build_isolation()) | ||
| 61 | |||
| 62 | cmd_opts.add_option( | ||
| 63 | '-d', '--dest', '--destination-dir', '--destination-directory', | ||
| 64 | dest='download_dir', | ||
| 65 | metavar='dir', | ||
| 66 | default=os.curdir, | ||
| 67 | help=("Download packages into <dir>."), | ||
| 68 | ) | ||
| 69 | |||
| 70 | cmd_opts.add_option( | ||
| 71 | '--platform', | ||
| 72 | dest='platform', | ||
| 73 | metavar='platform', | ||
| 74 | default=None, | ||
| 75 | help=("Only download wheels compatible with <platform>. " | ||
| 76 | "Defaults to the platform of the running system."), | ||
| 77 | ) | ||
| 78 | |||
| 79 | cmd_opts.add_option( | ||
| 80 | '--python-version', | ||
| 81 | dest='python_version', | ||
| 82 | metavar='python_version', | ||
| 83 | default=None, | ||
| 84 | help=("Only download wheels compatible with Python " | ||
| 85 | "interpreter version <version>. If not specified, then the " | ||
| 86 | "current system interpreter minor version is used. A major " | ||
| 87 | "version (e.g. '2') can be specified to match all " | ||
| 88 | "minor revs of that major version. A minor version " | ||
| 89 | "(e.g. '34') can also be specified."), | ||
| 90 | ) | ||
| 91 | |||
| 92 | cmd_opts.add_option( | ||
| 93 | '--implementation', | ||
| 94 | dest='implementation', | ||
| 95 | metavar='implementation', | ||
| 96 | default=None, | ||
| 97 | help=("Only download wheels compatible with Python " | ||
| 98 | "implementation <implementation>, e.g. 'pp', 'jy', 'cp', " | ||
| 99 | " or 'ip'. If not specified, then the current " | ||
| 100 | "interpreter implementation is used. Use 'py' to force " | ||
| 101 | "implementation-agnostic wheels."), | ||
| 102 | ) | ||
| 103 | |||
| 104 | cmd_opts.add_option( | ||
| 105 | '--abi', | ||
| 106 | dest='abi', | ||
| 107 | metavar='abi', | ||
| 108 | default=None, | ||
| 109 | help=("Only download wheels compatible with Python " | ||
| 110 | "abi <abi>, e.g. 'pypy_41'. If not specified, then the " | ||
| 111 | "current interpreter abi tag is used. Generally " | ||
| 112 | "you will need to specify --implementation, " | ||
| 113 | "--platform, and --python-version when using " | ||
| 114 | "this option."), | ||
| 115 | ) | ||
| 116 | |||
| 117 | index_opts = cmdoptions.make_option_group( | ||
| 118 | cmdoptions.index_group, | ||
| 119 | self.parser, | ||
| 120 | ) | ||
| 121 | |||
| 122 | self.parser.insert_option_group(0, index_opts) | ||
| 123 | self.parser.insert_option_group(0, cmd_opts) | ||
| 124 | |||
| 125 | def run(self, options, args): | ||
| 126 | options.ignore_installed = True | ||
| 127 | # editable doesn't really make sense for `pip download`, but the bowels | ||
| 128 | # of the RequirementSet code require that property. | ||
| 129 | options.editables = [] | ||
| 130 | |||
| 131 | if options.python_version: | ||
| 132 | python_versions = [options.python_version] | ||
| 133 | else: | ||
| 134 | python_versions = None | ||
| 135 | |||
| 136 | dist_restriction_set = any([ | ||
| 137 | options.python_version, | ||
| 138 | options.platform, | ||
| 139 | options.abi, | ||
| 140 | options.implementation, | ||
| 141 | ]) | ||
| 142 | binary_only = FormatControl(set(), {':all:'}) | ||
| 143 | no_sdist_dependencies = ( | ||
| 144 | options.format_control != binary_only and | ||
| 145 | not options.ignore_dependencies | ||
| 146 | ) | ||
| 147 | if dist_restriction_set and no_sdist_dependencies: | ||
| 148 | raise CommandError( | ||
| 149 | "When restricting platform and interpreter constraints using " | ||
| 150 | "--python-version, --platform, --abi, or --implementation, " | ||
| 151 | "either --no-deps must be set, or --only-binary=:all: must be " | ||
| 152 | "set and --no-binary must not be set (or must be set to " | ||
| 153 | ":none:)." | ||
| 154 | ) | ||
| 155 | |||
| 156 | options.src_dir = os.path.abspath(options.src_dir) | ||
| 157 | options.download_dir = normalize_path(options.download_dir) | ||
| 158 | |||
| 159 | ensure_dir(options.download_dir) | ||
| 160 | |||
| 161 | with self._build_session(options) as session: | ||
| 162 | finder = self._build_package_finder( | ||
| 163 | options=options, | ||
| 164 | session=session, | ||
| 165 | platform=options.platform, | ||
| 166 | python_versions=python_versions, | ||
| 167 | abi=options.abi, | ||
| 168 | implementation=options.implementation, | ||
| 169 | ) | ||
| 170 | build_delete = (not (options.no_clean or options.build_dir)) | ||
| 171 | if options.cache_dir and not check_path_owner(options.cache_dir): | ||
| 172 | logger.warning( | ||
| 173 | "The directory '%s' or its parent directory is not owned " | ||
| 174 | "by the current user and caching wheels has been " | ||
| 175 | "disabled. check the permissions and owner of that " | ||
| 176 | "directory. If executing pip with sudo, you may want " | ||
| 177 | "sudo's -H flag.", | ||
| 178 | options.cache_dir, | ||
| 179 | ) | ||
| 180 | options.cache_dir = None | ||
| 181 | |||
| 182 | with TempDirectory( | ||
| 183 | options.build_dir, delete=build_delete, kind="download" | ||
| 184 | ) as directory: | ||
| 185 | |||
| 186 | requirement_set = RequirementSet( | ||
| 187 | require_hashes=options.require_hashes, | ||
| 188 | ) | ||
| 189 | self.populate_requirement_set( | ||
| 190 | requirement_set, | ||
| 191 | args, | ||
| 192 | options, | ||
| 193 | finder, | ||
| 194 | session, | ||
| 195 | self.name, | ||
| 196 | None | ||
| 197 | ) | ||
| 198 | |||
| 199 | preparer = RequirementPreparer( | ||
| 200 | build_dir=directory.path, | ||
| 201 | src_dir=options.src_dir, | ||
| 202 | download_dir=options.download_dir, | ||
| 203 | wheel_download_dir=None, | ||
| 204 | progress_bar=options.progress_bar, | ||
| 205 | build_isolation=options.build_isolation, | ||
| 206 | ) | ||
| 207 | |||
| 208 | resolver = Resolver( | ||
| 209 | preparer=preparer, | ||
| 210 | finder=finder, | ||
| 211 | session=session, | ||
| 212 | wheel_cache=None, | ||
| 213 | use_user_site=False, | ||
| 214 | upgrade_strategy="to-satisfy-only", | ||
| 215 | force_reinstall=False, | ||
| 216 | ignore_dependencies=options.ignore_dependencies, | ||
| 217 | ignore_requires_python=False, | ||
| 218 | ignore_installed=True, | ||
| 219 | isolated=options.isolated_mode, | ||
| 220 | ) | ||
| 221 | resolver.resolve(requirement_set) | ||
| 222 | |||
| 223 | downloaded = ' '.join([ | ||
| 224 | req.name for req in requirement_set.successfully_downloaded | ||
| 225 | ]) | ||
| 226 | if downloaded: | ||
| 227 | logger.info('Successfully downloaded %s', downloaded) | ||
| 228 | |||
| 229 | # Clean up | ||
| 230 | if not options.no_clean: | ||
| 231 | requirement_set.cleanup_files() | ||
| 232 | |||
| 233 | return requirement_set | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/freeze.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/freeze.py deleted file mode 100644 index ac562d7..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/freeze.py +++ /dev/null | |||
| @@ -1,96 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import sys | ||
| 4 | |||
| 5 | from pip._internal import index | ||
| 6 | from pip._internal.basecommand import Command | ||
| 7 | from pip._internal.cache import WheelCache | ||
| 8 | from pip._internal.compat import stdlib_pkgs | ||
| 9 | from pip._internal.operations.freeze import freeze | ||
| 10 | |||
| 11 | DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'} | ||
| 12 | |||
| 13 | |||
| 14 | class FreezeCommand(Command): | ||
| 15 | """ | ||
| 16 | Output installed packages in requirements format. | ||
| 17 | |||
| 18 | packages are listed in a case-insensitive sorted order. | ||
| 19 | """ | ||
| 20 | name = 'freeze' | ||
| 21 | usage = """ | ||
| 22 | %prog [options]""" | ||
| 23 | summary = 'Output installed packages in requirements format.' | ||
| 24 | log_streams = ("ext://sys.stderr", "ext://sys.stderr") | ||
| 25 | |||
| 26 | def __init__(self, *args, **kw): | ||
| 27 | super(FreezeCommand, self).__init__(*args, **kw) | ||
| 28 | |||
| 29 | self.cmd_opts.add_option( | ||
| 30 | '-r', '--requirement', | ||
| 31 | dest='requirements', | ||
| 32 | action='append', | ||
| 33 | default=[], | ||
| 34 | metavar='file', | ||
| 35 | help="Use the order in the given requirements file and its " | ||
| 36 | "comments when generating output. This option can be " | ||
| 37 | "used multiple times.") | ||
| 38 | self.cmd_opts.add_option( | ||
| 39 | '-f', '--find-links', | ||
| 40 | dest='find_links', | ||
| 41 | action='append', | ||
| 42 | default=[], | ||
| 43 | metavar='URL', | ||
| 44 | help='URL for finding packages, which will be added to the ' | ||
| 45 | 'output.') | ||
| 46 | self.cmd_opts.add_option( | ||
| 47 | '-l', '--local', | ||
| 48 | dest='local', | ||
| 49 | action='store_true', | ||
| 50 | default=False, | ||
| 51 | help='If in a virtualenv that has global access, do not output ' | ||
| 52 | 'globally-installed packages.') | ||
| 53 | self.cmd_opts.add_option( | ||
| 54 | '--user', | ||
| 55 | dest='user', | ||
| 56 | action='store_true', | ||
| 57 | default=False, | ||
| 58 | help='Only output packages installed in user-site.') | ||
| 59 | self.cmd_opts.add_option( | ||
| 60 | '--all', | ||
| 61 | dest='freeze_all', | ||
| 62 | action='store_true', | ||
| 63 | help='Do not skip these packages in the output:' | ||
| 64 | ' %s' % ', '.join(DEV_PKGS)) | ||
| 65 | self.cmd_opts.add_option( | ||
| 66 | '--exclude-editable', | ||
| 67 | dest='exclude_editable', | ||
| 68 | action='store_true', | ||
| 69 | help='Exclude editable package from output.') | ||
| 70 | |||
| 71 | self.parser.insert_option_group(0, self.cmd_opts) | ||
| 72 | |||
| 73 | def run(self, options, args): | ||
| 74 | format_control = index.FormatControl(set(), set()) | ||
| 75 | wheel_cache = WheelCache(options.cache_dir, format_control) | ||
| 76 | skip = set(stdlib_pkgs) | ||
| 77 | if not options.freeze_all: | ||
| 78 | skip.update(DEV_PKGS) | ||
| 79 | |||
| 80 | freeze_kwargs = dict( | ||
| 81 | requirement=options.requirements, | ||
| 82 | find_links=options.find_links, | ||
| 83 | local_only=options.local, | ||
| 84 | user_only=options.user, | ||
| 85 | skip_regex=options.skip_requirements_regex, | ||
| 86 | isolated=options.isolated_mode, | ||
| 87 | wheel_cache=wheel_cache, | ||
| 88 | skip=skip, | ||
| 89 | exclude_editable=options.exclude_editable, | ||
| 90 | ) | ||
| 91 | |||
| 92 | try: | ||
| 93 | for line in freeze(**freeze_kwargs): | ||
| 94 | sys.stdout.write(line + '\n') | ||
| 95 | finally: | ||
| 96 | wheel_cache.cleanup() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/hash.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/hash.py deleted file mode 100644 index 0ce1419..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/hash.py +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import hashlib | ||
| 4 | import logging | ||
| 5 | import sys | ||
| 6 | |||
| 7 | from pip._internal.basecommand import Command | ||
| 8 | from pip._internal.status_codes import ERROR | ||
| 9 | from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES | ||
| 10 | from pip._internal.utils.misc import read_chunks | ||
| 11 | |||
| 12 | logger = logging.getLogger(__name__) | ||
| 13 | |||
| 14 | |||
| 15 | class HashCommand(Command): | ||
| 16 | """ | ||
| 17 | Compute a hash of a local package archive. | ||
| 18 | |||
| 19 | These can be used with --hash in a requirements file to do repeatable | ||
| 20 | installs. | ||
| 21 | |||
| 22 | """ | ||
| 23 | name = 'hash' | ||
| 24 | usage = '%prog [options] <file> ...' | ||
| 25 | summary = 'Compute hashes of package archives.' | ||
| 26 | ignore_require_venv = True | ||
| 27 | |||
| 28 | def __init__(self, *args, **kw): | ||
| 29 | super(HashCommand, self).__init__(*args, **kw) | ||
| 30 | self.cmd_opts.add_option( | ||
| 31 | '-a', '--algorithm', | ||
| 32 | dest='algorithm', | ||
| 33 | choices=STRONG_HASHES, | ||
| 34 | action='store', | ||
| 35 | default=FAVORITE_HASH, | ||
| 36 | help='The hash algorithm to use: one of %s' % | ||
| 37 | ', '.join(STRONG_HASHES)) | ||
| 38 | self.parser.insert_option_group(0, self.cmd_opts) | ||
| 39 | |||
| 40 | def run(self, options, args): | ||
| 41 | if not args: | ||
| 42 | self.parser.print_usage(sys.stderr) | ||
| 43 | return ERROR | ||
| 44 | |||
| 45 | algorithm = options.algorithm | ||
| 46 | for path in args: | ||
| 47 | logger.info('%s:\n--hash=%s:%s', | ||
| 48 | path, algorithm, _hash_of_file(path, algorithm)) | ||
| 49 | |||
| 50 | |||
| 51 | def _hash_of_file(path, algorithm): | ||
| 52 | """Return the hash digest of a file.""" | ||
| 53 | with open(path, 'rb') as archive: | ||
| 54 | hash = hashlib.new(algorithm) | ||
| 55 | for chunk in read_chunks(archive): | ||
| 56 | hash.update(chunk) | ||
| 57 | return hash.hexdigest() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/help.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/help.py deleted file mode 100644 index f4a0e40..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/help.py +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | from pip._internal.basecommand import SUCCESS, Command | ||
| 4 | from pip._internal.exceptions import CommandError | ||
| 5 | |||
| 6 | |||
| 7 | class HelpCommand(Command): | ||
| 8 | """Show help for commands""" | ||
| 9 | name = 'help' | ||
| 10 | usage = """ | ||
| 11 | %prog <command>""" | ||
| 12 | summary = 'Show help for commands.' | ||
| 13 | ignore_require_venv = True | ||
| 14 | |||
| 15 | def run(self, options, args): | ||
| 16 | from pip._internal.commands import commands_dict, get_similar_commands | ||
| 17 | |||
| 18 | try: | ||
| 19 | # 'pip help' with no args is handled by pip.__init__.parseopt() | ||
| 20 | cmd_name = args[0] # the command we need help for | ||
| 21 | except IndexError: | ||
| 22 | return SUCCESS | ||
| 23 | |||
| 24 | if cmd_name not in commands_dict: | ||
| 25 | guess = get_similar_commands(cmd_name) | ||
| 26 | |||
| 27 | msg = ['unknown command "%s"' % cmd_name] | ||
| 28 | if guess: | ||
| 29 | msg.append('maybe you meant "%s"' % guess) | ||
| 30 | |||
| 31 | raise CommandError(' - '.join(msg)) | ||
| 32 | |||
| 33 | command = commands_dict[cmd_name]() | ||
| 34 | command.parser.print_help() | ||
| 35 | |||
| 36 | return SUCCESS | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/install.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/install.py deleted file mode 100644 index 057a64e..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/install.py +++ /dev/null | |||
| @@ -1,502 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import errno | ||
| 4 | import logging | ||
| 5 | import operator | ||
| 6 | import os | ||
| 7 | import shutil | ||
| 8 | from optparse import SUPPRESS_HELP | ||
| 9 | |||
| 10 | from pip._internal import cmdoptions | ||
| 11 | from pip._internal.basecommand import RequirementCommand | ||
| 12 | from pip._internal.cache import WheelCache | ||
| 13 | from pip._internal.exceptions import ( | ||
| 14 | CommandError, InstallationError, PreviousBuildDirError, | ||
| 15 | ) | ||
| 16 | from pip._internal.locations import distutils_scheme, virtualenv_no_global | ||
| 17 | from pip._internal.operations.check import check_install_conflicts | ||
| 18 | from pip._internal.operations.prepare import RequirementPreparer | ||
| 19 | from pip._internal.req import RequirementSet, install_given_reqs | ||
| 20 | from pip._internal.resolve import Resolver | ||
| 21 | from pip._internal.status_codes import ERROR | ||
| 22 | from pip._internal.utils.filesystem import check_path_owner | ||
| 23 | from pip._internal.utils.misc import ensure_dir, get_installed_version | ||
| 24 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 25 | from pip._internal.wheel import WheelBuilder | ||
| 26 | |||
| 27 | try: | ||
| 28 | import wheel | ||
| 29 | except ImportError: | ||
| 30 | wheel = None | ||
| 31 | |||
| 32 | |||
| 33 | logger = logging.getLogger(__name__) | ||
| 34 | |||
| 35 | |||
| 36 | class InstallCommand(RequirementCommand): | ||
| 37 | """ | ||
| 38 | Install packages from: | ||
| 39 | |||
| 40 | - PyPI (and other indexes) using requirement specifiers. | ||
| 41 | - VCS project urls. | ||
| 42 | - Local project directories. | ||
| 43 | - Local or remote source archives. | ||
| 44 | |||
| 45 | pip also supports installing from "requirements files", which provide | ||
| 46 | an easy way to specify a whole environment to be installed. | ||
| 47 | """ | ||
| 48 | name = 'install' | ||
| 49 | |||
| 50 | usage = """ | ||
| 51 | %prog [options] <requirement specifier> [package-index-options] ... | ||
| 52 | %prog [options] -r <requirements file> [package-index-options] ... | ||
| 53 | %prog [options] [-e] <vcs project url> ... | ||
| 54 | %prog [options] [-e] <local project path> ... | ||
| 55 | %prog [options] <archive url/path> ...""" | ||
| 56 | |||
| 57 | summary = 'Install packages.' | ||
| 58 | |||
| 59 | def __init__(self, *args, **kw): | ||
| 60 | super(InstallCommand, self).__init__(*args, **kw) | ||
| 61 | |||
| 62 | cmd_opts = self.cmd_opts | ||
| 63 | |||
| 64 | cmd_opts.add_option(cmdoptions.requirements()) | ||
| 65 | cmd_opts.add_option(cmdoptions.constraints()) | ||
| 66 | cmd_opts.add_option(cmdoptions.no_deps()) | ||
| 67 | cmd_opts.add_option(cmdoptions.pre()) | ||
| 68 | |||
| 69 | cmd_opts.add_option(cmdoptions.editable()) | ||
| 70 | cmd_opts.add_option( | ||
| 71 | '-t', '--target', | ||
| 72 | dest='target_dir', | ||
| 73 | metavar='dir', | ||
| 74 | default=None, | ||
| 75 | help='Install packages into <dir>. ' | ||
| 76 | 'By default this will not replace existing files/folders in ' | ||
| 77 | '<dir>. Use --upgrade to replace existing packages in <dir> ' | ||
| 78 | 'with new versions.' | ||
| 79 | ) | ||
| 80 | cmd_opts.add_option( | ||
| 81 | '--user', | ||
| 82 | dest='use_user_site', | ||
| 83 | action='store_true', | ||
| 84 | help="Install to the Python user install directory for your " | ||
| 85 | "platform. Typically ~/.local/, or %APPDATA%\\Python on " | ||
| 86 | "Windows. (See the Python documentation for site.USER_BASE " | ||
| 87 | "for full details.)") | ||
| 88 | cmd_opts.add_option( | ||
| 89 | '--no-user', | ||
| 90 | dest='use_user_site', | ||
| 91 | action='store_false', | ||
| 92 | help=SUPPRESS_HELP) | ||
| 93 | cmd_opts.add_option( | ||
| 94 | '--root', | ||
| 95 | dest='root_path', | ||
| 96 | metavar='dir', | ||
| 97 | default=None, | ||
| 98 | help="Install everything relative to this alternate root " | ||
| 99 | "directory.") | ||
| 100 | cmd_opts.add_option( | ||
| 101 | '--prefix', | ||
| 102 | dest='prefix_path', | ||
| 103 | metavar='dir', | ||
| 104 | default=None, | ||
| 105 | help="Installation prefix where lib, bin and other top-level " | ||
| 106 | "folders are placed") | ||
| 107 | |||
| 108 | cmd_opts.add_option(cmdoptions.build_dir()) | ||
| 109 | |||
| 110 | cmd_opts.add_option(cmdoptions.src()) | ||
| 111 | |||
| 112 | cmd_opts.add_option( | ||
| 113 | '-U', '--upgrade', | ||
| 114 | dest='upgrade', | ||
| 115 | action='store_true', | ||
| 116 | help='Upgrade all specified packages to the newest available ' | ||
| 117 | 'version. The handling of dependencies depends on the ' | ||
| 118 | 'upgrade-strategy used.' | ||
| 119 | ) | ||
| 120 | |||
| 121 | cmd_opts.add_option( | ||
| 122 | '--upgrade-strategy', | ||
| 123 | dest='upgrade_strategy', | ||
| 124 | default='only-if-needed', | ||
| 125 | choices=['only-if-needed', 'eager'], | ||
| 126 | help='Determines how dependency upgrading should be handled ' | ||
| 127 | '[default: %default]. ' | ||
| 128 | '"eager" - dependencies are upgraded regardless of ' | ||
| 129 | 'whether the currently installed version satisfies the ' | ||
| 130 | 'requirements of the upgraded package(s). ' | ||
| 131 | '"only-if-needed" - are upgraded only when they do not ' | ||
| 132 | 'satisfy the requirements of the upgraded package(s).' | ||
| 133 | ) | ||
| 134 | |||
| 135 | cmd_opts.add_option( | ||
| 136 | '--force-reinstall', | ||
| 137 | dest='force_reinstall', | ||
| 138 | action='store_true', | ||
| 139 | help='Reinstall all packages even if they are already ' | ||
| 140 | 'up-to-date.') | ||
| 141 | |||
| 142 | cmd_opts.add_option( | ||
| 143 | '-I', '--ignore-installed', | ||
| 144 | dest='ignore_installed', | ||
| 145 | action='store_true', | ||
| 146 | help='Ignore the installed packages (reinstalling instead).') | ||
| 147 | |||
| 148 | cmd_opts.add_option(cmdoptions.ignore_requires_python()) | ||
| 149 | cmd_opts.add_option(cmdoptions.no_build_isolation()) | ||
| 150 | |||
| 151 | cmd_opts.add_option(cmdoptions.install_options()) | ||
| 152 | cmd_opts.add_option(cmdoptions.global_options()) | ||
| 153 | |||
| 154 | cmd_opts.add_option( | ||
| 155 | "--compile", | ||
| 156 | action="store_true", | ||
| 157 | dest="compile", | ||
| 158 | default=True, | ||
| 159 | help="Compile Python source files to bytecode", | ||
| 160 | ) | ||
| 161 | |||
| 162 | cmd_opts.add_option( | ||
| 163 | "--no-compile", | ||
| 164 | action="store_false", | ||
| 165 | dest="compile", | ||
| 166 | help="Do not compile Python source files to bytecode", | ||
| 167 | ) | ||
| 168 | |||
| 169 | cmd_opts.add_option( | ||
| 170 | "--no-warn-script-location", | ||
| 171 | action="store_false", | ||
| 172 | dest="warn_script_location", | ||
| 173 | default=True, | ||
| 174 | help="Do not warn when installing scripts outside PATH", | ||
| 175 | ) | ||
| 176 | cmd_opts.add_option( | ||
| 177 | "--no-warn-conflicts", | ||
| 178 | action="store_false", | ||
| 179 | dest="warn_about_conflicts", | ||
| 180 | default=True, | ||
| 181 | help="Do not warn about broken dependencies", | ||
| 182 | ) | ||
| 183 | |||
| 184 | cmd_opts.add_option(cmdoptions.no_binary()) | ||
| 185 | cmd_opts.add_option(cmdoptions.only_binary()) | ||
| 186 | cmd_opts.add_option(cmdoptions.no_clean()) | ||
| 187 | cmd_opts.add_option(cmdoptions.require_hashes()) | ||
| 188 | cmd_opts.add_option(cmdoptions.progress_bar()) | ||
| 189 | |||
| 190 | index_opts = cmdoptions.make_option_group( | ||
| 191 | cmdoptions.index_group, | ||
| 192 | self.parser, | ||
| 193 | ) | ||
| 194 | |||
| 195 | self.parser.insert_option_group(0, index_opts) | ||
| 196 | self.parser.insert_option_group(0, cmd_opts) | ||
| 197 | |||
| 198 | def run(self, options, args): | ||
| 199 | cmdoptions.check_install_build_global(options) | ||
| 200 | |||
| 201 | upgrade_strategy = "to-satisfy-only" | ||
| 202 | if options.upgrade: | ||
| 203 | upgrade_strategy = options.upgrade_strategy | ||
| 204 | |||
| 205 | if options.build_dir: | ||
| 206 | options.build_dir = os.path.abspath(options.build_dir) | ||
| 207 | |||
| 208 | options.src_dir = os.path.abspath(options.src_dir) | ||
| 209 | install_options = options.install_options or [] | ||
| 210 | if options.use_user_site: | ||
| 211 | if options.prefix_path: | ||
| 212 | raise CommandError( | ||
| 213 | "Can not combine '--user' and '--prefix' as they imply " | ||
| 214 | "different installation locations" | ||
| 215 | ) | ||
| 216 | if virtualenv_no_global(): | ||
| 217 | raise InstallationError( | ||
| 218 | "Can not perform a '--user' install. User site-packages " | ||
| 219 | "are not visible in this virtualenv." | ||
| 220 | ) | ||
| 221 | install_options.append('--user') | ||
| 222 | install_options.append('--prefix=') | ||
| 223 | |||
| 224 | target_temp_dir = TempDirectory(kind="target") | ||
| 225 | if options.target_dir: | ||
| 226 | options.ignore_installed = True | ||
| 227 | options.target_dir = os.path.abspath(options.target_dir) | ||
| 228 | if (os.path.exists(options.target_dir) and not | ||
| 229 | os.path.isdir(options.target_dir)): | ||
| 230 | raise CommandError( | ||
| 231 | "Target path exists but is not a directory, will not " | ||
| 232 | "continue." | ||
| 233 | ) | ||
| 234 | |||
| 235 | # Create a target directory for using with the target option | ||
| 236 | target_temp_dir.create() | ||
| 237 | install_options.append('--home=' + target_temp_dir.path) | ||
| 238 | |||
| 239 | global_options = options.global_options or [] | ||
| 240 | |||
| 241 | with self._build_session(options) as session: | ||
| 242 | finder = self._build_package_finder(options, session) | ||
| 243 | build_delete = (not (options.no_clean or options.build_dir)) | ||
| 244 | wheel_cache = WheelCache(options.cache_dir, options.format_control) | ||
| 245 | |||
| 246 | if options.cache_dir and not check_path_owner(options.cache_dir): | ||
| 247 | logger.warning( | ||
| 248 | "The directory '%s' or its parent directory is not owned " | ||
| 249 | "by the current user and caching wheels has been " | ||
| 250 | "disabled. check the permissions and owner of that " | ||
| 251 | "directory. If executing pip with sudo, you may want " | ||
| 252 | "sudo's -H flag.", | ||
| 253 | options.cache_dir, | ||
| 254 | ) | ||
| 255 | options.cache_dir = None | ||
| 256 | |||
| 257 | with TempDirectory( | ||
| 258 | options.build_dir, delete=build_delete, kind="install" | ||
| 259 | ) as directory: | ||
| 260 | requirement_set = RequirementSet( | ||
| 261 | require_hashes=options.require_hashes, | ||
| 262 | ) | ||
| 263 | |||
| 264 | try: | ||
| 265 | self.populate_requirement_set( | ||
| 266 | requirement_set, args, options, finder, session, | ||
| 267 | self.name, wheel_cache | ||
| 268 | ) | ||
| 269 | preparer = RequirementPreparer( | ||
| 270 | build_dir=directory.path, | ||
| 271 | src_dir=options.src_dir, | ||
| 272 | download_dir=None, | ||
| 273 | wheel_download_dir=None, | ||
| 274 | progress_bar=options.progress_bar, | ||
| 275 | build_isolation=options.build_isolation, | ||
| 276 | ) | ||
| 277 | |||
| 278 | resolver = Resolver( | ||
| 279 | preparer=preparer, | ||
| 280 | finder=finder, | ||
| 281 | session=session, | ||
| 282 | wheel_cache=wheel_cache, | ||
| 283 | use_user_site=options.use_user_site, | ||
| 284 | upgrade_strategy=upgrade_strategy, | ||
| 285 | force_reinstall=options.force_reinstall, | ||
| 286 | ignore_dependencies=options.ignore_dependencies, | ||
| 287 | ignore_requires_python=options.ignore_requires_python, | ||
| 288 | ignore_installed=options.ignore_installed, | ||
| 289 | isolated=options.isolated_mode, | ||
| 290 | ) | ||
| 291 | resolver.resolve(requirement_set) | ||
| 292 | |||
| 293 | # If caching is disabled or wheel is not installed don't | ||
| 294 | # try to build wheels. | ||
| 295 | if wheel and options.cache_dir: | ||
| 296 | # build wheels before install. | ||
| 297 | wb = WheelBuilder( | ||
| 298 | finder, preparer, wheel_cache, | ||
| 299 | build_options=[], global_options=[], | ||
| 300 | ) | ||
| 301 | # Ignore the result: a failed wheel will be | ||
| 302 | # installed from the sdist/vcs whatever. | ||
| 303 | wb.build( | ||
| 304 | requirement_set.requirements.values(), | ||
| 305 | session=session, autobuilding=True | ||
| 306 | ) | ||
| 307 | |||
| 308 | to_install = resolver.get_installation_order( | ||
| 309 | requirement_set | ||
| 310 | ) | ||
| 311 | |||
| 312 | # Consistency Checking of the package set we're installing. | ||
| 313 | should_warn_about_conflicts = ( | ||
| 314 | not options.ignore_dependencies and | ||
| 315 | options.warn_about_conflicts | ||
| 316 | ) | ||
| 317 | if should_warn_about_conflicts: | ||
| 318 | self._warn_about_conflicts(to_install) | ||
| 319 | |||
| 320 | # Don't warn about script install locations if | ||
| 321 | # --target has been specified | ||
| 322 | warn_script_location = options.warn_script_location | ||
| 323 | if options.target_dir: | ||
| 324 | warn_script_location = False | ||
| 325 | |||
| 326 | installed = install_given_reqs( | ||
| 327 | to_install, | ||
| 328 | install_options, | ||
| 329 | global_options, | ||
| 330 | root=options.root_path, | ||
| 331 | home=target_temp_dir.path, | ||
| 332 | prefix=options.prefix_path, | ||
| 333 | pycompile=options.compile, | ||
| 334 | warn_script_location=warn_script_location, | ||
| 335 | use_user_site=options.use_user_site, | ||
| 336 | ) | ||
| 337 | |||
| 338 | possible_lib_locations = get_lib_location_guesses( | ||
| 339 | user=options.use_user_site, | ||
| 340 | home=target_temp_dir.path, | ||
| 341 | root=options.root_path, | ||
| 342 | prefix=options.prefix_path, | ||
| 343 | isolated=options.isolated_mode, | ||
| 344 | ) | ||
| 345 | reqs = sorted(installed, key=operator.attrgetter('name')) | ||
| 346 | items = [] | ||
| 347 | for req in reqs: | ||
| 348 | item = req.name | ||
| 349 | try: | ||
| 350 | installed_version = get_installed_version( | ||
| 351 | req.name, possible_lib_locations | ||
| 352 | ) | ||
| 353 | if installed_version: | ||
| 354 | item += '-' + installed_version | ||
| 355 | except Exception: | ||
| 356 | pass | ||
| 357 | items.append(item) | ||
| 358 | installed = ' '.join(items) | ||
| 359 | if installed: | ||
| 360 | logger.info('Successfully installed %s', installed) | ||
| 361 | except EnvironmentError as error: | ||
| 362 | show_traceback = (self.verbosity >= 1) | ||
| 363 | |||
| 364 | message = create_env_error_message( | ||
| 365 | error, show_traceback, options.use_user_site, | ||
| 366 | ) | ||
| 367 | logger.error(message, exc_info=show_traceback) | ||
| 368 | |||
| 369 | return ERROR | ||
| 370 | except PreviousBuildDirError: | ||
| 371 | options.no_clean = True | ||
| 372 | raise | ||
| 373 | finally: | ||
| 374 | # Clean up | ||
| 375 | if not options.no_clean: | ||
| 376 | requirement_set.cleanup_files() | ||
| 377 | wheel_cache.cleanup() | ||
| 378 | |||
| 379 | if options.target_dir: | ||
| 380 | self._handle_target_dir( | ||
| 381 | options.target_dir, target_temp_dir, options.upgrade | ||
| 382 | ) | ||
| 383 | return requirement_set | ||
| 384 | |||
| 385 | def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): | ||
| 386 | ensure_dir(target_dir) | ||
| 387 | |||
| 388 | # Checking both purelib and platlib directories for installed | ||
| 389 | # packages to be moved to target directory | ||
| 390 | lib_dir_list = [] | ||
| 391 | |||
| 392 | with target_temp_dir: | ||
| 393 | # Checking both purelib and platlib directories for installed | ||
| 394 | # packages to be moved to target directory | ||
| 395 | scheme = distutils_scheme('', home=target_temp_dir.path) | ||
| 396 | purelib_dir = scheme['purelib'] | ||
| 397 | platlib_dir = scheme['platlib'] | ||
| 398 | data_dir = scheme['data'] | ||
| 399 | |||
| 400 | if os.path.exists(purelib_dir): | ||
| 401 | lib_dir_list.append(purelib_dir) | ||
| 402 | if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: | ||
| 403 | lib_dir_list.append(platlib_dir) | ||
| 404 | if os.path.exists(data_dir): | ||
| 405 | lib_dir_list.append(data_dir) | ||
| 406 | |||
| 407 | for lib_dir in lib_dir_list: | ||
| 408 | for item in os.listdir(lib_dir): | ||
| 409 | if lib_dir == data_dir: | ||
| 410 | ddir = os.path.join(data_dir, item) | ||
| 411 | if any(s.startswith(ddir) for s in lib_dir_list[:-1]): | ||
| 412 | continue | ||
| 413 | target_item_dir = os.path.join(target_dir, item) | ||
| 414 | if os.path.exists(target_item_dir): | ||
| 415 | if not upgrade: | ||
| 416 | logger.warning( | ||
| 417 | 'Target directory %s already exists. Specify ' | ||
| 418 | '--upgrade to force replacement.', | ||
| 419 | target_item_dir | ||
| 420 | ) | ||
| 421 | continue | ||
| 422 | if os.path.islink(target_item_dir): | ||
| 423 | logger.warning( | ||
| 424 | 'Target directory %s already exists and is ' | ||
| 425 | 'a link. Pip will not automatically replace ' | ||
| 426 | 'links, please remove if replacement is ' | ||
| 427 | 'desired.', | ||
| 428 | target_item_dir | ||
| 429 | ) | ||
| 430 | continue | ||
| 431 | if os.path.isdir(target_item_dir): | ||
| 432 | shutil.rmtree(target_item_dir) | ||
| 433 | else: | ||
| 434 | os.remove(target_item_dir) | ||
| 435 | |||
| 436 | shutil.move( | ||
| 437 | os.path.join(lib_dir, item), | ||
| 438 | target_item_dir | ||
| 439 | ) | ||
| 440 | |||
| 441 | def _warn_about_conflicts(self, to_install): | ||
| 442 | package_set, _dep_info = check_install_conflicts(to_install) | ||
| 443 | missing, conflicting = _dep_info | ||
| 444 | |||
| 445 | # NOTE: There is some duplication here from pip check | ||
| 446 | for project_name in missing: | ||
| 447 | version = package_set[project_name][0] | ||
| 448 | for dependency in missing[project_name]: | ||
| 449 | logger.critical( | ||
| 450 | "%s %s requires %s, which is not installed.", | ||
| 451 | project_name, version, dependency[1], | ||
| 452 | ) | ||
| 453 | |||
| 454 | for project_name in conflicting: | ||
| 455 | version = package_set[project_name][0] | ||
| 456 | for dep_name, dep_version, req in conflicting[project_name]: | ||
| 457 | logger.critical( | ||
| 458 | "%s %s has requirement %s, but you'll have %s %s which is " | ||
| 459 | "incompatible.", | ||
| 460 | project_name, version, req, dep_name, dep_version, | ||
| 461 | ) | ||
| 462 | |||
| 463 | |||
| 464 | def get_lib_location_guesses(*args, **kwargs): | ||
| 465 | scheme = distutils_scheme('', *args, **kwargs) | ||
| 466 | return [scheme['purelib'], scheme['platlib']] | ||
| 467 | |||
| 468 | |||
| 469 | def create_env_error_message(error, show_traceback, using_user_site): | ||
| 470 | """Format an error message for an EnvironmentError | ||
| 471 | |||
| 472 | It may occur anytime during the execution of the install command. | ||
| 473 | """ | ||
| 474 | parts = [] | ||
| 475 | |||
| 476 | # Mention the error if we are not going to show a traceback | ||
| 477 | parts.append("Could not install packages due to an EnvironmentError") | ||
| 478 | if not show_traceback: | ||
| 479 | parts.append(": ") | ||
| 480 | parts.append(str(error)) | ||
| 481 | else: | ||
| 482 | parts.append(".") | ||
| 483 | |||
| 484 | # Spilt the error indication from a helper message (if any) | ||
| 485 | parts[-1] += "\n" | ||
| 486 | |||
| 487 | # Suggest useful actions to the user: | ||
| 488 | # (1) using user site-packages or (2) verifying the permissions | ||
| 489 | if error.errno == errno.EACCES: | ||
| 490 | user_option_part = "Consider using the `--user` option" | ||
| 491 | permissions_part = "Check the permissions" | ||
| 492 | |||
| 493 | if not using_user_site: | ||
| 494 | parts.extend([ | ||
| 495 | user_option_part, " or ", | ||
| 496 | permissions_part.lower(), | ||
| 497 | ]) | ||
| 498 | else: | ||
| 499 | parts.append(permissions_part) | ||
| 500 | parts.append(".\n") | ||
| 501 | |||
| 502 | return "".join(parts).strip() + "\n" | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/list.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/list.py deleted file mode 100644 index 1b46c6f..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/list.py +++ /dev/null | |||
| @@ -1,343 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import json | ||
| 4 | import logging | ||
| 5 | import warnings | ||
| 6 | |||
| 7 | from pip._vendor import six | ||
| 8 | from pip._vendor.six.moves import zip_longest | ||
| 9 | |||
| 10 | from pip._internal.basecommand import Command | ||
| 11 | from pip._internal.cmdoptions import index_group, make_option_group | ||
| 12 | from pip._internal.exceptions import CommandError | ||
| 13 | from pip._internal.index import PackageFinder | ||
| 14 | from pip._internal.utils.deprecation import RemovedInPip11Warning | ||
| 15 | from pip._internal.utils.misc import ( | ||
| 16 | dist_is_editable, get_installed_distributions, | ||
| 17 | ) | ||
| 18 | from pip._internal.utils.packaging import get_installer | ||
| 19 | |||
| 20 | logger = logging.getLogger(__name__) | ||
| 21 | |||
| 22 | |||
| 23 | class ListCommand(Command): | ||
| 24 | """ | ||
| 25 | List installed packages, including editables. | ||
| 26 | |||
| 27 | Packages are listed in a case-insensitive sorted order. | ||
| 28 | """ | ||
| 29 | name = 'list' | ||
| 30 | usage = """ | ||
| 31 | %prog [options]""" | ||
| 32 | summary = 'List installed packages.' | ||
| 33 | |||
| 34 | def __init__(self, *args, **kw): | ||
| 35 | super(ListCommand, self).__init__(*args, **kw) | ||
| 36 | |||
| 37 | cmd_opts = self.cmd_opts | ||
| 38 | |||
| 39 | cmd_opts.add_option( | ||
| 40 | '-o', '--outdated', | ||
| 41 | action='store_true', | ||
| 42 | default=False, | ||
| 43 | help='List outdated packages') | ||
| 44 | cmd_opts.add_option( | ||
| 45 | '-u', '--uptodate', | ||
| 46 | action='store_true', | ||
| 47 | default=False, | ||
| 48 | help='List uptodate packages') | ||
| 49 | cmd_opts.add_option( | ||
| 50 | '-e', '--editable', | ||
| 51 | action='store_true', | ||
| 52 | default=False, | ||
| 53 | help='List editable projects.') | ||
| 54 | cmd_opts.add_option( | ||
| 55 | '-l', '--local', | ||
| 56 | action='store_true', | ||
| 57 | default=False, | ||
| 58 | help=('If in a virtualenv that has global access, do not list ' | ||
| 59 | 'globally-installed packages.'), | ||
| 60 | ) | ||
| 61 | self.cmd_opts.add_option( | ||
| 62 | '--user', | ||
| 63 | dest='user', | ||
| 64 | action='store_true', | ||
| 65 | default=False, | ||
| 66 | help='Only output packages installed in user-site.') | ||
| 67 | |||
| 68 | cmd_opts.add_option( | ||
| 69 | '--pre', | ||
| 70 | action='store_true', | ||
| 71 | default=False, | ||
| 72 | help=("Include pre-release and development versions. By default, " | ||
| 73 | "pip only finds stable versions."), | ||
| 74 | ) | ||
| 75 | |||
| 76 | cmd_opts.add_option( | ||
| 77 | '--format', | ||
| 78 | action='store', | ||
| 79 | dest='list_format', | ||
| 80 | default="columns", | ||
| 81 | choices=('legacy', 'columns', 'freeze', 'json'), | ||
| 82 | help="Select the output format among: columns (default), freeze, " | ||
| 83 | "json, or legacy.", | ||
| 84 | ) | ||
| 85 | |||
| 86 | cmd_opts.add_option( | ||
| 87 | '--not-required', | ||
| 88 | action='store_true', | ||
| 89 | dest='not_required', | ||
| 90 | help="List packages that are not dependencies of " | ||
| 91 | "installed packages.", | ||
| 92 | ) | ||
| 93 | |||
| 94 | cmd_opts.add_option( | ||
| 95 | '--exclude-editable', | ||
| 96 | action='store_false', | ||
| 97 | dest='include_editable', | ||
| 98 | help='Exclude editable package from output.', | ||
| 99 | ) | ||
| 100 | cmd_opts.add_option( | ||
| 101 | '--include-editable', | ||
| 102 | action='store_true', | ||
| 103 | dest='include_editable', | ||
| 104 | help='Include editable package from output.', | ||
| 105 | default=True, | ||
| 106 | ) | ||
| 107 | index_opts = make_option_group(index_group, self.parser) | ||
| 108 | |||
| 109 | self.parser.insert_option_group(0, index_opts) | ||
| 110 | self.parser.insert_option_group(0, cmd_opts) | ||
| 111 | |||
| 112 | def _build_package_finder(self, options, index_urls, session): | ||
| 113 | """ | ||
| 114 | Create a package finder appropriate to this list command. | ||
| 115 | """ | ||
| 116 | return PackageFinder( | ||
| 117 | find_links=options.find_links, | ||
| 118 | index_urls=index_urls, | ||
| 119 | allow_all_prereleases=options.pre, | ||
| 120 | trusted_hosts=options.trusted_hosts, | ||
| 121 | process_dependency_links=options.process_dependency_links, | ||
| 122 | session=session, | ||
| 123 | ) | ||
| 124 | |||
| 125 | def run(self, options, args): | ||
| 126 | if options.list_format == "legacy": | ||
| 127 | warnings.warn( | ||
| 128 | "The legacy format has been deprecated and will be removed " | ||
| 129 | "in the future.", | ||
| 130 | RemovedInPip11Warning, | ||
| 131 | ) | ||
| 132 | |||
| 133 | if options.outdated and options.uptodate: | ||
| 134 | raise CommandError( | ||
| 135 | "Options --outdated and --uptodate cannot be combined.") | ||
| 136 | |||
| 137 | packages = get_installed_distributions( | ||
| 138 | local_only=options.local, | ||
| 139 | user_only=options.user, | ||
| 140 | editables_only=options.editable, | ||
| 141 | include_editables=options.include_editable, | ||
| 142 | ) | ||
| 143 | |||
| 144 | if options.outdated: | ||
| 145 | packages = self.get_outdated(packages, options) | ||
| 146 | elif options.uptodate: | ||
| 147 | packages = self.get_uptodate(packages, options) | ||
| 148 | |||
| 149 | if options.not_required: | ||
| 150 | packages = self.get_not_required(packages, options) | ||
| 151 | |||
| 152 | self.output_package_listing(packages, options) | ||
| 153 | |||
| 154 | def get_outdated(self, packages, options): | ||
| 155 | return [ | ||
| 156 | dist for dist in self.iter_packages_latest_infos(packages, options) | ||
| 157 | if dist.latest_version > dist.parsed_version | ||
| 158 | ] | ||
| 159 | |||
| 160 | def get_uptodate(self, packages, options): | ||
| 161 | return [ | ||
| 162 | dist for dist in self.iter_packages_latest_infos(packages, options) | ||
| 163 | if dist.latest_version == dist.parsed_version | ||
| 164 | ] | ||
| 165 | |||
| 166 | def get_not_required(self, packages, options): | ||
| 167 | dep_keys = set() | ||
| 168 | for dist in packages: | ||
| 169 | dep_keys.update(requirement.key for requirement in dist.requires()) | ||
| 170 | return {pkg for pkg in packages if pkg.key not in dep_keys} | ||
| 171 | |||
| 172 | def iter_packages_latest_infos(self, packages, options): | ||
| 173 | index_urls = [options.index_url] + options.extra_index_urls | ||
| 174 | if options.no_index: | ||
| 175 | logger.debug('Ignoring indexes: %s', ','.join(index_urls)) | ||
| 176 | index_urls = [] | ||
| 177 | |||
| 178 | dependency_links = [] | ||
| 179 | for dist in packages: | ||
| 180 | if dist.has_metadata('dependency_links.txt'): | ||
| 181 | dependency_links.extend( | ||
| 182 | dist.get_metadata_lines('dependency_links.txt'), | ||
| 183 | ) | ||
| 184 | |||
| 185 | with self._build_session(options) as session: | ||
| 186 | finder = self._build_package_finder(options, index_urls, session) | ||
| 187 | finder.add_dependency_links(dependency_links) | ||
| 188 | |||
| 189 | for dist in packages: | ||
| 190 | typ = 'unknown' | ||
| 191 | all_candidates = finder.find_all_candidates(dist.key) | ||
| 192 | if not options.pre: | ||
| 193 | # Remove prereleases | ||
| 194 | all_candidates = [candidate for candidate in all_candidates | ||
| 195 | if not candidate.version.is_prerelease] | ||
| 196 | |||
| 197 | if not all_candidates: | ||
| 198 | continue | ||
| 199 | best_candidate = max(all_candidates, | ||
| 200 | key=finder._candidate_sort_key) | ||
| 201 | remote_version = best_candidate.version | ||
| 202 | if best_candidate.location.is_wheel: | ||
| 203 | typ = 'wheel' | ||
| 204 | else: | ||
| 205 | typ = 'sdist' | ||
| 206 | # This is dirty but makes the rest of the code much cleaner | ||
| 207 | dist.latest_version = remote_version | ||
| 208 | dist.latest_filetype = typ | ||
| 209 | yield dist | ||
| 210 | |||
| 211 | def output_legacy(self, dist, options): | ||
| 212 | if options.verbose >= 1: | ||
| 213 | return '%s (%s, %s, %s)' % ( | ||
| 214 | dist.project_name, | ||
| 215 | dist.version, | ||
| 216 | dist.location, | ||
| 217 | get_installer(dist), | ||
| 218 | ) | ||
| 219 | elif dist_is_editable(dist): | ||
| 220 | return '%s (%s, %s)' % ( | ||
| 221 | dist.project_name, | ||
| 222 | dist.version, | ||
| 223 | dist.location, | ||
| 224 | ) | ||
| 225 | else: | ||
| 226 | return '%s (%s)' % (dist.project_name, dist.version) | ||
| 227 | |||
| 228 | def output_legacy_latest(self, dist, options): | ||
| 229 | return '%s - Latest: %s [%s]' % ( | ||
| 230 | self.output_legacy(dist, options), | ||
| 231 | dist.latest_version, | ||
| 232 | dist.latest_filetype, | ||
| 233 | ) | ||
| 234 | |||
| 235 | def output_package_listing(self, packages, options): | ||
| 236 | packages = sorted( | ||
| 237 | packages, | ||
| 238 | key=lambda dist: dist.project_name.lower(), | ||
| 239 | ) | ||
| 240 | if options.list_format == 'columns' and packages: | ||
| 241 | data, header = format_for_columns(packages, options) | ||
| 242 | self.output_package_listing_columns(data, header) | ||
| 243 | elif options.list_format == 'freeze': | ||
| 244 | for dist in packages: | ||
| 245 | if options.verbose >= 1: | ||
| 246 | logger.info("%s==%s (%s)", dist.project_name, | ||
| 247 | dist.version, dist.location) | ||
| 248 | else: | ||
| 249 | logger.info("%s==%s", dist.project_name, dist.version) | ||
| 250 | elif options.list_format == 'json': | ||
| 251 | logger.info(format_for_json(packages, options)) | ||
| 252 | elif options.list_format == "legacy": | ||
| 253 | for dist in packages: | ||
| 254 | if options.outdated: | ||
| 255 | logger.info(self.output_legacy_latest(dist, options)) | ||
| 256 | else: | ||
| 257 | logger.info(self.output_legacy(dist, options)) | ||
| 258 | |||
| 259 | def output_package_listing_columns(self, data, header): | ||
| 260 | # insert the header first: we need to know the size of column names | ||
| 261 | if len(data) > 0: | ||
| 262 | data.insert(0, header) | ||
| 263 | |||
| 264 | pkg_strings, sizes = tabulate(data) | ||
| 265 | |||
| 266 | # Create and add a separator. | ||
| 267 | if len(data) > 0: | ||
| 268 | pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) | ||
| 269 | |||
| 270 | for val in pkg_strings: | ||
| 271 | logger.info(val) | ||
| 272 | |||
| 273 | |||
| 274 | def tabulate(vals): | ||
| 275 | # From pfmoore on GitHub: | ||
| 276 | # https://github.com/pypa/pip/issues/3651#issuecomment-216932564 | ||
| 277 | assert len(vals) > 0 | ||
| 278 | |||
| 279 | sizes = [0] * max(len(x) for x in vals) | ||
| 280 | for row in vals: | ||
| 281 | sizes = [max(s, len(str(c))) for s, c in zip_longest(sizes, row)] | ||
| 282 | |||
| 283 | result = [] | ||
| 284 | for row in vals: | ||
| 285 | display = " ".join([str(c).ljust(s) if c is not None else '' | ||
| 286 | for s, c in zip_longest(sizes, row)]) | ||
| 287 | result.append(display) | ||
| 288 | |||
| 289 | return result, sizes | ||
| 290 | |||
| 291 | |||
| 292 | def format_for_columns(pkgs, options): | ||
| 293 | """ | ||
| 294 | Convert the package data into something usable | ||
| 295 | by output_package_listing_columns. | ||
| 296 | """ | ||
| 297 | running_outdated = options.outdated | ||
| 298 | # Adjust the header for the `pip list --outdated` case. | ||
| 299 | if running_outdated: | ||
| 300 | header = ["Package", "Version", "Latest", "Type"] | ||
| 301 | else: | ||
| 302 | header = ["Package", "Version"] | ||
| 303 | |||
| 304 | data = [] | ||
| 305 | if options.verbose >= 1 or any(dist_is_editable(x) for x in pkgs): | ||
| 306 | header.append("Location") | ||
| 307 | if options.verbose >= 1: | ||
| 308 | header.append("Installer") | ||
| 309 | |||
| 310 | for proj in pkgs: | ||
| 311 | # if we're working on the 'outdated' list, separate out the | ||
| 312 | # latest_version and type | ||
| 313 | row = [proj.project_name, proj.version] | ||
| 314 | |||
| 315 | if running_outdated: | ||
| 316 | row.append(proj.latest_version) | ||
| 317 | row.append(proj.latest_filetype) | ||
| 318 | |||
| 319 | if options.verbose >= 1 or dist_is_editable(proj): | ||
| 320 | row.append(proj.location) | ||
| 321 | if options.verbose >= 1: | ||
| 322 | row.append(get_installer(proj)) | ||
| 323 | |||
| 324 | data.append(row) | ||
| 325 | |||
| 326 | return data, header | ||
| 327 | |||
| 328 | |||
| 329 | def format_for_json(packages, options): | ||
| 330 | data = [] | ||
| 331 | for dist in packages: | ||
| 332 | info = { | ||
| 333 | 'name': dist.project_name, | ||
| 334 | 'version': six.text_type(dist.version), | ||
| 335 | } | ||
| 336 | if options.verbose >= 1: | ||
| 337 | info['location'] = dist.location | ||
| 338 | info['installer'] = get_installer(dist) | ||
| 339 | if options.outdated: | ||
| 340 | info['latest_version'] = six.text_type(dist.latest_version) | ||
| 341 | info['latest_filetype'] = dist.latest_filetype | ||
| 342 | data.append(info) | ||
| 343 | return json.dumps(data) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/search.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/search.py deleted file mode 100644 index 83895ce..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/search.py +++ /dev/null | |||
| @@ -1,135 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import sys | ||
| 5 | import textwrap | ||
| 6 | from collections import OrderedDict | ||
| 7 | |||
| 8 | from pip._vendor import pkg_resources | ||
| 9 | from pip._vendor.packaging.version import parse as parse_version | ||
| 10 | # NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is | ||
| 11 | # why we ignore the type on this import | ||
| 12 | from pip._vendor.six.moves import xmlrpc_client # type: ignore | ||
| 13 | |||
| 14 | from pip._internal.basecommand import SUCCESS, Command | ||
| 15 | from pip._internal.compat import get_terminal_size | ||
| 16 | from pip._internal.download import PipXmlrpcTransport | ||
| 17 | from pip._internal.exceptions import CommandError | ||
| 18 | from pip._internal.models import PyPI | ||
| 19 | from pip._internal.status_codes import NO_MATCHES_FOUND | ||
| 20 | from pip._internal.utils.logging import indent_log | ||
| 21 | |||
| 22 | logger = logging.getLogger(__name__) | ||
| 23 | |||
| 24 | |||
| 25 | class SearchCommand(Command): | ||
| 26 | """Search for PyPI packages whose name or summary contains <query>.""" | ||
| 27 | name = 'search' | ||
| 28 | usage = """ | ||
| 29 | %prog [options] <query>""" | ||
| 30 | summary = 'Search PyPI for packages.' | ||
| 31 | ignore_require_venv = True | ||
| 32 | |||
| 33 | def __init__(self, *args, **kw): | ||
| 34 | super(SearchCommand, self).__init__(*args, **kw) | ||
| 35 | self.cmd_opts.add_option( | ||
| 36 | '-i', '--index', | ||
| 37 | dest='index', | ||
| 38 | metavar='URL', | ||
| 39 | default=PyPI.pypi_url, | ||
| 40 | help='Base URL of Python Package Index (default %default)') | ||
| 41 | |||
| 42 | self.parser.insert_option_group(0, self.cmd_opts) | ||
| 43 | |||
| 44 | def run(self, options, args): | ||
| 45 | if not args: | ||
| 46 | raise CommandError('Missing required argument (search query).') | ||
| 47 | query = args | ||
| 48 | pypi_hits = self.search(query, options) | ||
| 49 | hits = transform_hits(pypi_hits) | ||
| 50 | |||
| 51 | terminal_width = None | ||
| 52 | if sys.stdout.isatty(): | ||
| 53 | terminal_width = get_terminal_size()[0] | ||
| 54 | |||
| 55 | print_results(hits, terminal_width=terminal_width) | ||
| 56 | if pypi_hits: | ||
| 57 | return SUCCESS | ||
| 58 | return NO_MATCHES_FOUND | ||
| 59 | |||
| 60 | def search(self, query, options): | ||
| 61 | index_url = options.index | ||
| 62 | with self._build_session(options) as session: | ||
| 63 | transport = PipXmlrpcTransport(index_url, session) | ||
| 64 | pypi = xmlrpc_client.ServerProxy(index_url, transport) | ||
| 65 | hits = pypi.search({'name': query, 'summary': query}, 'or') | ||
| 66 | return hits | ||
| 67 | |||
| 68 | |||
| 69 | def transform_hits(hits): | ||
| 70 | """ | ||
| 71 | The list from pypi is really a list of versions. We want a list of | ||
| 72 | packages with the list of versions stored inline. This converts the | ||
| 73 | list from pypi into one we can use. | ||
| 74 | """ | ||
| 75 | packages = OrderedDict() | ||
| 76 | for hit in hits: | ||
| 77 | name = hit['name'] | ||
| 78 | summary = hit['summary'] | ||
| 79 | version = hit['version'] | ||
| 80 | |||
| 81 | if name not in packages.keys(): | ||
| 82 | packages[name] = { | ||
| 83 | 'name': name, | ||
| 84 | 'summary': summary, | ||
| 85 | 'versions': [version], | ||
| 86 | } | ||
| 87 | else: | ||
| 88 | packages[name]['versions'].append(version) | ||
| 89 | |||
| 90 | # if this is the highest version, replace summary and score | ||
| 91 | if version == highest_version(packages[name]['versions']): | ||
| 92 | packages[name]['summary'] = summary | ||
| 93 | |||
| 94 | return list(packages.values()) | ||
| 95 | |||
| 96 | |||
| 97 | def print_results(hits, name_column_width=None, terminal_width=None): | ||
| 98 | if not hits: | ||
| 99 | return | ||
| 100 | if name_column_width is None: | ||
| 101 | name_column_width = max([ | ||
| 102 | len(hit['name']) + len(highest_version(hit.get('versions', ['-']))) | ||
| 103 | for hit in hits | ||
| 104 | ]) + 4 | ||
| 105 | |||
| 106 | installed_packages = [p.project_name for p in pkg_resources.working_set] | ||
| 107 | for hit in hits: | ||
| 108 | name = hit['name'] | ||
| 109 | summary = hit['summary'] or '' | ||
| 110 | latest = highest_version(hit.get('versions', ['-'])) | ||
| 111 | if terminal_width is not None: | ||
| 112 | target_width = terminal_width - name_column_width - 5 | ||
| 113 | if target_width > 10: | ||
| 114 | # wrap and indent summary to fit terminal | ||
| 115 | summary = textwrap.wrap(summary, target_width) | ||
| 116 | summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) | ||
| 117 | |||
| 118 | line = '%-*s - %s' % (name_column_width, | ||
| 119 | '%s (%s)' % (name, latest), summary) | ||
| 120 | try: | ||
| 121 | logger.info(line) | ||
| 122 | if name in installed_packages: | ||
| 123 | dist = pkg_resources.get_distribution(name) | ||
| 124 | with indent_log(): | ||
| 125 | if dist.version == latest: | ||
| 126 | logger.info('INSTALLED: %s (latest)', dist.version) | ||
| 127 | else: | ||
| 128 | logger.info('INSTALLED: %s', dist.version) | ||
| 129 | logger.info('LATEST: %s', latest) | ||
| 130 | except UnicodeEncodeError: | ||
| 131 | pass | ||
| 132 | |||
| 133 | |||
| 134 | def highest_version(versions): | ||
| 135 | return max(versions, key=parse_version) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/show.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/show.py deleted file mode 100644 index bad9628..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/show.py +++ /dev/null | |||
| @@ -1,164 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os | ||
| 5 | from email.parser import FeedParser # type: ignore | ||
| 6 | |||
| 7 | from pip._vendor import pkg_resources | ||
| 8 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 9 | |||
| 10 | from pip._internal.basecommand import Command | ||
| 11 | from pip._internal.status_codes import ERROR, SUCCESS | ||
| 12 | |||
| 13 | logger = logging.getLogger(__name__) | ||
| 14 | |||
| 15 | |||
| 16 | class ShowCommand(Command): | ||
| 17 | """Show information about one or more installed packages.""" | ||
| 18 | name = 'show' | ||
| 19 | usage = """ | ||
| 20 | %prog [options] <package> ...""" | ||
| 21 | summary = 'Show information about installed packages.' | ||
| 22 | ignore_require_venv = True | ||
| 23 | |||
| 24 | def __init__(self, *args, **kw): | ||
| 25 | super(ShowCommand, self).__init__(*args, **kw) | ||
| 26 | self.cmd_opts.add_option( | ||
| 27 | '-f', '--files', | ||
| 28 | dest='files', | ||
| 29 | action='store_true', | ||
| 30 | default=False, | ||
| 31 | help='Show the full list of installed files for each package.') | ||
| 32 | |||
| 33 | self.parser.insert_option_group(0, self.cmd_opts) | ||
| 34 | |||
| 35 | def run(self, options, args): | ||
| 36 | if not args: | ||
| 37 | logger.warning('ERROR: Please provide a package name or names.') | ||
| 38 | return ERROR | ||
| 39 | query = args | ||
| 40 | |||
| 41 | results = search_packages_info(query) | ||
| 42 | if not print_results( | ||
| 43 | results, list_files=options.files, verbose=options.verbose): | ||
| 44 | return ERROR | ||
| 45 | return SUCCESS | ||
| 46 | |||
| 47 | |||
| 48 | def search_packages_info(query): | ||
| 49 | """ | ||
| 50 | Gather details from installed distributions. Print distribution name, | ||
| 51 | version, location, and installed files. Installed files requires a | ||
| 52 | pip generated 'installed-files.txt' in the distributions '.egg-info' | ||
| 53 | directory. | ||
| 54 | """ | ||
| 55 | installed = {} | ||
| 56 | for p in pkg_resources.working_set: | ||
| 57 | installed[canonicalize_name(p.project_name)] = p | ||
| 58 | |||
| 59 | query_names = [canonicalize_name(name) for name in query] | ||
| 60 | |||
| 61 | for dist in [installed[pkg] for pkg in query_names if pkg in installed]: | ||
| 62 | package = { | ||
| 63 | 'name': dist.project_name, | ||
| 64 | 'version': dist.version, | ||
| 65 | 'location': dist.location, | ||
| 66 | 'requires': [dep.project_name for dep in dist.requires()], | ||
| 67 | } | ||
| 68 | file_list = None | ||
| 69 | metadata = None | ||
| 70 | if isinstance(dist, pkg_resources.DistInfoDistribution): | ||
| 71 | # RECORDs should be part of .dist-info metadatas | ||
| 72 | if dist.has_metadata('RECORD'): | ||
| 73 | lines = dist.get_metadata_lines('RECORD') | ||
| 74 | paths = [l.split(',')[0] for l in lines] | ||
| 75 | paths = [os.path.join(dist.location, p) for p in paths] | ||
| 76 | file_list = [os.path.relpath(p, dist.location) for p in paths] | ||
| 77 | |||
| 78 | if dist.has_metadata('METADATA'): | ||
| 79 | metadata = dist.get_metadata('METADATA') | ||
| 80 | else: | ||
| 81 | # Otherwise use pip's log for .egg-info's | ||
| 82 | if dist.has_metadata('installed-files.txt'): | ||
| 83 | paths = dist.get_metadata_lines('installed-files.txt') | ||
| 84 | paths = [os.path.join(dist.egg_info, p) for p in paths] | ||
| 85 | file_list = [os.path.relpath(p, dist.location) for p in paths] | ||
| 86 | |||
| 87 | if dist.has_metadata('PKG-INFO'): | ||
| 88 | metadata = dist.get_metadata('PKG-INFO') | ||
| 89 | |||
| 90 | if dist.has_metadata('entry_points.txt'): | ||
| 91 | entry_points = dist.get_metadata_lines('entry_points.txt') | ||
| 92 | package['entry_points'] = entry_points | ||
| 93 | |||
| 94 | if dist.has_metadata('INSTALLER'): | ||
| 95 | for line in dist.get_metadata_lines('INSTALLER'): | ||
| 96 | if line.strip(): | ||
| 97 | package['installer'] = line.strip() | ||
| 98 | break | ||
| 99 | |||
| 100 | # @todo: Should pkg_resources.Distribution have a | ||
| 101 | # `get_pkg_info` method? | ||
| 102 | feed_parser = FeedParser() | ||
| 103 | feed_parser.feed(metadata) | ||
| 104 | pkg_info_dict = feed_parser.close() | ||
| 105 | for key in ('metadata-version', 'summary', | ||
| 106 | 'home-page', 'author', 'author-email', 'license'): | ||
| 107 | package[key] = pkg_info_dict.get(key) | ||
| 108 | |||
| 109 | # It looks like FeedParser cannot deal with repeated headers | ||
| 110 | classifiers = [] | ||
| 111 | for line in metadata.splitlines(): | ||
| 112 | if line.startswith('Classifier: '): | ||
| 113 | classifiers.append(line[len('Classifier: '):]) | ||
| 114 | package['classifiers'] = classifiers | ||
| 115 | |||
| 116 | if file_list: | ||
| 117 | package['files'] = sorted(file_list) | ||
| 118 | yield package | ||
| 119 | |||
| 120 | |||
| 121 | def print_results(distributions, list_files=False, verbose=False): | ||
| 122 | """ | ||
| 123 | Print the informations from installed distributions found. | ||
| 124 | """ | ||
| 125 | results_printed = False | ||
| 126 | for i, dist in enumerate(distributions): | ||
| 127 | results_printed = True | ||
| 128 | if i > 0: | ||
| 129 | logger.info("---") | ||
| 130 | |||
| 131 | name = dist.get('name', '') | ||
| 132 | required_by = [ | ||
| 133 | pkg.project_name for pkg in pkg_resources.working_set | ||
| 134 | if name in [required.name for required in pkg.requires()] | ||
| 135 | ] | ||
| 136 | |||
| 137 | logger.info("Name: %s", name) | ||
| 138 | logger.info("Version: %s", dist.get('version', '')) | ||
| 139 | logger.info("Summary: %s", dist.get('summary', '')) | ||
| 140 | logger.info("Home-page: %s", dist.get('home-page', '')) | ||
| 141 | logger.info("Author: %s", dist.get('author', '')) | ||
| 142 | logger.info("Author-email: %s", dist.get('author-email', '')) | ||
| 143 | logger.info("License: %s", dist.get('license', '')) | ||
| 144 | logger.info("Location: %s", dist.get('location', '')) | ||
| 145 | logger.info("Requires: %s", ', '.join(dist.get('requires', []))) | ||
| 146 | logger.info("Required-by: %s", ', '.join(required_by)) | ||
| 147 | |||
| 148 | if verbose: | ||
| 149 | logger.info("Metadata-Version: %s", | ||
| 150 | dist.get('metadata-version', '')) | ||
| 151 | logger.info("Installer: %s", dist.get('installer', '')) | ||
| 152 | logger.info("Classifiers:") | ||
| 153 | for classifier in dist.get('classifiers', []): | ||
| 154 | logger.info(" %s", classifier) | ||
| 155 | logger.info("Entry-points:") | ||
| 156 | for entry in dist.get('entry_points', []): | ||
| 157 | logger.info(" %s", entry.strip()) | ||
| 158 | if list_files: | ||
| 159 | logger.info("Files:") | ||
| 160 | for line in dist.get('files', []): | ||
| 161 | logger.info(" %s", line.strip()) | ||
| 162 | if "files" not in dist: | ||
| 163 | logger.info("Cannot locate installed-files.txt") | ||
| 164 | return results_printed | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/uninstall.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/uninstall.py deleted file mode 100644 index 3bfa07f..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/uninstall.py +++ /dev/null | |||
| @@ -1,71 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 4 | |||
| 5 | from pip._internal.basecommand import Command | ||
| 6 | from pip._internal.exceptions import InstallationError | ||
| 7 | from pip._internal.req import InstallRequirement, parse_requirements | ||
| 8 | |||
| 9 | |||
| 10 | class UninstallCommand(Command): | ||
| 11 | """ | ||
| 12 | Uninstall packages. | ||
| 13 | |||
| 14 | pip is able to uninstall most installed packages. Known exceptions are: | ||
| 15 | |||
| 16 | - Pure distutils packages installed with ``python setup.py install``, which | ||
| 17 | leave behind no metadata to determine what files were installed. | ||
| 18 | - Script wrappers installed by ``python setup.py develop``. | ||
| 19 | """ | ||
| 20 | name = 'uninstall' | ||
| 21 | usage = """ | ||
| 22 | %prog [options] <package> ... | ||
| 23 | %prog [options] -r <requirements file> ...""" | ||
| 24 | summary = 'Uninstall packages.' | ||
| 25 | |||
| 26 | def __init__(self, *args, **kw): | ||
| 27 | super(UninstallCommand, self).__init__(*args, **kw) | ||
| 28 | self.cmd_opts.add_option( | ||
| 29 | '-r', '--requirement', | ||
| 30 | dest='requirements', | ||
| 31 | action='append', | ||
| 32 | default=[], | ||
| 33 | metavar='file', | ||
| 34 | help='Uninstall all the packages listed in the given requirements ' | ||
| 35 | 'file. This option can be used multiple times.', | ||
| 36 | ) | ||
| 37 | self.cmd_opts.add_option( | ||
| 38 | '-y', '--yes', | ||
| 39 | dest='yes', | ||
| 40 | action='store_true', | ||
| 41 | help="Don't ask for confirmation of uninstall deletions.") | ||
| 42 | |||
| 43 | self.parser.insert_option_group(0, self.cmd_opts) | ||
| 44 | |||
| 45 | def run(self, options, args): | ||
| 46 | with self._build_session(options) as session: | ||
| 47 | reqs_to_uninstall = {} | ||
| 48 | for name in args: | ||
| 49 | req = InstallRequirement.from_line( | ||
| 50 | name, isolated=options.isolated_mode, | ||
| 51 | ) | ||
| 52 | if req.name: | ||
| 53 | reqs_to_uninstall[canonicalize_name(req.name)] = req | ||
| 54 | for filename in options.requirements: | ||
| 55 | for req in parse_requirements( | ||
| 56 | filename, | ||
| 57 | options=options, | ||
| 58 | session=session): | ||
| 59 | if req.name: | ||
| 60 | reqs_to_uninstall[canonicalize_name(req.name)] = req | ||
| 61 | if not reqs_to_uninstall: | ||
| 62 | raise InstallationError( | ||
| 63 | 'You must give at least one requirement to %(name)s (see ' | ||
| 64 | '"pip help %(name)s")' % dict(name=self.name) | ||
| 65 | ) | ||
| 66 | for req in reqs_to_uninstall.values(): | ||
| 67 | uninstall_pathset = req.uninstall( | ||
| 68 | auto_confirm=options.yes, verbose=self.verbosity > 0, | ||
| 69 | ) | ||
| 70 | if uninstall_pathset: | ||
| 71 | uninstall_pathset.commit() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/wheel.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/wheel.py deleted file mode 100644 index ed8cdfc..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/commands/wheel.py +++ /dev/null | |||
| @@ -1,179 +0,0 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import logging | ||
| 5 | import os | ||
| 6 | |||
| 7 | from pip._internal import cmdoptions | ||
| 8 | from pip._internal.basecommand import RequirementCommand | ||
| 9 | from pip._internal.cache import WheelCache | ||
| 10 | from pip._internal.exceptions import CommandError, PreviousBuildDirError | ||
| 11 | from pip._internal.operations.prepare import RequirementPreparer | ||
| 12 | from pip._internal.req import RequirementSet | ||
| 13 | from pip._internal.resolve import Resolver | ||
| 14 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 15 | from pip._internal.wheel import WheelBuilder | ||
| 16 | |||
| 17 | logger = logging.getLogger(__name__) | ||
| 18 | |||
| 19 | |||
| 20 | class WheelCommand(RequirementCommand): | ||
| 21 | """ | ||
| 22 | Build Wheel archives for your requirements and dependencies. | ||
| 23 | |||
| 24 | Wheel is a built-package format, and offers the advantage of not | ||
| 25 | recompiling your software during every install. For more details, see the | ||
| 26 | wheel docs: https://wheel.readthedocs.io/en/latest/ | ||
| 27 | |||
| 28 | Requirements: setuptools>=0.8, and wheel. | ||
| 29 | |||
| 30 | 'pip wheel' uses the bdist_wheel setuptools extension from the wheel | ||
| 31 | package to build individual wheels. | ||
| 32 | |||
| 33 | """ | ||
| 34 | |||
| 35 | name = 'wheel' | ||
| 36 | usage = """ | ||
| 37 | %prog [options] <requirement specifier> ... | ||
| 38 | %prog [options] -r <requirements file> ... | ||
| 39 | %prog [options] [-e] <vcs project url> ... | ||
| 40 | %prog [options] [-e] <local project path> ... | ||
| 41 | %prog [options] <archive url/path> ...""" | ||
| 42 | |||
| 43 | summary = 'Build wheels from your requirements.' | ||
| 44 | |||
| 45 | def __init__(self, *args, **kw): | ||
| 46 | super(WheelCommand, self).__init__(*args, **kw) | ||
| 47 | |||
| 48 | cmd_opts = self.cmd_opts | ||
| 49 | |||
| 50 | cmd_opts.add_option( | ||
| 51 | '-w', '--wheel-dir', | ||
| 52 | dest='wheel_dir', | ||
| 53 | metavar='dir', | ||
| 54 | default=os.curdir, | ||
| 55 | help=("Build wheels into <dir>, where the default is the " | ||
| 56 | "current working directory."), | ||
| 57 | ) | ||
| 58 | cmd_opts.add_option(cmdoptions.no_binary()) | ||
| 59 | cmd_opts.add_option(cmdoptions.only_binary()) | ||
| 60 | cmd_opts.add_option( | ||
| 61 | '--build-option', | ||
| 62 | dest='build_options', | ||
| 63 | metavar='options', | ||
| 64 | action='append', | ||
| 65 | help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", | ||
| 66 | ) | ||
| 67 | cmd_opts.add_option(cmdoptions.no_build_isolation()) | ||
| 68 | cmd_opts.add_option(cmdoptions.constraints()) | ||
| 69 | cmd_opts.add_option(cmdoptions.editable()) | ||
| 70 | cmd_opts.add_option(cmdoptions.requirements()) | ||
| 71 | cmd_opts.add_option(cmdoptions.src()) | ||
| 72 | cmd_opts.add_option(cmdoptions.ignore_requires_python()) | ||
| 73 | cmd_opts.add_option(cmdoptions.no_deps()) | ||
| 74 | cmd_opts.add_option(cmdoptions.build_dir()) | ||
| 75 | cmd_opts.add_option(cmdoptions.progress_bar()) | ||
| 76 | |||
| 77 | cmd_opts.add_option( | ||
| 78 | '--global-option', | ||
| 79 | dest='global_options', | ||
| 80 | action='append', | ||
| 81 | metavar='options', | ||
| 82 | help="Extra global options to be supplied to the setup.py " | ||
| 83 | "call before the 'bdist_wheel' command.") | ||
| 84 | |||
| 85 | cmd_opts.add_option( | ||
| 86 | '--pre', | ||
| 87 | action='store_true', | ||
| 88 | default=False, | ||
| 89 | help=("Include pre-release and development versions. By default, " | ||
| 90 | "pip only finds stable versions."), | ||
| 91 | ) | ||
| 92 | |||
| 93 | cmd_opts.add_option(cmdoptions.no_clean()) | ||
| 94 | cmd_opts.add_option(cmdoptions.require_hashes()) | ||
| 95 | |||
| 96 | index_opts = cmdoptions.make_option_group( | ||
| 97 | cmdoptions.index_group, | ||
| 98 | self.parser, | ||
| 99 | ) | ||
| 100 | |||
| 101 | self.parser.insert_option_group(0, index_opts) | ||
| 102 | self.parser.insert_option_group(0, cmd_opts) | ||
| 103 | |||
| 104 | def run(self, options, args): | ||
| 105 | cmdoptions.check_install_build_global(options) | ||
| 106 | |||
| 107 | index_urls = [options.index_url] + options.extra_index_urls | ||
| 108 | if options.no_index: | ||
| 109 | logger.debug('Ignoring indexes: %s', ','.join(index_urls)) | ||
| 110 | index_urls = [] | ||
| 111 | |||
| 112 | if options.build_dir: | ||
| 113 | options.build_dir = os.path.abspath(options.build_dir) | ||
| 114 | |||
| 115 | options.src_dir = os.path.abspath(options.src_dir) | ||
| 116 | |||
| 117 | with self._build_session(options) as session: | ||
| 118 | finder = self._build_package_finder(options, session) | ||
| 119 | build_delete = (not (options.no_clean or options.build_dir)) | ||
| 120 | wheel_cache = WheelCache(options.cache_dir, options.format_control) | ||
| 121 | |||
| 122 | with TempDirectory( | ||
| 123 | options.build_dir, delete=build_delete, kind="wheel" | ||
| 124 | ) as directory: | ||
| 125 | requirement_set = RequirementSet( | ||
| 126 | require_hashes=options.require_hashes, | ||
| 127 | ) | ||
| 128 | |||
| 129 | try: | ||
| 130 | self.populate_requirement_set( | ||
| 131 | requirement_set, args, options, finder, session, | ||
| 132 | self.name, wheel_cache | ||
| 133 | ) | ||
| 134 | |||
| 135 | preparer = RequirementPreparer( | ||
| 136 | build_dir=directory.path, | ||
| 137 | src_dir=options.src_dir, | ||
| 138 | download_dir=None, | ||
| 139 | wheel_download_dir=options.wheel_dir, | ||
| 140 | progress_bar=options.progress_bar, | ||
| 141 | build_isolation=options.build_isolation, | ||
| 142 | ) | ||
| 143 | |||
| 144 | resolver = Resolver( | ||
| 145 | preparer=preparer, | ||
| 146 | finder=finder, | ||
| 147 | session=session, | ||
| 148 | wheel_cache=wheel_cache, | ||
| 149 | use_user_site=False, | ||
| 150 | upgrade_strategy="to-satisfy-only", | ||
| 151 | force_reinstall=False, | ||
| 152 | ignore_dependencies=options.ignore_dependencies, | ||
| 153 | ignore_requires_python=options.ignore_requires_python, | ||
| 154 | ignore_installed=True, | ||
| 155 | isolated=options.isolated_mode, | ||
| 156 | ) | ||
| 157 | resolver.resolve(requirement_set) | ||
| 158 | |||
| 159 | # build wheels | ||
| 160 | wb = WheelBuilder( | ||
| 161 | finder, preparer, wheel_cache, | ||
| 162 | build_options=options.build_options or [], | ||
| 163 | global_options=options.global_options or [], | ||
| 164 | no_clean=options.no_clean, | ||
| 165 | ) | ||
| 166 | wheels_built_successfully = wb.build( | ||
| 167 | requirement_set.requirements.values(), session=session, | ||
| 168 | ) | ||
| 169 | if not wheels_built_successfully: | ||
| 170 | raise CommandError( | ||
| 171 | "Failed to build one or more wheels" | ||
| 172 | ) | ||
| 173 | except PreviousBuildDirError: | ||
| 174 | options.no_clean = True | ||
| 175 | raise | ||
| 176 | finally: | ||
| 177 | if not options.no_clean: | ||
| 178 | requirement_set.cleanup_files() | ||
| 179 | wheel_cache.cleanup() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/compat.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/compat.py deleted file mode 100644 index 064717d..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/compat.py +++ /dev/null | |||
| @@ -1,235 +0,0 @@ | |||
| 1 | """Stuff that differs in different Python versions and platform | ||
| 2 | distributions.""" | ||
| 3 | from __future__ import absolute_import, division | ||
| 4 | |||
| 5 | import codecs | ||
| 6 | import locale | ||
| 7 | import logging | ||
| 8 | import os | ||
| 9 | import shutil | ||
| 10 | import sys | ||
| 11 | |||
| 12 | from pip._vendor.six import text_type | ||
| 13 | |||
| 14 | try: | ||
| 15 | import ipaddress | ||
| 16 | except ImportError: | ||
| 17 | try: | ||
| 18 | from pip._vendor import ipaddress # type: ignore | ||
| 19 | except ImportError: | ||
| 20 | import ipaddr as ipaddress # type: ignore | ||
| 21 | ipaddress.ip_address = ipaddress.IPAddress | ||
| 22 | ipaddress.ip_network = ipaddress.IPNetwork | ||
| 23 | |||
| 24 | |||
| 25 | __all__ = [ | ||
| 26 | "ipaddress", "uses_pycache", "console_to_str", "native_str", | ||
| 27 | "get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile", "get_terminal_size", | ||
| 28 | ] | ||
| 29 | |||
| 30 | |||
| 31 | logger = logging.getLogger(__name__) | ||
| 32 | |||
| 33 | if sys.version_info >= (3, 4): | ||
| 34 | uses_pycache = True | ||
| 35 | from importlib.util import cache_from_source | ||
| 36 | else: | ||
| 37 | import imp | ||
| 38 | |||
| 39 | try: | ||
| 40 | cache_from_source = imp.cache_from_source # type: ignore | ||
| 41 | except AttributeError: | ||
| 42 | # does not use __pycache__ | ||
| 43 | cache_from_source = None | ||
| 44 | |||
| 45 | uses_pycache = cache_from_source is not None | ||
| 46 | |||
| 47 | |||
| 48 | if sys.version_info >= (3, 5): | ||
| 49 | backslashreplace_decode = "backslashreplace" | ||
| 50 | else: | ||
| 51 | # In version 3.4 and older, backslashreplace exists | ||
| 52 | # but does not support use for decoding. | ||
| 53 | # We implement our own replace handler for this | ||
| 54 | # situation, so that we can consistently use | ||
| 55 | # backslash replacement for all versions. | ||
| 56 | def backslashreplace_decode_fn(err): | ||
| 57 | raw_bytes = (err.object[i] for i in range(err.start, err.end)) | ||
| 58 | if sys.version_info[0] == 2: | ||
| 59 | # Python 2 gave us characters - convert to numeric bytes | ||
| 60 | raw_bytes = (ord(b) for b in raw_bytes) | ||
| 61 | return u"".join(u"\\x%x" % c for c in raw_bytes), err.end | ||
| 62 | codecs.register_error( | ||
| 63 | "backslashreplace_decode", | ||
| 64 | backslashreplace_decode_fn, | ||
| 65 | ) | ||
| 66 | backslashreplace_decode = "backslashreplace_decode" | ||
| 67 | |||
| 68 | |||
| 69 | def console_to_str(data): | ||
| 70 | """Return a string, safe for output, of subprocess output. | ||
| 71 | |||
| 72 | We assume the data is in the locale preferred encoding. | ||
| 73 | If it won't decode properly, we warn the user but decode as | ||
| 74 | best we can. | ||
| 75 | |||
| 76 | We also ensure that the output can be safely written to | ||
| 77 | standard output without encoding errors. | ||
| 78 | """ | ||
| 79 | |||
| 80 | # First, get the encoding we assume. This is the preferred | ||
| 81 | # encoding for the locale, unless that is not found, or | ||
| 82 | # it is ASCII, in which case assume UTF-8 | ||
| 83 | encoding = locale.getpreferredencoding() | ||
| 84 | if (not encoding) or codecs.lookup(encoding).name == "ascii": | ||
| 85 | encoding = "utf-8" | ||
| 86 | |||
| 87 | # Now try to decode the data - if we fail, warn the user and | ||
| 88 | # decode with replacement. | ||
| 89 | try: | ||
| 90 | s = data.decode(encoding) | ||
| 91 | except UnicodeDecodeError: | ||
| 92 | logger.warning( | ||
| 93 | "Subprocess output does not appear to be encoded as %s", | ||
| 94 | encoding, | ||
| 95 | ) | ||
| 96 | s = data.decode(encoding, errors=backslashreplace_decode) | ||
| 97 | |||
| 98 | # Make sure we can print the output, by encoding it to the output | ||
| 99 | # encoding with replacement of unencodable characters, and then | ||
| 100 | # decoding again. | ||
| 101 | # We use stderr's encoding because it's less likely to be | ||
| 102 | # redirected and if we don't find an encoding we skip this | ||
| 103 | # step (on the assumption that output is wrapped by something | ||
| 104 | # that won't fail). | ||
| 105 | # The double getattr is to deal with the possibility that we're | ||
| 106 | # being called in a situation where sys.__stderr__ doesn't exist, | ||
| 107 | # or doesn't have an encoding attribute. Neither of these cases | ||
| 108 | # should occur in normal pip use, but there's no harm in checking | ||
| 109 | # in case people use pip in (unsupported) unusual situations. | ||
| 110 | output_encoding = getattr(getattr(sys, "__stderr__", None), | ||
| 111 | "encoding", None) | ||
| 112 | |||
| 113 | if output_encoding: | ||
| 114 | s = s.encode(output_encoding, errors="backslashreplace") | ||
| 115 | s = s.decode(output_encoding) | ||
| 116 | |||
| 117 | return s | ||
| 118 | |||
| 119 | |||
| 120 | if sys.version_info >= (3,): | ||
| 121 | def native_str(s, replace=False): | ||
| 122 | if isinstance(s, bytes): | ||
| 123 | return s.decode('utf-8', 'replace' if replace else 'strict') | ||
| 124 | return s | ||
| 125 | |||
| 126 | else: | ||
| 127 | def native_str(s, replace=False): | ||
| 128 | # Replace is ignored -- unicode to UTF-8 can't fail | ||
| 129 | if isinstance(s, text_type): | ||
| 130 | return s.encode('utf-8') | ||
| 131 | return s | ||
| 132 | |||
| 133 | |||
| 134 | def get_path_uid(path): | ||
| 135 | """ | ||
| 136 | Return path's uid. | ||
| 137 | |||
| 138 | Does not follow symlinks: | ||
| 139 | https://github.com/pypa/pip/pull/935#discussion_r5307003 | ||
| 140 | |||
| 141 | Placed this function in compat due to differences on AIX and | ||
| 142 | Jython, that should eventually go away. | ||
| 143 | |||
| 144 | :raises OSError: When path is a symlink or can't be read. | ||
| 145 | """ | ||
| 146 | if hasattr(os, 'O_NOFOLLOW'): | ||
| 147 | fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) | ||
| 148 | file_uid = os.fstat(fd).st_uid | ||
| 149 | os.close(fd) | ||
| 150 | else: # AIX and Jython | ||
| 151 | # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW | ||
| 152 | if not os.path.islink(path): | ||
| 153 | # older versions of Jython don't have `os.fstat` | ||
| 154 | file_uid = os.stat(path).st_uid | ||
| 155 | else: | ||
| 156 | # raise OSError for parity with os.O_NOFOLLOW above | ||
| 157 | raise OSError( | ||
| 158 | "%s is a symlink; Will not return uid for symlinks" % path | ||
| 159 | ) | ||
| 160 | return file_uid | ||
| 161 | |||
| 162 | |||
| 163 | def expanduser(path): | ||
| 164 | """ | ||
| 165 | Expand ~ and ~user constructions. | ||
| 166 | |||
| 167 | Includes a workaround for http://bugs.python.org/issue14768 | ||
| 168 | """ | ||
| 169 | expanded = os.path.expanduser(path) | ||
| 170 | if path.startswith('~/') and expanded.startswith('//'): | ||
| 171 | expanded = expanded[1:] | ||
| 172 | return expanded | ||
| 173 | |||
| 174 | |||
| 175 | # packages in the stdlib that may have installation metadata, but should not be | ||
| 176 | # considered 'installed'. this theoretically could be determined based on | ||
| 177 | # dist.location (py27:`sysconfig.get_paths()['stdlib']`, | ||
| 178 | # py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may | ||
| 179 | # make this ineffective, so hard-coding | ||
| 180 | stdlib_pkgs = {"python", "wsgiref", "argparse"} | ||
| 181 | |||
| 182 | |||
| 183 | # windows detection, covers cpython and ironpython | ||
| 184 | WINDOWS = (sys.platform.startswith("win") or | ||
| 185 | (sys.platform == 'cli' and os.name == 'nt')) | ||
| 186 | |||
| 187 | |||
| 188 | def samefile(file1, file2): | ||
| 189 | """Provide an alternative for os.path.samefile on Windows/Python2""" | ||
| 190 | if hasattr(os.path, 'samefile'): | ||
| 191 | return os.path.samefile(file1, file2) | ||
| 192 | else: | ||
| 193 | path1 = os.path.normcase(os.path.abspath(file1)) | ||
| 194 | path2 = os.path.normcase(os.path.abspath(file2)) | ||
| 195 | return path1 == path2 | ||
| 196 | |||
| 197 | |||
| 198 | if hasattr(shutil, 'get_terminal_size'): | ||
| 199 | def get_terminal_size(): | ||
| 200 | """ | ||
| 201 | Returns a tuple (x, y) representing the width(x) and the height(y) | ||
| 202 | in characters of the terminal window. | ||
| 203 | """ | ||
| 204 | return tuple(shutil.get_terminal_size()) | ||
| 205 | else: | ||
| 206 | def get_terminal_size(): | ||
| 207 | """ | ||
| 208 | Returns a tuple (x, y) representing the width(x) and the height(y) | ||
| 209 | in characters of the terminal window. | ||
| 210 | """ | ||
| 211 | def ioctl_GWINSZ(fd): | ||
| 212 | try: | ||
| 213 | import fcntl | ||
| 214 | import termios | ||
| 215 | import struct | ||
| 216 | cr = struct.unpack_from( | ||
| 217 | 'hh', | ||
| 218 | fcntl.ioctl(fd, termios.TIOCGWINSZ, '12345678') | ||
| 219 | ) | ||
| 220 | except: | ||
| 221 | return None | ||
| 222 | if cr == (0, 0): | ||
| 223 | return None | ||
| 224 | return cr | ||
| 225 | cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) | ||
| 226 | if not cr: | ||
| 227 | try: | ||
| 228 | fd = os.open(os.ctermid(), os.O_RDONLY) | ||
| 229 | cr = ioctl_GWINSZ(fd) | ||
| 230 | os.close(fd) | ||
| 231 | except: | ||
| 232 | pass | ||
| 233 | if not cr: | ||
| 234 | cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) | ||
| 235 | return int(cr[1]), int(cr[0]) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/configuration.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/configuration.py deleted file mode 100644 index 07af373..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/configuration.py +++ /dev/null | |||
| @@ -1,378 +0,0 @@ | |||
| 1 | """Configuration management setup | ||
| 2 | |||
| 3 | Some terminology: | ||
| 4 | - name | ||
| 5 | As written in config files. | ||
| 6 | - value | ||
| 7 | Value associated with a name | ||
| 8 | - key | ||
| 9 | Name combined with it's section (section.name) | ||
| 10 | - variant | ||
| 11 | A single word describing where the configuration key-value pair came from | ||
| 12 | """ | ||
| 13 | |||
| 14 | import locale | ||
| 15 | import logging | ||
| 16 | import os | ||
| 17 | |||
| 18 | from pip._vendor import six | ||
| 19 | from pip._vendor.six.moves import configparser | ||
| 20 | |||
| 21 | from pip._internal.exceptions import ConfigurationError | ||
| 22 | from pip._internal.locations import ( | ||
| 23 | legacy_config_file, new_config_file, running_under_virtualenv, | ||
| 24 | site_config_files, venv_config_file, | ||
| 25 | ) | ||
| 26 | from pip._internal.utils.misc import ensure_dir, enum | ||
| 27 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 28 | |||
| 29 | if MYPY_CHECK_RUNNING: | ||
| 30 | from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple | ||
| 31 | |||
| 32 | RawConfigParser = configparser.RawConfigParser # Shorthand | ||
| 33 | Kind = NewType("Kind", str) | ||
| 34 | |||
| 35 | logger = logging.getLogger(__name__) | ||
| 36 | |||
| 37 | |||
| 38 | # NOTE: Maybe use the optionx attribute to normalize keynames. | ||
| 39 | def _normalize_name(name): | ||
| 40 | # type: (str) -> str | ||
| 41 | """Make a name consistent regardless of source (environment or file) | ||
| 42 | """ | ||
| 43 | name = name.lower().replace('_', '-') | ||
| 44 | if name.startswith('--'): | ||
| 45 | name = name[2:] # only prefer long opts | ||
| 46 | return name | ||
| 47 | |||
| 48 | |||
| 49 | def _disassemble_key(name): | ||
| 50 | # type: (str) -> List[str] | ||
| 51 | return name.split(".", 1) | ||
| 52 | |||
| 53 | |||
| 54 | # The kinds of configurations there are. | ||
| 55 | kinds = enum( | ||
| 56 | USER="user", # User Specific | ||
| 57 | GLOBAL="global", # System Wide | ||
| 58 | VENV="venv", # Virtual Environment Specific | ||
| 59 | ENV="env", # from PIP_CONFIG_FILE | ||
| 60 | ENV_VAR="env-var", # from Environment Variables | ||
| 61 | ) | ||
| 62 | |||
| 63 | |||
| 64 | class Configuration(object): | ||
| 65 | """Handles management of configuration. | ||
| 66 | |||
| 67 | Provides an interface to accessing and managing configuration files. | ||
| 68 | |||
| 69 | This class converts provides an API that takes "section.key-name" style | ||
| 70 | keys and stores the value associated with it as "key-name" under the | ||
| 71 | section "section". | ||
| 72 | |||
| 73 | This allows for a clean interface wherein the both the section and the | ||
| 74 | key-name are preserved in an easy to manage form in the configuration files | ||
| 75 | and the data stored is also nice. | ||
| 76 | """ | ||
| 77 | |||
| 78 | def __init__(self, isolated, load_only=None): | ||
| 79 | # type: (bool, Kind) -> None | ||
| 80 | super(Configuration, self).__init__() | ||
| 81 | |||
| 82 | _valid_load_only = [kinds.USER, kinds.GLOBAL, kinds.VENV, None] | ||
| 83 | if load_only not in _valid_load_only: | ||
| 84 | raise ConfigurationError( | ||
| 85 | "Got invalid value for load_only - should be one of {}".format( | ||
| 86 | ", ".join(map(repr, _valid_load_only[:-1])) | ||
| 87 | ) | ||
| 88 | ) | ||
| 89 | self.isolated = isolated # type: bool | ||
| 90 | self.load_only = load_only # type: Optional[Kind] | ||
| 91 | |||
| 92 | # The order here determines the override order. | ||
| 93 | self._override_order = [ | ||
| 94 | kinds.GLOBAL, kinds.USER, kinds.VENV, kinds.ENV, kinds.ENV_VAR | ||
| 95 | ] | ||
| 96 | |||
| 97 | self._ignore_env_names = ["version", "help"] | ||
| 98 | |||
| 99 | # Because we keep track of where we got the data from | ||
| 100 | self._parsers = { | ||
| 101 | variant: [] for variant in self._override_order | ||
| 102 | } # type: Dict[Kind, List[Tuple[str, RawConfigParser]]] | ||
| 103 | self._config = { | ||
| 104 | variant: {} for variant in self._override_order | ||
| 105 | } # type: Dict[Kind, Dict[str, Any]] | ||
| 106 | self._modified_parsers = [] # type: List[Tuple[str, RawConfigParser]] | ||
| 107 | |||
| 108 | def load(self): | ||
| 109 | # type: () -> None | ||
| 110 | """Loads configuration from configuration files and environment | ||
| 111 | """ | ||
| 112 | self._load_config_files() | ||
| 113 | if not self.isolated: | ||
| 114 | self._load_environment_vars() | ||
| 115 | |||
| 116 | def get_file_to_edit(self): | ||
| 117 | # type: () -> Optional[str] | ||
| 118 | """Returns the file with highest priority in configuration | ||
| 119 | """ | ||
| 120 | assert self.load_only is not None, \ | ||
| 121 | "Need to be specified a file to be editing" | ||
| 122 | |||
| 123 | try: | ||
| 124 | return self._get_parser_to_modify()[0] | ||
| 125 | except IndexError: | ||
| 126 | return None | ||
| 127 | |||
| 128 | def items(self): | ||
| 129 | # type: () -> Iterable[Tuple[str, Any]] | ||
| 130 | """Returns key-value pairs like dict.items() representing the loaded | ||
| 131 | configuration | ||
| 132 | """ | ||
| 133 | return self._dictionary.items() | ||
| 134 | |||
| 135 | def get_value(self, key): | ||
| 136 | # type: (str) -> Any | ||
| 137 | """Get a value from the configuration. | ||
| 138 | """ | ||
| 139 | try: | ||
| 140 | return self._dictionary[key] | ||
| 141 | except KeyError: | ||
| 142 | raise ConfigurationError("No such key - {}".format(key)) | ||
| 143 | |||
| 144 | def set_value(self, key, value): | ||
| 145 | # type: (str, Any) -> None | ||
| 146 | """Modify a value in the configuration. | ||
| 147 | """ | ||
| 148 | self._ensure_have_load_only() | ||
| 149 | |||
| 150 | fname, parser = self._get_parser_to_modify() | ||
| 151 | |||
| 152 | if parser is not None: | ||
| 153 | section, name = _disassemble_key(key) | ||
| 154 | |||
| 155 | # Modify the parser and the configuration | ||
| 156 | if not parser.has_section(section): | ||
| 157 | parser.add_section(section) | ||
| 158 | parser.set(section, name, value) | ||
| 159 | |||
| 160 | self._config[self.load_only][key] = value | ||
| 161 | self._mark_as_modified(fname, parser) | ||
| 162 | |||
| 163 | def unset_value(self, key): | ||
| 164 | # type: (str) -> None | ||
| 165 | """Unset a value in the configuration. | ||
| 166 | """ | ||
| 167 | self._ensure_have_load_only() | ||
| 168 | |||
| 169 | if key not in self._config[self.load_only]: | ||
| 170 | raise ConfigurationError("No such key - {}".format(key)) | ||
| 171 | |||
| 172 | fname, parser = self._get_parser_to_modify() | ||
| 173 | |||
| 174 | if parser is not None: | ||
| 175 | section, name = _disassemble_key(key) | ||
| 176 | |||
| 177 | # Remove the key in the parser | ||
| 178 | modified_something = False | ||
| 179 | if parser.has_section(section): | ||
| 180 | # Returns whether the option was removed or not | ||
| 181 | modified_something = parser.remove_option(section, name) | ||
| 182 | |||
| 183 | if modified_something: | ||
| 184 | # name removed from parser, section may now be empty | ||
| 185 | section_iter = iter(parser.items(section)) | ||
| 186 | try: | ||
| 187 | val = six.next(section_iter) | ||
| 188 | except StopIteration: | ||
| 189 | val = None | ||
| 190 | |||
| 191 | if val is None: | ||
| 192 | parser.remove_section(section) | ||
| 193 | |||
| 194 | self._mark_as_modified(fname, parser) | ||
| 195 | else: | ||
| 196 | raise ConfigurationError( | ||
| 197 | "Fatal Internal error [id=1]. Please report as a bug." | ||
| 198 | ) | ||
| 199 | |||
| 200 | del self._config[self.load_only][key] | ||
| 201 | |||
| 202 | def save(self): | ||
| 203 | # type: () -> None | ||
| 204 | """Save the currentin-memory state. | ||
| 205 | """ | ||
| 206 | self._ensure_have_load_only() | ||
| 207 | |||
| 208 | for fname, parser in self._modified_parsers: | ||
| 209 | logger.info("Writing to %s", fname) | ||
| 210 | |||
| 211 | # Ensure directory exists. | ||
| 212 | ensure_dir(os.path.dirname(fname)) | ||
| 213 | |||
| 214 | with open(fname, "w") as f: | ||
| 215 | parser.write(f) # type: ignore | ||
| 216 | |||
| 217 | # | ||
| 218 | # Private routines | ||
| 219 | # | ||
| 220 | |||
| 221 | def _ensure_have_load_only(self): | ||
| 222 | # type: () -> None | ||
| 223 | if self.load_only is None: | ||
| 224 | raise ConfigurationError("Needed a specific file to be modifying.") | ||
| 225 | logger.debug("Will be working with %s variant only", self.load_only) | ||
| 226 | |||
| 227 | @property | ||
| 228 | def _dictionary(self): | ||
| 229 | # type: () -> Dict[str, Any] | ||
| 230 | """A dictionary representing the loaded configuration. | ||
| 231 | """ | ||
| 232 | # NOTE: Dictionaries are not populated if not loaded. So, conditionals | ||
| 233 | # are not needed here. | ||
| 234 | retval = {} | ||
| 235 | |||
| 236 | for variant in self._override_order: | ||
| 237 | retval.update(self._config[variant]) | ||
| 238 | |||
| 239 | return retval | ||
| 240 | |||
| 241 | def _load_config_files(self): | ||
| 242 | # type: () -> None | ||
| 243 | """Loads configuration from configuration files | ||
| 244 | """ | ||
| 245 | config_files = dict(self._iter_config_files()) | ||
| 246 | if config_files[kinds.ENV][0:1] == [os.devnull]: | ||
| 247 | logger.debug( | ||
| 248 | "Skipping loading configuration files due to " | ||
| 249 | "environment's PIP_CONFIG_FILE being os.devnull" | ||
| 250 | ) | ||
| 251 | return | ||
| 252 | |||
| 253 | for variant, files in config_files.items(): | ||
| 254 | for fname in files: | ||
| 255 | # If there's specific variant set in `load_only`, load only | ||
| 256 | # that variant, not the others. | ||
| 257 | if self.load_only is not None and variant != self.load_only: | ||
| 258 | logger.debug( | ||
| 259 | "Skipping file '%s' (variant: %s)", fname, variant | ||
| 260 | ) | ||
| 261 | continue | ||
| 262 | |||
| 263 | parser = self._load_file(variant, fname) | ||
| 264 | |||
| 265 | # Keeping track of the parsers used | ||
| 266 | self._parsers[variant].append((fname, parser)) | ||
| 267 | |||
| 268 | def _load_file(self, variant, fname): | ||
| 269 | # type: (Kind, str) -> RawConfigParser | ||
| 270 | logger.debug("For variant '%s', will try loading '%s'", variant, fname) | ||
| 271 | parser = self._construct_parser(fname) | ||
| 272 | |||
| 273 | for section in parser.sections(): | ||
| 274 | items = parser.items(section) | ||
| 275 | self._config[variant].update(self._normalized_keys(section, items)) | ||
| 276 | |||
| 277 | return parser | ||
| 278 | |||
| 279 | def _construct_parser(self, fname): | ||
| 280 | # type: (str) -> RawConfigParser | ||
| 281 | parser = configparser.RawConfigParser() | ||
| 282 | # If there is no such file, don't bother reading it but create the | ||
| 283 | # parser anyway, to hold the data. | ||
| 284 | # Doing this is useful when modifying and saving files, where we don't | ||
| 285 | # need to construct a parser. | ||
| 286 | if os.path.exists(fname): | ||
| 287 | try: | ||
| 288 | parser.read(fname) | ||
| 289 | except UnicodeDecodeError: | ||
| 290 | raise ConfigurationError(( | ||
| 291 | "ERROR: " | ||
| 292 | "Configuration file contains invalid %s characters.\n" | ||
| 293 | "Please fix your configuration, located at %s\n" | ||
| 294 | ) % (locale.getpreferredencoding(False), fname)) | ||
| 295 | return parser | ||
| 296 | |||
| 297 | def _load_environment_vars(self): | ||
| 298 | # type: () -> None | ||
| 299 | """Loads configuration from environment variables | ||
| 300 | """ | ||
| 301 | self._config[kinds.ENV_VAR].update( | ||
| 302 | self._normalized_keys(":env:", self._get_environ_vars()) | ||
| 303 | ) | ||
| 304 | |||
| 305 | def _normalized_keys(self, section, items): | ||
| 306 | # type: (str, Iterable[Tuple[str, Any]]) -> Dict[str, Any] | ||
| 307 | """Normalizes items to construct a dictionary with normalized keys. | ||
| 308 | |||
| 309 | This routine is where the names become keys and are made the same | ||
| 310 | regardless of source - configuration files or environment. | ||
| 311 | """ | ||
| 312 | normalized = {} | ||
| 313 | for name, val in items: | ||
| 314 | key = section + "." + _normalize_name(name) | ||
| 315 | normalized[key] = val | ||
| 316 | return normalized | ||
| 317 | |||
| 318 | def _get_environ_vars(self): | ||
| 319 | # type: () -> Iterable[Tuple[str, str]] | ||
| 320 | """Returns a generator with all environmental vars with prefix PIP_""" | ||
| 321 | for key, val in os.environ.items(): | ||
| 322 | should_be_yielded = ( | ||
| 323 | key.startswith("PIP_") and | ||
| 324 | key[4:].lower() not in self._ignore_env_names | ||
| 325 | ) | ||
| 326 | if should_be_yielded: | ||
| 327 | yield key[4:].lower(), val | ||
| 328 | |||
| 329 | # XXX: This is patched in the tests. | ||
| 330 | def _iter_config_files(self): | ||
| 331 | # type: () -> Iterable[Tuple[Kind, List[str]]] | ||
| 332 | """Yields variant and configuration files associated with it. | ||
| 333 | |||
| 334 | This should be treated like items of a dictionary. | ||
| 335 | """ | ||
| 336 | # SMELL: Move the conditions out of this function | ||
| 337 | |||
| 338 | # environment variables have the lowest priority | ||
| 339 | config_file = os.environ.get('PIP_CONFIG_FILE', None) | ||
| 340 | if config_file is not None: | ||
| 341 | yield kinds.ENV, [config_file] | ||
| 342 | else: | ||
| 343 | yield kinds.ENV, [] | ||
| 344 | |||
| 345 | # at the base we have any global configuration | ||
| 346 | yield kinds.GLOBAL, list(site_config_files) | ||
| 347 | |||
| 348 | # per-user configuration next | ||
| 349 | should_load_user_config = not self.isolated and not ( | ||
| 350 | config_file and os.path.exists(config_file) | ||
| 351 | ) | ||
| 352 | if should_load_user_config: | ||
| 353 | # The legacy config file is overridden by the new config file | ||
| 354 | yield kinds.USER, [legacy_config_file, new_config_file] | ||
| 355 | |||
| 356 | # finally virtualenv configuration first trumping others | ||
| 357 | if running_under_virtualenv(): | ||
| 358 | yield kinds.VENV, [venv_config_file] | ||
| 359 | |||
| 360 | def _get_parser_to_modify(self): | ||
| 361 | # type: () -> Tuple[str, RawConfigParser] | ||
| 362 | # Determine which parser to modify | ||
| 363 | parsers = self._parsers[self.load_only] | ||
| 364 | if not parsers: | ||
| 365 | # This should not happen if everything works correctly. | ||
| 366 | raise ConfigurationError( | ||
| 367 | "Fatal Internal error [id=2]. Please report as a bug." | ||
| 368 | ) | ||
| 369 | |||
| 370 | # Use the highest priority parser. | ||
| 371 | return parsers[-1] | ||
| 372 | |||
| 373 | # XXX: This is patched in the tests. | ||
| 374 | def _mark_as_modified(self, fname, parser): | ||
| 375 | # type: (str, RawConfigParser) -> None | ||
| 376 | file_parser_tuple = (fname, parser) | ||
| 377 | if file_parser_tuple not in self._modified_parsers: | ||
| 378 | self._modified_parsers.append(file_parser_tuple) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/download.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/download.py deleted file mode 100644 index e0e2d24..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/download.py +++ /dev/null | |||
| @@ -1,922 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import cgi | ||
| 4 | import email.utils | ||
| 5 | import getpass | ||
| 6 | import json | ||
| 7 | import logging | ||
| 8 | import mimetypes | ||
| 9 | import os | ||
| 10 | import platform | ||
| 11 | import re | ||
| 12 | import shutil | ||
| 13 | import sys | ||
| 14 | |||
| 15 | from pip._vendor import requests, six, urllib3 | ||
| 16 | from pip._vendor.cachecontrol import CacheControlAdapter | ||
| 17 | from pip._vendor.cachecontrol.caches import FileCache | ||
| 18 | from pip._vendor.lockfile import LockError | ||
| 19 | from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter | ||
| 20 | from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth | ||
| 21 | from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response | ||
| 22 | from pip._vendor.requests.structures import CaseInsensitiveDict | ||
| 23 | from pip._vendor.requests.utils import get_netrc_auth | ||
| 24 | # NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is | ||
| 25 | # why we ignore the type on this import | ||
| 26 | from pip._vendor.six.moves import xmlrpc_client # type: ignore | ||
| 27 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 28 | from pip._vendor.six.moves.urllib import request as urllib_request | ||
| 29 | from pip._vendor.six.moves.urllib.parse import unquote as urllib_unquote | ||
| 30 | from pip._vendor.urllib3.util import IS_PYOPENSSL | ||
| 31 | |||
| 32 | import pip | ||
| 33 | from pip._internal.compat import WINDOWS | ||
| 34 | from pip._internal.exceptions import HashMismatch, InstallationError | ||
| 35 | from pip._internal.locations import write_delete_marker_file | ||
| 36 | from pip._internal.models import PyPI | ||
| 37 | from pip._internal.utils.encoding import auto_decode | ||
| 38 | from pip._internal.utils.filesystem import check_path_owner | ||
| 39 | from pip._internal.utils.glibc import libc_ver | ||
| 40 | from pip._internal.utils.logging import indent_log | ||
| 41 | from pip._internal.utils.misc import ( | ||
| 42 | ARCHIVE_EXTENSIONS, ask_path_exists, backup_dir, call_subprocess, consume, | ||
| 43 | display_path, format_size, get_installed_version, rmtree, splitext, | ||
| 44 | unpack_file, | ||
| 45 | ) | ||
| 46 | from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM | ||
| 47 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 48 | from pip._internal.utils.ui import DownloadProgressProvider | ||
| 49 | from pip._internal.vcs import vcs | ||
| 50 | |||
| 51 | try: | ||
| 52 | import ssl # noqa | ||
| 53 | except ImportError: | ||
| 54 | ssl = None | ||
| 55 | |||
| 56 | HAS_TLS = (ssl is not None) or IS_PYOPENSSL | ||
| 57 | |||
| 58 | __all__ = ['get_file_content', | ||
| 59 | 'is_url', 'url_to_path', 'path_to_url', | ||
| 60 | 'is_archive_file', 'unpack_vcs_link', | ||
| 61 | 'unpack_file_url', 'is_vcs_url', 'is_file_url', | ||
| 62 | 'unpack_http_url', 'unpack_url'] | ||
| 63 | |||
| 64 | |||
| 65 | logger = logging.getLogger(__name__) | ||
| 66 | |||
| 67 | |||
| 68 | def user_agent(): | ||
| 69 | """ | ||
| 70 | Return a string representing the user agent. | ||
| 71 | """ | ||
| 72 | data = { | ||
| 73 | "installer": {"name": "pip", "version": pip.__version__}, | ||
| 74 | "python": platform.python_version(), | ||
| 75 | "implementation": { | ||
| 76 | "name": platform.python_implementation(), | ||
| 77 | }, | ||
| 78 | } | ||
| 79 | |||
| 80 | if data["implementation"]["name"] == 'CPython': | ||
| 81 | data["implementation"]["version"] = platform.python_version() | ||
| 82 | elif data["implementation"]["name"] == 'PyPy': | ||
| 83 | if sys.pypy_version_info.releaselevel == 'final': | ||
| 84 | pypy_version_info = sys.pypy_version_info[:3] | ||
| 85 | else: | ||
| 86 | pypy_version_info = sys.pypy_version_info | ||
| 87 | data["implementation"]["version"] = ".".join( | ||
| 88 | [str(x) for x in pypy_version_info] | ||
| 89 | ) | ||
| 90 | elif data["implementation"]["name"] == 'Jython': | ||
| 91 | # Complete Guess | ||
| 92 | data["implementation"]["version"] = platform.python_version() | ||
| 93 | elif data["implementation"]["name"] == 'IronPython': | ||
| 94 | # Complete Guess | ||
| 95 | data["implementation"]["version"] = platform.python_version() | ||
| 96 | |||
| 97 | if sys.platform.startswith("linux"): | ||
| 98 | from pip._vendor import distro | ||
| 99 | distro_infos = dict(filter( | ||
| 100 | lambda x: x[1], | ||
| 101 | zip(["name", "version", "id"], distro.linux_distribution()), | ||
| 102 | )) | ||
| 103 | libc = dict(filter( | ||
| 104 | lambda x: x[1], | ||
| 105 | zip(["lib", "version"], libc_ver()), | ||
| 106 | )) | ||
| 107 | if libc: | ||
| 108 | distro_infos["libc"] = libc | ||
| 109 | if distro_infos: | ||
| 110 | data["distro"] = distro_infos | ||
| 111 | |||
| 112 | if sys.platform.startswith("darwin") and platform.mac_ver()[0]: | ||
| 113 | data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} | ||
| 114 | |||
| 115 | if platform.system(): | ||
| 116 | data.setdefault("system", {})["name"] = platform.system() | ||
| 117 | |||
| 118 | if platform.release(): | ||
| 119 | data.setdefault("system", {})["release"] = platform.release() | ||
| 120 | |||
| 121 | if platform.machine(): | ||
| 122 | data["cpu"] = platform.machine() | ||
| 123 | |||
| 124 | if HAS_TLS: | ||
| 125 | data["openssl_version"] = ssl.OPENSSL_VERSION | ||
| 126 | |||
| 127 | setuptools_version = get_installed_version("setuptools") | ||
| 128 | if setuptools_version is not None: | ||
| 129 | data["setuptools_version"] = setuptools_version | ||
| 130 | |||
| 131 | return "{data[installer][name]}/{data[installer][version]} {json}".format( | ||
| 132 | data=data, | ||
| 133 | json=json.dumps(data, separators=(",", ":"), sort_keys=True), | ||
| 134 | ) | ||
| 135 | |||
| 136 | |||
| 137 | class MultiDomainBasicAuth(AuthBase): | ||
| 138 | |||
| 139 | def __init__(self, prompting=True): | ||
| 140 | self.prompting = prompting | ||
| 141 | self.passwords = {} | ||
| 142 | |||
| 143 | def __call__(self, req): | ||
| 144 | parsed = urllib_parse.urlparse(req.url) | ||
| 145 | |||
| 146 | # Get the netloc without any embedded credentials | ||
| 147 | netloc = parsed.netloc.rsplit("@", 1)[-1] | ||
| 148 | |||
| 149 | # Set the url of the request to the url without any credentials | ||
| 150 | req.url = urllib_parse.urlunparse(parsed[:1] + (netloc,) + parsed[2:]) | ||
| 151 | |||
| 152 | # Use any stored credentials that we have for this netloc | ||
| 153 | username, password = self.passwords.get(netloc, (None, None)) | ||
| 154 | |||
| 155 | # Extract credentials embedded in the url if we have none stored | ||
| 156 | if username is None: | ||
| 157 | username, password = self.parse_credentials(parsed.netloc) | ||
| 158 | |||
| 159 | # Get creds from netrc if we still don't have them | ||
| 160 | if username is None and password is None: | ||
| 161 | netrc_auth = get_netrc_auth(req.url) | ||
| 162 | username, password = netrc_auth if netrc_auth else (None, None) | ||
| 163 | |||
| 164 | if username or password: | ||
| 165 | # Store the username and password | ||
| 166 | self.passwords[netloc] = (username, password) | ||
| 167 | |||
| 168 | # Send the basic auth with this request | ||
| 169 | req = HTTPBasicAuth(username or "", password or "")(req) | ||
| 170 | |||
| 171 | # Attach a hook to handle 401 responses | ||
| 172 | req.register_hook("response", self.handle_401) | ||
| 173 | |||
| 174 | return req | ||
| 175 | |||
| 176 | def handle_401(self, resp, **kwargs): | ||
| 177 | # We only care about 401 responses, anything else we want to just | ||
| 178 | # pass through the actual response | ||
| 179 | if resp.status_code != 401: | ||
| 180 | return resp | ||
| 181 | |||
| 182 | # We are not able to prompt the user so simply return the response | ||
| 183 | if not self.prompting: | ||
| 184 | return resp | ||
| 185 | |||
| 186 | parsed = urllib_parse.urlparse(resp.url) | ||
| 187 | |||
| 188 | # Prompt the user for a new username and password | ||
| 189 | username = six.moves.input("User for %s: " % parsed.netloc) | ||
| 190 | password = getpass.getpass("Password: ") | ||
| 191 | |||
| 192 | # Store the new username and password to use for future requests | ||
| 193 | if username or password: | ||
| 194 | self.passwords[parsed.netloc] = (username, password) | ||
| 195 | |||
| 196 | # Consume content and release the original connection to allow our new | ||
| 197 | # request to reuse the same one. | ||
| 198 | resp.content | ||
| 199 | resp.raw.release_conn() | ||
| 200 | |||
| 201 | # Add our new username and password to the request | ||
| 202 | req = HTTPBasicAuth(username or "", password or "")(resp.request) | ||
| 203 | |||
| 204 | # Send our new request | ||
| 205 | new_resp = resp.connection.send(req, **kwargs) | ||
| 206 | new_resp.history.append(resp) | ||
| 207 | |||
| 208 | return new_resp | ||
| 209 | |||
| 210 | def parse_credentials(self, netloc): | ||
| 211 | if "@" in netloc: | ||
| 212 | userinfo = netloc.rsplit("@", 1)[0] | ||
| 213 | if ":" in userinfo: | ||
| 214 | user, pwd = userinfo.split(":", 1) | ||
| 215 | return (urllib_unquote(user), urllib_unquote(pwd)) | ||
| 216 | return urllib_unquote(userinfo), None | ||
| 217 | return None, None | ||
| 218 | |||
| 219 | |||
| 220 | class LocalFSAdapter(BaseAdapter): | ||
| 221 | |||
| 222 | def send(self, request, stream=None, timeout=None, verify=None, cert=None, | ||
| 223 | proxies=None): | ||
| 224 | pathname = url_to_path(request.url) | ||
| 225 | |||
| 226 | resp = Response() | ||
| 227 | resp.status_code = 200 | ||
| 228 | resp.url = request.url | ||
| 229 | |||
| 230 | try: | ||
| 231 | stats = os.stat(pathname) | ||
| 232 | except OSError as exc: | ||
| 233 | resp.status_code = 404 | ||
| 234 | resp.raw = exc | ||
| 235 | else: | ||
| 236 | modified = email.utils.formatdate(stats.st_mtime, usegmt=True) | ||
| 237 | content_type = mimetypes.guess_type(pathname)[0] or "text/plain" | ||
| 238 | resp.headers = CaseInsensitiveDict({ | ||
| 239 | "Content-Type": content_type, | ||
| 240 | "Content-Length": stats.st_size, | ||
| 241 | "Last-Modified": modified, | ||
| 242 | }) | ||
| 243 | |||
| 244 | resp.raw = open(pathname, "rb") | ||
| 245 | resp.close = resp.raw.close | ||
| 246 | |||
| 247 | return resp | ||
| 248 | |||
| 249 | def close(self): | ||
| 250 | pass | ||
| 251 | |||
| 252 | |||
| 253 | class SafeFileCache(FileCache): | ||
| 254 | """ | ||
| 255 | A file based cache which is safe to use even when the target directory may | ||
| 256 | not be accessible or writable. | ||
| 257 | """ | ||
| 258 | |||
| 259 | def __init__(self, *args, **kwargs): | ||
| 260 | super(SafeFileCache, self).__init__(*args, **kwargs) | ||
| 261 | |||
| 262 | # Check to ensure that the directory containing our cache directory | ||
| 263 | # is owned by the user current executing pip. If it does not exist | ||
| 264 | # we will check the parent directory until we find one that does exist. | ||
| 265 | # If it is not owned by the user executing pip then we will disable | ||
| 266 | # the cache and log a warning. | ||
| 267 | if not check_path_owner(self.directory): | ||
| 268 | logger.warning( | ||
| 269 | "The directory '%s' or its parent directory is not owned by " | ||
| 270 | "the current user and the cache has been disabled. Please " | ||
| 271 | "check the permissions and owner of that directory. If " | ||
| 272 | "executing pip with sudo, you may want sudo's -H flag.", | ||
| 273 | self.directory, | ||
| 274 | ) | ||
| 275 | |||
| 276 | # Set our directory to None to disable the Cache | ||
| 277 | self.directory = None | ||
| 278 | |||
| 279 | def get(self, *args, **kwargs): | ||
| 280 | # If we don't have a directory, then the cache should be a no-op. | ||
| 281 | if self.directory is None: | ||
| 282 | return | ||
| 283 | |||
| 284 | try: | ||
| 285 | return super(SafeFileCache, self).get(*args, **kwargs) | ||
| 286 | except (LockError, OSError, IOError): | ||
| 287 | # We intentionally silence this error, if we can't access the cache | ||
| 288 | # then we can just skip caching and process the request as if | ||
| 289 | # caching wasn't enabled. | ||
| 290 | pass | ||
| 291 | |||
| 292 | def set(self, *args, **kwargs): | ||
| 293 | # If we don't have a directory, then the cache should be a no-op. | ||
| 294 | if self.directory is None: | ||
| 295 | return | ||
| 296 | |||
| 297 | try: | ||
| 298 | return super(SafeFileCache, self).set(*args, **kwargs) | ||
| 299 | except (LockError, OSError, IOError): | ||
| 300 | # We intentionally silence this error, if we can't access the cache | ||
| 301 | # then we can just skip caching and process the request as if | ||
| 302 | # caching wasn't enabled. | ||
| 303 | pass | ||
| 304 | |||
| 305 | def delete(self, *args, **kwargs): | ||
| 306 | # If we don't have a directory, then the cache should be a no-op. | ||
| 307 | if self.directory is None: | ||
| 308 | return | ||
| 309 | |||
| 310 | try: | ||
| 311 | return super(SafeFileCache, self).delete(*args, **kwargs) | ||
| 312 | except (LockError, OSError, IOError): | ||
| 313 | # We intentionally silence this error, if we can't access the cache | ||
| 314 | # then we can just skip caching and process the request as if | ||
| 315 | # caching wasn't enabled. | ||
| 316 | pass | ||
| 317 | |||
| 318 | |||
| 319 | class InsecureHTTPAdapter(HTTPAdapter): | ||
| 320 | |||
| 321 | def cert_verify(self, conn, url, verify, cert): | ||
| 322 | conn.cert_reqs = 'CERT_NONE' | ||
| 323 | conn.ca_certs = None | ||
| 324 | |||
| 325 | |||
| 326 | class PipSession(requests.Session): | ||
| 327 | |||
| 328 | timeout = None | ||
| 329 | |||
| 330 | def __init__(self, *args, **kwargs): | ||
| 331 | retries = kwargs.pop("retries", 0) | ||
| 332 | cache = kwargs.pop("cache", None) | ||
| 333 | insecure_hosts = kwargs.pop("insecure_hosts", []) | ||
| 334 | |||
| 335 | super(PipSession, self).__init__(*args, **kwargs) | ||
| 336 | |||
| 337 | # Attach our User Agent to the request | ||
| 338 | self.headers["User-Agent"] = user_agent() | ||
| 339 | |||
| 340 | # Attach our Authentication handler to the session | ||
| 341 | self.auth = MultiDomainBasicAuth() | ||
| 342 | |||
| 343 | # Create our urllib3.Retry instance which will allow us to customize | ||
| 344 | # how we handle retries. | ||
| 345 | retries = urllib3.Retry( | ||
| 346 | # Set the total number of retries that a particular request can | ||
| 347 | # have. | ||
| 348 | total=retries, | ||
| 349 | |||
| 350 | # A 503 error from PyPI typically means that the Fastly -> Origin | ||
| 351 | # connection got interrupted in some way. A 503 error in general | ||
| 352 | # is typically considered a transient error so we'll go ahead and | ||
| 353 | # retry it. | ||
| 354 | # A 500 may indicate transient error in Amazon S3 | ||
| 355 | # A 520 or 527 - may indicate transient error in CloudFlare | ||
| 356 | status_forcelist=[500, 503, 520, 527], | ||
| 357 | |||
| 358 | # Add a small amount of back off between failed requests in | ||
| 359 | # order to prevent hammering the service. | ||
| 360 | backoff_factor=0.25, | ||
| 361 | ) | ||
| 362 | |||
| 363 | # We want to _only_ cache responses on securely fetched origins. We do | ||
| 364 | # this because we can't validate the response of an insecurely fetched | ||
| 365 | # origin, and we don't want someone to be able to poison the cache and | ||
| 366 | # require manual eviction from the cache to fix it. | ||
| 367 | if cache: | ||
| 368 | secure_adapter = CacheControlAdapter( | ||
| 369 | cache=SafeFileCache(cache, use_dir_lock=True), | ||
| 370 | max_retries=retries, | ||
| 371 | ) | ||
| 372 | else: | ||
| 373 | secure_adapter = HTTPAdapter(max_retries=retries) | ||
| 374 | |||
| 375 | # Our Insecure HTTPAdapter disables HTTPS validation. It does not | ||
| 376 | # support caching (see above) so we'll use it for all http:// URLs as | ||
| 377 | # well as any https:// host that we've marked as ignoring TLS errors | ||
| 378 | # for. | ||
| 379 | insecure_adapter = InsecureHTTPAdapter(max_retries=retries) | ||
| 380 | |||
| 381 | self.mount("https://", secure_adapter) | ||
| 382 | self.mount("http://", insecure_adapter) | ||
| 383 | |||
| 384 | # Enable file:// urls | ||
| 385 | self.mount("file://", LocalFSAdapter()) | ||
| 386 | |||
| 387 | # We want to use a non-validating adapter for any requests which are | ||
| 388 | # deemed insecure. | ||
| 389 | for host in insecure_hosts: | ||
| 390 | self.mount("https://{}/".format(host), insecure_adapter) | ||
| 391 | |||
| 392 | def request(self, method, url, *args, **kwargs): | ||
| 393 | # Allow setting a default timeout on a session | ||
| 394 | kwargs.setdefault("timeout", self.timeout) | ||
| 395 | |||
| 396 | # Dispatch the actual request | ||
| 397 | return super(PipSession, self).request(method, url, *args, **kwargs) | ||
| 398 | |||
| 399 | |||
| 400 | def get_file_content(url, comes_from=None, session=None): | ||
| 401 | """Gets the content of a file; it may be a filename, file: URL, or | ||
| 402 | http: URL. Returns (location, content). Content is unicode. | ||
| 403 | |||
| 404 | :param url: File path or url. | ||
| 405 | :param comes_from: Origin description of requirements. | ||
| 406 | :param session: Instance of pip.download.PipSession. | ||
| 407 | """ | ||
| 408 | if session is None: | ||
| 409 | raise TypeError( | ||
| 410 | "get_file_content() missing 1 required keyword argument: 'session'" | ||
| 411 | ) | ||
| 412 | |||
| 413 | match = _scheme_re.search(url) | ||
| 414 | if match: | ||
| 415 | scheme = match.group(1).lower() | ||
| 416 | if (scheme == 'file' and comes_from and | ||
| 417 | comes_from.startswith('http')): | ||
| 418 | raise InstallationError( | ||
| 419 | 'Requirements file %s references URL %s, which is local' | ||
| 420 | % (comes_from, url)) | ||
| 421 | if scheme == 'file': | ||
| 422 | path = url.split(':', 1)[1] | ||
| 423 | path = path.replace('\\', '/') | ||
| 424 | match = _url_slash_drive_re.match(path) | ||
| 425 | if match: | ||
| 426 | path = match.group(1) + ':' + path.split('|', 1)[1] | ||
| 427 | path = urllib_parse.unquote(path) | ||
| 428 | if path.startswith('/'): | ||
| 429 | path = '/' + path.lstrip('/') | ||
| 430 | url = path | ||
| 431 | else: | ||
| 432 | # FIXME: catch some errors | ||
| 433 | resp = session.get(url) | ||
| 434 | resp.raise_for_status() | ||
| 435 | return resp.url, resp.text | ||
| 436 | try: | ||
| 437 | with open(url, 'rb') as f: | ||
| 438 | content = auto_decode(f.read()) | ||
| 439 | except IOError as exc: | ||
| 440 | raise InstallationError( | ||
| 441 | 'Could not open requirements file: %s' % str(exc) | ||
| 442 | ) | ||
| 443 | return url, content | ||
| 444 | |||
| 445 | |||
| 446 | _scheme_re = re.compile(r'^(http|https|file):', re.I) | ||
| 447 | _url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I) | ||
| 448 | |||
| 449 | |||
| 450 | def is_url(name): | ||
| 451 | """Returns true if the name looks like a URL""" | ||
| 452 | if ':' not in name: | ||
| 453 | return False | ||
| 454 | scheme = name.split(':', 1)[0].lower() | ||
| 455 | return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes | ||
| 456 | |||
| 457 | |||
| 458 | def url_to_path(url): | ||
| 459 | """ | ||
| 460 | Convert a file: URL to a path. | ||
| 461 | """ | ||
| 462 | assert url.startswith('file:'), ( | ||
| 463 | "You can only turn file: urls into filenames (not %r)" % url) | ||
| 464 | |||
| 465 | _, netloc, path, _, _ = urllib_parse.urlsplit(url) | ||
| 466 | |||
| 467 | # if we have a UNC path, prepend UNC share notation | ||
| 468 | if netloc: | ||
| 469 | netloc = '\\\\' + netloc | ||
| 470 | |||
| 471 | path = urllib_request.url2pathname(netloc + path) | ||
| 472 | return path | ||
| 473 | |||
| 474 | |||
| 475 | def path_to_url(path): | ||
| 476 | """ | ||
| 477 | Convert a path to a file: URL. The path will be made absolute and have | ||
| 478 | quoted path parts. | ||
| 479 | """ | ||
| 480 | path = os.path.normpath(os.path.abspath(path)) | ||
| 481 | url = urllib_parse.urljoin('file:', urllib_request.pathname2url(path)) | ||
| 482 | return url | ||
| 483 | |||
| 484 | |||
| 485 | def is_archive_file(name): | ||
| 486 | """Return True if `name` is a considered as an archive file.""" | ||
| 487 | ext = splitext(name)[1].lower() | ||
| 488 | if ext in ARCHIVE_EXTENSIONS: | ||
| 489 | return True | ||
| 490 | return False | ||
| 491 | |||
| 492 | |||
| 493 | def unpack_vcs_link(link, location): | ||
| 494 | vcs_backend = _get_used_vcs_backend(link) | ||
| 495 | vcs_backend.unpack(location) | ||
| 496 | |||
| 497 | |||
| 498 | def _get_used_vcs_backend(link): | ||
| 499 | for backend in vcs.backends: | ||
| 500 | if link.scheme in backend.schemes: | ||
| 501 | vcs_backend = backend(link.url) | ||
| 502 | return vcs_backend | ||
| 503 | |||
| 504 | |||
| 505 | def is_vcs_url(link): | ||
| 506 | return bool(_get_used_vcs_backend(link)) | ||
| 507 | |||
| 508 | |||
| 509 | def is_file_url(link): | ||
| 510 | return link.url.lower().startswith('file:') | ||
| 511 | |||
| 512 | |||
| 513 | def is_dir_url(link): | ||
| 514 | """Return whether a file:// Link points to a directory. | ||
| 515 | |||
| 516 | ``link`` must not have any other scheme but file://. Call is_file_url() | ||
| 517 | first. | ||
| 518 | |||
| 519 | """ | ||
| 520 | link_path = url_to_path(link.url_without_fragment) | ||
| 521 | return os.path.isdir(link_path) | ||
| 522 | |||
| 523 | |||
| 524 | def _progress_indicator(iterable, *args, **kwargs): | ||
| 525 | return iterable | ||
| 526 | |||
| 527 | |||
| 528 | def _download_url(resp, link, content_file, hashes, progress_bar): | ||
| 529 | try: | ||
| 530 | total_length = int(resp.headers['content-length']) | ||
| 531 | except (ValueError, KeyError, TypeError): | ||
| 532 | total_length = 0 | ||
| 533 | |||
| 534 | cached_resp = getattr(resp, "from_cache", False) | ||
| 535 | if logger.getEffectiveLevel() > logging.INFO: | ||
| 536 | show_progress = False | ||
| 537 | elif cached_resp: | ||
| 538 | show_progress = False | ||
| 539 | elif total_length > (40 * 1000): | ||
| 540 | show_progress = True | ||
| 541 | elif not total_length: | ||
| 542 | show_progress = True | ||
| 543 | else: | ||
| 544 | show_progress = False | ||
| 545 | |||
| 546 | show_url = link.show_url | ||
| 547 | |||
| 548 | def resp_read(chunk_size): | ||
| 549 | try: | ||
| 550 | # Special case for urllib3. | ||
| 551 | for chunk in resp.raw.stream( | ||
| 552 | chunk_size, | ||
| 553 | # We use decode_content=False here because we don't | ||
| 554 | # want urllib3 to mess with the raw bytes we get | ||
| 555 | # from the server. If we decompress inside of | ||
| 556 | # urllib3 then we cannot verify the checksum | ||
| 557 | # because the checksum will be of the compressed | ||
| 558 | # file. This breakage will only occur if the | ||
| 559 | # server adds a Content-Encoding header, which | ||
| 560 | # depends on how the server was configured: | ||
| 561 | # - Some servers will notice that the file isn't a | ||
| 562 | # compressible file and will leave the file alone | ||
| 563 | # and with an empty Content-Encoding | ||
| 564 | # - Some servers will notice that the file is | ||
| 565 | # already compressed and will leave the file | ||
| 566 | # alone and will add a Content-Encoding: gzip | ||
| 567 | # header | ||
| 568 | # - Some servers won't notice anything at all and | ||
| 569 | # will take a file that's already been compressed | ||
| 570 | # and compress it again and set the | ||
| 571 | # Content-Encoding: gzip header | ||
| 572 | # | ||
| 573 | # By setting this not to decode automatically we | ||
| 574 | # hope to eliminate problems with the second case. | ||
| 575 | decode_content=False): | ||
| 576 | yield chunk | ||
| 577 | except AttributeError: | ||
| 578 | # Standard file-like object. | ||
| 579 | while True: | ||
| 580 | chunk = resp.raw.read(chunk_size) | ||
| 581 | if not chunk: | ||
| 582 | break | ||
| 583 | yield chunk | ||
| 584 | |||
| 585 | def written_chunks(chunks): | ||
| 586 | for chunk in chunks: | ||
| 587 | content_file.write(chunk) | ||
| 588 | yield chunk | ||
| 589 | |||
| 590 | progress_indicator = _progress_indicator | ||
| 591 | |||
| 592 | if link.netloc == PyPI.netloc: | ||
| 593 | url = show_url | ||
| 594 | else: | ||
| 595 | url = link.url_without_fragment | ||
| 596 | |||
| 597 | if show_progress: # We don't show progress on cached responses | ||
| 598 | progress_indicator = DownloadProgressProvider(progress_bar, | ||
| 599 | max=total_length) | ||
| 600 | if total_length: | ||
| 601 | logger.info("Downloading %s (%s)", url, format_size(total_length)) | ||
| 602 | else: | ||
| 603 | logger.info("Downloading %s", url) | ||
| 604 | elif cached_resp: | ||
| 605 | logger.info("Using cached %s", url) | ||
| 606 | else: | ||
| 607 | logger.info("Downloading %s", url) | ||
| 608 | |||
| 609 | logger.debug('Downloading from URL %s', link) | ||
| 610 | |||
| 611 | downloaded_chunks = written_chunks( | ||
| 612 | progress_indicator( | ||
| 613 | resp_read(CONTENT_CHUNK_SIZE), | ||
| 614 | CONTENT_CHUNK_SIZE | ||
| 615 | ) | ||
| 616 | ) | ||
| 617 | if hashes: | ||
| 618 | hashes.check_against_chunks(downloaded_chunks) | ||
| 619 | else: | ||
| 620 | consume(downloaded_chunks) | ||
| 621 | |||
| 622 | |||
| 623 | def _copy_file(filename, location, link): | ||
| 624 | copy = True | ||
| 625 | download_location = os.path.join(location, link.filename) | ||
| 626 | if os.path.exists(download_location): | ||
| 627 | response = ask_path_exists( | ||
| 628 | 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)abort' % | ||
| 629 | display_path(download_location), ('i', 'w', 'b', 'a')) | ||
| 630 | if response == 'i': | ||
| 631 | copy = False | ||
| 632 | elif response == 'w': | ||
| 633 | logger.warning('Deleting %s', display_path(download_location)) | ||
| 634 | os.remove(download_location) | ||
| 635 | elif response == 'b': | ||
| 636 | dest_file = backup_dir(download_location) | ||
| 637 | logger.warning( | ||
| 638 | 'Backing up %s to %s', | ||
| 639 | display_path(download_location), | ||
| 640 | display_path(dest_file), | ||
| 641 | ) | ||
| 642 | shutil.move(download_location, dest_file) | ||
| 643 | elif response == 'a': | ||
| 644 | sys.exit(-1) | ||
| 645 | if copy: | ||
| 646 | shutil.copy(filename, download_location) | ||
| 647 | logger.info('Saved %s', display_path(download_location)) | ||
| 648 | |||
| 649 | |||
| 650 | def unpack_http_url(link, location, download_dir=None, | ||
| 651 | session=None, hashes=None, progress_bar="on"): | ||
| 652 | if session is None: | ||
| 653 | raise TypeError( | ||
| 654 | "unpack_http_url() missing 1 required keyword argument: 'session'" | ||
| 655 | ) | ||
| 656 | |||
| 657 | with TempDirectory(kind="unpack") as temp_dir: | ||
| 658 | # If a download dir is specified, is the file already downloaded there? | ||
| 659 | already_downloaded_path = None | ||
| 660 | if download_dir: | ||
| 661 | already_downloaded_path = _check_download_dir(link, | ||
| 662 | download_dir, | ||
| 663 | hashes) | ||
| 664 | |||
| 665 | if already_downloaded_path: | ||
| 666 | from_path = already_downloaded_path | ||
| 667 | content_type = mimetypes.guess_type(from_path)[0] | ||
| 668 | else: | ||
| 669 | # let's download to a tmp dir | ||
| 670 | from_path, content_type = _download_http_url(link, | ||
| 671 | session, | ||
| 672 | temp_dir.path, | ||
| 673 | hashes, | ||
| 674 | progress_bar) | ||
| 675 | |||
| 676 | # unpack the archive to the build dir location. even when only | ||
| 677 | # downloading archives, they have to be unpacked to parse dependencies | ||
| 678 | unpack_file(from_path, location, content_type, link) | ||
| 679 | |||
| 680 | # a download dir is specified; let's copy the archive there | ||
| 681 | if download_dir and not already_downloaded_path: | ||
| 682 | _copy_file(from_path, download_dir, link) | ||
| 683 | |||
| 684 | if not already_downloaded_path: | ||
| 685 | os.unlink(from_path) | ||
| 686 | |||
| 687 | |||
| 688 | def unpack_file_url(link, location, download_dir=None, hashes=None): | ||
| 689 | """Unpack link into location. | ||
| 690 | |||
| 691 | If download_dir is provided and link points to a file, make a copy | ||
| 692 | of the link file inside download_dir. | ||
| 693 | """ | ||
| 694 | link_path = url_to_path(link.url_without_fragment) | ||
| 695 | |||
| 696 | # If it's a url to a local directory | ||
| 697 | if is_dir_url(link): | ||
| 698 | if os.path.isdir(location): | ||
| 699 | rmtree(location) | ||
| 700 | shutil.copytree(link_path, location, symlinks=True) | ||
| 701 | if download_dir: | ||
| 702 | logger.info('Link is a directory, ignoring download_dir') | ||
| 703 | return | ||
| 704 | |||
| 705 | # If --require-hashes is off, `hashes` is either empty, the | ||
| 706 | # link's embedded hash, or MissingHashes; it is required to | ||
| 707 | # match. If --require-hashes is on, we are satisfied by any | ||
| 708 | # hash in `hashes` matching: a URL-based or an option-based | ||
| 709 | # one; no internet-sourced hash will be in `hashes`. | ||
| 710 | if hashes: | ||
| 711 | hashes.check_against_path(link_path) | ||
| 712 | |||
| 713 | # If a download dir is specified, is the file already there and valid? | ||
| 714 | already_downloaded_path = None | ||
| 715 | if download_dir: | ||
| 716 | already_downloaded_path = _check_download_dir(link, | ||
| 717 | download_dir, | ||
| 718 | hashes) | ||
| 719 | |||
| 720 | if already_downloaded_path: | ||
| 721 | from_path = already_downloaded_path | ||
| 722 | else: | ||
| 723 | from_path = link_path | ||
| 724 | |||
| 725 | content_type = mimetypes.guess_type(from_path)[0] | ||
| 726 | |||
| 727 | # unpack the archive to the build dir location. even when only downloading | ||
| 728 | # archives, they have to be unpacked to parse dependencies | ||
| 729 | unpack_file(from_path, location, content_type, link) | ||
| 730 | |||
| 731 | # a download dir is specified and not already downloaded | ||
| 732 | if download_dir and not already_downloaded_path: | ||
| 733 | _copy_file(from_path, download_dir, link) | ||
| 734 | |||
| 735 | |||
| 736 | def _copy_dist_from_dir(link_path, location): | ||
| 737 | """Copy distribution files in `link_path` to `location`. | ||
| 738 | |||
| 739 | Invoked when user requests to install a local directory. E.g.: | ||
| 740 | |||
| 741 | pip install . | ||
| 742 | pip install ~/dev/git-repos/python-prompt-toolkit | ||
| 743 | |||
| 744 | """ | ||
| 745 | |||
| 746 | # Note: This is currently VERY SLOW if you have a lot of data in the | ||
| 747 | # directory, because it copies everything with `shutil.copytree`. | ||
| 748 | # What it should really do is build an sdist and install that. | ||
| 749 | # See https://github.com/pypa/pip/issues/2195 | ||
| 750 | |||
| 751 | if os.path.isdir(location): | ||
| 752 | rmtree(location) | ||
| 753 | |||
| 754 | # build an sdist | ||
| 755 | setup_py = 'setup.py' | ||
| 756 | sdist_args = [sys.executable] | ||
| 757 | sdist_args.append('-c') | ||
| 758 | sdist_args.append(SETUPTOOLS_SHIM % setup_py) | ||
| 759 | sdist_args.append('sdist') | ||
| 760 | sdist_args += ['--dist-dir', location] | ||
| 761 | logger.info('Running setup.py sdist for %s', link_path) | ||
| 762 | |||
| 763 | with indent_log(): | ||
| 764 | call_subprocess(sdist_args, cwd=link_path, show_stdout=False) | ||
| 765 | |||
| 766 | # unpack sdist into `location` | ||
| 767 | sdist = os.path.join(location, os.listdir(location)[0]) | ||
| 768 | logger.info('Unpacking sdist %s into %s', sdist, location) | ||
| 769 | unpack_file(sdist, location, content_type=None, link=None) | ||
| 770 | |||
| 771 | |||
| 772 | class PipXmlrpcTransport(xmlrpc_client.Transport): | ||
| 773 | """Provide a `xmlrpclib.Transport` implementation via a `PipSession` | ||
| 774 | object. | ||
| 775 | """ | ||
| 776 | |||
| 777 | def __init__(self, index_url, session, use_datetime=False): | ||
| 778 | xmlrpc_client.Transport.__init__(self, use_datetime) | ||
| 779 | index_parts = urllib_parse.urlparse(index_url) | ||
| 780 | self._scheme = index_parts.scheme | ||
| 781 | self._session = session | ||
| 782 | |||
| 783 | def request(self, host, handler, request_body, verbose=False): | ||
| 784 | parts = (self._scheme, host, handler, None, None, None) | ||
| 785 | url = urllib_parse.urlunparse(parts) | ||
| 786 | try: | ||
| 787 | headers = {'Content-Type': 'text/xml'} | ||
| 788 | response = self._session.post(url, data=request_body, | ||
| 789 | headers=headers, stream=True) | ||
| 790 | response.raise_for_status() | ||
| 791 | self.verbose = verbose | ||
| 792 | return self.parse_response(response.raw) | ||
| 793 | except requests.HTTPError as exc: | ||
| 794 | logger.critical( | ||
| 795 | "HTTP error %s while getting %s", | ||
| 796 | exc.response.status_code, url, | ||
| 797 | ) | ||
| 798 | raise | ||
| 799 | |||
| 800 | |||
| 801 | def unpack_url(link, location, download_dir=None, | ||
| 802 | only_download=False, session=None, hashes=None, | ||
| 803 | progress_bar="on"): | ||
| 804 | """Unpack link. | ||
| 805 | If link is a VCS link: | ||
| 806 | if only_download, export into download_dir and ignore location | ||
| 807 | else unpack into location | ||
| 808 | for other types of link: | ||
| 809 | - unpack into location | ||
| 810 | - if download_dir, copy the file into download_dir | ||
| 811 | - if only_download, mark location for deletion | ||
| 812 | |||
| 813 | :param hashes: A Hashes object, one of whose embedded hashes must match, | ||
| 814 | or HashMismatch will be raised. If the Hashes is empty, no matches are | ||
| 815 | required, and unhashable types of requirements (like VCS ones, which | ||
| 816 | would ordinarily raise HashUnsupported) are allowed. | ||
| 817 | """ | ||
| 818 | # non-editable vcs urls | ||
| 819 | if is_vcs_url(link): | ||
| 820 | unpack_vcs_link(link, location) | ||
| 821 | |||
| 822 | # file urls | ||
| 823 | elif is_file_url(link): | ||
| 824 | unpack_file_url(link, location, download_dir, hashes=hashes) | ||
| 825 | |||
| 826 | # http urls | ||
| 827 | else: | ||
| 828 | if session is None: | ||
| 829 | session = PipSession() | ||
| 830 | |||
| 831 | unpack_http_url( | ||
| 832 | link, | ||
| 833 | location, | ||
| 834 | download_dir, | ||
| 835 | session, | ||
| 836 | hashes=hashes, | ||
| 837 | progress_bar=progress_bar | ||
| 838 | ) | ||
| 839 | if only_download: | ||
| 840 | write_delete_marker_file(location) | ||
| 841 | |||
| 842 | |||
| 843 | def _download_http_url(link, session, temp_dir, hashes, progress_bar): | ||
| 844 | """Download link url into temp_dir using provided session""" | ||
| 845 | target_url = link.url.split('#', 1)[0] | ||
| 846 | try: | ||
| 847 | resp = session.get( | ||
| 848 | target_url, | ||
| 849 | # We use Accept-Encoding: identity here because requests | ||
| 850 | # defaults to accepting compressed responses. This breaks in | ||
| 851 | # a variety of ways depending on how the server is configured. | ||
| 852 | # - Some servers will notice that the file isn't a compressible | ||
| 853 | # file and will leave the file alone and with an empty | ||
| 854 | # Content-Encoding | ||
| 855 | # - Some servers will notice that the file is already | ||
| 856 | # compressed and will leave the file alone and will add a | ||
| 857 | # Content-Encoding: gzip header | ||
| 858 | # - Some servers won't notice anything at all and will take | ||
| 859 | # a file that's already been compressed and compress it again | ||
| 860 | # and set the Content-Encoding: gzip header | ||
| 861 | # By setting this to request only the identity encoding We're | ||
| 862 | # hoping to eliminate the third case. Hopefully there does not | ||
| 863 | # exist a server which when given a file will notice it is | ||
| 864 | # already compressed and that you're not asking for a | ||
| 865 | # compressed file and will then decompress it before sending | ||
| 866 | # because if that's the case I don't think it'll ever be | ||
| 867 | # possible to make this work. | ||
| 868 | headers={"Accept-Encoding": "identity"}, | ||
| 869 | stream=True, | ||
| 870 | ) | ||
| 871 | resp.raise_for_status() | ||
| 872 | except requests.HTTPError as exc: | ||
| 873 | logger.critical( | ||
| 874 | "HTTP error %s while getting %s", exc.response.status_code, link, | ||
| 875 | ) | ||
| 876 | raise | ||
| 877 | |||
| 878 | content_type = resp.headers.get('content-type', '') | ||
| 879 | filename = link.filename # fallback | ||
| 880 | # Have a look at the Content-Disposition header for a better guess | ||
| 881 | content_disposition = resp.headers.get('content-disposition') | ||
| 882 | if content_disposition: | ||
| 883 | type, params = cgi.parse_header(content_disposition) | ||
| 884 | # We use ``or`` here because we don't want to use an "empty" value | ||
| 885 | # from the filename param. | ||
| 886 | filename = params.get('filename') or filename | ||
| 887 | ext = splitext(filename)[1] | ||
| 888 | if not ext: | ||
| 889 | ext = mimetypes.guess_extension(content_type) | ||
| 890 | if ext: | ||
| 891 | filename += ext | ||
| 892 | if not ext and link.url != resp.url: | ||
| 893 | ext = os.path.splitext(resp.url)[1] | ||
| 894 | if ext: | ||
| 895 | filename += ext | ||
| 896 | file_path = os.path.join(temp_dir, filename) | ||
| 897 | with open(file_path, 'wb') as content_file: | ||
| 898 | _download_url(resp, link, content_file, hashes, progress_bar) | ||
| 899 | return file_path, content_type | ||
| 900 | |||
| 901 | |||
| 902 | def _check_download_dir(link, download_dir, hashes): | ||
| 903 | """ Check download_dir for previously downloaded file with correct hash | ||
| 904 | If a correct file is found return its path else None | ||
| 905 | """ | ||
| 906 | download_path = os.path.join(download_dir, link.filename) | ||
| 907 | if os.path.exists(download_path): | ||
| 908 | # If already downloaded, does its hash match? | ||
| 909 | logger.info('File was already downloaded %s', download_path) | ||
| 910 | if hashes: | ||
| 911 | try: | ||
| 912 | hashes.check_against_path(download_path) | ||
| 913 | except HashMismatch: | ||
| 914 | logger.warning( | ||
| 915 | 'Previously-downloaded file %s has bad hash. ' | ||
| 916 | 'Re-downloading.', | ||
| 917 | download_path | ||
| 918 | ) | ||
| 919 | os.unlink(download_path) | ||
| 920 | return None | ||
| 921 | return download_path | ||
| 922 | return None | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/exceptions.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/exceptions.py deleted file mode 100644 index 28705c8..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/exceptions.py +++ /dev/null | |||
| @@ -1,249 +0,0 @@ | |||
| 1 | """Exceptions used throughout package""" | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | from itertools import chain, groupby, repeat | ||
| 5 | |||
| 6 | from pip._vendor.six import iteritems | ||
| 7 | |||
| 8 | |||
| 9 | class PipError(Exception): | ||
| 10 | """Base pip exception""" | ||
| 11 | |||
| 12 | |||
| 13 | class ConfigurationError(PipError): | ||
| 14 | """General exception in configuration""" | ||
| 15 | |||
| 16 | |||
| 17 | class InstallationError(PipError): | ||
| 18 | """General exception during installation""" | ||
| 19 | |||
| 20 | |||
| 21 | class UninstallationError(PipError): | ||
| 22 | """General exception during uninstallation""" | ||
| 23 | |||
| 24 | |||
| 25 | class DistributionNotFound(InstallationError): | ||
| 26 | """Raised when a distribution cannot be found to satisfy a requirement""" | ||
| 27 | |||
| 28 | |||
| 29 | class RequirementsFileParseError(InstallationError): | ||
| 30 | """Raised when a general error occurs parsing a requirements file line.""" | ||
| 31 | |||
| 32 | |||
| 33 | class BestVersionAlreadyInstalled(PipError): | ||
| 34 | """Raised when the most up-to-date version of a package is already | ||
| 35 | installed.""" | ||
| 36 | |||
| 37 | |||
| 38 | class BadCommand(PipError): | ||
| 39 | """Raised when virtualenv or a command is not found""" | ||
| 40 | |||
| 41 | |||
| 42 | class CommandError(PipError): | ||
| 43 | """Raised when there is an error in command-line arguments""" | ||
| 44 | |||
| 45 | |||
| 46 | class PreviousBuildDirError(PipError): | ||
| 47 | """Raised when there's a previous conflicting build directory""" | ||
| 48 | |||
| 49 | |||
| 50 | class InvalidWheelFilename(InstallationError): | ||
| 51 | """Invalid wheel filename.""" | ||
| 52 | |||
| 53 | |||
| 54 | class UnsupportedWheel(InstallationError): | ||
| 55 | """Unsupported wheel.""" | ||
| 56 | |||
| 57 | |||
| 58 | class HashErrors(InstallationError): | ||
| 59 | """Multiple HashError instances rolled into one for reporting""" | ||
| 60 | |||
| 61 | def __init__(self): | ||
| 62 | self.errors = [] | ||
| 63 | |||
| 64 | def append(self, error): | ||
| 65 | self.errors.append(error) | ||
| 66 | |||
| 67 | def __str__(self): | ||
| 68 | lines = [] | ||
| 69 | self.errors.sort(key=lambda e: e.order) | ||
| 70 | for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): | ||
| 71 | lines.append(cls.head) | ||
| 72 | lines.extend(e.body() for e in errors_of_cls) | ||
| 73 | if lines: | ||
| 74 | return '\n'.join(lines) | ||
| 75 | |||
| 76 | def __nonzero__(self): | ||
| 77 | return bool(self.errors) | ||
| 78 | |||
| 79 | def __bool__(self): | ||
| 80 | return self.__nonzero__() | ||
| 81 | |||
| 82 | |||
| 83 | class HashError(InstallationError): | ||
| 84 | """ | ||
| 85 | A failure to verify a package against known-good hashes | ||
| 86 | |||
| 87 | :cvar order: An int sorting hash exception classes by difficulty of | ||
| 88 | recovery (lower being harder), so the user doesn't bother fretting | ||
| 89 | about unpinned packages when he has deeper issues, like VCS | ||
| 90 | dependencies, to deal with. Also keeps error reports in a | ||
| 91 | deterministic order. | ||
| 92 | :cvar head: A section heading for display above potentially many | ||
| 93 | exceptions of this kind | ||
| 94 | :ivar req: The InstallRequirement that triggered this error. This is | ||
| 95 | pasted on after the exception is instantiated, because it's not | ||
| 96 | typically available earlier. | ||
| 97 | |||
| 98 | """ | ||
| 99 | req = None | ||
| 100 | head = '' | ||
| 101 | |||
| 102 | def body(self): | ||
| 103 | """Return a summary of me for display under the heading. | ||
| 104 | |||
| 105 | This default implementation simply prints a description of the | ||
| 106 | triggering requirement. | ||
| 107 | |||
| 108 | :param req: The InstallRequirement that provoked this error, with | ||
| 109 | populate_link() having already been called | ||
| 110 | |||
| 111 | """ | ||
| 112 | return ' %s' % self._requirement_name() | ||
| 113 | |||
| 114 | def __str__(self): | ||
| 115 | return '%s\n%s' % (self.head, self.body()) | ||
| 116 | |||
| 117 | def _requirement_name(self): | ||
| 118 | """Return a description of the requirement that triggered me. | ||
| 119 | |||
| 120 | This default implementation returns long description of the req, with | ||
| 121 | line numbers | ||
| 122 | |||
| 123 | """ | ||
| 124 | return str(self.req) if self.req else 'unknown package' | ||
| 125 | |||
| 126 | |||
| 127 | class VcsHashUnsupported(HashError): | ||
| 128 | """A hash was provided for a version-control-system-based requirement, but | ||
| 129 | we don't have a method for hashing those.""" | ||
| 130 | |||
| 131 | order = 0 | ||
| 132 | head = ("Can't verify hashes for these requirements because we don't " | ||
| 133 | "have a way to hash version control repositories:") | ||
| 134 | |||
| 135 | |||
| 136 | class DirectoryUrlHashUnsupported(HashError): | ||
| 137 | """A hash was provided for a version-control-system-based requirement, but | ||
| 138 | we don't have a method for hashing those.""" | ||
| 139 | |||
| 140 | order = 1 | ||
| 141 | head = ("Can't verify hashes for these file:// requirements because they " | ||
| 142 | "point to directories:") | ||
| 143 | |||
| 144 | |||
| 145 | class HashMissing(HashError): | ||
| 146 | """A hash was needed for a requirement but is absent.""" | ||
| 147 | |||
| 148 | order = 2 | ||
| 149 | head = ('Hashes are required in --require-hashes mode, but they are ' | ||
| 150 | 'missing from some requirements. Here is a list of those ' | ||
| 151 | 'requirements along with the hashes their downloaded archives ' | ||
| 152 | 'actually had. Add lines like these to your requirements files to ' | ||
| 153 | 'prevent tampering. (If you did not enable --require-hashes ' | ||
| 154 | 'manually, note that it turns on automatically when any package ' | ||
| 155 | 'has a hash.)') | ||
| 156 | |||
| 157 | def __init__(self, gotten_hash): | ||
| 158 | """ | ||
| 159 | :param gotten_hash: The hash of the (possibly malicious) archive we | ||
| 160 | just downloaded | ||
| 161 | """ | ||
| 162 | self.gotten_hash = gotten_hash | ||
| 163 | |||
| 164 | def body(self): | ||
| 165 | # Dodge circular import. | ||
| 166 | from pip._internal.utils.hashes import FAVORITE_HASH | ||
| 167 | |||
| 168 | package = None | ||
| 169 | if self.req: | ||
| 170 | # In the case of URL-based requirements, display the original URL | ||
| 171 | # seen in the requirements file rather than the package name, | ||
| 172 | # so the output can be directly copied into the requirements file. | ||
| 173 | package = (self.req.original_link if self.req.original_link | ||
| 174 | # In case someone feeds something downright stupid | ||
| 175 | # to InstallRequirement's constructor. | ||
| 176 | else getattr(self.req, 'req', None)) | ||
| 177 | return ' %s --hash=%s:%s' % (package or 'unknown package', | ||
| 178 | FAVORITE_HASH, | ||
| 179 | self.gotten_hash) | ||
| 180 | |||
| 181 | |||
| 182 | class HashUnpinned(HashError): | ||
| 183 | """A requirement had a hash specified but was not pinned to a specific | ||
| 184 | version.""" | ||
| 185 | |||
| 186 | order = 3 | ||
| 187 | head = ('In --require-hashes mode, all requirements must have their ' | ||
| 188 | 'versions pinned with ==. These do not:') | ||
| 189 | |||
| 190 | |||
| 191 | class HashMismatch(HashError): | ||
| 192 | """ | ||
| 193 | Distribution file hash values don't match. | ||
| 194 | |||
| 195 | :ivar package_name: The name of the package that triggered the hash | ||
| 196 | mismatch. Feel free to write to this after the exception is raise to | ||
| 197 | improve its error message. | ||
| 198 | |||
| 199 | """ | ||
| 200 | order = 4 | ||
| 201 | head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' | ||
| 202 | 'FILE. If you have updated the package versions, please update ' | ||
| 203 | 'the hashes. Otherwise, examine the package contents carefully; ' | ||
| 204 | 'someone may have tampered with them.') | ||
| 205 | |||
| 206 | def __init__(self, allowed, gots): | ||
| 207 | """ | ||
| 208 | :param allowed: A dict of algorithm names pointing to lists of allowed | ||
| 209 | hex digests | ||
| 210 | :param gots: A dict of algorithm names pointing to hashes we | ||
| 211 | actually got from the files under suspicion | ||
| 212 | """ | ||
| 213 | self.allowed = allowed | ||
| 214 | self.gots = gots | ||
| 215 | |||
| 216 | def body(self): | ||
| 217 | return ' %s:\n%s' % (self._requirement_name(), | ||
| 218 | self._hash_comparison()) | ||
| 219 | |||
| 220 | def _hash_comparison(self): | ||
| 221 | """ | ||
| 222 | Return a comparison of actual and expected hash values. | ||
| 223 | |||
| 224 | Example:: | ||
| 225 | |||
| 226 | Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde | ||
| 227 | or 123451234512345123451234512345123451234512345 | ||
| 228 | Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef | ||
| 229 | |||
| 230 | """ | ||
| 231 | def hash_then_or(hash_name): | ||
| 232 | # For now, all the decent hashes have 6-char names, so we can get | ||
| 233 | # away with hard-coding space literals. | ||
| 234 | return chain([hash_name], repeat(' or')) | ||
| 235 | |||
| 236 | lines = [] | ||
| 237 | for hash_name, expecteds in iteritems(self.allowed): | ||
| 238 | prefix = hash_then_or(hash_name) | ||
| 239 | lines.extend((' Expected %s %s' % (next(prefix), e)) | ||
| 240 | for e in expecteds) | ||
| 241 | lines.append(' Got %s\n' % | ||
| 242 | self.gots[hash_name].hexdigest()) | ||
| 243 | prefix = ' or' | ||
| 244 | return '\n'.join(lines) | ||
| 245 | |||
| 246 | |||
| 247 | class UnsupportedPythonVersion(InstallationError): | ||
| 248 | """Unsupported python version according to Requires-Python package | ||
| 249 | metadata.""" | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/index.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/index.py deleted file mode 100644 index 15e0bf3..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/index.py +++ /dev/null | |||
| @@ -1,1117 +0,0 @@ | |||
| 1 | """Routines related to PyPI, indexes""" | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import cgi | ||
| 5 | import itertools | ||
| 6 | import logging | ||
| 7 | import mimetypes | ||
| 8 | import os | ||
| 9 | import posixpath | ||
| 10 | import re | ||
| 11 | import sys | ||
| 12 | import warnings | ||
| 13 | from collections import namedtuple | ||
| 14 | |||
| 15 | from pip._vendor import html5lib, requests, six | ||
| 16 | from pip._vendor.distlib.compat import unescape | ||
| 17 | from pip._vendor.packaging import specifiers | ||
| 18 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 19 | from pip._vendor.packaging.version import parse as parse_version | ||
| 20 | from pip._vendor.requests.exceptions import SSLError | ||
| 21 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 22 | from pip._vendor.six.moves.urllib import request as urllib_request | ||
| 23 | |||
| 24 | from pip._internal.compat import ipaddress | ||
| 25 | from pip._internal.download import HAS_TLS, is_url, path_to_url, url_to_path | ||
| 26 | from pip._internal.exceptions import ( | ||
| 27 | BestVersionAlreadyInstalled, DistributionNotFound, InvalidWheelFilename, | ||
| 28 | UnsupportedWheel, | ||
| 29 | ) | ||
| 30 | from pip._internal.models import PyPI | ||
| 31 | from pip._internal.pep425tags import get_supported | ||
| 32 | from pip._internal.utils.deprecation import RemovedInPip11Warning | ||
| 33 | from pip._internal.utils.logging import indent_log | ||
| 34 | from pip._internal.utils.misc import ( | ||
| 35 | ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, cached_property, normalize_path, | ||
| 36 | splitext, | ||
| 37 | ) | ||
| 38 | from pip._internal.utils.packaging import check_requires_python | ||
| 39 | from pip._internal.wheel import Wheel, wheel_ext | ||
| 40 | |||
| 41 | __all__ = ['FormatControl', 'fmt_ctl_handle_mutual_exclude', 'PackageFinder'] | ||
| 42 | |||
| 43 | |||
| 44 | SECURE_ORIGINS = [ | ||
| 45 | # protocol, hostname, port | ||
| 46 | # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) | ||
| 47 | ("https", "*", "*"), | ||
| 48 | ("*", "localhost", "*"), | ||
| 49 | ("*", "127.0.0.0/8", "*"), | ||
| 50 | ("*", "::1/128", "*"), | ||
| 51 | ("file", "*", None), | ||
| 52 | # ssh is always secure. | ||
| 53 | ("ssh", "*", "*"), | ||
| 54 | ] | ||
| 55 | |||
| 56 | |||
| 57 | logger = logging.getLogger(__name__) | ||
| 58 | |||
| 59 | |||
| 60 | class InstallationCandidate(object): | ||
| 61 | |||
| 62 | def __init__(self, project, version, location): | ||
| 63 | self.project = project | ||
| 64 | self.version = parse_version(version) | ||
| 65 | self.location = location | ||
| 66 | self._key = (self.project, self.version, self.location) | ||
| 67 | |||
| 68 | def __repr__(self): | ||
| 69 | return "<InstallationCandidate({!r}, {!r}, {!r})>".format( | ||
| 70 | self.project, self.version, self.location, | ||
| 71 | ) | ||
| 72 | |||
| 73 | def __hash__(self): | ||
| 74 | return hash(self._key) | ||
| 75 | |||
| 76 | def __lt__(self, other): | ||
| 77 | return self._compare(other, lambda s, o: s < o) | ||
| 78 | |||
| 79 | def __le__(self, other): | ||
| 80 | return self._compare(other, lambda s, o: s <= o) | ||
| 81 | |||
| 82 | def __eq__(self, other): | ||
| 83 | return self._compare(other, lambda s, o: s == o) | ||
| 84 | |||
| 85 | def __ge__(self, other): | ||
| 86 | return self._compare(other, lambda s, o: s >= o) | ||
| 87 | |||
| 88 | def __gt__(self, other): | ||
| 89 | return self._compare(other, lambda s, o: s > o) | ||
| 90 | |||
| 91 | def __ne__(self, other): | ||
| 92 | return self._compare(other, lambda s, o: s != o) | ||
| 93 | |||
| 94 | def _compare(self, other, method): | ||
| 95 | if not isinstance(other, InstallationCandidate): | ||
| 96 | return NotImplemented | ||
| 97 | |||
| 98 | return method(self._key, other._key) | ||
| 99 | |||
| 100 | |||
| 101 | class PackageFinder(object): | ||
| 102 | """This finds packages. | ||
| 103 | |||
| 104 | This is meant to match easy_install's technique for looking for | ||
| 105 | packages, by reading pages and looking for appropriate links. | ||
| 106 | """ | ||
| 107 | |||
| 108 | def __init__(self, find_links, index_urls, allow_all_prereleases=False, | ||
| 109 | trusted_hosts=None, process_dependency_links=False, | ||
| 110 | session=None, format_control=None, platform=None, | ||
| 111 | versions=None, abi=None, implementation=None): | ||
| 112 | """Create a PackageFinder. | ||
| 113 | |||
| 114 | :param format_control: A FormatControl object or None. Used to control | ||
| 115 | the selection of source packages / binary packages when consulting | ||
| 116 | the index and links. | ||
| 117 | :param platform: A string or None. If None, searches for packages | ||
| 118 | that are supported by the current system. Otherwise, will find | ||
| 119 | packages that can be built on the platform passed in. These | ||
| 120 | packages will only be downloaded for distribution: they will | ||
| 121 | not be built locally. | ||
| 122 | :param versions: A list of strings or None. This is passed directly | ||
| 123 | to pep425tags.py in the get_supported() method. | ||
| 124 | :param abi: A string or None. This is passed directly | ||
| 125 | to pep425tags.py in the get_supported() method. | ||
| 126 | :param implementation: A string or None. This is passed directly | ||
| 127 | to pep425tags.py in the get_supported() method. | ||
| 128 | """ | ||
| 129 | if session is None: | ||
| 130 | raise TypeError( | ||
| 131 | "PackageFinder() missing 1 required keyword argument: " | ||
| 132 | "'session'" | ||
| 133 | ) | ||
| 134 | |||
| 135 | # Build find_links. If an argument starts with ~, it may be | ||
| 136 | # a local file relative to a home directory. So try normalizing | ||
| 137 | # it and if it exists, use the normalized version. | ||
| 138 | # This is deliberately conservative - it might be fine just to | ||
| 139 | # blindly normalize anything starting with a ~... | ||
| 140 | self.find_links = [] | ||
| 141 | for link in find_links: | ||
| 142 | if link.startswith('~'): | ||
| 143 | new_link = normalize_path(link) | ||
| 144 | if os.path.exists(new_link): | ||
| 145 | link = new_link | ||
| 146 | self.find_links.append(link) | ||
| 147 | |||
| 148 | self.index_urls = index_urls | ||
| 149 | self.dependency_links = [] | ||
| 150 | |||
| 151 | # These are boring links that have already been logged somehow: | ||
| 152 | self.logged_links = set() | ||
| 153 | |||
| 154 | self.format_control = format_control or FormatControl(set(), set()) | ||
| 155 | |||
| 156 | # Domains that we won't emit warnings for when not using HTTPS | ||
| 157 | self.secure_origins = [ | ||
| 158 | ("*", host, "*") | ||
| 159 | for host in (trusted_hosts if trusted_hosts else []) | ||
| 160 | ] | ||
| 161 | |||
| 162 | # Do we want to allow _all_ pre-releases? | ||
| 163 | self.allow_all_prereleases = allow_all_prereleases | ||
| 164 | |||
| 165 | # Do we process dependency links? | ||
| 166 | self.process_dependency_links = process_dependency_links | ||
| 167 | |||
| 168 | # The Session we'll use to make requests | ||
| 169 | self.session = session | ||
| 170 | |||
| 171 | # The valid tags to check potential found wheel candidates against | ||
| 172 | self.valid_tags = get_supported( | ||
| 173 | versions=versions, | ||
| 174 | platform=platform, | ||
| 175 | abi=abi, | ||
| 176 | impl=implementation, | ||
| 177 | ) | ||
| 178 | |||
| 179 | # If we don't have TLS enabled, then WARN if anyplace we're looking | ||
| 180 | # relies on TLS. | ||
| 181 | if not HAS_TLS: | ||
| 182 | for link in itertools.chain(self.index_urls, self.find_links): | ||
| 183 | parsed = urllib_parse.urlparse(link) | ||
| 184 | if parsed.scheme == "https": | ||
| 185 | logger.warning( | ||
| 186 | "pip is configured with locations that require " | ||
| 187 | "TLS/SSL, however the ssl module in Python is not " | ||
| 188 | "available." | ||
| 189 | ) | ||
| 190 | break | ||
| 191 | |||
| 192 | def get_formatted_locations(self): | ||
| 193 | lines = [] | ||
| 194 | if self.index_urls and self.index_urls != [PyPI.simple_url]: | ||
| 195 | lines.append( | ||
| 196 | "Looking in indexes: {}".format(", ".join(self.index_urls)) | ||
| 197 | ) | ||
| 198 | if self.find_links: | ||
| 199 | lines.append( | ||
| 200 | "Looking in links: {}".format(", ".join(self.find_links)) | ||
| 201 | ) | ||
| 202 | return "\n".join(lines) | ||
| 203 | |||
| 204 | def add_dependency_links(self, links): | ||
| 205 | # # FIXME: this shouldn't be global list this, it should only | ||
| 206 | # # apply to requirements of the package that specifies the | ||
| 207 | # # dependency_links value | ||
| 208 | # # FIXME: also, we should track comes_from (i.e., use Link) | ||
| 209 | if self.process_dependency_links: | ||
| 210 | warnings.warn( | ||
| 211 | "Dependency Links processing has been deprecated and will be " | ||
| 212 | "removed in a future release.", | ||
| 213 | RemovedInPip11Warning, | ||
| 214 | ) | ||
| 215 | self.dependency_links.extend(links) | ||
| 216 | |||
| 217 | @staticmethod | ||
| 218 | def _sort_locations(locations, expand_dir=False): | ||
| 219 | """ | ||
| 220 | Sort locations into "files" (archives) and "urls", and return | ||
| 221 | a pair of lists (files,urls) | ||
| 222 | """ | ||
| 223 | files = [] | ||
| 224 | urls = [] | ||
| 225 | |||
| 226 | # puts the url for the given file path into the appropriate list | ||
| 227 | def sort_path(path): | ||
| 228 | url = path_to_url(path) | ||
| 229 | if mimetypes.guess_type(url, strict=False)[0] == 'text/html': | ||
| 230 | urls.append(url) | ||
| 231 | else: | ||
| 232 | files.append(url) | ||
| 233 | |||
| 234 | for url in locations: | ||
| 235 | |||
| 236 | is_local_path = os.path.exists(url) | ||
| 237 | is_file_url = url.startswith('file:') | ||
| 238 | |||
| 239 | if is_local_path or is_file_url: | ||
| 240 | if is_local_path: | ||
| 241 | path = url | ||
| 242 | else: | ||
| 243 | path = url_to_path(url) | ||
| 244 | if os.path.isdir(path): | ||
| 245 | if expand_dir: | ||
| 246 | path = os.path.realpath(path) | ||
| 247 | for item in os.listdir(path): | ||
| 248 | sort_path(os.path.join(path, item)) | ||
| 249 | elif is_file_url: | ||
| 250 | urls.append(url) | ||
| 251 | elif os.path.isfile(path): | ||
| 252 | sort_path(path) | ||
| 253 | else: | ||
| 254 | logger.warning( | ||
| 255 | "Url '%s' is ignored: it is neither a file " | ||
| 256 | "nor a directory.", url, | ||
| 257 | ) | ||
| 258 | elif is_url(url): | ||
| 259 | # Only add url with clear scheme | ||
| 260 | urls.append(url) | ||
| 261 | else: | ||
| 262 | logger.warning( | ||
| 263 | "Url '%s' is ignored. It is either a non-existing " | ||
| 264 | "path or lacks a specific scheme.", url, | ||
| 265 | ) | ||
| 266 | |||
| 267 | return files, urls | ||
| 268 | |||
| 269 | def _candidate_sort_key(self, candidate): | ||
| 270 | """ | ||
| 271 | Function used to generate link sort key for link tuples. | ||
| 272 | The greater the return value, the more preferred it is. | ||
| 273 | If not finding wheels, then sorted by version only. | ||
| 274 | If finding wheels, then the sort order is by version, then: | ||
| 275 | 1. existing installs | ||
| 276 | 2. wheels ordered via Wheel.support_index_min(self.valid_tags) | ||
| 277 | 3. source archives | ||
| 278 | Note: it was considered to embed this logic into the Link | ||
| 279 | comparison operators, but then different sdist links | ||
| 280 | with the same version, would have to be considered equal | ||
| 281 | """ | ||
| 282 | support_num = len(self.valid_tags) | ||
| 283 | build_tag = tuple() | ||
| 284 | if candidate.location.is_wheel: | ||
| 285 | # can raise InvalidWheelFilename | ||
| 286 | wheel = Wheel(candidate.location.filename) | ||
| 287 | if not wheel.supported(self.valid_tags): | ||
| 288 | raise UnsupportedWheel( | ||
| 289 | "%s is not a supported wheel for this platform. It " | ||
| 290 | "can't be sorted." % wheel.filename | ||
| 291 | ) | ||
| 292 | pri = -(wheel.support_index_min(self.valid_tags)) | ||
| 293 | if wheel.build_tag is not None: | ||
| 294 | match = re.match(r'^(\d+)(.*)$', wheel.build_tag) | ||
| 295 | build_tag_groups = match.groups() | ||
| 296 | build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) | ||
| 297 | else: # sdist | ||
| 298 | pri = -(support_num) | ||
| 299 | return (candidate.version, build_tag, pri) | ||
| 300 | |||
| 301 | def _validate_secure_origin(self, logger, location): | ||
| 302 | # Determine if this url used a secure transport mechanism | ||
| 303 | parsed = urllib_parse.urlparse(str(location)) | ||
| 304 | origin = (parsed.scheme, parsed.hostname, parsed.port) | ||
| 305 | |||
| 306 | # The protocol to use to see if the protocol matches. | ||
| 307 | # Don't count the repository type as part of the protocol: in | ||
| 308 | # cases such as "git+ssh", only use "ssh". (I.e., Only verify against | ||
| 309 | # the last scheme.) | ||
| 310 | protocol = origin[0].rsplit('+', 1)[-1] | ||
| 311 | |||
| 312 | # Determine if our origin is a secure origin by looking through our | ||
| 313 | # hardcoded list of secure origins, as well as any additional ones | ||
| 314 | # configured on this PackageFinder instance. | ||
| 315 | for secure_origin in (SECURE_ORIGINS + self.secure_origins): | ||
| 316 | if protocol != secure_origin[0] and secure_origin[0] != "*": | ||
| 317 | continue | ||
| 318 | |||
| 319 | try: | ||
| 320 | # We need to do this decode dance to ensure that we have a | ||
| 321 | # unicode object, even on Python 2.x. | ||
| 322 | addr = ipaddress.ip_address( | ||
| 323 | origin[1] | ||
| 324 | if ( | ||
| 325 | isinstance(origin[1], six.text_type) or | ||
| 326 | origin[1] is None | ||
| 327 | ) | ||
| 328 | else origin[1].decode("utf8") | ||
| 329 | ) | ||
| 330 | network = ipaddress.ip_network( | ||
| 331 | secure_origin[1] | ||
| 332 | if isinstance(secure_origin[1], six.text_type) | ||
| 333 | else secure_origin[1].decode("utf8") | ||
| 334 | ) | ||
| 335 | except ValueError: | ||
| 336 | # We don't have both a valid address or a valid network, so | ||
| 337 | # we'll check this origin against hostnames. | ||
| 338 | if (origin[1] and | ||
| 339 | origin[1].lower() != secure_origin[1].lower() and | ||
| 340 | secure_origin[1] != "*"): | ||
| 341 | continue | ||
| 342 | else: | ||
| 343 | # We have a valid address and network, so see if the address | ||
| 344 | # is contained within the network. | ||
| 345 | if addr not in network: | ||
| 346 | continue | ||
| 347 | |||
| 348 | # Check to see if the port patches | ||
| 349 | if (origin[2] != secure_origin[2] and | ||
| 350 | secure_origin[2] != "*" and | ||
| 351 | secure_origin[2] is not None): | ||
| 352 | continue | ||
| 353 | |||
| 354 | # If we've gotten here, then this origin matches the current | ||
| 355 | # secure origin and we should return True | ||
| 356 | return True | ||
| 357 | |||
| 358 | # If we've gotten to this point, then the origin isn't secure and we | ||
| 359 | # will not accept it as a valid location to search. We will however | ||
| 360 | # log a warning that we are ignoring it. | ||
| 361 | logger.warning( | ||
| 362 | "The repository located at %s is not a trusted or secure host and " | ||
| 363 | "is being ignored. If this repository is available via HTTPS we " | ||
| 364 | "recommend you use HTTPS instead, otherwise you may silence " | ||
| 365 | "this warning and allow it anyway with '--trusted-host %s'.", | ||
| 366 | parsed.hostname, | ||
| 367 | parsed.hostname, | ||
| 368 | ) | ||
| 369 | |||
| 370 | return False | ||
| 371 | |||
| 372 | def _get_index_urls_locations(self, project_name): | ||
| 373 | """Returns the locations found via self.index_urls | ||
| 374 | |||
| 375 | Checks the url_name on the main (first in the list) index and | ||
| 376 | use this url_name to produce all locations | ||
| 377 | """ | ||
| 378 | |||
| 379 | def mkurl_pypi_url(url): | ||
| 380 | loc = posixpath.join( | ||
| 381 | url, | ||
| 382 | urllib_parse.quote(canonicalize_name(project_name))) | ||
| 383 | # For maximum compatibility with easy_install, ensure the path | ||
| 384 | # ends in a trailing slash. Although this isn't in the spec | ||
| 385 | # (and PyPI can handle it without the slash) some other index | ||
| 386 | # implementations might break if they relied on easy_install's | ||
| 387 | # behavior. | ||
| 388 | if not loc.endswith('/'): | ||
| 389 | loc = loc + '/' | ||
| 390 | return loc | ||
| 391 | |||
| 392 | return [mkurl_pypi_url(url) for url in self.index_urls] | ||
| 393 | |||
| 394 | def find_all_candidates(self, project_name): | ||
| 395 | """Find all available InstallationCandidate for project_name | ||
| 396 | |||
| 397 | This checks index_urls, find_links and dependency_links. | ||
| 398 | All versions found are returned as an InstallationCandidate list. | ||
| 399 | |||
| 400 | See _link_package_versions for details on which files are accepted | ||
| 401 | """ | ||
| 402 | index_locations = self._get_index_urls_locations(project_name) | ||
| 403 | index_file_loc, index_url_loc = self._sort_locations(index_locations) | ||
| 404 | fl_file_loc, fl_url_loc = self._sort_locations( | ||
| 405 | self.find_links, expand_dir=True, | ||
| 406 | ) | ||
| 407 | dep_file_loc, dep_url_loc = self._sort_locations(self.dependency_links) | ||
| 408 | |||
| 409 | file_locations = (Link(url) for url in itertools.chain( | ||
| 410 | index_file_loc, fl_file_loc, dep_file_loc, | ||
| 411 | )) | ||
| 412 | |||
| 413 | # We trust every url that the user has given us whether it was given | ||
| 414 | # via --index-url or --find-links | ||
| 415 | # We explicitly do not trust links that came from dependency_links | ||
| 416 | # We want to filter out any thing which does not have a secure origin. | ||
| 417 | url_locations = [ | ||
| 418 | link for link in itertools.chain( | ||
| 419 | (Link(url) for url in index_url_loc), | ||
| 420 | (Link(url) for url in fl_url_loc), | ||
| 421 | (Link(url) for url in dep_url_loc), | ||
| 422 | ) | ||
| 423 | if self._validate_secure_origin(logger, link) | ||
| 424 | ] | ||
| 425 | |||
| 426 | logger.debug('%d location(s) to search for versions of %s:', | ||
| 427 | len(url_locations), project_name) | ||
| 428 | |||
| 429 | for location in url_locations: | ||
| 430 | logger.debug('* %s', location) | ||
| 431 | |||
| 432 | canonical_name = canonicalize_name(project_name) | ||
| 433 | formats = fmt_ctl_formats(self.format_control, canonical_name) | ||
| 434 | search = Search(project_name, canonical_name, formats) | ||
| 435 | find_links_versions = self._package_versions( | ||
| 436 | # We trust every directly linked archive in find_links | ||
| 437 | (Link(url, '-f') for url in self.find_links), | ||
| 438 | search | ||
| 439 | ) | ||
| 440 | |||
| 441 | page_versions = [] | ||
| 442 | for page in self._get_pages(url_locations, project_name): | ||
| 443 | logger.debug('Analyzing links from page %s', page.url) | ||
| 444 | with indent_log(): | ||
| 445 | page_versions.extend( | ||
| 446 | self._package_versions(page.links, search) | ||
| 447 | ) | ||
| 448 | |||
| 449 | dependency_versions = self._package_versions( | ||
| 450 | (Link(url) for url in self.dependency_links), search | ||
| 451 | ) | ||
| 452 | if dependency_versions: | ||
| 453 | logger.debug( | ||
| 454 | 'dependency_links found: %s', | ||
| 455 | ', '.join([ | ||
| 456 | version.location.url for version in dependency_versions | ||
| 457 | ]) | ||
| 458 | ) | ||
| 459 | |||
| 460 | file_versions = self._package_versions(file_locations, search) | ||
| 461 | if file_versions: | ||
| 462 | file_versions.sort(reverse=True) | ||
| 463 | logger.debug( | ||
| 464 | 'Local files found: %s', | ||
| 465 | ', '.join([ | ||
| 466 | url_to_path(candidate.location.url) | ||
| 467 | for candidate in file_versions | ||
| 468 | ]) | ||
| 469 | ) | ||
| 470 | |||
| 471 | # This is an intentional priority ordering | ||
| 472 | return ( | ||
| 473 | file_versions + find_links_versions + page_versions + | ||
| 474 | dependency_versions | ||
| 475 | ) | ||
| 476 | |||
| 477 | def find_requirement(self, req, upgrade): | ||
| 478 | """Try to find a Link matching req | ||
| 479 | |||
| 480 | Expects req, an InstallRequirement and upgrade, a boolean | ||
| 481 | Returns a Link if found, | ||
| 482 | Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise | ||
| 483 | """ | ||
| 484 | all_candidates = self.find_all_candidates(req.name) | ||
| 485 | |||
| 486 | # Filter out anything which doesn't match our specifier | ||
| 487 | compatible_versions = set( | ||
| 488 | req.specifier.filter( | ||
| 489 | # We turn the version object into a str here because otherwise | ||
| 490 | # when we're debundled but setuptools isn't, Python will see | ||
| 491 | # packaging.version.Version and | ||
| 492 | # pkg_resources._vendor.packaging.version.Version as different | ||
| 493 | # types. This way we'll use a str as a common data interchange | ||
| 494 | # format. If we stop using the pkg_resources provided specifier | ||
| 495 | # and start using our own, we can drop the cast to str(). | ||
| 496 | [str(c.version) for c in all_candidates], | ||
| 497 | prereleases=( | ||
| 498 | self.allow_all_prereleases | ||
| 499 | if self.allow_all_prereleases else None | ||
| 500 | ), | ||
| 501 | ) | ||
| 502 | ) | ||
| 503 | applicable_candidates = [ | ||
| 504 | # Again, converting to str to deal with debundling. | ||
| 505 | c for c in all_candidates if str(c.version) in compatible_versions | ||
| 506 | ] | ||
| 507 | |||
| 508 | if applicable_candidates: | ||
| 509 | best_candidate = max(applicable_candidates, | ||
| 510 | key=self._candidate_sort_key) | ||
| 511 | else: | ||
| 512 | best_candidate = None | ||
| 513 | |||
| 514 | if req.satisfied_by is not None: | ||
| 515 | installed_version = parse_version(req.satisfied_by.version) | ||
| 516 | else: | ||
| 517 | installed_version = None | ||
| 518 | |||
| 519 | if installed_version is None and best_candidate is None: | ||
| 520 | logger.critical( | ||
| 521 | 'Could not find a version that satisfies the requirement %s ' | ||
| 522 | '(from versions: %s)', | ||
| 523 | req, | ||
| 524 | ', '.join( | ||
| 525 | sorted( | ||
| 526 | {str(c.version) for c in all_candidates}, | ||
| 527 | key=parse_version, | ||
| 528 | ) | ||
| 529 | ) | ||
| 530 | ) | ||
| 531 | |||
| 532 | raise DistributionNotFound( | ||
| 533 | 'No matching distribution found for %s' % req | ||
| 534 | ) | ||
| 535 | |||
| 536 | best_installed = False | ||
| 537 | if installed_version and ( | ||
| 538 | best_candidate is None or | ||
| 539 | best_candidate.version <= installed_version): | ||
| 540 | best_installed = True | ||
| 541 | |||
| 542 | if not upgrade and installed_version is not None: | ||
| 543 | if best_installed: | ||
| 544 | logger.debug( | ||
| 545 | 'Existing installed version (%s) is most up-to-date and ' | ||
| 546 | 'satisfies requirement', | ||
| 547 | installed_version, | ||
| 548 | ) | ||
| 549 | else: | ||
| 550 | logger.debug( | ||
| 551 | 'Existing installed version (%s) satisfies requirement ' | ||
| 552 | '(most up-to-date version is %s)', | ||
| 553 | installed_version, | ||
| 554 | best_candidate.version, | ||
| 555 | ) | ||
| 556 | return None | ||
| 557 | |||
| 558 | if best_installed: | ||
| 559 | # We have an existing version, and its the best version | ||
| 560 | logger.debug( | ||
| 561 | 'Installed version (%s) is most up-to-date (past versions: ' | ||
| 562 | '%s)', | ||
| 563 | installed_version, | ||
| 564 | ', '.join(sorted(compatible_versions, key=parse_version)) or | ||
| 565 | "none", | ||
| 566 | ) | ||
| 567 | raise BestVersionAlreadyInstalled | ||
| 568 | |||
| 569 | logger.debug( | ||
| 570 | 'Using version %s (newest of versions: %s)', | ||
| 571 | best_candidate.version, | ||
| 572 | ', '.join(sorted(compatible_versions, key=parse_version)) | ||
| 573 | ) | ||
| 574 | return best_candidate.location | ||
| 575 | |||
| 576 | def _get_pages(self, locations, project_name): | ||
| 577 | """ | ||
| 578 | Yields (page, page_url) from the given locations, skipping | ||
| 579 | locations that have errors. | ||
| 580 | """ | ||
| 581 | seen = set() | ||
| 582 | for location in locations: | ||
| 583 | if location in seen: | ||
| 584 | continue | ||
| 585 | seen.add(location) | ||
| 586 | |||
| 587 | page = self._get_page(location) | ||
| 588 | if page is None: | ||
| 589 | continue | ||
| 590 | |||
| 591 | yield page | ||
| 592 | |||
| 593 | _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') | ||
| 594 | |||
| 595 | def _sort_links(self, links): | ||
| 596 | """ | ||
| 597 | Returns elements of links in order, non-egg links first, egg links | ||
| 598 | second, while eliminating duplicates | ||
| 599 | """ | ||
| 600 | eggs, no_eggs = [], [] | ||
| 601 | seen = set() | ||
| 602 | for link in links: | ||
| 603 | if link not in seen: | ||
| 604 | seen.add(link) | ||
| 605 | if link.egg_fragment: | ||
| 606 | eggs.append(link) | ||
| 607 | else: | ||
| 608 | no_eggs.append(link) | ||
| 609 | return no_eggs + eggs | ||
| 610 | |||
| 611 | def _package_versions(self, links, search): | ||
| 612 | result = [] | ||
| 613 | for link in self._sort_links(links): | ||
| 614 | v = self._link_package_versions(link, search) | ||
| 615 | if v is not None: | ||
| 616 | result.append(v) | ||
| 617 | return result | ||
| 618 | |||
| 619 | def _log_skipped_link(self, link, reason): | ||
| 620 | if link not in self.logged_links: | ||
| 621 | logger.debug('Skipping link %s; %s', link, reason) | ||
| 622 | self.logged_links.add(link) | ||
| 623 | |||
| 624 | def _link_package_versions(self, link, search): | ||
| 625 | """Return an InstallationCandidate or None""" | ||
| 626 | version = None | ||
| 627 | if link.egg_fragment: | ||
| 628 | egg_info = link.egg_fragment | ||
| 629 | ext = link.ext | ||
| 630 | else: | ||
| 631 | egg_info, ext = link.splitext() | ||
| 632 | if not ext: | ||
| 633 | self._log_skipped_link(link, 'not a file') | ||
| 634 | return | ||
| 635 | if ext not in SUPPORTED_EXTENSIONS: | ||
| 636 | self._log_skipped_link( | ||
| 637 | link, 'unsupported archive format: %s' % ext, | ||
| 638 | ) | ||
| 639 | return | ||
| 640 | if "binary" not in search.formats and ext == wheel_ext: | ||
| 641 | self._log_skipped_link( | ||
| 642 | link, 'No binaries permitted for %s' % search.supplied, | ||
| 643 | ) | ||
| 644 | return | ||
| 645 | if "macosx10" in link.path and ext == '.zip': | ||
| 646 | self._log_skipped_link(link, 'macosx10 one') | ||
| 647 | return | ||
| 648 | if ext == wheel_ext: | ||
| 649 | try: | ||
| 650 | wheel = Wheel(link.filename) | ||
| 651 | except InvalidWheelFilename: | ||
| 652 | self._log_skipped_link(link, 'invalid wheel filename') | ||
| 653 | return | ||
| 654 | if canonicalize_name(wheel.name) != search.canonical: | ||
| 655 | self._log_skipped_link( | ||
| 656 | link, 'wrong project name (not %s)' % search.supplied) | ||
| 657 | return | ||
| 658 | |||
| 659 | if not wheel.supported(self.valid_tags): | ||
| 660 | self._log_skipped_link( | ||
| 661 | link, 'it is not compatible with this Python') | ||
| 662 | return | ||
| 663 | |||
| 664 | version = wheel.version | ||
| 665 | |||
| 666 | # This should be up by the search.ok_binary check, but see issue 2700. | ||
| 667 | if "source" not in search.formats and ext != wheel_ext: | ||
| 668 | self._log_skipped_link( | ||
| 669 | link, 'No sources permitted for %s' % search.supplied, | ||
| 670 | ) | ||
| 671 | return | ||
| 672 | |||
| 673 | if not version: | ||
| 674 | version = egg_info_matches(egg_info, search.supplied, link) | ||
| 675 | if version is None: | ||
| 676 | self._log_skipped_link( | ||
| 677 | link, 'wrong project name (not %s)' % search.supplied) | ||
| 678 | return | ||
| 679 | |||
| 680 | match = self._py_version_re.search(version) | ||
| 681 | if match: | ||
| 682 | version = version[:match.start()] | ||
| 683 | py_version = match.group(1) | ||
| 684 | if py_version != sys.version[:3]: | ||
| 685 | self._log_skipped_link( | ||
| 686 | link, 'Python version is incorrect') | ||
| 687 | return | ||
| 688 | try: | ||
| 689 | support_this_python = check_requires_python(link.requires_python) | ||
| 690 | except specifiers.InvalidSpecifier: | ||
| 691 | logger.debug("Package %s has an invalid Requires-Python entry: %s", | ||
| 692 | link.filename, link.requires_python) | ||
| 693 | support_this_python = True | ||
| 694 | |||
| 695 | if not support_this_python: | ||
| 696 | logger.debug("The package %s is incompatible with the python" | ||
| 697 | "version in use. Acceptable python versions are:%s", | ||
| 698 | link, link.requires_python) | ||
| 699 | return | ||
| 700 | logger.debug('Found link %s, version: %s', link, version) | ||
| 701 | |||
| 702 | return InstallationCandidate(search.supplied, version, link) | ||
| 703 | |||
| 704 | def _get_page(self, link): | ||
| 705 | return HTMLPage.get_page(link, session=self.session) | ||
| 706 | |||
| 707 | |||
| 708 | def egg_info_matches( | ||
| 709 | egg_info, search_name, link, | ||
| 710 | _egg_info_re=re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.I)): | ||
| 711 | """Pull the version part out of a string. | ||
| 712 | |||
| 713 | :param egg_info: The string to parse. E.g. foo-2.1 | ||
| 714 | :param search_name: The name of the package this belongs to. None to | ||
| 715 | infer the name. Note that this cannot unambiguously parse strings | ||
| 716 | like foo-2-2 which might be foo, 2-2 or foo-2, 2. | ||
| 717 | :param link: The link the string came from, for logging on failure. | ||
| 718 | """ | ||
| 719 | match = _egg_info_re.search(egg_info) | ||
| 720 | if not match: | ||
| 721 | logger.debug('Could not parse version from link: %s', link) | ||
| 722 | return None | ||
| 723 | if search_name is None: | ||
| 724 | full_match = match.group(0) | ||
| 725 | return full_match[full_match.index('-'):] | ||
| 726 | name = match.group(0).lower() | ||
| 727 | # To match the "safe" name that pkg_resources creates: | ||
| 728 | name = name.replace('_', '-') | ||
| 729 | # project name and version must be separated by a dash | ||
| 730 | look_for = search_name.lower() + "-" | ||
| 731 | if name.startswith(look_for): | ||
| 732 | return match.group(0)[len(look_for):] | ||
| 733 | else: | ||
| 734 | return None | ||
| 735 | |||
| 736 | |||
| 737 | class HTMLPage(object): | ||
| 738 | """Represents one page, along with its URL""" | ||
| 739 | |||
| 740 | def __init__(self, content, url, headers=None): | ||
| 741 | # Determine if we have any encoding information in our headers | ||
| 742 | encoding = None | ||
| 743 | if headers and "Content-Type" in headers: | ||
| 744 | content_type, params = cgi.parse_header(headers["Content-Type"]) | ||
| 745 | |||
| 746 | if "charset" in params: | ||
| 747 | encoding = params['charset'] | ||
| 748 | |||
| 749 | self.content = content | ||
| 750 | self.parsed = html5lib.parse( | ||
| 751 | self.content, | ||
| 752 | transport_encoding=encoding, | ||
| 753 | namespaceHTMLElements=False, | ||
| 754 | ) | ||
| 755 | self.url = url | ||
| 756 | self.headers = headers | ||
| 757 | |||
| 758 | def __str__(self): | ||
| 759 | return self.url | ||
| 760 | |||
| 761 | @classmethod | ||
| 762 | def get_page(cls, link, skip_archives=True, session=None): | ||
| 763 | if session is None: | ||
| 764 | raise TypeError( | ||
| 765 | "get_page() missing 1 required keyword argument: 'session'" | ||
| 766 | ) | ||
| 767 | |||
| 768 | url = link.url | ||
| 769 | url = url.split('#', 1)[0] | ||
| 770 | |||
| 771 | # Check for VCS schemes that do not support lookup as web pages. | ||
| 772 | from pip._internal.vcs import VcsSupport | ||
| 773 | for scheme in VcsSupport.schemes: | ||
| 774 | if url.lower().startswith(scheme) and url[len(scheme)] in '+:': | ||
| 775 | logger.debug('Cannot look at %s URL %s', scheme, link) | ||
| 776 | return None | ||
| 777 | |||
| 778 | try: | ||
| 779 | if skip_archives: | ||
| 780 | filename = link.filename | ||
| 781 | for bad_ext in ARCHIVE_EXTENSIONS: | ||
| 782 | if filename.endswith(bad_ext): | ||
| 783 | content_type = cls._get_content_type( | ||
| 784 | url, session=session, | ||
| 785 | ) | ||
| 786 | if content_type.lower().startswith('text/html'): | ||
| 787 | break | ||
| 788 | else: | ||
| 789 | logger.debug( | ||
| 790 | 'Skipping page %s because of Content-Type: %s', | ||
| 791 | link, | ||
| 792 | content_type, | ||
| 793 | ) | ||
| 794 | return | ||
| 795 | |||
| 796 | logger.debug('Getting page %s', url) | ||
| 797 | |||
| 798 | # Tack index.html onto file:// URLs that point to directories | ||
| 799 | (scheme, netloc, path, params, query, fragment) = \ | ||
| 800 | urllib_parse.urlparse(url) | ||
| 801 | if (scheme == 'file' and | ||
| 802 | os.path.isdir(urllib_request.url2pathname(path))): | ||
| 803 | # add trailing slash if not present so urljoin doesn't trim | ||
| 804 | # final segment | ||
| 805 | if not url.endswith('/'): | ||
| 806 | url += '/' | ||
| 807 | url = urllib_parse.urljoin(url, 'index.html') | ||
| 808 | logger.debug(' file: URL is directory, getting %s', url) | ||
| 809 | |||
| 810 | resp = session.get( | ||
| 811 | url, | ||
| 812 | headers={ | ||
| 813 | "Accept": "text/html", | ||
| 814 | "Cache-Control": "max-age=600", | ||
| 815 | }, | ||
| 816 | ) | ||
| 817 | resp.raise_for_status() | ||
| 818 | |||
| 819 | # The check for archives above only works if the url ends with | ||
| 820 | # something that looks like an archive. However that is not a | ||
| 821 | # requirement of an url. Unless we issue a HEAD request on every | ||
| 822 | # url we cannot know ahead of time for sure if something is HTML | ||
| 823 | # or not. However we can check after we've downloaded it. | ||
| 824 | content_type = resp.headers.get('Content-Type', 'unknown') | ||
| 825 | if not content_type.lower().startswith("text/html"): | ||
| 826 | logger.debug( | ||
| 827 | 'Skipping page %s because of Content-Type: %s', | ||
| 828 | link, | ||
| 829 | content_type, | ||
| 830 | ) | ||
| 831 | return | ||
| 832 | |||
| 833 | inst = cls(resp.content, resp.url, resp.headers) | ||
| 834 | except requests.HTTPError as exc: | ||
| 835 | cls._handle_fail(link, exc, url) | ||
| 836 | except SSLError as exc: | ||
| 837 | reason = "There was a problem confirming the ssl certificate: " | ||
| 838 | reason += str(exc) | ||
| 839 | cls._handle_fail(link, reason, url, meth=logger.info) | ||
| 840 | except requests.ConnectionError as exc: | ||
| 841 | cls._handle_fail(link, "connection error: %s" % exc, url) | ||
| 842 | except requests.Timeout: | ||
| 843 | cls._handle_fail(link, "timed out", url) | ||
| 844 | else: | ||
| 845 | return inst | ||
| 846 | |||
| 847 | @staticmethod | ||
| 848 | def _handle_fail(link, reason, url, meth=None): | ||
| 849 | if meth is None: | ||
| 850 | meth = logger.debug | ||
| 851 | |||
| 852 | meth("Could not fetch URL %s: %s - skipping", link, reason) | ||
| 853 | |||
| 854 | @staticmethod | ||
| 855 | def _get_content_type(url, session): | ||
| 856 | """Get the Content-Type of the given url, using a HEAD request""" | ||
| 857 | scheme, netloc, path, query, fragment = urllib_parse.urlsplit(url) | ||
| 858 | if scheme not in {'http', 'https'}: | ||
| 859 | # FIXME: some warning or something? | ||
| 860 | # assertion error? | ||
| 861 | return '' | ||
| 862 | |||
| 863 | resp = session.head(url, allow_redirects=True) | ||
| 864 | resp.raise_for_status() | ||
| 865 | |||
| 866 | return resp.headers.get("Content-Type", "") | ||
| 867 | |||
| 868 | @cached_property | ||
| 869 | def base_url(self): | ||
| 870 | bases = [ | ||
| 871 | x for x in self.parsed.findall(".//base") | ||
| 872 | if x.get("href") is not None | ||
| 873 | ] | ||
| 874 | if bases and bases[0].get("href"): | ||
| 875 | return bases[0].get("href") | ||
| 876 | else: | ||
| 877 | return self.url | ||
| 878 | |||
| 879 | @property | ||
| 880 | def links(self): | ||
| 881 | """Yields all links in the page""" | ||
| 882 | for anchor in self.parsed.findall(".//a"): | ||
| 883 | if anchor.get("href"): | ||
| 884 | href = anchor.get("href") | ||
| 885 | url = self.clean_link( | ||
| 886 | urllib_parse.urljoin(self.base_url, href) | ||
| 887 | ) | ||
| 888 | pyrequire = anchor.get('data-requires-python') | ||
| 889 | pyrequire = unescape(pyrequire) if pyrequire else None | ||
| 890 | yield Link(url, self, requires_python=pyrequire) | ||
| 891 | |||
| 892 | _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) | ||
| 893 | |||
| 894 | def clean_link(self, url): | ||
| 895 | """Makes sure a link is fully encoded. That is, if a ' ' shows up in | ||
| 896 | the link, it will be rewritten to %20 (while not over-quoting | ||
| 897 | % or other characters).""" | ||
| 898 | return self._clean_re.sub( | ||
| 899 | lambda match: '%%%2x' % ord(match.group(0)), url) | ||
| 900 | |||
| 901 | |||
| 902 | class Link(object): | ||
| 903 | |||
| 904 | def __init__(self, url, comes_from=None, requires_python=None): | ||
| 905 | """ | ||
| 906 | Object representing a parsed link from https://pypi.org/simple/* | ||
| 907 | |||
| 908 | url: | ||
| 909 | url of the resource pointed to (href of the link) | ||
| 910 | comes_from: | ||
| 911 | instance of HTMLPage where the link was found, or string. | ||
| 912 | requires_python: | ||
| 913 | String containing the `Requires-Python` metadata field, specified | ||
| 914 | in PEP 345. This may be specified by a data-requires-python | ||
| 915 | attribute in the HTML link tag, as described in PEP 503. | ||
| 916 | """ | ||
| 917 | |||
| 918 | # url can be a UNC windows share | ||
| 919 | if url.startswith('\\\\'): | ||
| 920 | url = path_to_url(url) | ||
| 921 | |||
| 922 | self.url = url | ||
| 923 | self.comes_from = comes_from | ||
| 924 | self.requires_python = requires_python if requires_python else None | ||
| 925 | |||
| 926 | def __str__(self): | ||
| 927 | if self.requires_python: | ||
| 928 | rp = ' (requires-python:%s)' % self.requires_python | ||
| 929 | else: | ||
| 930 | rp = '' | ||
| 931 | if self.comes_from: | ||
| 932 | return '%s (from %s)%s' % (self.url, self.comes_from, rp) | ||
| 933 | else: | ||
| 934 | return str(self.url) | ||
| 935 | |||
| 936 | def __repr__(self): | ||
| 937 | return '<Link %s>' % self | ||
| 938 | |||
| 939 | def __eq__(self, other): | ||
| 940 | if not isinstance(other, Link): | ||
| 941 | return NotImplemented | ||
| 942 | return self.url == other.url | ||
| 943 | |||
| 944 | def __ne__(self, other): | ||
| 945 | if not isinstance(other, Link): | ||
| 946 | return NotImplemented | ||
| 947 | return self.url != other.url | ||
| 948 | |||
| 949 | def __lt__(self, other): | ||
| 950 | if not isinstance(other, Link): | ||
| 951 | return NotImplemented | ||
| 952 | return self.url < other.url | ||
| 953 | |||
| 954 | def __le__(self, other): | ||
| 955 | if not isinstance(other, Link): | ||
| 956 | return NotImplemented | ||
| 957 | return self.url <= other.url | ||
| 958 | |||
| 959 | def __gt__(self, other): | ||
| 960 | if not isinstance(other, Link): | ||
| 961 | return NotImplemented | ||
| 962 | return self.url > other.url | ||
| 963 | |||
| 964 | def __ge__(self, other): | ||
| 965 | if not isinstance(other, Link): | ||
| 966 | return NotImplemented | ||
| 967 | return self.url >= other.url | ||
| 968 | |||
| 969 | def __hash__(self): | ||
| 970 | return hash(self.url) | ||
| 971 | |||
| 972 | @property | ||
| 973 | def filename(self): | ||
| 974 | _, netloc, path, _, _ = urllib_parse.urlsplit(self.url) | ||
| 975 | name = posixpath.basename(path.rstrip('/')) or netloc | ||
| 976 | name = urllib_parse.unquote(name) | ||
| 977 | assert name, ('URL %r produced no filename' % self.url) | ||
| 978 | return name | ||
| 979 | |||
| 980 | @property | ||
| 981 | def scheme(self): | ||
| 982 | return urllib_parse.urlsplit(self.url)[0] | ||
| 983 | |||
| 984 | @property | ||
| 985 | def netloc(self): | ||
| 986 | return urllib_parse.urlsplit(self.url)[1] | ||
| 987 | |||
| 988 | @property | ||
| 989 | def path(self): | ||
| 990 | return urllib_parse.unquote(urllib_parse.urlsplit(self.url)[2]) | ||
| 991 | |||
| 992 | def splitext(self): | ||
| 993 | return splitext(posixpath.basename(self.path.rstrip('/'))) | ||
| 994 | |||
| 995 | @property | ||
| 996 | def ext(self): | ||
| 997 | return self.splitext()[1] | ||
| 998 | |||
| 999 | @property | ||
| 1000 | def url_without_fragment(self): | ||
| 1001 | scheme, netloc, path, query, fragment = urllib_parse.urlsplit(self.url) | ||
| 1002 | return urllib_parse.urlunsplit((scheme, netloc, path, query, None)) | ||
| 1003 | |||
| 1004 | _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') | ||
| 1005 | |||
| 1006 | @property | ||
| 1007 | def egg_fragment(self): | ||
| 1008 | match = self._egg_fragment_re.search(self.url) | ||
| 1009 | if not match: | ||
| 1010 | return None | ||
| 1011 | return match.group(1) | ||
| 1012 | |||
| 1013 | _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') | ||
| 1014 | |||
| 1015 | @property | ||
| 1016 | def subdirectory_fragment(self): | ||
| 1017 | match = self._subdirectory_fragment_re.search(self.url) | ||
| 1018 | if not match: | ||
| 1019 | return None | ||
| 1020 | return match.group(1) | ||
| 1021 | |||
| 1022 | _hash_re = re.compile( | ||
| 1023 | r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)' | ||
| 1024 | ) | ||
| 1025 | |||
| 1026 | @property | ||
| 1027 | def hash(self): | ||
| 1028 | match = self._hash_re.search(self.url) | ||
| 1029 | if match: | ||
| 1030 | return match.group(2) | ||
| 1031 | return None | ||
| 1032 | |||
| 1033 | @property | ||
| 1034 | def hash_name(self): | ||
| 1035 | match = self._hash_re.search(self.url) | ||
| 1036 | if match: | ||
| 1037 | return match.group(1) | ||
| 1038 | return None | ||
| 1039 | |||
| 1040 | @property | ||
| 1041 | def show_url(self): | ||
| 1042 | return posixpath.basename(self.url.split('#', 1)[0].split('?', 1)[0]) | ||
| 1043 | |||
| 1044 | @property | ||
| 1045 | def is_wheel(self): | ||
| 1046 | return self.ext == wheel_ext | ||
| 1047 | |||
| 1048 | @property | ||
| 1049 | def is_artifact(self): | ||
| 1050 | """ | ||
| 1051 | Determines if this points to an actual artifact (e.g. a tarball) or if | ||
| 1052 | it points to an "abstract" thing like a path or a VCS location. | ||
| 1053 | """ | ||
| 1054 | from pip._internal.vcs import vcs | ||
| 1055 | |||
| 1056 | if self.scheme in vcs.all_schemes: | ||
| 1057 | return False | ||
| 1058 | |||
| 1059 | return True | ||
| 1060 | |||
| 1061 | |||
| 1062 | FormatControl = namedtuple('FormatControl', 'no_binary only_binary') | ||
| 1063 | """This object has two fields, no_binary and only_binary. | ||
| 1064 | |||
| 1065 | If a field is falsy, it isn't set. If it is {':all:'}, it should match all | ||
| 1066 | packages except those listed in the other field. Only one field can be set | ||
| 1067 | to {':all:'} at a time. The rest of the time exact package name matches | ||
| 1068 | are listed, with any given package only showing up in one field at a time. | ||
| 1069 | """ | ||
| 1070 | |||
| 1071 | |||
| 1072 | def fmt_ctl_handle_mutual_exclude(value, target, other): | ||
| 1073 | new = value.split(',') | ||
| 1074 | while ':all:' in new: | ||
| 1075 | other.clear() | ||
| 1076 | target.clear() | ||
| 1077 | target.add(':all:') | ||
| 1078 | del new[:new.index(':all:') + 1] | ||
| 1079 | if ':none:' not in new: | ||
| 1080 | # Without a none, we want to discard everything as :all: covers it | ||
| 1081 | return | ||
| 1082 | for name in new: | ||
| 1083 | if name == ':none:': | ||
| 1084 | target.clear() | ||
| 1085 | continue | ||
| 1086 | name = canonicalize_name(name) | ||
| 1087 | other.discard(name) | ||
| 1088 | target.add(name) | ||
| 1089 | |||
| 1090 | |||
| 1091 | def fmt_ctl_formats(fmt_ctl, canonical_name): | ||
| 1092 | result = {"binary", "source"} | ||
| 1093 | if canonical_name in fmt_ctl.only_binary: | ||
| 1094 | result.discard('source') | ||
| 1095 | elif canonical_name in fmt_ctl.no_binary: | ||
| 1096 | result.discard('binary') | ||
| 1097 | elif ':all:' in fmt_ctl.only_binary: | ||
| 1098 | result.discard('source') | ||
| 1099 | elif ':all:' in fmt_ctl.no_binary: | ||
| 1100 | result.discard('binary') | ||
| 1101 | return frozenset(result) | ||
| 1102 | |||
| 1103 | |||
| 1104 | def fmt_ctl_no_binary(fmt_ctl): | ||
| 1105 | fmt_ctl_handle_mutual_exclude( | ||
| 1106 | ':all:', fmt_ctl.no_binary, fmt_ctl.only_binary, | ||
| 1107 | ) | ||
| 1108 | |||
| 1109 | |||
| 1110 | Search = namedtuple('Search', 'supplied canonical formats') | ||
| 1111 | """Capture key aspects of a search. | ||
| 1112 | |||
| 1113 | :attribute supplied: The user supplied package. | ||
| 1114 | :attribute canonical: The canonical package name. | ||
| 1115 | :attribute formats: The formats allowed for this package. Should be a set | ||
| 1116 | with 'binary' or 'source' or both in it. | ||
| 1117 | """ | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/locations.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/locations.py deleted file mode 100644 index ce8f7e9..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/locations.py +++ /dev/null | |||
| @@ -1,194 +0,0 @@ | |||
| 1 | """Locations where we look for configs, install stuff, etc""" | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import os | ||
| 5 | import os.path | ||
| 6 | import platform | ||
| 7 | import site | ||
| 8 | import sys | ||
| 9 | import sysconfig | ||
| 10 | from distutils import sysconfig as distutils_sysconfig | ||
| 11 | from distutils.command.install import SCHEME_KEYS, install # type: ignore | ||
| 12 | |||
| 13 | from pip._internal.compat import WINDOWS, expanduser | ||
| 14 | from pip._internal.utils import appdirs | ||
| 15 | |||
| 16 | # Application Directories | ||
| 17 | USER_CACHE_DIR = appdirs.user_cache_dir("pip") | ||
| 18 | |||
| 19 | |||
| 20 | DELETE_MARKER_MESSAGE = '''\ | ||
| 21 | This file is placed here by pip to indicate the source was put | ||
| 22 | here by pip. | ||
| 23 | |||
| 24 | Once this package is successfully installed this source code will be | ||
| 25 | deleted (unless you remove this file). | ||
| 26 | ''' | ||
| 27 | PIP_DELETE_MARKER_FILENAME = 'pip-delete-this-directory.txt' | ||
| 28 | |||
| 29 | |||
| 30 | def write_delete_marker_file(directory): | ||
| 31 | """ | ||
| 32 | Write the pip delete marker file into this directory. | ||
| 33 | """ | ||
| 34 | filepath = os.path.join(directory, PIP_DELETE_MARKER_FILENAME) | ||
| 35 | with open(filepath, 'w') as marker_fp: | ||
| 36 | marker_fp.write(DELETE_MARKER_MESSAGE) | ||
| 37 | |||
| 38 | |||
| 39 | def running_under_virtualenv(): | ||
| 40 | """ | ||
| 41 | Return True if we're running inside a virtualenv, False otherwise. | ||
| 42 | |||
| 43 | """ | ||
| 44 | if hasattr(sys, 'real_prefix'): | ||
| 45 | return True | ||
| 46 | elif sys.prefix != getattr(sys, "base_prefix", sys.prefix): | ||
| 47 | return True | ||
| 48 | |||
| 49 | return False | ||
| 50 | |||
| 51 | |||
| 52 | def virtualenv_no_global(): | ||
| 53 | """ | ||
| 54 | Return True if in a venv and no system site packages. | ||
| 55 | """ | ||
| 56 | # this mirrors the logic in virtualenv.py for locating the | ||
| 57 | # no-global-site-packages.txt file | ||
| 58 | site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) | ||
| 59 | no_global_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt') | ||
| 60 | if running_under_virtualenv() and os.path.isfile(no_global_file): | ||
| 61 | return True | ||
| 62 | |||
| 63 | |||
| 64 | if running_under_virtualenv(): | ||
| 65 | src_prefix = os.path.join(sys.prefix, 'src') | ||
| 66 | else: | ||
| 67 | # FIXME: keep src in cwd for now (it is not a temporary folder) | ||
| 68 | try: | ||
| 69 | src_prefix = os.path.join(os.getcwd(), 'src') | ||
| 70 | except OSError: | ||
| 71 | # In case the current working directory has been renamed or deleted | ||
| 72 | sys.exit( | ||
| 73 | "The folder you are executing pip from can no longer be found." | ||
| 74 | ) | ||
| 75 | |||
| 76 | # under macOS + virtualenv sys.prefix is not properly resolved | ||
| 77 | # it is something like /path/to/python/bin/.. | ||
| 78 | # Note: using realpath due to tmp dirs on OSX being symlinks | ||
| 79 | src_prefix = os.path.abspath(src_prefix) | ||
| 80 | |||
| 81 | # FIXME doesn't account for venv linked to global site-packages | ||
| 82 | |||
| 83 | site_packages = sysconfig.get_path("purelib") | ||
| 84 | # This is because of a bug in PyPy's sysconfig module, see | ||
| 85 | # https://bitbucket.org/pypy/pypy/issues/2506/sysconfig-returns-incorrect-paths | ||
| 86 | # for more information. | ||
| 87 | if platform.python_implementation().lower() == "pypy": | ||
| 88 | site_packages = distutils_sysconfig.get_python_lib() | ||
| 89 | try: | ||
| 90 | # Use getusersitepackages if this is present, as it ensures that the | ||
| 91 | # value is initialised properly. | ||
| 92 | user_site = site.getusersitepackages() | ||
| 93 | except AttributeError: | ||
| 94 | user_site = site.USER_SITE | ||
| 95 | user_dir = expanduser('~') | ||
| 96 | if WINDOWS: | ||
| 97 | bin_py = os.path.join(sys.prefix, 'Scripts') | ||
| 98 | bin_user = os.path.join(user_site, 'Scripts') | ||
| 99 | # buildout uses 'bin' on Windows too? | ||
| 100 | if not os.path.exists(bin_py): | ||
| 101 | bin_py = os.path.join(sys.prefix, 'bin') | ||
| 102 | bin_user = os.path.join(user_site, 'bin') | ||
| 103 | |||
| 104 | config_basename = 'pip.ini' | ||
| 105 | |||
| 106 | legacy_storage_dir = os.path.join(user_dir, 'pip') | ||
| 107 | legacy_config_file = os.path.join( | ||
| 108 | legacy_storage_dir, | ||
| 109 | config_basename, | ||
| 110 | ) | ||
| 111 | else: | ||
| 112 | bin_py = os.path.join(sys.prefix, 'bin') | ||
| 113 | bin_user = os.path.join(user_site, 'bin') | ||
| 114 | |||
| 115 | config_basename = 'pip.conf' | ||
| 116 | |||
| 117 | legacy_storage_dir = os.path.join(user_dir, '.pip') | ||
| 118 | legacy_config_file = os.path.join( | ||
| 119 | legacy_storage_dir, | ||
| 120 | config_basename, | ||
| 121 | ) | ||
| 122 | # Forcing to use /usr/local/bin for standard macOS framework installs | ||
| 123 | # Also log to ~/Library/Logs/ for use with the Console.app log viewer | ||
| 124 | if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': | ||
| 125 | bin_py = '/usr/local/bin' | ||
| 126 | |||
| 127 | site_config_files = [ | ||
| 128 | os.path.join(path, config_basename) | ||
| 129 | for path in appdirs.site_config_dirs('pip') | ||
| 130 | ] | ||
| 131 | |||
| 132 | venv_config_file = os.path.join(sys.prefix, config_basename) | ||
| 133 | new_config_file = os.path.join(appdirs.user_config_dir("pip"), config_basename) | ||
| 134 | |||
| 135 | |||
| 136 | def distutils_scheme(dist_name, user=False, home=None, root=None, | ||
| 137 | isolated=False, prefix=None): | ||
| 138 | """ | ||
| 139 | Return a distutils install scheme | ||
| 140 | """ | ||
| 141 | from distutils.dist import Distribution | ||
| 142 | |||
| 143 | scheme = {} | ||
| 144 | |||
| 145 | if isolated: | ||
| 146 | extra_dist_args = {"script_args": ["--no-user-cfg"]} | ||
| 147 | else: | ||
| 148 | extra_dist_args = {} | ||
| 149 | dist_args = {'name': dist_name} | ||
| 150 | dist_args.update(extra_dist_args) | ||
| 151 | |||
| 152 | d = Distribution(dist_args) | ||
| 153 | d.parse_config_files() | ||
| 154 | i = d.get_command_obj('install', create=True) | ||
| 155 | # NOTE: setting user or home has the side-effect of creating the home dir | ||
| 156 | # or user base for installations during finalize_options() | ||
| 157 | # ideally, we'd prefer a scheme class that has no side-effects. | ||
| 158 | assert not (user and prefix), "user={} prefix={}".format(user, prefix) | ||
| 159 | i.user = user or i.user | ||
| 160 | if user: | ||
| 161 | i.prefix = "" | ||
| 162 | i.prefix = prefix or i.prefix | ||
| 163 | i.home = home or i.home | ||
| 164 | i.root = root or i.root | ||
| 165 | i.finalize_options() | ||
| 166 | for key in SCHEME_KEYS: | ||
| 167 | scheme[key] = getattr(i, 'install_' + key) | ||
| 168 | |||
| 169 | # install_lib specified in setup.cfg should install *everything* | ||
| 170 | # into there (i.e. it takes precedence over both purelib and | ||
| 171 | # platlib). Note, i.install_lib is *always* set after | ||
| 172 | # finalize_options(); we only want to override here if the user | ||
| 173 | # has explicitly requested it hence going back to the config | ||
| 174 | if 'install_lib' in d.get_option_dict('install'): | ||
| 175 | scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) | ||
| 176 | |||
| 177 | if running_under_virtualenv(): | ||
| 178 | scheme['headers'] = os.path.join( | ||
| 179 | sys.prefix, | ||
| 180 | 'include', | ||
| 181 | 'site', | ||
| 182 | 'python' + sys.version[:3], | ||
| 183 | dist_name, | ||
| 184 | ) | ||
| 185 | |||
| 186 | if root is not None: | ||
| 187 | path_no_drive = os.path.splitdrive( | ||
| 188 | os.path.abspath(scheme["headers"]))[1] | ||
| 189 | scheme["headers"] = os.path.join( | ||
| 190 | root, | ||
| 191 | path_no_drive[1:], | ||
| 192 | ) | ||
| 193 | |||
| 194 | return scheme | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/models/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/models/__init__.py deleted file mode 100644 index 2d080a4..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/models/__init__.py +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | from pip._internal.models.index import Index, PyPI | ||
| 2 | |||
| 3 | |||
| 4 | __all__ = ["Index", "PyPI"] | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/models/index.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/models/index.py deleted file mode 100644 index 161de50..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/models/index.py +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 2 | |||
| 3 | |||
| 4 | class Index(object): | ||
| 5 | def __init__(self, url): | ||
| 6 | self.url = url | ||
| 7 | self.netloc = urllib_parse.urlsplit(url).netloc | ||
| 8 | self.simple_url = self.url_to_path('simple') | ||
| 9 | self.pypi_url = self.url_to_path('pypi') | ||
| 10 | |||
| 11 | def url_to_path(self, path): | ||
| 12 | return urllib_parse.urljoin(self.url, path) | ||
| 13 | |||
| 14 | |||
| 15 | PyPI = Index('https://pypi.org/') | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/__init__.py +++ /dev/null | |||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/check.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/check.py deleted file mode 100644 index bab6b9f..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/check.py +++ /dev/null | |||
| @@ -1,106 +0,0 @@ | |||
| 1 | """Validation of dependencies of packages | ||
| 2 | """ | ||
| 3 | |||
| 4 | from collections import namedtuple | ||
| 5 | |||
| 6 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 7 | |||
| 8 | from pip._internal.operations.prepare import make_abstract_dist | ||
| 9 | |||
| 10 | from pip._internal.utils.misc import get_installed_distributions | ||
| 11 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 12 | |||
| 13 | if MYPY_CHECK_RUNNING: | ||
| 14 | from pip._internal.req.req_install import InstallRequirement | ||
| 15 | from typing import Any, Dict, Iterator, Set, Tuple, List | ||
| 16 | |||
| 17 | # Shorthands | ||
| 18 | PackageSet = Dict[str, 'PackageDetails'] | ||
| 19 | Missing = Tuple[str, Any] | ||
| 20 | Conflicting = Tuple[str, str, Any] | ||
| 21 | |||
| 22 | MissingDict = Dict[str, List[Missing]] | ||
| 23 | ConflictingDict = Dict[str, List[Conflicting]] | ||
| 24 | CheckResult = Tuple[MissingDict, ConflictingDict] | ||
| 25 | |||
| 26 | PackageDetails = namedtuple('PackageDetails', ['version', 'requires']) | ||
| 27 | |||
| 28 | |||
| 29 | def create_package_set_from_installed(**kwargs): | ||
| 30 | # type: (**Any) -> PackageSet | ||
| 31 | """Converts a list of distributions into a PackageSet. | ||
| 32 | """ | ||
| 33 | # Default to using all packages installed on the system | ||
| 34 | if kwargs == {}: | ||
| 35 | kwargs = {"local_only": False, "skip": ()} | ||
| 36 | retval = {} | ||
| 37 | for dist in get_installed_distributions(**kwargs): | ||
| 38 | name = canonicalize_name(dist.project_name) | ||
| 39 | retval[name] = PackageDetails(dist.version, dist.requires()) | ||
| 40 | return retval | ||
| 41 | |||
| 42 | |||
| 43 | def check_package_set(package_set): | ||
| 44 | # type: (PackageSet) -> CheckResult | ||
| 45 | """Check if a package set is consistent | ||
| 46 | """ | ||
| 47 | missing = dict() | ||
| 48 | conflicting = dict() | ||
| 49 | |||
| 50 | for package_name in package_set: | ||
| 51 | # Info about dependencies of package_name | ||
| 52 | missing_deps = set() # type: Set[Missing] | ||
| 53 | conflicting_deps = set() # type: Set[Conflicting] | ||
| 54 | |||
| 55 | for req in package_set[package_name].requires: | ||
| 56 | name = canonicalize_name(req.project_name) # type: str | ||
| 57 | |||
| 58 | # Check if it's missing | ||
| 59 | if name not in package_set: | ||
| 60 | missed = True | ||
| 61 | if req.marker is not None: | ||
| 62 | missed = req.marker.evaluate() | ||
| 63 | if missed: | ||
| 64 | missing_deps.add((name, req)) | ||
| 65 | continue | ||
| 66 | |||
| 67 | # Check if there's a conflict | ||
| 68 | version = package_set[name].version # type: str | ||
| 69 | if not req.specifier.contains(version, prereleases=True): | ||
| 70 | conflicting_deps.add((name, version, req)) | ||
| 71 | |||
| 72 | def str_key(x): | ||
| 73 | return str(x) | ||
| 74 | |||
| 75 | if missing_deps: | ||
| 76 | missing[package_name] = sorted(missing_deps, key=str_key) | ||
| 77 | if conflicting_deps: | ||
| 78 | conflicting[package_name] = sorted(conflicting_deps, key=str_key) | ||
| 79 | |||
| 80 | return missing, conflicting | ||
| 81 | |||
| 82 | |||
| 83 | def check_install_conflicts(to_install): | ||
| 84 | # type: (List[InstallRequirement]) -> Tuple[PackageSet, CheckResult] | ||
| 85 | """For checking if the dependency graph would be consistent after \ | ||
| 86 | installing given requirements | ||
| 87 | """ | ||
| 88 | # Start from the current state | ||
| 89 | state = create_package_set_from_installed() | ||
| 90 | _simulate_installation_of(to_install, state) | ||
| 91 | return state, check_package_set(state) | ||
| 92 | |||
| 93 | |||
| 94 | # NOTE from @pradyunsg | ||
| 95 | # This required a minor update in dependency link handling logic over at | ||
| 96 | # operations.prepare.IsSDist.dist() to get it working | ||
| 97 | def _simulate_installation_of(to_install, state): | ||
| 98 | # type: (List[InstallRequirement], PackageSet) -> None | ||
| 99 | """Computes the version of packages after installing to_install. | ||
| 100 | """ | ||
| 101 | |||
| 102 | # Modify it as installing requirement_set would (assuming no errors) | ||
| 103 | for inst_req in to_install: | ||
| 104 | dist = make_abstract_dist(inst_req).dist(finder=None) | ||
| 105 | name = canonicalize_name(dist.key) | ||
| 106 | state[name] = PackageDetails(dist.version, dist.requires()) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/freeze.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/freeze.py deleted file mode 100644 index 000102d..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/freeze.py +++ /dev/null | |||
| @@ -1,252 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import collections | ||
| 4 | import logging | ||
| 5 | import os | ||
| 6 | import re | ||
| 7 | import warnings | ||
| 8 | |||
| 9 | from pip._vendor import pkg_resources, six | ||
| 10 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 11 | from pip._vendor.pkg_resources import RequirementParseError | ||
| 12 | |||
| 13 | from pip._internal.exceptions import InstallationError | ||
| 14 | from pip._internal.req import InstallRequirement | ||
| 15 | from pip._internal.req.req_file import COMMENT_RE | ||
| 16 | from pip._internal.utils.deprecation import RemovedInPip11Warning | ||
| 17 | from pip._internal.utils.misc import ( | ||
| 18 | dist_is_editable, get_installed_distributions, | ||
| 19 | ) | ||
| 20 | |||
| 21 | logger = logging.getLogger(__name__) | ||
| 22 | |||
| 23 | |||
| 24 | def freeze( | ||
| 25 | requirement=None, | ||
| 26 | find_links=None, local_only=None, user_only=None, skip_regex=None, | ||
| 27 | isolated=False, | ||
| 28 | wheel_cache=None, | ||
| 29 | exclude_editable=False, | ||
| 30 | skip=()): | ||
| 31 | find_links = find_links or [] | ||
| 32 | skip_match = None | ||
| 33 | |||
| 34 | if skip_regex: | ||
| 35 | skip_match = re.compile(skip_regex).search | ||
| 36 | |||
| 37 | dependency_links = [] | ||
| 38 | |||
| 39 | for dist in pkg_resources.working_set: | ||
| 40 | if dist.has_metadata('dependency_links.txt'): | ||
| 41 | dependency_links.extend( | ||
| 42 | dist.get_metadata_lines('dependency_links.txt') | ||
| 43 | ) | ||
| 44 | for link in find_links: | ||
| 45 | if '#egg=' in link: | ||
| 46 | dependency_links.append(link) | ||
| 47 | for link in find_links: | ||
| 48 | yield '-f %s' % link | ||
| 49 | installations = {} | ||
| 50 | for dist in get_installed_distributions(local_only=local_only, | ||
| 51 | skip=(), | ||
| 52 | user_only=user_only): | ||
| 53 | try: | ||
| 54 | req = FrozenRequirement.from_dist( | ||
| 55 | dist, | ||
| 56 | dependency_links | ||
| 57 | ) | ||
| 58 | except RequirementParseError: | ||
| 59 | logger.warning( | ||
| 60 | "Could not parse requirement: %s", | ||
| 61 | dist.project_name | ||
| 62 | ) | ||
| 63 | continue | ||
| 64 | if exclude_editable and req.editable: | ||
| 65 | continue | ||
| 66 | installations[req.name] = req | ||
| 67 | |||
| 68 | if requirement: | ||
| 69 | # the options that don't get turned into an InstallRequirement | ||
| 70 | # should only be emitted once, even if the same option is in multiple | ||
| 71 | # requirements files, so we need to keep track of what has been emitted | ||
| 72 | # so that we don't emit it again if it's seen again | ||
| 73 | emitted_options = set() | ||
| 74 | # keep track of which files a requirement is in so that we can | ||
| 75 | # give an accurate warning if a requirement appears multiple times. | ||
| 76 | req_files = collections.defaultdict(list) | ||
| 77 | for req_file_path in requirement: | ||
| 78 | with open(req_file_path) as req_file: | ||
| 79 | for line in req_file: | ||
| 80 | if (not line.strip() or | ||
| 81 | line.strip().startswith('#') or | ||
| 82 | (skip_match and skip_match(line)) or | ||
| 83 | line.startswith(( | ||
| 84 | '-r', '--requirement', | ||
| 85 | '-Z', '--always-unzip', | ||
| 86 | '-f', '--find-links', | ||
| 87 | '-i', '--index-url', | ||
| 88 | '--pre', | ||
| 89 | '--trusted-host', | ||
| 90 | '--process-dependency-links', | ||
| 91 | '--extra-index-url'))): | ||
| 92 | line = line.rstrip() | ||
| 93 | if line not in emitted_options: | ||
| 94 | emitted_options.add(line) | ||
| 95 | yield line | ||
| 96 | continue | ||
| 97 | |||
| 98 | if line.startswith('-e') or line.startswith('--editable'): | ||
| 99 | if line.startswith('-e'): | ||
| 100 | line = line[2:].strip() | ||
| 101 | else: | ||
| 102 | line = line[len('--editable'):].strip().lstrip('=') | ||
| 103 | line_req = InstallRequirement.from_editable( | ||
| 104 | line, | ||
| 105 | isolated=isolated, | ||
| 106 | wheel_cache=wheel_cache, | ||
| 107 | ) | ||
| 108 | else: | ||
| 109 | line_req = InstallRequirement.from_line( | ||
| 110 | COMMENT_RE.sub('', line).strip(), | ||
| 111 | isolated=isolated, | ||
| 112 | wheel_cache=wheel_cache, | ||
| 113 | ) | ||
| 114 | |||
| 115 | if not line_req.name: | ||
| 116 | logger.info( | ||
| 117 | "Skipping line in requirement file [%s] because " | ||
| 118 | "it's not clear what it would install: %s", | ||
| 119 | req_file_path, line.strip(), | ||
| 120 | ) | ||
| 121 | logger.info( | ||
| 122 | " (add #egg=PackageName to the URL to avoid" | ||
| 123 | " this warning)" | ||
| 124 | ) | ||
| 125 | elif line_req.name not in installations: | ||
| 126 | # either it's not installed, or it is installed | ||
| 127 | # but has been processed already | ||
| 128 | if not req_files[line_req.name]: | ||
| 129 | logger.warning( | ||
| 130 | "Requirement file [%s] contains %s, but that " | ||
| 131 | "package is not installed", | ||
| 132 | req_file_path, | ||
| 133 | COMMENT_RE.sub('', line).strip(), | ||
| 134 | ) | ||
| 135 | else: | ||
| 136 | req_files[line_req.name].append(req_file_path) | ||
| 137 | else: | ||
| 138 | yield str(installations[line_req.name]).rstrip() | ||
| 139 | del installations[line_req.name] | ||
| 140 | req_files[line_req.name].append(req_file_path) | ||
| 141 | |||
| 142 | # Warn about requirements that were included multiple times (in a | ||
| 143 | # single requirements file or in different requirements files). | ||
| 144 | for name, files in six.iteritems(req_files): | ||
| 145 | if len(files) > 1: | ||
| 146 | logger.warning("Requirement %s included multiple times [%s]", | ||
| 147 | name, ', '.join(sorted(set(files)))) | ||
| 148 | |||
| 149 | yield( | ||
| 150 | '## The following requirements were added by ' | ||
| 151 | 'pip freeze:' | ||
| 152 | ) | ||
| 153 | for installation in sorted( | ||
| 154 | installations.values(), key=lambda x: x.name.lower()): | ||
| 155 | if canonicalize_name(installation.name) not in skip: | ||
| 156 | yield str(installation).rstrip() | ||
| 157 | |||
| 158 | |||
| 159 | class FrozenRequirement(object): | ||
| 160 | def __init__(self, name, req, editable, comments=()): | ||
| 161 | self.name = name | ||
| 162 | self.req = req | ||
| 163 | self.editable = editable | ||
| 164 | self.comments = comments | ||
| 165 | |||
| 166 | _rev_re = re.compile(r'-r(\d+)$') | ||
| 167 | _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') | ||
| 168 | |||
| 169 | @classmethod | ||
| 170 | def from_dist(cls, dist, dependency_links): | ||
| 171 | location = os.path.normcase(os.path.abspath(dist.location)) | ||
| 172 | comments = [] | ||
| 173 | from pip._internal.vcs import vcs, get_src_requirement | ||
| 174 | if dist_is_editable(dist) and vcs.get_backend_name(location): | ||
| 175 | editable = True | ||
| 176 | try: | ||
| 177 | req = get_src_requirement(dist, location) | ||
| 178 | except InstallationError as exc: | ||
| 179 | logger.warning( | ||
| 180 | "Error when trying to get requirement for VCS system %s, " | ||
| 181 | "falling back to uneditable format", exc | ||
| 182 | ) | ||
| 183 | req = None | ||
| 184 | if req is None: | ||
| 185 | logger.warning( | ||
| 186 | 'Could not determine repository location of %s', location | ||
| 187 | ) | ||
| 188 | comments.append( | ||
| 189 | '## !! Could not determine repository location' | ||
| 190 | ) | ||
| 191 | req = dist.as_requirement() | ||
| 192 | editable = False | ||
| 193 | else: | ||
| 194 | editable = False | ||
| 195 | req = dist.as_requirement() | ||
| 196 | specs = req.specs | ||
| 197 | assert len(specs) == 1 and specs[0][0] in ["==", "==="], \ | ||
| 198 | 'Expected 1 spec with == or ===; specs = %r; dist = %r' % \ | ||
| 199 | (specs, dist) | ||
| 200 | version = specs[0][1] | ||
| 201 | ver_match = cls._rev_re.search(version) | ||
| 202 | date_match = cls._date_re.search(version) | ||
| 203 | if ver_match or date_match: | ||
| 204 | svn_backend = vcs.get_backend('svn') | ||
| 205 | if svn_backend: | ||
| 206 | svn_location = svn_backend().get_location( | ||
| 207 | dist, | ||
| 208 | dependency_links, | ||
| 209 | ) | ||
| 210 | if not svn_location: | ||
| 211 | logger.warning( | ||
| 212 | 'Warning: cannot find svn location for %s', req, | ||
| 213 | ) | ||
| 214 | comments.append( | ||
| 215 | '## FIXME: could not find svn URL in dependency_links ' | ||
| 216 | 'for this package:' | ||
| 217 | ) | ||
| 218 | else: | ||
| 219 | warnings.warn( | ||
| 220 | "SVN editable detection based on dependency links " | ||
| 221 | "will be dropped in the future.", | ||
| 222 | RemovedInPip11Warning, | ||
| 223 | ) | ||
| 224 | comments.append( | ||
| 225 | '# Installing as editable to satisfy requirement %s:' % | ||
| 226 | req | ||
| 227 | ) | ||
| 228 | if ver_match: | ||
| 229 | rev = ver_match.group(1) | ||
| 230 | else: | ||
| 231 | rev = '{%s}' % date_match.group(1) | ||
| 232 | editable = True | ||
| 233 | req = '%s@%s#egg=%s' % ( | ||
| 234 | svn_location, | ||
| 235 | rev, | ||
| 236 | cls.egg_name(dist) | ||
| 237 | ) | ||
| 238 | return cls(dist.project_name, req, editable, comments) | ||
| 239 | |||
| 240 | @staticmethod | ||
| 241 | def egg_name(dist): | ||
| 242 | name = dist.egg_name() | ||
| 243 | match = re.search(r'-py\d\.\d$', name) | ||
| 244 | if match: | ||
| 245 | name = name[:match.start()] | ||
| 246 | return name | ||
| 247 | |||
| 248 | def __str__(self): | ||
| 249 | req = self.req | ||
| 250 | if self.editable: | ||
| 251 | req = '-e %s' % req | ||
| 252 | return '\n'.join(list(self.comments) + [str(req)]) + '\n' | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/prepare.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/prepare.py deleted file mode 100644 index c1e8158..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/prepare.py +++ /dev/null | |||
| @@ -1,380 +0,0 @@ | |||
| 1 | """Prepares a distribution for installation | ||
| 2 | """ | ||
| 3 | |||
| 4 | import itertools | ||
| 5 | import logging | ||
| 6 | import os | ||
| 7 | import sys | ||
| 8 | from copy import copy | ||
| 9 | |||
| 10 | from pip._vendor import pkg_resources, requests | ||
| 11 | |||
| 12 | from pip._internal.build_env import NoOpBuildEnvironment | ||
| 13 | from pip._internal.compat import expanduser | ||
| 14 | from pip._internal.download import ( | ||
| 15 | is_dir_url, is_file_url, is_vcs_url, unpack_url, url_to_path, | ||
| 16 | ) | ||
| 17 | from pip._internal.exceptions import ( | ||
| 18 | DirectoryUrlHashUnsupported, HashUnpinned, InstallationError, | ||
| 19 | PreviousBuildDirError, VcsHashUnsupported, | ||
| 20 | ) | ||
| 21 | from pip._internal.index import FormatControl | ||
| 22 | from pip._internal.req.req_install import InstallRequirement | ||
| 23 | from pip._internal.utils.hashes import MissingHashes | ||
| 24 | from pip._internal.utils.logging import indent_log | ||
| 25 | from pip._internal.utils.misc import ( | ||
| 26 | call_subprocess, display_path, normalize_path, | ||
| 27 | ) | ||
| 28 | from pip._internal.utils.ui import open_spinner | ||
| 29 | from pip._internal.vcs import vcs | ||
| 30 | |||
| 31 | logger = logging.getLogger(__name__) | ||
| 32 | |||
| 33 | |||
| 34 | def make_abstract_dist(req): | ||
| 35 | """Factory to make an abstract dist object. | ||
| 36 | |||
| 37 | Preconditions: Either an editable req with a source_dir, or satisfied_by or | ||
| 38 | a wheel link, or a non-editable req with a source_dir. | ||
| 39 | |||
| 40 | :return: A concrete DistAbstraction. | ||
| 41 | """ | ||
| 42 | if req.editable: | ||
| 43 | return IsSDist(req) | ||
| 44 | elif req.link and req.link.is_wheel: | ||
| 45 | return IsWheel(req) | ||
| 46 | else: | ||
| 47 | return IsSDist(req) | ||
| 48 | |||
| 49 | |||
| 50 | def _install_build_reqs(finder, prefix, build_requirements): | ||
| 51 | # NOTE: What follows is not a very good thing. | ||
| 52 | # Eventually, this should move into the BuildEnvironment class and | ||
| 53 | # that should handle all the isolation and sub-process invocation. | ||
| 54 | finder = copy(finder) | ||
| 55 | finder.format_control = FormatControl(set(), set([":all:"])) | ||
| 56 | urls = [ | ||
| 57 | finder.find_requirement( | ||
| 58 | InstallRequirement.from_line(r), upgrade=False).url | ||
| 59 | for r in build_requirements | ||
| 60 | ] | ||
| 61 | args = [ | ||
| 62 | sys.executable, '-m', 'pip', 'install', '--ignore-installed', | ||
| 63 | '--no-user', '--prefix', prefix, | ||
| 64 | ] + list(urls) | ||
| 65 | |||
| 66 | with open_spinner("Installing build dependencies") as spinner: | ||
| 67 | call_subprocess(args, show_stdout=False, spinner=spinner) | ||
| 68 | |||
| 69 | |||
| 70 | class DistAbstraction(object): | ||
| 71 | """Abstracts out the wheel vs non-wheel Resolver.resolve() logic. | ||
| 72 | |||
| 73 | The requirements for anything installable are as follows: | ||
| 74 | - we must be able to determine the requirement name | ||
| 75 | (or we can't correctly handle the non-upgrade case). | ||
| 76 | - we must be able to generate a list of run-time dependencies | ||
| 77 | without installing any additional packages (or we would | ||
| 78 | have to either burn time by doing temporary isolated installs | ||
| 79 | or alternatively violate pips 'don't start installing unless | ||
| 80 | all requirements are available' rule - neither of which are | ||
| 81 | desirable). | ||
| 82 | - for packages with setup requirements, we must also be able | ||
| 83 | to determine their requirements without installing additional | ||
| 84 | packages (for the same reason as run-time dependencies) | ||
| 85 | - we must be able to create a Distribution object exposing the | ||
| 86 | above metadata. | ||
| 87 | """ | ||
| 88 | |||
| 89 | def __init__(self, req): | ||
| 90 | self.req = req | ||
| 91 | |||
| 92 | def dist(self, finder): | ||
| 93 | """Return a setuptools Dist object.""" | ||
| 94 | raise NotImplementedError(self.dist) | ||
| 95 | |||
| 96 | def prep_for_dist(self, finder): | ||
| 97 | """Ensure that we can get a Dist for this requirement.""" | ||
| 98 | raise NotImplementedError(self.dist) | ||
| 99 | |||
| 100 | |||
| 101 | class IsWheel(DistAbstraction): | ||
| 102 | |||
| 103 | def dist(self, finder): | ||
| 104 | return list(pkg_resources.find_distributions( | ||
| 105 | self.req.source_dir))[0] | ||
| 106 | |||
| 107 | def prep_for_dist(self, finder, build_isolation): | ||
| 108 | # FIXME:https://github.com/pypa/pip/issues/1112 | ||
| 109 | pass | ||
| 110 | |||
| 111 | |||
| 112 | class IsSDist(DistAbstraction): | ||
| 113 | |||
| 114 | def dist(self, finder): | ||
| 115 | dist = self.req.get_dist() | ||
| 116 | # FIXME: shouldn't be globally added. | ||
| 117 | if finder and dist.has_metadata('dependency_links.txt'): | ||
| 118 | finder.add_dependency_links( | ||
| 119 | dist.get_metadata_lines('dependency_links.txt') | ||
| 120 | ) | ||
| 121 | return dist | ||
| 122 | |||
| 123 | def prep_for_dist(self, finder, build_isolation): | ||
| 124 | # Before calling "setup.py egg_info", we need to set-up the build | ||
| 125 | # environment. | ||
| 126 | build_requirements, isolate = self.req.get_pep_518_info() | ||
| 127 | should_isolate = build_isolation and isolate | ||
| 128 | |||
| 129 | minimum_requirements = ('setuptools', 'wheel') | ||
| 130 | missing_requirements = set(minimum_requirements) - set( | ||
| 131 | pkg_resources.Requirement(r).key | ||
| 132 | for r in build_requirements | ||
| 133 | ) | ||
| 134 | if missing_requirements: | ||
| 135 | def format_reqs(rs): | ||
| 136 | return ' and '.join(map(repr, sorted(rs))) | ||
| 137 | logger.warning( | ||
| 138 | "Missing build time requirements in pyproject.toml for %s: " | ||
| 139 | "%s.", self.req, format_reqs(missing_requirements) | ||
| 140 | ) | ||
| 141 | logger.warning( | ||
| 142 | "This version of pip does not implement PEP 517 so it cannot " | ||
| 143 | "build a wheel without %s.", format_reqs(minimum_requirements) | ||
| 144 | ) | ||
| 145 | |||
| 146 | if should_isolate: | ||
| 147 | with self.req.build_env: | ||
| 148 | pass | ||
| 149 | _install_build_reqs(finder, self.req.build_env.path, | ||
| 150 | build_requirements) | ||
| 151 | else: | ||
| 152 | self.req.build_env = NoOpBuildEnvironment(no_clean=False) | ||
| 153 | |||
| 154 | self.req.run_egg_info() | ||
| 155 | self.req.assert_source_matches_version() | ||
| 156 | |||
| 157 | |||
| 158 | class Installed(DistAbstraction): | ||
| 159 | |||
| 160 | def dist(self, finder): | ||
| 161 | return self.req.satisfied_by | ||
| 162 | |||
| 163 | def prep_for_dist(self, finder): | ||
| 164 | pass | ||
| 165 | |||
| 166 | |||
| 167 | class RequirementPreparer(object): | ||
| 168 | """Prepares a Requirement | ||
| 169 | """ | ||
| 170 | |||
| 171 | def __init__(self, build_dir, download_dir, src_dir, wheel_download_dir, | ||
| 172 | progress_bar, build_isolation): | ||
| 173 | super(RequirementPreparer, self).__init__() | ||
| 174 | |||
| 175 | self.src_dir = src_dir | ||
| 176 | self.build_dir = build_dir | ||
| 177 | |||
| 178 | # Where still packed archives should be written to. If None, they are | ||
| 179 | # not saved, and are deleted immediately after unpacking. | ||
| 180 | self.download_dir = download_dir | ||
| 181 | |||
| 182 | # Where still-packed .whl files should be written to. If None, they are | ||
| 183 | # written to the download_dir parameter. Separate to download_dir to | ||
| 184 | # permit only keeping wheel archives for pip wheel. | ||
| 185 | if wheel_download_dir: | ||
| 186 | wheel_download_dir = normalize_path(wheel_download_dir) | ||
| 187 | self.wheel_download_dir = wheel_download_dir | ||
| 188 | |||
| 189 | # NOTE | ||
| 190 | # download_dir and wheel_download_dir overlap semantically and may | ||
| 191 | # be combined if we're willing to have non-wheel archives present in | ||
| 192 | # the wheelhouse output by 'pip wheel'. | ||
| 193 | |||
| 194 | self.progress_bar = progress_bar | ||
| 195 | |||
| 196 | # Is build isolation allowed? | ||
| 197 | self.build_isolation = build_isolation | ||
| 198 | |||
| 199 | @property | ||
| 200 | def _download_should_save(self): | ||
| 201 | # TODO: Modify to reduce indentation needed | ||
| 202 | if self.download_dir: | ||
| 203 | self.download_dir = expanduser(self.download_dir) | ||
| 204 | if os.path.exists(self.download_dir): | ||
| 205 | return True | ||
| 206 | else: | ||
| 207 | logger.critical('Could not find download directory') | ||
| 208 | raise InstallationError( | ||
| 209 | "Could not find or access download directory '%s'" | ||
| 210 | % display_path(self.download_dir)) | ||
| 211 | return False | ||
| 212 | |||
| 213 | def prepare_linked_requirement(self, req, session, finder, | ||
| 214 | upgrade_allowed, require_hashes): | ||
| 215 | """Prepare a requirement that would be obtained from req.link | ||
| 216 | """ | ||
| 217 | # TODO: Breakup into smaller functions | ||
| 218 | if req.link and req.link.scheme == 'file': | ||
| 219 | path = url_to_path(req.link.url) | ||
| 220 | logger.info('Processing %s', display_path(path)) | ||
| 221 | else: | ||
| 222 | logger.info('Collecting %s', req) | ||
| 223 | |||
| 224 | with indent_log(): | ||
| 225 | # @@ if filesystem packages are not marked | ||
| 226 | # editable in a req, a non deterministic error | ||
| 227 | # occurs when the script attempts to unpack the | ||
| 228 | # build directory | ||
| 229 | req.ensure_has_source_dir(self.build_dir) | ||
| 230 | # If a checkout exists, it's unwise to keep going. version | ||
| 231 | # inconsistencies are logged later, but do not fail the | ||
| 232 | # installation. | ||
| 233 | # FIXME: this won't upgrade when there's an existing | ||
| 234 | # package unpacked in `req.source_dir` | ||
| 235 | # package unpacked in `req.source_dir` | ||
| 236 | if os.path.exists(os.path.join(req.source_dir, 'setup.py')): | ||
| 237 | raise PreviousBuildDirError( | ||
| 238 | "pip can't proceed with requirements '%s' due to a" | ||
| 239 | " pre-existing build directory (%s). This is " | ||
| 240 | "likely due to a previous installation that failed" | ||
| 241 | ". pip is being responsible and not assuming it " | ||
| 242 | "can delete this. Please delete it and try again." | ||
| 243 | % (req, req.source_dir) | ||
| 244 | ) | ||
| 245 | req.populate_link(finder, upgrade_allowed, require_hashes) | ||
| 246 | |||
| 247 | # We can't hit this spot and have populate_link return None. | ||
| 248 | # req.satisfied_by is None here (because we're | ||
| 249 | # guarded) and upgrade has no impact except when satisfied_by | ||
| 250 | # is not None. | ||
| 251 | # Then inside find_requirement existing_applicable -> False | ||
| 252 | # If no new versions are found, DistributionNotFound is raised, | ||
| 253 | # otherwise a result is guaranteed. | ||
| 254 | assert req.link | ||
| 255 | link = req.link | ||
| 256 | |||
| 257 | # Now that we have the real link, we can tell what kind of | ||
| 258 | # requirements we have and raise some more informative errors | ||
| 259 | # than otherwise. (For example, we can raise VcsHashUnsupported | ||
| 260 | # for a VCS URL rather than HashMissing.) | ||
| 261 | if require_hashes: | ||
| 262 | # We could check these first 2 conditions inside | ||
| 263 | # unpack_url and save repetition of conditions, but then | ||
| 264 | # we would report less-useful error messages for | ||
| 265 | # unhashable requirements, complaining that there's no | ||
| 266 | # hash provided. | ||
| 267 | if is_vcs_url(link): | ||
| 268 | raise VcsHashUnsupported() | ||
| 269 | elif is_file_url(link) and is_dir_url(link): | ||
| 270 | raise DirectoryUrlHashUnsupported() | ||
| 271 | if not req.original_link and not req.is_pinned: | ||
| 272 | # Unpinned packages are asking for trouble when a new | ||
| 273 | # version is uploaded. This isn't a security check, but | ||
| 274 | # it saves users a surprising hash mismatch in the | ||
| 275 | # future. | ||
| 276 | # | ||
| 277 | # file:/// URLs aren't pinnable, so don't complain | ||
| 278 | # about them not being pinned. | ||
| 279 | raise HashUnpinned() | ||
| 280 | |||
| 281 | hashes = req.hashes(trust_internet=not require_hashes) | ||
| 282 | if require_hashes and not hashes: | ||
| 283 | # Known-good hashes are missing for this requirement, so | ||
| 284 | # shim it with a facade object that will provoke hash | ||
| 285 | # computation and then raise a HashMissing exception | ||
| 286 | # showing the user what the hash should be. | ||
| 287 | hashes = MissingHashes() | ||
| 288 | |||
| 289 | try: | ||
| 290 | download_dir = self.download_dir | ||
| 291 | # We always delete unpacked sdists after pip ran. | ||
| 292 | autodelete_unpacked = True | ||
| 293 | if req.link.is_wheel and self.wheel_download_dir: | ||
| 294 | # when doing 'pip wheel` we download wheels to a | ||
| 295 | # dedicated dir. | ||
| 296 | download_dir = self.wheel_download_dir | ||
| 297 | if req.link.is_wheel: | ||
| 298 | if download_dir: | ||
| 299 | # When downloading, we only unpack wheels to get | ||
| 300 | # metadata. | ||
| 301 | autodelete_unpacked = True | ||
| 302 | else: | ||
| 303 | # When installing a wheel, we use the unpacked | ||
| 304 | # wheel. | ||
| 305 | autodelete_unpacked = False | ||
| 306 | unpack_url( | ||
| 307 | req.link, req.source_dir, | ||
| 308 | download_dir, autodelete_unpacked, | ||
| 309 | session=session, hashes=hashes, | ||
| 310 | progress_bar=self.progress_bar | ||
| 311 | ) | ||
| 312 | except requests.HTTPError as exc: | ||
| 313 | logger.critical( | ||
| 314 | 'Could not install requirement %s because of error %s', | ||
| 315 | req, | ||
| 316 | exc, | ||
| 317 | ) | ||
| 318 | raise InstallationError( | ||
| 319 | 'Could not install requirement %s because of HTTP ' | ||
| 320 | 'error %s for URL %s' % | ||
| 321 | (req, exc, req.link) | ||
| 322 | ) | ||
| 323 | abstract_dist = make_abstract_dist(req) | ||
| 324 | abstract_dist.prep_for_dist(finder, self.build_isolation) | ||
| 325 | if self._download_should_save: | ||
| 326 | # Make a .zip of the source_dir we already created. | ||
| 327 | if req.link.scheme in vcs.all_schemes: | ||
| 328 | req.archive(self.download_dir) | ||
| 329 | return abstract_dist | ||
| 330 | |||
| 331 | def prepare_editable_requirement(self, req, require_hashes, use_user_site, | ||
| 332 | finder): | ||
| 333 | """Prepare an editable requirement | ||
| 334 | """ | ||
| 335 | assert req.editable, "cannot prepare a non-editable req as editable" | ||
| 336 | |||
| 337 | logger.info('Obtaining %s', req) | ||
| 338 | |||
| 339 | with indent_log(): | ||
| 340 | if require_hashes: | ||
| 341 | raise InstallationError( | ||
| 342 | 'The editable requirement %s cannot be installed when ' | ||
| 343 | 'requiring hashes, because there is no single file to ' | ||
| 344 | 'hash.' % req | ||
| 345 | ) | ||
| 346 | req.ensure_has_source_dir(self.src_dir) | ||
| 347 | req.update_editable(not self._download_should_save) | ||
| 348 | |||
| 349 | abstract_dist = make_abstract_dist(req) | ||
| 350 | abstract_dist.prep_for_dist(finder, self.build_isolation) | ||
| 351 | |||
| 352 | if self._download_should_save: | ||
| 353 | req.archive(self.download_dir) | ||
| 354 | req.check_if_exists(use_user_site) | ||
| 355 | |||
| 356 | return abstract_dist | ||
| 357 | |||
| 358 | def prepare_installed_requirement(self, req, require_hashes, skip_reason): | ||
| 359 | """Prepare an already-installed requirement | ||
| 360 | """ | ||
| 361 | assert req.satisfied_by, "req should have been satisfied but isn't" | ||
| 362 | assert skip_reason is not None, ( | ||
| 363 | "did not get skip reason skipped but req.satisfied_by " | ||
| 364 | "is set to %r" % (req.satisfied_by,) | ||
| 365 | ) | ||
| 366 | logger.info( | ||
| 367 | 'Requirement %s: %s (%s)', | ||
| 368 | skip_reason, req, req.satisfied_by.version | ||
| 369 | ) | ||
| 370 | with indent_log(): | ||
| 371 | if require_hashes: | ||
| 372 | logger.debug( | ||
| 373 | 'Since it is already installed, we are trusting this ' | ||
| 374 | 'package without checking its hash. To ensure a ' | ||
| 375 | 'completely repeatable environment, install into an ' | ||
| 376 | 'empty virtualenv.' | ||
| 377 | ) | ||
| 378 | abstract_dist = Installed(req) | ||
| 379 | |||
| 380 | return abstract_dist | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/pep425tags.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/pep425tags.py deleted file mode 100644 index 5d31310..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/pep425tags.py +++ /dev/null | |||
| @@ -1,317 +0,0 @@ | |||
| 1 | """Generate and work with PEP 425 Compatibility Tags.""" | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import distutils.util | ||
| 5 | import logging | ||
| 6 | import platform | ||
| 7 | import re | ||
| 8 | import sys | ||
| 9 | import sysconfig | ||
| 10 | import warnings | ||
| 11 | from collections import OrderedDict | ||
| 12 | |||
| 13 | import pip._internal.utils.glibc | ||
| 14 | |||
| 15 | logger = logging.getLogger(__name__) | ||
| 16 | |||
| 17 | _osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') | ||
| 18 | |||
| 19 | |||
| 20 | def get_config_var(var): | ||
| 21 | try: | ||
| 22 | return sysconfig.get_config_var(var) | ||
| 23 | except IOError as e: # Issue #1074 | ||
| 24 | warnings.warn("{}".format(e), RuntimeWarning) | ||
| 25 | return None | ||
| 26 | |||
| 27 | |||
| 28 | def get_abbr_impl(): | ||
| 29 | """Return abbreviated implementation name.""" | ||
| 30 | if hasattr(sys, 'pypy_version_info'): | ||
| 31 | pyimpl = 'pp' | ||
| 32 | elif sys.platform.startswith('java'): | ||
| 33 | pyimpl = 'jy' | ||
| 34 | elif sys.platform == 'cli': | ||
| 35 | pyimpl = 'ip' | ||
| 36 | else: | ||
| 37 | pyimpl = 'cp' | ||
| 38 | return pyimpl | ||
| 39 | |||
| 40 | |||
| 41 | def get_impl_ver(): | ||
| 42 | """Return implementation version.""" | ||
| 43 | impl_ver = get_config_var("py_version_nodot") | ||
| 44 | if not impl_ver or get_abbr_impl() == 'pp': | ||
| 45 | impl_ver = ''.join(map(str, get_impl_version_info())) | ||
| 46 | return impl_ver | ||
| 47 | |||
| 48 | |||
| 49 | def get_impl_version_info(): | ||
| 50 | """Return sys.version_info-like tuple for use in decrementing the minor | ||
| 51 | version.""" | ||
| 52 | if get_abbr_impl() == 'pp': | ||
| 53 | # as per https://github.com/pypa/pip/issues/2882 | ||
| 54 | return (sys.version_info[0], sys.pypy_version_info.major, | ||
| 55 | sys.pypy_version_info.minor) | ||
| 56 | else: | ||
| 57 | return sys.version_info[0], sys.version_info[1] | ||
| 58 | |||
| 59 | |||
| 60 | def get_impl_tag(): | ||
| 61 | """ | ||
| 62 | Returns the Tag for this specific implementation. | ||
| 63 | """ | ||
| 64 | return "{}{}".format(get_abbr_impl(), get_impl_ver()) | ||
| 65 | |||
| 66 | |||
| 67 | def get_flag(var, fallback, expected=True, warn=True): | ||
| 68 | """Use a fallback method for determining SOABI flags if the needed config | ||
| 69 | var is unset or unavailable.""" | ||
| 70 | val = get_config_var(var) | ||
| 71 | if val is None: | ||
| 72 | if warn: | ||
| 73 | logger.debug("Config variable '%s' is unset, Python ABI tag may " | ||
| 74 | "be incorrect", var) | ||
| 75 | return fallback() | ||
| 76 | return val == expected | ||
| 77 | |||
| 78 | |||
| 79 | def get_abi_tag(): | ||
| 80 | """Return the ABI tag based on SOABI (if available) or emulate SOABI | ||
| 81 | (CPython 2, PyPy).""" | ||
| 82 | soabi = get_config_var('SOABI') | ||
| 83 | impl = get_abbr_impl() | ||
| 84 | if not soabi and impl in {'cp', 'pp'} and hasattr(sys, 'maxunicode'): | ||
| 85 | d = '' | ||
| 86 | m = '' | ||
| 87 | u = '' | ||
| 88 | if get_flag('Py_DEBUG', | ||
| 89 | lambda: hasattr(sys, 'gettotalrefcount'), | ||
| 90 | warn=(impl == 'cp')): | ||
| 91 | d = 'd' | ||
| 92 | if get_flag('WITH_PYMALLOC', | ||
| 93 | lambda: impl == 'cp', | ||
| 94 | warn=(impl == 'cp')): | ||
| 95 | m = 'm' | ||
| 96 | if get_flag('Py_UNICODE_SIZE', | ||
| 97 | lambda: sys.maxunicode == 0x10ffff, | ||
| 98 | expected=4, | ||
| 99 | warn=(impl == 'cp' and | ||
| 100 | sys.version_info < (3, 3))) \ | ||
| 101 | and sys.version_info < (3, 3): | ||
| 102 | u = 'u' | ||
| 103 | abi = '%s%s%s%s%s' % (impl, get_impl_ver(), d, m, u) | ||
| 104 | elif soabi and soabi.startswith('cpython-'): | ||
| 105 | abi = 'cp' + soabi.split('-')[1] | ||
| 106 | elif soabi: | ||
| 107 | abi = soabi.replace('.', '_').replace('-', '_') | ||
| 108 | else: | ||
| 109 | abi = None | ||
| 110 | return abi | ||
| 111 | |||
| 112 | |||
| 113 | def _is_running_32bit(): | ||
| 114 | return sys.maxsize == 2147483647 | ||
| 115 | |||
| 116 | |||
| 117 | def get_platform(): | ||
| 118 | """Return our platform name 'win32', 'linux_x86_64'""" | ||
| 119 | if sys.platform == 'darwin': | ||
| 120 | # distutils.util.get_platform() returns the release based on the value | ||
| 121 | # of MACOSX_DEPLOYMENT_TARGET on which Python was built, which may | ||
| 122 | # be significantly older than the user's current machine. | ||
| 123 | release, _, machine = platform.mac_ver() | ||
| 124 | split_ver = release.split('.') | ||
| 125 | |||
| 126 | if machine == "x86_64" and _is_running_32bit(): | ||
| 127 | machine = "i386" | ||
| 128 | elif machine == "ppc64" and _is_running_32bit(): | ||
| 129 | machine = "ppc" | ||
| 130 | |||
| 131 | return 'macosx_{}_{}_{}'.format(split_ver[0], split_ver[1], machine) | ||
| 132 | |||
| 133 | # XXX remove distutils dependency | ||
| 134 | result = distutils.util.get_platform().replace('.', '_').replace('-', '_') | ||
| 135 | if result == "linux_x86_64" and _is_running_32bit(): | ||
| 136 | # 32 bit Python program (running on a 64 bit Linux): pip should only | ||
| 137 | # install and run 32 bit compiled extensions in that case. | ||
| 138 | result = "linux_i686" | ||
| 139 | |||
| 140 | return result | ||
| 141 | |||
| 142 | |||
| 143 | def is_manylinux1_compatible(): | ||
| 144 | # Only Linux, and only x86-64 / i686 | ||
| 145 | if get_platform() not in {"linux_x86_64", "linux_i686"}: | ||
| 146 | return False | ||
| 147 | |||
| 148 | # Check for presence of _manylinux module | ||
| 149 | try: | ||
| 150 | import _manylinux | ||
| 151 | return bool(_manylinux.manylinux1_compatible) | ||
| 152 | except (ImportError, AttributeError): | ||
| 153 | # Fall through to heuristic check below | ||
| 154 | pass | ||
| 155 | |||
| 156 | # Check glibc version. CentOS 5 uses glibc 2.5. | ||
| 157 | return pip._internal.utils.glibc.have_compatible_glibc(2, 5) | ||
| 158 | |||
| 159 | |||
| 160 | def get_darwin_arches(major, minor, machine): | ||
| 161 | """Return a list of supported arches (including group arches) for | ||
| 162 | the given major, minor and machine architecture of an macOS machine. | ||
| 163 | """ | ||
| 164 | arches = [] | ||
| 165 | |||
| 166 | def _supports_arch(major, minor, arch): | ||
| 167 | # Looking at the application support for macOS versions in the chart | ||
| 168 | # provided by https://en.wikipedia.org/wiki/OS_X#Versions it appears | ||
| 169 | # our timeline looks roughly like: | ||
| 170 | # | ||
| 171 | # 10.0 - Introduces ppc support. | ||
| 172 | # 10.4 - Introduces ppc64, i386, and x86_64 support, however the ppc64 | ||
| 173 | # and x86_64 support is CLI only, and cannot be used for GUI | ||
| 174 | # applications. | ||
| 175 | # 10.5 - Extends ppc64 and x86_64 support to cover GUI applications. | ||
| 176 | # 10.6 - Drops support for ppc64 | ||
| 177 | # 10.7 - Drops support for ppc | ||
| 178 | # | ||
| 179 | # Given that we do not know if we're installing a CLI or a GUI | ||
| 180 | # application, we must be conservative and assume it might be a GUI | ||
| 181 | # application and behave as if ppc64 and x86_64 support did not occur | ||
| 182 | # until 10.5. | ||
| 183 | # | ||
| 184 | # Note: The above information is taken from the "Application support" | ||
| 185 | # column in the chart not the "Processor support" since I believe | ||
| 186 | # that we care about what instruction sets an application can use | ||
| 187 | # not which processors the OS supports. | ||
| 188 | if arch == 'ppc': | ||
| 189 | return (major, minor) <= (10, 5) | ||
| 190 | if arch == 'ppc64': | ||
| 191 | return (major, minor) == (10, 5) | ||
| 192 | if arch == 'i386': | ||
| 193 | return (major, minor) >= (10, 4) | ||
| 194 | if arch == 'x86_64': | ||
| 195 | return (major, minor) >= (10, 5) | ||
| 196 | if arch in groups: | ||
| 197 | for garch in groups[arch]: | ||
| 198 | if _supports_arch(major, minor, garch): | ||
| 199 | return True | ||
| 200 | return False | ||
| 201 | |||
| 202 | groups = OrderedDict([ | ||
| 203 | ("fat", ("i386", "ppc")), | ||
| 204 | ("intel", ("x86_64", "i386")), | ||
| 205 | ("fat64", ("x86_64", "ppc64")), | ||
| 206 | ("fat32", ("x86_64", "i386", "ppc")), | ||
| 207 | ]) | ||
| 208 | |||
| 209 | if _supports_arch(major, minor, machine): | ||
| 210 | arches.append(machine) | ||
| 211 | |||
| 212 | for garch in groups: | ||
| 213 | if machine in groups[garch] and _supports_arch(major, minor, garch): | ||
| 214 | arches.append(garch) | ||
| 215 | |||
| 216 | arches.append('universal') | ||
| 217 | |||
| 218 | return arches | ||
| 219 | |||
| 220 | |||
| 221 | def get_supported(versions=None, noarch=False, platform=None, | ||
| 222 | impl=None, abi=None): | ||
| 223 | """Return a list of supported tags for each version specified in | ||
| 224 | `versions`. | ||
| 225 | |||
| 226 | :param versions: a list of string versions, of the form ["33", "32"], | ||
| 227 | or None. The first version will be assumed to support our ABI. | ||
| 228 | :param platform: specify the exact platform you want valid | ||
| 229 | tags for, or None. If None, use the local system platform. | ||
| 230 | :param impl: specify the exact implementation you want valid | ||
| 231 | tags for, or None. If None, use the local interpreter impl. | ||
| 232 | :param abi: specify the exact abi you want valid | ||
| 233 | tags for, or None. If None, use the local interpreter abi. | ||
| 234 | """ | ||
| 235 | supported = [] | ||
| 236 | |||
| 237 | # Versions must be given with respect to the preference | ||
| 238 | if versions is None: | ||
| 239 | versions = [] | ||
| 240 | version_info = get_impl_version_info() | ||
| 241 | major = version_info[:-1] | ||
| 242 | # Support all previous minor Python versions. | ||
| 243 | for minor in range(version_info[-1], -1, -1): | ||
| 244 | versions.append(''.join(map(str, major + (minor,)))) | ||
| 245 | |||
| 246 | impl = impl or get_abbr_impl() | ||
| 247 | |||
| 248 | abis = [] | ||
| 249 | |||
| 250 | abi = abi or get_abi_tag() | ||
| 251 | if abi: | ||
| 252 | abis[0:0] = [abi] | ||
| 253 | |||
| 254 | abi3s = set() | ||
| 255 | import imp | ||
| 256 | for suffix in imp.get_suffixes(): | ||
| 257 | if suffix[0].startswith('.abi'): | ||
| 258 | abi3s.add(suffix[0].split('.', 2)[1]) | ||
| 259 | |||
| 260 | abis.extend(sorted(list(abi3s))) | ||
| 261 | |||
| 262 | abis.append('none') | ||
| 263 | |||
| 264 | if not noarch: | ||
| 265 | arch = platform or get_platform() | ||
| 266 | if arch.startswith('macosx'): | ||
| 267 | # support macosx-10.6-intel on macosx-10.9-x86_64 | ||
| 268 | match = _osx_arch_pat.match(arch) | ||
| 269 | if match: | ||
| 270 | name, major, minor, actual_arch = match.groups() | ||
| 271 | tpl = '{}_{}_%i_%s'.format(name, major) | ||
| 272 | arches = [] | ||
| 273 | for m in reversed(range(int(minor) + 1)): | ||
| 274 | for a in get_darwin_arches(int(major), m, actual_arch): | ||
| 275 | arches.append(tpl % (m, a)) | ||
| 276 | else: | ||
| 277 | # arch pattern didn't match (?!) | ||
| 278 | arches = [arch] | ||
| 279 | elif platform is None and is_manylinux1_compatible(): | ||
| 280 | arches = [arch.replace('linux', 'manylinux1'), arch] | ||
| 281 | else: | ||
| 282 | arches = [arch] | ||
| 283 | |||
| 284 | # Current version, current API (built specifically for our Python): | ||
| 285 | for abi in abis: | ||
| 286 | for arch in arches: | ||
| 287 | supported.append(('%s%s' % (impl, versions[0]), abi, arch)) | ||
| 288 | |||
| 289 | # abi3 modules compatible with older version of Python | ||
| 290 | for version in versions[1:]: | ||
| 291 | # abi3 was introduced in Python 3.2 | ||
| 292 | if version in {'31', '30'}: | ||
| 293 | break | ||
| 294 | for abi in abi3s: # empty set if not Python 3 | ||
| 295 | for arch in arches: | ||
| 296 | supported.append(("%s%s" % (impl, version), abi, arch)) | ||
| 297 | |||
| 298 | # Has binaries, does not use the Python API: | ||
| 299 | for arch in arches: | ||
| 300 | supported.append(('py%s' % (versions[0][0]), 'none', arch)) | ||
| 301 | |||
| 302 | # No abi / arch, but requires our implementation: | ||
| 303 | supported.append(('%s%s' % (impl, versions[0]), 'none', 'any')) | ||
| 304 | # Tagged specifically as being cross-version compatible | ||
| 305 | # (with just the major version specified) | ||
| 306 | supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any')) | ||
| 307 | |||
| 308 | # No abi / arch, generic Python | ||
| 309 | for i, version in enumerate(versions): | ||
| 310 | supported.append(('py%s' % (version,), 'none', 'any')) | ||
| 311 | if i == 0: | ||
| 312 | supported.append(('py%s' % (version[0]), 'none', 'any')) | ||
| 313 | |||
| 314 | return supported | ||
| 315 | |||
| 316 | |||
| 317 | implementation_tag = get_impl_tag() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/__init__.py deleted file mode 100644 index 07ae607..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/__init__.py +++ /dev/null | |||
| @@ -1,69 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | |||
| 5 | from .req_install import InstallRequirement | ||
| 6 | from .req_set import RequirementSet | ||
| 7 | from .req_file import parse_requirements | ||
| 8 | from pip._internal.utils.logging import indent_log | ||
| 9 | |||
| 10 | |||
| 11 | __all__ = [ | ||
| 12 | "RequirementSet", "InstallRequirement", | ||
| 13 | "parse_requirements", "install_given_reqs", | ||
| 14 | ] | ||
| 15 | |||
| 16 | logger = logging.getLogger(__name__) | ||
| 17 | |||
| 18 | |||
| 19 | def install_given_reqs(to_install, install_options, global_options=(), | ||
| 20 | *args, **kwargs): | ||
| 21 | """ | ||
| 22 | Install everything in the given list. | ||
| 23 | |||
| 24 | (to be called after having downloaded and unpacked the packages) | ||
| 25 | """ | ||
| 26 | |||
| 27 | if to_install: | ||
| 28 | logger.info( | ||
| 29 | 'Installing collected packages: %s', | ||
| 30 | ', '.join([req.name for req in to_install]), | ||
| 31 | ) | ||
| 32 | |||
| 33 | with indent_log(): | ||
| 34 | for requirement in to_install: | ||
| 35 | if requirement.conflicts_with: | ||
| 36 | logger.info( | ||
| 37 | 'Found existing installation: %s', | ||
| 38 | requirement.conflicts_with, | ||
| 39 | ) | ||
| 40 | with indent_log(): | ||
| 41 | uninstalled_pathset = requirement.uninstall( | ||
| 42 | auto_confirm=True | ||
| 43 | ) | ||
| 44 | try: | ||
| 45 | requirement.install( | ||
| 46 | install_options, | ||
| 47 | global_options, | ||
| 48 | *args, | ||
| 49 | **kwargs | ||
| 50 | ) | ||
| 51 | except: | ||
| 52 | should_rollback = ( | ||
| 53 | requirement.conflicts_with and | ||
| 54 | not requirement.install_succeeded | ||
| 55 | ) | ||
| 56 | # if install did not succeed, rollback previous uninstall | ||
| 57 | if should_rollback: | ||
| 58 | uninstalled_pathset.rollback() | ||
| 59 | raise | ||
| 60 | else: | ||
| 61 | should_commit = ( | ||
| 62 | requirement.conflicts_with and | ||
| 63 | requirement.install_succeeded | ||
| 64 | ) | ||
| 65 | if should_commit: | ||
| 66 | uninstalled_pathset.commit() | ||
| 67 | requirement.remove_temporary_source() | ||
| 68 | |||
| 69 | return to_install | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py deleted file mode 100644 index 9e6ef41..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py +++ /dev/null | |||
| @@ -1,338 +0,0 @@ | |||
| 1 | """ | ||
| 2 | Requirements file parsing | ||
| 3 | """ | ||
| 4 | |||
| 5 | from __future__ import absolute_import | ||
| 6 | |||
| 7 | import optparse | ||
| 8 | import os | ||
| 9 | import re | ||
| 10 | import shlex | ||
| 11 | import sys | ||
| 12 | |||
| 13 | from pip._vendor.six.moves import filterfalse | ||
| 14 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 15 | |||
| 16 | from pip._internal import cmdoptions | ||
| 17 | from pip._internal.download import get_file_content | ||
| 18 | from pip._internal.exceptions import RequirementsFileParseError | ||
| 19 | from pip._internal.req.req_install import InstallRequirement | ||
| 20 | |||
| 21 | __all__ = ['parse_requirements'] | ||
| 22 | |||
| 23 | SCHEME_RE = re.compile(r'^(http|https|file):', re.I) | ||
| 24 | COMMENT_RE = re.compile(r'(^|\s)+#.*$') | ||
| 25 | |||
| 26 | # Matches environment variable-style values in '${MY_VARIABLE_1}' with the | ||
| 27 | # variable name consisting of only uppercase letters, digits or the '_' | ||
| 28 | # (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, | ||
| 29 | # 2013 Edition. | ||
| 30 | ENV_VAR_RE = re.compile(r'(?P<var>\$\{(?P<name>[A-Z0-9_]+)\})') | ||
| 31 | |||
| 32 | SUPPORTED_OPTIONS = [ | ||
| 33 | cmdoptions.constraints, | ||
| 34 | cmdoptions.editable, | ||
| 35 | cmdoptions.requirements, | ||
| 36 | cmdoptions.no_index, | ||
| 37 | cmdoptions.index_url, | ||
| 38 | cmdoptions.find_links, | ||
| 39 | cmdoptions.extra_index_url, | ||
| 40 | cmdoptions.always_unzip, | ||
| 41 | cmdoptions.no_binary, | ||
| 42 | cmdoptions.only_binary, | ||
| 43 | cmdoptions.pre, | ||
| 44 | cmdoptions.process_dependency_links, | ||
| 45 | cmdoptions.trusted_host, | ||
| 46 | cmdoptions.require_hashes, | ||
| 47 | ] | ||
| 48 | |||
| 49 | # options to be passed to requirements | ||
| 50 | SUPPORTED_OPTIONS_REQ = [ | ||
| 51 | cmdoptions.install_options, | ||
| 52 | cmdoptions.global_options, | ||
| 53 | cmdoptions.hash, | ||
| 54 | ] | ||
| 55 | |||
| 56 | # the 'dest' string values | ||
| 57 | SUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ] | ||
| 58 | |||
| 59 | |||
| 60 | def parse_requirements(filename, finder=None, comes_from=None, options=None, | ||
| 61 | session=None, constraint=False, wheel_cache=None): | ||
| 62 | """Parse a requirements file and yield InstallRequirement instances. | ||
| 63 | |||
| 64 | :param filename: Path or url of requirements file. | ||
| 65 | :param finder: Instance of pip.index.PackageFinder. | ||
| 66 | :param comes_from: Origin description of requirements. | ||
| 67 | :param options: cli options. | ||
| 68 | :param session: Instance of pip.download.PipSession. | ||
| 69 | :param constraint: If true, parsing a constraint file rather than | ||
| 70 | requirements file. | ||
| 71 | :param wheel_cache: Instance of pip.wheel.WheelCache | ||
| 72 | """ | ||
| 73 | if session is None: | ||
| 74 | raise TypeError( | ||
| 75 | "parse_requirements() missing 1 required keyword argument: " | ||
| 76 | "'session'" | ||
| 77 | ) | ||
| 78 | |||
| 79 | _, content = get_file_content( | ||
| 80 | filename, comes_from=comes_from, session=session | ||
| 81 | ) | ||
| 82 | |||
| 83 | lines_enum = preprocess(content, options) | ||
| 84 | |||
| 85 | for line_number, line in lines_enum: | ||
| 86 | req_iter = process_line(line, filename, line_number, finder, | ||
| 87 | comes_from, options, session, wheel_cache, | ||
| 88 | constraint=constraint) | ||
| 89 | for req in req_iter: | ||
| 90 | yield req | ||
| 91 | |||
| 92 | |||
| 93 | def preprocess(content, options): | ||
| 94 | """Split, filter, and join lines, and return a line iterator | ||
| 95 | |||
| 96 | :param content: the content of the requirements file | ||
| 97 | :param options: cli options | ||
| 98 | """ | ||
| 99 | lines_enum = enumerate(content.splitlines(), start=1) | ||
| 100 | lines_enum = join_lines(lines_enum) | ||
| 101 | lines_enum = ignore_comments(lines_enum) | ||
| 102 | lines_enum = skip_regex(lines_enum, options) | ||
| 103 | lines_enum = expand_env_variables(lines_enum) | ||
| 104 | return lines_enum | ||
| 105 | |||
| 106 | |||
| 107 | def process_line(line, filename, line_number, finder=None, comes_from=None, | ||
| 108 | options=None, session=None, wheel_cache=None, | ||
| 109 | constraint=False): | ||
| 110 | """Process a single requirements line; This can result in creating/yielding | ||
| 111 | requirements, or updating the finder. | ||
| 112 | |||
| 113 | For lines that contain requirements, the only options that have an effect | ||
| 114 | are from SUPPORTED_OPTIONS_REQ, and they are scoped to the | ||
| 115 | requirement. Other options from SUPPORTED_OPTIONS may be present, but are | ||
| 116 | ignored. | ||
| 117 | |||
| 118 | For lines that do not contain requirements, the only options that have an | ||
| 119 | effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may | ||
| 120 | be present, but are ignored. These lines may contain multiple options | ||
| 121 | (although our docs imply only one is supported), and all our parsed and | ||
| 122 | affect the finder. | ||
| 123 | |||
| 124 | :param constraint: If True, parsing a constraints file. | ||
| 125 | :param options: OptionParser options that we may update | ||
| 126 | """ | ||
| 127 | parser = build_parser(line) | ||
| 128 | defaults = parser.get_default_values() | ||
| 129 | defaults.index_url = None | ||
| 130 | if finder: | ||
| 131 | # `finder.format_control` will be updated during parsing | ||
| 132 | defaults.format_control = finder.format_control | ||
| 133 | args_str, options_str = break_args_options(line) | ||
| 134 | if sys.version_info < (2, 7, 3): | ||
| 135 | # Prior to 2.7.3, shlex cannot deal with unicode entries | ||
| 136 | options_str = options_str.encode('utf8') | ||
| 137 | opts, _ = parser.parse_args(shlex.split(options_str), defaults) | ||
| 138 | |||
| 139 | # preserve for the nested code path | ||
| 140 | line_comes_from = '%s %s (line %s)' % ( | ||
| 141 | '-c' if constraint else '-r', filename, line_number, | ||
| 142 | ) | ||
| 143 | |||
| 144 | # yield a line requirement | ||
| 145 | if args_str: | ||
| 146 | isolated = options.isolated_mode if options else False | ||
| 147 | if options: | ||
| 148 | cmdoptions.check_install_build_global(options, opts) | ||
| 149 | # get the options that apply to requirements | ||
| 150 | req_options = {} | ||
| 151 | for dest in SUPPORTED_OPTIONS_REQ_DEST: | ||
| 152 | if dest in opts.__dict__ and opts.__dict__[dest]: | ||
| 153 | req_options[dest] = opts.__dict__[dest] | ||
| 154 | yield InstallRequirement.from_line( | ||
| 155 | args_str, line_comes_from, constraint=constraint, | ||
| 156 | isolated=isolated, options=req_options, wheel_cache=wheel_cache | ||
| 157 | ) | ||
| 158 | |||
| 159 | # yield an editable requirement | ||
| 160 | elif opts.editables: | ||
| 161 | isolated = options.isolated_mode if options else False | ||
| 162 | yield InstallRequirement.from_editable( | ||
| 163 | opts.editables[0], comes_from=line_comes_from, | ||
| 164 | constraint=constraint, isolated=isolated, wheel_cache=wheel_cache | ||
| 165 | ) | ||
| 166 | |||
| 167 | # parse a nested requirements file | ||
| 168 | elif opts.requirements or opts.constraints: | ||
| 169 | if opts.requirements: | ||
| 170 | req_path = opts.requirements[0] | ||
| 171 | nested_constraint = False | ||
| 172 | else: | ||
| 173 | req_path = opts.constraints[0] | ||
| 174 | nested_constraint = True | ||
| 175 | # original file is over http | ||
| 176 | if SCHEME_RE.search(filename): | ||
| 177 | # do a url join so relative paths work | ||
| 178 | req_path = urllib_parse.urljoin(filename, req_path) | ||
| 179 | # original file and nested file are paths | ||
| 180 | elif not SCHEME_RE.search(req_path): | ||
| 181 | # do a join so relative paths work | ||
| 182 | req_path = os.path.join(os.path.dirname(filename), req_path) | ||
| 183 | # TODO: Why not use `comes_from='-r {} (line {})'` here as well? | ||
| 184 | parser = parse_requirements( | ||
| 185 | req_path, finder, comes_from, options, session, | ||
| 186 | constraint=nested_constraint, wheel_cache=wheel_cache | ||
| 187 | ) | ||
| 188 | for req in parser: | ||
| 189 | yield req | ||
| 190 | |||
| 191 | # percolate hash-checking option upward | ||
| 192 | elif opts.require_hashes: | ||
| 193 | options.require_hashes = opts.require_hashes | ||
| 194 | |||
| 195 | # set finder options | ||
| 196 | elif finder: | ||
| 197 | if opts.index_url: | ||
| 198 | finder.index_urls = [opts.index_url] | ||
| 199 | if opts.no_index is True: | ||
| 200 | finder.index_urls = [] | ||
| 201 | if opts.extra_index_urls: | ||
| 202 | finder.index_urls.extend(opts.extra_index_urls) | ||
| 203 | if opts.find_links: | ||
| 204 | # FIXME: it would be nice to keep track of the source | ||
| 205 | # of the find_links: support a find-links local path | ||
| 206 | # relative to a requirements file. | ||
| 207 | value = opts.find_links[0] | ||
| 208 | req_dir = os.path.dirname(os.path.abspath(filename)) | ||
| 209 | relative_to_reqs_file = os.path.join(req_dir, value) | ||
| 210 | if os.path.exists(relative_to_reqs_file): | ||
| 211 | value = relative_to_reqs_file | ||
| 212 | finder.find_links.append(value) | ||
| 213 | if opts.pre: | ||
| 214 | finder.allow_all_prereleases = True | ||
| 215 | if opts.process_dependency_links: | ||
| 216 | finder.process_dependency_links = True | ||
| 217 | if opts.trusted_hosts: | ||
| 218 | finder.secure_origins.extend( | ||
| 219 | ("*", host, "*") for host in opts.trusted_hosts) | ||
| 220 | |||
| 221 | |||
| 222 | def break_args_options(line): | ||
| 223 | """Break up the line into an args and options string. We only want to shlex | ||
| 224 | (and then optparse) the options, not the args. args can contain markers | ||
| 225 | which are corrupted by shlex. | ||
| 226 | """ | ||
| 227 | tokens = line.split(' ') | ||
| 228 | args = [] | ||
| 229 | options = tokens[:] | ||
| 230 | for token in tokens: | ||
| 231 | if token.startswith('-') or token.startswith('--'): | ||
| 232 | break | ||
| 233 | else: | ||
| 234 | args.append(token) | ||
| 235 | options.pop(0) | ||
| 236 | return ' '.join(args), ' '.join(options) | ||
| 237 | |||
| 238 | |||
| 239 | def build_parser(line): | ||
| 240 | """ | ||
| 241 | Return a parser for parsing requirement lines | ||
| 242 | """ | ||
| 243 | parser = optparse.OptionParser(add_help_option=False) | ||
| 244 | |||
| 245 | option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ | ||
| 246 | for option_factory in option_factories: | ||
| 247 | option = option_factory() | ||
| 248 | parser.add_option(option) | ||
| 249 | |||
| 250 | # By default optparse sys.exits on parsing errors. We want to wrap | ||
| 251 | # that in our own exception. | ||
| 252 | def parser_exit(self, msg): | ||
| 253 | # add offending line | ||
| 254 | msg = 'Invalid requirement: %s\n%s' % (line, msg) | ||
| 255 | raise RequirementsFileParseError(msg) | ||
| 256 | parser.exit = parser_exit | ||
| 257 | |||
| 258 | return parser | ||
| 259 | |||
| 260 | |||
| 261 | def join_lines(lines_enum): | ||
| 262 | """Joins a line ending in '\' with the previous line (except when following | ||
| 263 | comments). The joined line takes on the index of the first line. | ||
| 264 | """ | ||
| 265 | primary_line_number = None | ||
| 266 | new_line = [] | ||
| 267 | for line_number, line in lines_enum: | ||
| 268 | if not line.endswith('\\') or COMMENT_RE.match(line): | ||
| 269 | if COMMENT_RE.match(line): | ||
| 270 | # this ensures comments are always matched later | ||
| 271 | line = ' ' + line | ||
| 272 | if new_line: | ||
| 273 | new_line.append(line) | ||
| 274 | yield primary_line_number, ''.join(new_line) | ||
| 275 | new_line = [] | ||
| 276 | else: | ||
| 277 | yield line_number, line | ||
| 278 | else: | ||
| 279 | if not new_line: | ||
| 280 | primary_line_number = line_number | ||
| 281 | new_line.append(line.strip('\\')) | ||
| 282 | |||
| 283 | # last line contains \ | ||
| 284 | if new_line: | ||
| 285 | yield primary_line_number, ''.join(new_line) | ||
| 286 | |||
| 287 | # TODO: handle space after '\'. | ||
| 288 | |||
| 289 | |||
| 290 | def ignore_comments(lines_enum): | ||
| 291 | """ | ||
| 292 | Strips comments and filter empty lines. | ||
| 293 | """ | ||
| 294 | for line_number, line in lines_enum: | ||
| 295 | line = COMMENT_RE.sub('', line) | ||
| 296 | line = line.strip() | ||
| 297 | if line: | ||
| 298 | yield line_number, line | ||
| 299 | |||
| 300 | |||
| 301 | def skip_regex(lines_enum, options): | ||
| 302 | """ | ||
| 303 | Skip lines that match '--skip-requirements-regex' pattern | ||
| 304 | |||
| 305 | Note: the regex pattern is only built once | ||
| 306 | """ | ||
| 307 | skip_regex = options.skip_requirements_regex if options else None | ||
| 308 | if skip_regex: | ||
| 309 | pattern = re.compile(skip_regex) | ||
| 310 | lines_enum = filterfalse(lambda e: pattern.search(e[1]), lines_enum) | ||
| 311 | return lines_enum | ||
| 312 | |||
| 313 | |||
| 314 | def expand_env_variables(lines_enum): | ||
| 315 | """Replace all environment variables that can be retrieved via `os.getenv`. | ||
| 316 | |||
| 317 | The only allowed format for environment variables defined in the | ||
| 318 | requirement file is `${MY_VARIABLE_1}` to ensure two things: | ||
| 319 | |||
| 320 | 1. Strings that contain a `$` aren't accidentally (partially) expanded. | ||
| 321 | 2. Ensure consistency across platforms for requirement files. | ||
| 322 | |||
| 323 | These points are the result of a discusssion on the `github pull | ||
| 324 | request #3514 <https://github.com/pypa/pip/pull/3514>`_. | ||
| 325 | |||
| 326 | Valid characters in variable names follow the `POSIX standard | ||
| 327 | <http://pubs.opengroup.org/onlinepubs/9699919799/>`_ and are limited | ||
| 328 | to uppercase letter, digits and the `_` (underscore). | ||
| 329 | """ | ||
| 330 | for line_number, line in lines_enum: | ||
| 331 | for env_var, var_name in ENV_VAR_RE.findall(line): | ||
| 332 | value = os.getenv(var_name) | ||
| 333 | if not value: | ||
| 334 | continue | ||
| 335 | |||
| 336 | line = line.replace(env_var, value) | ||
| 337 | |||
| 338 | yield line_number, line | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py deleted file mode 100644 index 9dd1523..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py +++ /dev/null | |||
| @@ -1,1115 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os | ||
| 5 | import re | ||
| 6 | import shutil | ||
| 7 | import sys | ||
| 8 | import sysconfig | ||
| 9 | import traceback | ||
| 10 | import warnings | ||
| 11 | import zipfile | ||
| 12 | from distutils.util import change_root | ||
| 13 | from email.parser import FeedParser # type: ignore | ||
| 14 | |||
| 15 | from pip._vendor import pkg_resources, pytoml, six | ||
| 16 | from pip._vendor.packaging import specifiers | ||
| 17 | from pip._vendor.packaging.markers import Marker | ||
| 18 | from pip._vendor.packaging.requirements import InvalidRequirement, Requirement | ||
| 19 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 20 | from pip._vendor.packaging.version import parse as parse_version | ||
| 21 | from pip._vendor.packaging.version import Version | ||
| 22 | from pip._vendor.pkg_resources import RequirementParseError, parse_requirements | ||
| 23 | |||
| 24 | from pip._internal import wheel | ||
| 25 | from pip._internal.build_env import BuildEnvironment | ||
| 26 | from pip._internal.compat import native_str | ||
| 27 | from pip._internal.download import ( | ||
| 28 | is_archive_file, is_url, path_to_url, url_to_path, | ||
| 29 | ) | ||
| 30 | from pip._internal.exceptions import InstallationError, UninstallationError | ||
| 31 | from pip._internal.locations import ( | ||
| 32 | PIP_DELETE_MARKER_FILENAME, running_under_virtualenv, | ||
| 33 | ) | ||
| 34 | from pip._internal.req.req_uninstall import UninstallPathSet | ||
| 35 | from pip._internal.utils.deprecation import RemovedInPip11Warning | ||
| 36 | from pip._internal.utils.hashes import Hashes | ||
| 37 | from pip._internal.utils.logging import indent_log | ||
| 38 | from pip._internal.utils.misc import ( | ||
| 39 | _make_build_dir, ask_path_exists, backup_dir, call_subprocess, | ||
| 40 | display_path, dist_in_site_packages, dist_in_usersite, ensure_dir, | ||
| 41 | get_installed_version, is_installable_dir, read_text_file, rmtree, | ||
| 42 | ) | ||
| 43 | from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM | ||
| 44 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 45 | from pip._internal.utils.ui import open_spinner | ||
| 46 | from pip._internal.vcs import vcs | ||
| 47 | from pip._internal.wheel import Wheel, move_wheel_files | ||
| 48 | |||
| 49 | logger = logging.getLogger(__name__) | ||
| 50 | |||
| 51 | operators = specifiers.Specifier._operators.keys() | ||
| 52 | |||
| 53 | |||
| 54 | def _strip_extras(path): | ||
| 55 | m = re.match(r'^(.+)(\[[^\]]+\])$', path) | ||
| 56 | extras = None | ||
| 57 | if m: | ||
| 58 | path_no_extras = m.group(1) | ||
| 59 | extras = m.group(2) | ||
| 60 | else: | ||
| 61 | path_no_extras = path | ||
| 62 | |||
| 63 | return path_no_extras, extras | ||
| 64 | |||
| 65 | |||
| 66 | class InstallRequirement(object): | ||
| 67 | """ | ||
| 68 | Represents something that may be installed later on, may have information | ||
| 69 | about where to fetch the relavant requirement and also contains logic for | ||
| 70 | installing the said requirement. | ||
| 71 | """ | ||
| 72 | |||
| 73 | def __init__(self, req, comes_from, source_dir=None, editable=False, | ||
| 74 | link=None, update=True, markers=None, | ||
| 75 | isolated=False, options=None, wheel_cache=None, | ||
| 76 | constraint=False, extras=()): | ||
| 77 | assert req is None or isinstance(req, Requirement), req | ||
| 78 | self.req = req | ||
| 79 | self.comes_from = comes_from | ||
| 80 | self.constraint = constraint | ||
| 81 | if source_dir is not None: | ||
| 82 | self.source_dir = os.path.normpath(os.path.abspath(source_dir)) | ||
| 83 | else: | ||
| 84 | self.source_dir = None | ||
| 85 | self.editable = editable | ||
| 86 | |||
| 87 | self._wheel_cache = wheel_cache | ||
| 88 | if link is not None: | ||
| 89 | self.link = self.original_link = link | ||
| 90 | else: | ||
| 91 | from pip._internal.index import Link | ||
| 92 | self.link = self.original_link = req and req.url and Link(req.url) | ||
| 93 | |||
| 94 | if extras: | ||
| 95 | self.extras = extras | ||
| 96 | elif req: | ||
| 97 | self.extras = { | ||
| 98 | pkg_resources.safe_extra(extra) for extra in req.extras | ||
| 99 | } | ||
| 100 | else: | ||
| 101 | self.extras = set() | ||
| 102 | if markers is not None: | ||
| 103 | self.markers = markers | ||
| 104 | else: | ||
| 105 | self.markers = req and req.marker | ||
| 106 | self._egg_info_path = None | ||
| 107 | # This holds the pkg_resources.Distribution object if this requirement | ||
| 108 | # is already available: | ||
| 109 | self.satisfied_by = None | ||
| 110 | # This hold the pkg_resources.Distribution object if this requirement | ||
| 111 | # conflicts with another installed distribution: | ||
| 112 | self.conflicts_with = None | ||
| 113 | # Temporary build location | ||
| 114 | self._temp_build_dir = TempDirectory(kind="req-build") | ||
| 115 | # Used to store the global directory where the _temp_build_dir should | ||
| 116 | # have been created. Cf _correct_build_location method. | ||
| 117 | self._ideal_build_dir = None | ||
| 118 | # True if the editable should be updated: | ||
| 119 | self.update = update | ||
| 120 | # Set to True after successful installation | ||
| 121 | self.install_succeeded = None | ||
| 122 | # UninstallPathSet of uninstalled distribution (for possible rollback) | ||
| 123 | self.uninstalled_pathset = None | ||
| 124 | self.options = options if options else {} | ||
| 125 | # Set to True after successful preparation of this requirement | ||
| 126 | self.prepared = False | ||
| 127 | self.is_direct = False | ||
| 128 | |||
| 129 | self.isolated = isolated | ||
| 130 | self.build_env = BuildEnvironment(no_clean=True) | ||
| 131 | |||
| 132 | @classmethod | ||
| 133 | def from_editable(cls, editable_req, comes_from=None, isolated=False, | ||
| 134 | options=None, wheel_cache=None, constraint=False): | ||
| 135 | from pip._internal.index import Link | ||
| 136 | |||
| 137 | name, url, extras_override = parse_editable(editable_req) | ||
| 138 | if url.startswith('file:'): | ||
| 139 | source_dir = url_to_path(url) | ||
| 140 | else: | ||
| 141 | source_dir = None | ||
| 142 | |||
| 143 | if name is not None: | ||
| 144 | try: | ||
| 145 | req = Requirement(name) | ||
| 146 | except InvalidRequirement: | ||
| 147 | raise InstallationError("Invalid requirement: '%s'" % name) | ||
| 148 | else: | ||
| 149 | req = None | ||
| 150 | return cls( | ||
| 151 | req, comes_from, source_dir=source_dir, | ||
| 152 | editable=True, | ||
| 153 | link=Link(url), | ||
| 154 | constraint=constraint, | ||
| 155 | isolated=isolated, | ||
| 156 | options=options if options else {}, | ||
| 157 | wheel_cache=wheel_cache, | ||
| 158 | extras=extras_override or (), | ||
| 159 | ) | ||
| 160 | |||
| 161 | @classmethod | ||
| 162 | def from_req(cls, req, comes_from=None, isolated=False, wheel_cache=None): | ||
| 163 | try: | ||
| 164 | req = Requirement(req) | ||
| 165 | except InvalidRequirement: | ||
| 166 | raise InstallationError("Invalid requirement: '%s'" % req) | ||
| 167 | if req.url: | ||
| 168 | raise InstallationError( | ||
| 169 | "Direct url requirement (like %s) are not allowed for " | ||
| 170 | "dependencies" % req | ||
| 171 | ) | ||
| 172 | return cls(req, comes_from, isolated=isolated, wheel_cache=wheel_cache) | ||
| 173 | |||
| 174 | @classmethod | ||
| 175 | def from_line( | ||
| 176 | cls, name, comes_from=None, isolated=False, options=None, | ||
| 177 | wheel_cache=None, constraint=False): | ||
| 178 | """Creates an InstallRequirement from a name, which might be a | ||
| 179 | requirement, directory containing 'setup.py', filename, or URL. | ||
| 180 | """ | ||
| 181 | from pip._internal.index import Link | ||
| 182 | |||
| 183 | if is_url(name): | ||
| 184 | marker_sep = '; ' | ||
| 185 | else: | ||
| 186 | marker_sep = ';' | ||
| 187 | if marker_sep in name: | ||
| 188 | name, markers = name.split(marker_sep, 1) | ||
| 189 | markers = markers.strip() | ||
| 190 | if not markers: | ||
| 191 | markers = None | ||
| 192 | else: | ||
| 193 | markers = Marker(markers) | ||
| 194 | else: | ||
| 195 | markers = None | ||
| 196 | name = name.strip() | ||
| 197 | req = None | ||
| 198 | path = os.path.normpath(os.path.abspath(name)) | ||
| 199 | link = None | ||
| 200 | extras = None | ||
| 201 | |||
| 202 | if is_url(name): | ||
| 203 | link = Link(name) | ||
| 204 | else: | ||
| 205 | p, extras = _strip_extras(path) | ||
| 206 | looks_like_dir = os.path.isdir(p) and ( | ||
| 207 | os.path.sep in name or | ||
| 208 | (os.path.altsep is not None and os.path.altsep in name) or | ||
| 209 | name.startswith('.') | ||
| 210 | ) | ||
| 211 | if looks_like_dir: | ||
| 212 | if not is_installable_dir(p): | ||
| 213 | raise InstallationError( | ||
| 214 | "Directory %r is not installable. File 'setup.py' " | ||
| 215 | "not found." % name | ||
| 216 | ) | ||
| 217 | link = Link(path_to_url(p)) | ||
| 218 | elif is_archive_file(p): | ||
| 219 | if not os.path.isfile(p): | ||
| 220 | logger.warning( | ||
| 221 | 'Requirement %r looks like a filename, but the ' | ||
| 222 | 'file does not exist', | ||
| 223 | name | ||
| 224 | ) | ||
| 225 | link = Link(path_to_url(p)) | ||
| 226 | |||
| 227 | # it's a local file, dir, or url | ||
| 228 | if link: | ||
| 229 | # Handle relative file URLs | ||
| 230 | if link.scheme == 'file' and re.search(r'\.\./', link.url): | ||
| 231 | link = Link( | ||
| 232 | path_to_url(os.path.normpath(os.path.abspath(link.path)))) | ||
| 233 | # wheel file | ||
| 234 | if link.is_wheel: | ||
| 235 | wheel = Wheel(link.filename) # can raise InvalidWheelFilename | ||
| 236 | req = "%s==%s" % (wheel.name, wheel.version) | ||
| 237 | else: | ||
| 238 | # set the req to the egg fragment. when it's not there, this | ||
| 239 | # will become an 'unnamed' requirement | ||
| 240 | req = link.egg_fragment | ||
| 241 | |||
| 242 | # a requirement specifier | ||
| 243 | else: | ||
| 244 | req = name | ||
| 245 | |||
| 246 | if extras: | ||
| 247 | extras = Requirement("placeholder" + extras.lower()).extras | ||
| 248 | else: | ||
| 249 | extras = () | ||
| 250 | if req is not None: | ||
| 251 | try: | ||
| 252 | req = Requirement(req) | ||
| 253 | except InvalidRequirement: | ||
| 254 | if os.path.sep in req: | ||
| 255 | add_msg = "It looks like a path." | ||
| 256 | add_msg += deduce_helpful_msg(req) | ||
| 257 | elif '=' in req and not any(op in req for op in operators): | ||
| 258 | add_msg = "= is not a valid operator. Did you mean == ?" | ||
| 259 | else: | ||
| 260 | add_msg = traceback.format_exc() | ||
| 261 | raise InstallationError( | ||
| 262 | "Invalid requirement: '%s'\n%s" % (req, add_msg)) | ||
| 263 | return cls( | ||
| 264 | req, comes_from, link=link, markers=markers, | ||
| 265 | isolated=isolated, | ||
| 266 | options=options if options else {}, | ||
| 267 | wheel_cache=wheel_cache, | ||
| 268 | constraint=constraint, | ||
| 269 | extras=extras, | ||
| 270 | ) | ||
| 271 | |||
| 272 | def __str__(self): | ||
| 273 | if self.req: | ||
| 274 | s = str(self.req) | ||
| 275 | if self.link: | ||
| 276 | s += ' from %s' % self.link.url | ||
| 277 | else: | ||
| 278 | s = self.link.url if self.link else None | ||
| 279 | if self.satisfied_by is not None: | ||
| 280 | s += ' in %s' % display_path(self.satisfied_by.location) | ||
| 281 | if self.comes_from: | ||
| 282 | if isinstance(self.comes_from, six.string_types): | ||
| 283 | comes_from = self.comes_from | ||
| 284 | else: | ||
| 285 | comes_from = self.comes_from.from_path() | ||
| 286 | if comes_from: | ||
| 287 | s += ' (from %s)' % comes_from | ||
| 288 | return s | ||
| 289 | |||
| 290 | def __repr__(self): | ||
| 291 | return '<%s object: %s editable=%r>' % ( | ||
| 292 | self.__class__.__name__, str(self), self.editable) | ||
| 293 | |||
| 294 | def populate_link(self, finder, upgrade, require_hashes): | ||
| 295 | """Ensure that if a link can be found for this, that it is found. | ||
| 296 | |||
| 297 | Note that self.link may still be None - if Upgrade is False and the | ||
| 298 | requirement is already installed. | ||
| 299 | |||
| 300 | If require_hashes is True, don't use the wheel cache, because cached | ||
| 301 | wheels, always built locally, have different hashes than the files | ||
| 302 | downloaded from the index server and thus throw false hash mismatches. | ||
| 303 | Furthermore, cached wheels at present have undeterministic contents due | ||
| 304 | to file modification times. | ||
| 305 | """ | ||
| 306 | if self.link is None: | ||
| 307 | self.link = finder.find_requirement(self, upgrade) | ||
| 308 | if self._wheel_cache is not None and not require_hashes: | ||
| 309 | old_link = self.link | ||
| 310 | self.link = self._wheel_cache.get(self.link, self.name) | ||
| 311 | if old_link != self.link: | ||
| 312 | logger.debug('Using cached wheel link: %s', self.link) | ||
| 313 | |||
| 314 | @property | ||
| 315 | def specifier(self): | ||
| 316 | return self.req.specifier | ||
| 317 | |||
| 318 | @property | ||
| 319 | def is_pinned(self): | ||
| 320 | """Return whether I am pinned to an exact version. | ||
| 321 | |||
| 322 | For example, some-package==1.2 is pinned; some-package>1.2 is not. | ||
| 323 | """ | ||
| 324 | specifiers = self.specifier | ||
| 325 | return (len(specifiers) == 1 and | ||
| 326 | next(iter(specifiers)).operator in {'==', '==='}) | ||
| 327 | |||
| 328 | def from_path(self): | ||
| 329 | if self.req is None: | ||
| 330 | return None | ||
| 331 | s = str(self.req) | ||
| 332 | if self.comes_from: | ||
| 333 | if isinstance(self.comes_from, six.string_types): | ||
| 334 | comes_from = self.comes_from | ||
| 335 | else: | ||
| 336 | comes_from = self.comes_from.from_path() | ||
| 337 | if comes_from: | ||
| 338 | s += '->' + comes_from | ||
| 339 | return s | ||
| 340 | |||
| 341 | def build_location(self, build_dir): | ||
| 342 | assert build_dir is not None | ||
| 343 | if self._temp_build_dir.path is not None: | ||
| 344 | return self._temp_build_dir.path | ||
| 345 | if self.req is None: | ||
| 346 | # for requirement via a path to a directory: the name of the | ||
| 347 | # package is not available yet so we create a temp directory | ||
| 348 | # Once run_egg_info will have run, we'll be able | ||
| 349 | # to fix it via _correct_build_location | ||
| 350 | # Some systems have /tmp as a symlink which confuses custom | ||
| 351 | # builds (such as numpy). Thus, we ensure that the real path | ||
| 352 | # is returned. | ||
| 353 | self._temp_build_dir.create() | ||
| 354 | self._ideal_build_dir = build_dir | ||
| 355 | |||
| 356 | return self._temp_build_dir.path | ||
| 357 | if self.editable: | ||
| 358 | name = self.name.lower() | ||
| 359 | else: | ||
| 360 | name = self.name | ||
| 361 | # FIXME: Is there a better place to create the build_dir? (hg and bzr | ||
| 362 | # need this) | ||
| 363 | if not os.path.exists(build_dir): | ||
| 364 | logger.debug('Creating directory %s', build_dir) | ||
| 365 | _make_build_dir(build_dir) | ||
| 366 | return os.path.join(build_dir, name) | ||
| 367 | |||
| 368 | def _correct_build_location(self): | ||
| 369 | """Move self._temp_build_dir to self._ideal_build_dir/self.req.name | ||
| 370 | |||
| 371 | For some requirements (e.g. a path to a directory), the name of the | ||
| 372 | package is not available until we run egg_info, so the build_location | ||
| 373 | will return a temporary directory and store the _ideal_build_dir. | ||
| 374 | |||
| 375 | This is only called by self.egg_info_path to fix the temporary build | ||
| 376 | directory. | ||
| 377 | """ | ||
| 378 | if self.source_dir is not None: | ||
| 379 | return | ||
| 380 | assert self.req is not None | ||
| 381 | assert self._temp_build_dir.path | ||
| 382 | assert self._ideal_build_dir.path | ||
| 383 | old_location = self._temp_build_dir.path | ||
| 384 | self._temp_build_dir.path = None | ||
| 385 | |||
| 386 | new_location = self.build_location(self._ideal_build_dir) | ||
| 387 | if os.path.exists(new_location): | ||
| 388 | raise InstallationError( | ||
| 389 | 'A package already exists in %s; please remove it to continue' | ||
| 390 | % display_path(new_location)) | ||
| 391 | logger.debug( | ||
| 392 | 'Moving package %s from %s to new location %s', | ||
| 393 | self, display_path(old_location), display_path(new_location), | ||
| 394 | ) | ||
| 395 | shutil.move(old_location, new_location) | ||
| 396 | self._temp_build_dir.path = new_location | ||
| 397 | self._ideal_build_dir = None | ||
| 398 | self.source_dir = os.path.normpath(os.path.abspath(new_location)) | ||
| 399 | self._egg_info_path = None | ||
| 400 | |||
| 401 | @property | ||
| 402 | def name(self): | ||
| 403 | if self.req is None: | ||
| 404 | return None | ||
| 405 | return native_str(pkg_resources.safe_name(self.req.name)) | ||
| 406 | |||
| 407 | @property | ||
| 408 | def setup_py_dir(self): | ||
| 409 | return os.path.join( | ||
| 410 | self.source_dir, | ||
| 411 | self.link and self.link.subdirectory_fragment or '') | ||
| 412 | |||
| 413 | @property | ||
| 414 | def setup_py(self): | ||
| 415 | assert self.source_dir, "No source dir for %s" % self | ||
| 416 | |||
| 417 | setup_py = os.path.join(self.setup_py_dir, 'setup.py') | ||
| 418 | |||
| 419 | # Python2 __file__ should not be unicode | ||
| 420 | if six.PY2 and isinstance(setup_py, six.text_type): | ||
| 421 | setup_py = setup_py.encode(sys.getfilesystemencoding()) | ||
| 422 | |||
| 423 | return setup_py | ||
| 424 | |||
| 425 | @property | ||
| 426 | def pyproject_toml(self): | ||
| 427 | assert self.source_dir, "No source dir for %s" % self | ||
| 428 | |||
| 429 | pp_toml = os.path.join(self.setup_py_dir, 'pyproject.toml') | ||
| 430 | |||
| 431 | # Python2 __file__ should not be unicode | ||
| 432 | if six.PY2 and isinstance(pp_toml, six.text_type): | ||
| 433 | pp_toml = pp_toml.encode(sys.getfilesystemencoding()) | ||
| 434 | |||
| 435 | return pp_toml | ||
| 436 | |||
| 437 | def get_pep_518_info(self): | ||
| 438 | """Get a list of the packages required to build the project, if any, | ||
| 439 | and a flag indicating whether pyproject.toml is present, indicating | ||
| 440 | that the build should be isolated. | ||
| 441 | |||
| 442 | Build requirements can be specified in a pyproject.toml, as described | ||
| 443 | in PEP 518. If this file exists but doesn't specify build | ||
| 444 | requirements, pip will default to installing setuptools and wheel. | ||
| 445 | """ | ||
| 446 | if os.path.isfile(self.pyproject_toml): | ||
| 447 | with open(self.pyproject_toml) as f: | ||
| 448 | pp_toml = pytoml.load(f) | ||
| 449 | build_sys = pp_toml.get('build-system', {}) | ||
| 450 | return (build_sys.get('requires', ['setuptools', 'wheel']), True) | ||
| 451 | return (['setuptools', 'wheel'], False) | ||
| 452 | |||
| 453 | def run_egg_info(self): | ||
| 454 | assert self.source_dir | ||
| 455 | if self.name: | ||
| 456 | logger.debug( | ||
| 457 | 'Running setup.py (path:%s) egg_info for package %s', | ||
| 458 | self.setup_py, self.name, | ||
| 459 | ) | ||
| 460 | else: | ||
| 461 | logger.debug( | ||
| 462 | 'Running setup.py (path:%s) egg_info for package from %s', | ||
| 463 | self.setup_py, self.link, | ||
| 464 | ) | ||
| 465 | |||
| 466 | with indent_log(): | ||
| 467 | script = SETUPTOOLS_SHIM % self.setup_py | ||
| 468 | base_cmd = [sys.executable, '-c', script] | ||
| 469 | if self.isolated: | ||
| 470 | base_cmd += ["--no-user-cfg"] | ||
| 471 | egg_info_cmd = base_cmd + ['egg_info'] | ||
| 472 | # We can't put the .egg-info files at the root, because then the | ||
| 473 | # source code will be mistaken for an installed egg, causing | ||
| 474 | # problems | ||
| 475 | if self.editable: | ||
| 476 | egg_base_option = [] | ||
| 477 | else: | ||
| 478 | egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info') | ||
| 479 | ensure_dir(egg_info_dir) | ||
| 480 | egg_base_option = ['--egg-base', 'pip-egg-info'] | ||
| 481 | with self.build_env: | ||
| 482 | call_subprocess( | ||
| 483 | egg_info_cmd + egg_base_option, | ||
| 484 | cwd=self.setup_py_dir, | ||
| 485 | show_stdout=False, | ||
| 486 | command_desc='python setup.py egg_info') | ||
| 487 | |||
| 488 | if not self.req: | ||
| 489 | if isinstance(parse_version(self.pkg_info()["Version"]), Version): | ||
| 490 | op = "==" | ||
| 491 | else: | ||
| 492 | op = "===" | ||
| 493 | self.req = Requirement( | ||
| 494 | "".join([ | ||
| 495 | self.pkg_info()["Name"], | ||
| 496 | op, | ||
| 497 | self.pkg_info()["Version"], | ||
| 498 | ]) | ||
| 499 | ) | ||
| 500 | self._correct_build_location() | ||
| 501 | else: | ||
| 502 | metadata_name = canonicalize_name(self.pkg_info()["Name"]) | ||
| 503 | if canonicalize_name(self.req.name) != metadata_name: | ||
| 504 | logger.warning( | ||
| 505 | 'Running setup.py (path:%s) egg_info for package %s ' | ||
| 506 | 'produced metadata for project name %s. Fix your ' | ||
| 507 | '#egg=%s fragments.', | ||
| 508 | self.setup_py, self.name, metadata_name, self.name | ||
| 509 | ) | ||
| 510 | self.req = Requirement(metadata_name) | ||
| 511 | |||
| 512 | def egg_info_data(self, filename): | ||
| 513 | if self.satisfied_by is not None: | ||
| 514 | if not self.satisfied_by.has_metadata(filename): | ||
| 515 | return None | ||
| 516 | return self.satisfied_by.get_metadata(filename) | ||
| 517 | assert self.source_dir | ||
| 518 | filename = self.egg_info_path(filename) | ||
| 519 | if not os.path.exists(filename): | ||
| 520 | return None | ||
| 521 | data = read_text_file(filename) | ||
| 522 | return data | ||
| 523 | |||
| 524 | def egg_info_path(self, filename): | ||
| 525 | if self._egg_info_path is None: | ||
| 526 | if self.editable: | ||
| 527 | base = self.source_dir | ||
| 528 | else: | ||
| 529 | base = os.path.join(self.setup_py_dir, 'pip-egg-info') | ||
| 530 | filenames = os.listdir(base) | ||
| 531 | if self.editable: | ||
| 532 | filenames = [] | ||
| 533 | for root, dirs, files in os.walk(base): | ||
| 534 | for dir in vcs.dirnames: | ||
| 535 | if dir in dirs: | ||
| 536 | dirs.remove(dir) | ||
| 537 | # Iterate over a copy of ``dirs``, since mutating | ||
| 538 | # a list while iterating over it can cause trouble. | ||
| 539 | # (See https://github.com/pypa/pip/pull/462.) | ||
| 540 | for dir in list(dirs): | ||
| 541 | # Don't search in anything that looks like a virtualenv | ||
| 542 | # environment | ||
| 543 | if ( | ||
| 544 | os.path.lexists( | ||
| 545 | os.path.join(root, dir, 'bin', 'python') | ||
| 546 | ) or | ||
| 547 | os.path.exists( | ||
| 548 | os.path.join( | ||
| 549 | root, dir, 'Scripts', 'Python.exe' | ||
| 550 | ) | ||
| 551 | )): | ||
| 552 | dirs.remove(dir) | ||
| 553 | # Also don't search through tests | ||
| 554 | elif dir == 'test' or dir == 'tests': | ||
| 555 | dirs.remove(dir) | ||
| 556 | filenames.extend([os.path.join(root, dir) | ||
| 557 | for dir in dirs]) | ||
| 558 | filenames = [f for f in filenames if f.endswith('.egg-info')] | ||
| 559 | |||
| 560 | if not filenames: | ||
| 561 | raise InstallationError( | ||
| 562 | 'No files/directories in %s (from %s)' % (base, filename) | ||
| 563 | ) | ||
| 564 | assert filenames, \ | ||
| 565 | "No files/directories in %s (from %s)" % (base, filename) | ||
| 566 | |||
| 567 | # if we have more than one match, we pick the toplevel one. This | ||
| 568 | # can easily be the case if there is a dist folder which contains | ||
| 569 | # an extracted tarball for testing purposes. | ||
| 570 | if len(filenames) > 1: | ||
| 571 | filenames.sort( | ||
| 572 | key=lambda x: x.count(os.path.sep) + | ||
| 573 | (os.path.altsep and x.count(os.path.altsep) or 0) | ||
| 574 | ) | ||
| 575 | self._egg_info_path = os.path.join(base, filenames[0]) | ||
| 576 | return os.path.join(self._egg_info_path, filename) | ||
| 577 | |||
| 578 | def pkg_info(self): | ||
| 579 | p = FeedParser() | ||
| 580 | data = self.egg_info_data('PKG-INFO') | ||
| 581 | if not data: | ||
| 582 | logger.warning( | ||
| 583 | 'No PKG-INFO file found in %s', | ||
| 584 | display_path(self.egg_info_path('PKG-INFO')), | ||
| 585 | ) | ||
| 586 | p.feed(data or '') | ||
| 587 | return p.close() | ||
| 588 | |||
| 589 | _requirements_section_re = re.compile(r'\[(.*?)\]') | ||
| 590 | |||
| 591 | @property | ||
| 592 | def installed_version(self): | ||
| 593 | return get_installed_version(self.name) | ||
| 594 | |||
| 595 | def assert_source_matches_version(self): | ||
| 596 | assert self.source_dir | ||
| 597 | version = self.pkg_info()['version'] | ||
| 598 | if self.req.specifier and version not in self.req.specifier: | ||
| 599 | logger.warning( | ||
| 600 | 'Requested %s, but installing version %s', | ||
| 601 | self, | ||
| 602 | version, | ||
| 603 | ) | ||
| 604 | else: | ||
| 605 | logger.debug( | ||
| 606 | 'Source in %s has version %s, which satisfies requirement %s', | ||
| 607 | display_path(self.source_dir), | ||
| 608 | version, | ||
| 609 | self, | ||
| 610 | ) | ||
| 611 | |||
| 612 | def update_editable(self, obtain=True): | ||
| 613 | if not self.link: | ||
| 614 | logger.debug( | ||
| 615 | "Cannot update repository at %s; repository location is " | ||
| 616 | "unknown", | ||
| 617 | self.source_dir, | ||
| 618 | ) | ||
| 619 | return | ||
| 620 | assert self.editable | ||
| 621 | assert self.source_dir | ||
| 622 | if self.link.scheme == 'file': | ||
| 623 | # Static paths don't get updated | ||
| 624 | return | ||
| 625 | assert '+' in self.link.url, "bad url: %r" % self.link.url | ||
| 626 | if not self.update: | ||
| 627 | return | ||
| 628 | vc_type, url = self.link.url.split('+', 1) | ||
| 629 | backend = vcs.get_backend(vc_type) | ||
| 630 | if backend: | ||
| 631 | vcs_backend = backend(self.link.url) | ||
| 632 | if obtain: | ||
| 633 | vcs_backend.obtain(self.source_dir) | ||
| 634 | else: | ||
| 635 | vcs_backend.export(self.source_dir) | ||
| 636 | else: | ||
| 637 | assert 0, ( | ||
| 638 | 'Unexpected version control type (in %s): %s' | ||
| 639 | % (self.link, vc_type)) | ||
| 640 | |||
| 641 | def uninstall(self, auto_confirm=False, verbose=False, | ||
| 642 | use_user_site=False): | ||
| 643 | """ | ||
| 644 | Uninstall the distribution currently satisfying this requirement. | ||
| 645 | |||
| 646 | Prompts before removing or modifying files unless | ||
| 647 | ``auto_confirm`` is True. | ||
| 648 | |||
| 649 | Refuses to delete or modify files outside of ``sys.prefix`` - | ||
| 650 | thus uninstallation within a virtual environment can only | ||
| 651 | modify that virtual environment, even if the virtualenv is | ||
| 652 | linked to global site-packages. | ||
| 653 | |||
| 654 | """ | ||
| 655 | if not self.check_if_exists(use_user_site): | ||
| 656 | logger.warning("Skipping %s as it is not installed.", self.name) | ||
| 657 | return | ||
| 658 | dist = self.satisfied_by or self.conflicts_with | ||
| 659 | |||
| 660 | uninstalled_pathset = UninstallPathSet.from_dist(dist) | ||
| 661 | uninstalled_pathset.remove(auto_confirm, verbose) | ||
| 662 | return uninstalled_pathset | ||
| 663 | |||
| 664 | def archive(self, build_dir): | ||
| 665 | assert self.source_dir | ||
| 666 | create_archive = True | ||
| 667 | archive_name = '%s-%s.zip' % (self.name, self.pkg_info()["version"]) | ||
| 668 | archive_path = os.path.join(build_dir, archive_name) | ||
| 669 | if os.path.exists(archive_path): | ||
| 670 | response = ask_path_exists( | ||
| 671 | 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)bort ' % | ||
| 672 | display_path(archive_path), ('i', 'w', 'b', 'a')) | ||
| 673 | if response == 'i': | ||
| 674 | create_archive = False | ||
| 675 | elif response == 'w': | ||
| 676 | logger.warning('Deleting %s', display_path(archive_path)) | ||
| 677 | os.remove(archive_path) | ||
| 678 | elif response == 'b': | ||
| 679 | dest_file = backup_dir(archive_path) | ||
| 680 | logger.warning( | ||
| 681 | 'Backing up %s to %s', | ||
| 682 | display_path(archive_path), | ||
| 683 | display_path(dest_file), | ||
| 684 | ) | ||
| 685 | shutil.move(archive_path, dest_file) | ||
| 686 | elif response == 'a': | ||
| 687 | sys.exit(-1) | ||
| 688 | if create_archive: | ||
| 689 | zip = zipfile.ZipFile( | ||
| 690 | archive_path, 'w', zipfile.ZIP_DEFLATED, | ||
| 691 | allowZip64=True | ||
| 692 | ) | ||
| 693 | dir = os.path.normcase(os.path.abspath(self.setup_py_dir)) | ||
| 694 | for dirpath, dirnames, filenames in os.walk(dir): | ||
| 695 | if 'pip-egg-info' in dirnames: | ||
| 696 | dirnames.remove('pip-egg-info') | ||
| 697 | for dirname in dirnames: | ||
| 698 | dirname = os.path.join(dirpath, dirname) | ||
| 699 | name = self._clean_zip_name(dirname, dir) | ||
| 700 | zipdir = zipfile.ZipInfo(self.name + '/' + name + '/') | ||
| 701 | zipdir.external_attr = 0x1ED << 16 # 0o755 | ||
| 702 | zip.writestr(zipdir, '') | ||
| 703 | for filename in filenames: | ||
| 704 | if filename == PIP_DELETE_MARKER_FILENAME: | ||
| 705 | continue | ||
| 706 | filename = os.path.join(dirpath, filename) | ||
| 707 | name = self._clean_zip_name(filename, dir) | ||
| 708 | zip.write(filename, self.name + '/' + name) | ||
| 709 | zip.close() | ||
| 710 | logger.info('Saved %s', display_path(archive_path)) | ||
| 711 | |||
| 712 | def _clean_zip_name(self, name, prefix): | ||
| 713 | assert name.startswith(prefix + os.path.sep), ( | ||
| 714 | "name %r doesn't start with prefix %r" % (name, prefix) | ||
| 715 | ) | ||
| 716 | name = name[len(prefix) + 1:] | ||
| 717 | name = name.replace(os.path.sep, '/') | ||
| 718 | return name | ||
| 719 | |||
| 720 | def match_markers(self, extras_requested=None): | ||
| 721 | if not extras_requested: | ||
| 722 | # Provide an extra to safely evaluate the markers | ||
| 723 | # without matching any extra | ||
| 724 | extras_requested = ('',) | ||
| 725 | if self.markers is not None: | ||
| 726 | return any( | ||
| 727 | self.markers.evaluate({'extra': extra}) | ||
| 728 | for extra in extras_requested) | ||
| 729 | else: | ||
| 730 | return True | ||
| 731 | |||
| 732 | def install(self, install_options, global_options=None, root=None, | ||
| 733 | home=None, prefix=None, warn_script_location=True, | ||
| 734 | use_user_site=False, pycompile=True): | ||
| 735 | global_options = global_options if global_options is not None else [] | ||
| 736 | if self.editable: | ||
| 737 | self.install_editable( | ||
| 738 | install_options, global_options, prefix=prefix, | ||
| 739 | ) | ||
| 740 | return | ||
| 741 | if self.is_wheel: | ||
| 742 | version = wheel.wheel_version(self.source_dir) | ||
| 743 | wheel.check_compatibility(version, self.name) | ||
| 744 | |||
| 745 | self.move_wheel_files( | ||
| 746 | self.source_dir, root=root, prefix=prefix, home=home, | ||
| 747 | warn_script_location=warn_script_location, | ||
| 748 | use_user_site=use_user_site, pycompile=pycompile, | ||
| 749 | ) | ||
| 750 | self.install_succeeded = True | ||
| 751 | return | ||
| 752 | |||
| 753 | # Extend the list of global and install options passed on to | ||
| 754 | # the setup.py call with the ones from the requirements file. | ||
| 755 | # Options specified in requirements file override those | ||
| 756 | # specified on the command line, since the last option given | ||
| 757 | # to setup.py is the one that is used. | ||
| 758 | global_options = list(global_options) + \ | ||
| 759 | self.options.get('global_options', []) | ||
| 760 | install_options = list(install_options) + \ | ||
| 761 | self.options.get('install_options', []) | ||
| 762 | |||
| 763 | if self.isolated: | ||
| 764 | global_options = global_options + ["--no-user-cfg"] | ||
| 765 | |||
| 766 | with TempDirectory(kind="record") as temp_dir: | ||
| 767 | record_filename = os.path.join(temp_dir.path, 'install-record.txt') | ||
| 768 | install_args = self.get_install_args( | ||
| 769 | global_options, record_filename, root, prefix, pycompile, | ||
| 770 | ) | ||
| 771 | msg = 'Running setup.py install for %s' % (self.name,) | ||
| 772 | with open_spinner(msg) as spinner: | ||
| 773 | with indent_log(): | ||
| 774 | with self.build_env: | ||
| 775 | call_subprocess( | ||
| 776 | install_args + install_options, | ||
| 777 | cwd=self.setup_py_dir, | ||
| 778 | show_stdout=False, | ||
| 779 | spinner=spinner, | ||
| 780 | ) | ||
| 781 | |||
| 782 | if not os.path.exists(record_filename): | ||
| 783 | logger.debug('Record file %s not found', record_filename) | ||
| 784 | return | ||
| 785 | self.install_succeeded = True | ||
| 786 | |||
| 787 | def prepend_root(path): | ||
| 788 | if root is None or not os.path.isabs(path): | ||
| 789 | return path | ||
| 790 | else: | ||
| 791 | return change_root(root, path) | ||
| 792 | |||
| 793 | with open(record_filename) as f: | ||
| 794 | for line in f: | ||
| 795 | directory = os.path.dirname(line) | ||
| 796 | if directory.endswith('.egg-info'): | ||
| 797 | egg_info_dir = prepend_root(directory) | ||
| 798 | break | ||
| 799 | else: | ||
| 800 | logger.warning( | ||
| 801 | 'Could not find .egg-info directory in install record' | ||
| 802 | ' for %s', | ||
| 803 | self, | ||
| 804 | ) | ||
| 805 | # FIXME: put the record somewhere | ||
| 806 | # FIXME: should this be an error? | ||
| 807 | return | ||
| 808 | new_lines = [] | ||
| 809 | with open(record_filename) as f: | ||
| 810 | for line in f: | ||
| 811 | filename = line.strip() | ||
| 812 | if os.path.isdir(filename): | ||
| 813 | filename += os.path.sep | ||
| 814 | new_lines.append( | ||
| 815 | os.path.relpath(prepend_root(filename), egg_info_dir) | ||
| 816 | ) | ||
| 817 | new_lines.sort() | ||
| 818 | ensure_dir(egg_info_dir) | ||
| 819 | inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') | ||
| 820 | with open(inst_files_path, 'w') as f: | ||
| 821 | f.write('\n'.join(new_lines) + '\n') | ||
| 822 | |||
| 823 | def ensure_has_source_dir(self, parent_dir): | ||
| 824 | """Ensure that a source_dir is set. | ||
| 825 | |||
| 826 | This will create a temporary build dir if the name of the requirement | ||
| 827 | isn't known yet. | ||
| 828 | |||
| 829 | :param parent_dir: The ideal pip parent_dir for the source_dir. | ||
| 830 | Generally src_dir for editables and build_dir for sdists. | ||
| 831 | :return: self.source_dir | ||
| 832 | """ | ||
| 833 | if self.source_dir is None: | ||
| 834 | self.source_dir = self.build_location(parent_dir) | ||
| 835 | return self.source_dir | ||
| 836 | |||
| 837 | def get_install_args(self, global_options, record_filename, root, prefix, | ||
| 838 | pycompile): | ||
| 839 | install_args = [sys.executable, "-u"] | ||
| 840 | install_args.append('-c') | ||
| 841 | install_args.append(SETUPTOOLS_SHIM % self.setup_py) | ||
| 842 | install_args += list(global_options) + \ | ||
| 843 | ['install', '--record', record_filename] | ||
| 844 | install_args += ['--single-version-externally-managed'] | ||
| 845 | |||
| 846 | if root is not None: | ||
| 847 | install_args += ['--root', root] | ||
| 848 | if prefix is not None: | ||
| 849 | install_args += ['--prefix', prefix] | ||
| 850 | |||
| 851 | if pycompile: | ||
| 852 | install_args += ["--compile"] | ||
| 853 | else: | ||
| 854 | install_args += ["--no-compile"] | ||
| 855 | |||
| 856 | if running_under_virtualenv(): | ||
| 857 | py_ver_str = 'python' + sysconfig.get_python_version() | ||
| 858 | install_args += ['--install-headers', | ||
| 859 | os.path.join(sys.prefix, 'include', 'site', | ||
| 860 | py_ver_str, self.name)] | ||
| 861 | |||
| 862 | return install_args | ||
| 863 | |||
| 864 | def remove_temporary_source(self): | ||
| 865 | """Remove the source files from this requirement, if they are marked | ||
| 866 | for deletion""" | ||
| 867 | if self.source_dir and os.path.exists( | ||
| 868 | os.path.join(self.source_dir, PIP_DELETE_MARKER_FILENAME)): | ||
| 869 | logger.debug('Removing source in %s', self.source_dir) | ||
| 870 | rmtree(self.source_dir) | ||
| 871 | self.source_dir = None | ||
| 872 | self._temp_build_dir.cleanup() | ||
| 873 | self.build_env.cleanup() | ||
| 874 | |||
| 875 | def install_editable(self, install_options, | ||
| 876 | global_options=(), prefix=None): | ||
| 877 | logger.info('Running setup.py develop for %s', self.name) | ||
| 878 | |||
| 879 | if self.isolated: | ||
| 880 | global_options = list(global_options) + ["--no-user-cfg"] | ||
| 881 | |||
| 882 | if prefix: | ||
| 883 | prefix_param = ['--prefix={}'.format(prefix)] | ||
| 884 | install_options = list(install_options) + prefix_param | ||
| 885 | |||
| 886 | with indent_log(): | ||
| 887 | # FIXME: should we do --install-headers here too? | ||
| 888 | with self.build_env: | ||
| 889 | call_subprocess( | ||
| 890 | [ | ||
| 891 | sys.executable, | ||
| 892 | '-c', | ||
| 893 | SETUPTOOLS_SHIM % self.setup_py | ||
| 894 | ] + | ||
| 895 | list(global_options) + | ||
| 896 | ['develop', '--no-deps'] + | ||
| 897 | list(install_options), | ||
| 898 | |||
| 899 | cwd=self.setup_py_dir, | ||
| 900 | show_stdout=False, | ||
| 901 | ) | ||
| 902 | |||
| 903 | self.install_succeeded = True | ||
| 904 | |||
| 905 | def check_if_exists(self, use_user_site): | ||
| 906 | """Find an installed distribution that satisfies or conflicts | ||
| 907 | with this requirement, and set self.satisfied_by or | ||
| 908 | self.conflicts_with appropriately. | ||
| 909 | """ | ||
| 910 | if self.req is None: | ||
| 911 | return False | ||
| 912 | try: | ||
| 913 | # get_distribution() will resolve the entire list of requirements | ||
| 914 | # anyway, and we've already determined that we need the requirement | ||
| 915 | # in question, so strip the marker so that we don't try to | ||
| 916 | # evaluate it. | ||
| 917 | no_marker = Requirement(str(self.req)) | ||
| 918 | no_marker.marker = None | ||
| 919 | self.satisfied_by = pkg_resources.get_distribution(str(no_marker)) | ||
| 920 | if self.editable and self.satisfied_by: | ||
| 921 | self.conflicts_with = self.satisfied_by | ||
| 922 | # when installing editables, nothing pre-existing should ever | ||
| 923 | # satisfy | ||
| 924 | self.satisfied_by = None | ||
| 925 | return True | ||
| 926 | except pkg_resources.DistributionNotFound: | ||
| 927 | return False | ||
| 928 | except pkg_resources.VersionConflict: | ||
| 929 | existing_dist = pkg_resources.get_distribution( | ||
| 930 | self.req.name | ||
| 931 | ) | ||
| 932 | if use_user_site: | ||
| 933 | if dist_in_usersite(existing_dist): | ||
| 934 | self.conflicts_with = existing_dist | ||
| 935 | elif (running_under_virtualenv() and | ||
| 936 | dist_in_site_packages(existing_dist)): | ||
| 937 | raise InstallationError( | ||
| 938 | "Will not install to the user site because it will " | ||
| 939 | "lack sys.path precedence to %s in %s" % | ||
| 940 | (existing_dist.project_name, existing_dist.location) | ||
| 941 | ) | ||
| 942 | else: | ||
| 943 | self.conflicts_with = existing_dist | ||
| 944 | return True | ||
| 945 | |||
| 946 | @property | ||
| 947 | def is_wheel(self): | ||
| 948 | return self.link and self.link.is_wheel | ||
| 949 | |||
| 950 | def move_wheel_files(self, wheeldir, root=None, home=None, prefix=None, | ||
| 951 | warn_script_location=True, use_user_site=False, | ||
| 952 | pycompile=True): | ||
| 953 | move_wheel_files( | ||
| 954 | self.name, self.req, wheeldir, | ||
| 955 | user=use_user_site, | ||
| 956 | home=home, | ||
| 957 | root=root, | ||
| 958 | prefix=prefix, | ||
| 959 | pycompile=pycompile, | ||
| 960 | isolated=self.isolated, | ||
| 961 | warn_script_location=warn_script_location, | ||
| 962 | ) | ||
| 963 | |||
| 964 | def get_dist(self): | ||
| 965 | """Return a pkg_resources.Distribution built from self.egg_info_path""" | ||
| 966 | egg_info = self.egg_info_path('').rstrip(os.path.sep) | ||
| 967 | base_dir = os.path.dirname(egg_info) | ||
| 968 | metadata = pkg_resources.PathMetadata(base_dir, egg_info) | ||
| 969 | dist_name = os.path.splitext(os.path.basename(egg_info))[0] | ||
| 970 | return pkg_resources.Distribution( | ||
| 971 | os.path.dirname(egg_info), | ||
| 972 | project_name=dist_name, | ||
| 973 | metadata=metadata, | ||
| 974 | ) | ||
| 975 | |||
| 976 | @property | ||
| 977 | def has_hash_options(self): | ||
| 978 | """Return whether any known-good hashes are specified as options. | ||
| 979 | |||
| 980 | These activate --require-hashes mode; hashes specified as part of a | ||
| 981 | URL do not. | ||
| 982 | |||
| 983 | """ | ||
| 984 | return bool(self.options.get('hashes', {})) | ||
| 985 | |||
| 986 | def hashes(self, trust_internet=True): | ||
| 987 | """Return a hash-comparer that considers my option- and URL-based | ||
| 988 | hashes to be known-good. | ||
| 989 | |||
| 990 | Hashes in URLs--ones embedded in the requirements file, not ones | ||
| 991 | downloaded from an index server--are almost peers with ones from | ||
| 992 | flags. They satisfy --require-hashes (whether it was implicitly or | ||
| 993 | explicitly activated) but do not activate it. md5 and sha224 are not | ||
| 994 | allowed in flags, which should nudge people toward good algos. We | ||
| 995 | always OR all hashes together, even ones from URLs. | ||
| 996 | |||
| 997 | :param trust_internet: Whether to trust URL-based (#md5=...) hashes | ||
| 998 | downloaded from the internet, as by populate_link() | ||
| 999 | |||
| 1000 | """ | ||
| 1001 | good_hashes = self.options.get('hashes', {}).copy() | ||
| 1002 | link = self.link if trust_internet else self.original_link | ||
| 1003 | if link and link.hash: | ||
| 1004 | good_hashes.setdefault(link.hash_name, []).append(link.hash) | ||
| 1005 | return Hashes(good_hashes) | ||
| 1006 | |||
| 1007 | |||
| 1008 | def _strip_postfix(req): | ||
| 1009 | """ | ||
| 1010 | Strip req postfix ( -dev, 0.2, etc ) | ||
| 1011 | """ | ||
| 1012 | # FIXME: use package_to_requirement? | ||
| 1013 | match = re.search(r'^(.*?)(?:-dev|-\d.*)$', req) | ||
| 1014 | if match: | ||
| 1015 | # Strip off -dev, -0.2, etc. | ||
| 1016 | warnings.warn( | ||
| 1017 | "#egg cleanup for editable urls will be dropped in the future", | ||
| 1018 | RemovedInPip11Warning, | ||
| 1019 | ) | ||
| 1020 | req = match.group(1) | ||
| 1021 | return req | ||
| 1022 | |||
| 1023 | |||
| 1024 | def parse_editable(editable_req): | ||
| 1025 | """Parses an editable requirement into: | ||
| 1026 | - a requirement name | ||
| 1027 | - an URL | ||
| 1028 | - extras | ||
| 1029 | - editable options | ||
| 1030 | Accepted requirements: | ||
| 1031 | svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir | ||
| 1032 | .[some_extra] | ||
| 1033 | """ | ||
| 1034 | |||
| 1035 | from pip._internal.index import Link | ||
| 1036 | |||
| 1037 | url = editable_req | ||
| 1038 | |||
| 1039 | # If a file path is specified with extras, strip off the extras. | ||
| 1040 | url_no_extras, extras = _strip_extras(url) | ||
| 1041 | |||
| 1042 | if os.path.isdir(url_no_extras): | ||
| 1043 | if not os.path.exists(os.path.join(url_no_extras, 'setup.py')): | ||
| 1044 | raise InstallationError( | ||
| 1045 | "Directory %r is not installable. File 'setup.py' not found." % | ||
| 1046 | url_no_extras | ||
| 1047 | ) | ||
| 1048 | # Treating it as code that has already been checked out | ||
| 1049 | url_no_extras = path_to_url(url_no_extras) | ||
| 1050 | |||
| 1051 | if url_no_extras.lower().startswith('file:'): | ||
| 1052 | package_name = Link(url_no_extras).egg_fragment | ||
| 1053 | if extras: | ||
| 1054 | return ( | ||
| 1055 | package_name, | ||
| 1056 | url_no_extras, | ||
| 1057 | Requirement("placeholder" + extras.lower()).extras, | ||
| 1058 | ) | ||
| 1059 | else: | ||
| 1060 | return package_name, url_no_extras, None | ||
| 1061 | |||
| 1062 | for version_control in vcs: | ||
| 1063 | if url.lower().startswith('%s:' % version_control): | ||
| 1064 | url = '%s+%s' % (version_control, url) | ||
| 1065 | break | ||
| 1066 | |||
| 1067 | if '+' not in url: | ||
| 1068 | raise InstallationError( | ||
| 1069 | '%s should either be a path to a local project or a VCS url ' | ||
| 1070 | 'beginning with svn+, git+, hg+, or bzr+' % | ||
| 1071 | editable_req | ||
| 1072 | ) | ||
| 1073 | |||
| 1074 | vc_type = url.split('+', 1)[0].lower() | ||
| 1075 | |||
| 1076 | if not vcs.get_backend(vc_type): | ||
| 1077 | error_message = 'For --editable=%s only ' % editable_req + \ | ||
| 1078 | ', '.join([backend.name + '+URL' for backend in vcs.backends]) + \ | ||
| 1079 | ' is currently supported' | ||
| 1080 | raise InstallationError(error_message) | ||
| 1081 | |||
| 1082 | package_name = Link(url).egg_fragment | ||
| 1083 | if not package_name: | ||
| 1084 | raise InstallationError( | ||
| 1085 | "Could not detect requirement name for '%s', please specify one " | ||
| 1086 | "with #egg=your_package_name" % editable_req | ||
| 1087 | ) | ||
| 1088 | return _strip_postfix(package_name), url, None | ||
| 1089 | |||
| 1090 | |||
| 1091 | def deduce_helpful_msg(req): | ||
| 1092 | """Returns helpful msg in case requirements file does not exist, | ||
| 1093 | or cannot be parsed. | ||
| 1094 | |||
| 1095 | :params req: Requirements file path | ||
| 1096 | """ | ||
| 1097 | msg = "" | ||
| 1098 | if os.path.exists(req): | ||
| 1099 | msg = " It does exist." | ||
| 1100 | # Try to parse and check if it is a requirements file. | ||
| 1101 | try: | ||
| 1102 | with open(req, 'r') as fp: | ||
| 1103 | # parse first line only | ||
| 1104 | next(parse_requirements(fp.read())) | ||
| 1105 | msg += " The argument you provided " + \ | ||
| 1106 | "(%s) appears to be a" % (req) + \ | ||
| 1107 | " requirements file. If that is the" + \ | ||
| 1108 | " case, use the '-r' flag to install" + \ | ||
| 1109 | " the packages specified within it." | ||
| 1110 | except RequirementParseError: | ||
| 1111 | logger.debug("Cannot parse '%s' as requirements \ | ||
| 1112 | file" % (req), exc_info=1) | ||
| 1113 | else: | ||
| 1114 | msg += " File '%s' does not exist." % (req) | ||
| 1115 | return msg | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_set.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_set.py deleted file mode 100644 index 78b7d32..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_set.py +++ /dev/null | |||
| @@ -1,164 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | from collections import OrderedDict | ||
| 5 | |||
| 6 | from pip._internal.exceptions import InstallationError | ||
| 7 | from pip._internal.utils.logging import indent_log | ||
| 8 | from pip._internal.wheel import Wheel | ||
| 9 | |||
| 10 | logger = logging.getLogger(__name__) | ||
| 11 | |||
| 12 | |||
| 13 | class RequirementSet(object): | ||
| 14 | |||
| 15 | def __init__(self, require_hashes=False): | ||
| 16 | """Create a RequirementSet. | ||
| 17 | |||
| 18 | :param wheel_cache: The pip wheel cache, for passing to | ||
| 19 | InstallRequirement. | ||
| 20 | """ | ||
| 21 | |||
| 22 | self.requirements = OrderedDict() | ||
| 23 | self.require_hashes = require_hashes | ||
| 24 | |||
| 25 | # Mapping of alias: real_name | ||
| 26 | self.requirement_aliases = {} | ||
| 27 | self.unnamed_requirements = [] | ||
| 28 | self.successfully_downloaded = [] | ||
| 29 | self.reqs_to_cleanup = [] | ||
| 30 | |||
| 31 | def __str__(self): | ||
| 32 | reqs = [req for req in self.requirements.values() | ||
| 33 | if not req.comes_from] | ||
| 34 | reqs.sort(key=lambda req: req.name.lower()) | ||
| 35 | return ' '.join([str(req.req) for req in reqs]) | ||
| 36 | |||
| 37 | def __repr__(self): | ||
| 38 | reqs = [req for req in self.requirements.values()] | ||
| 39 | reqs.sort(key=lambda req: req.name.lower()) | ||
| 40 | reqs_str = ', '.join([str(req.req) for req in reqs]) | ||
| 41 | return ('<%s object; %d requirement(s): %s>' | ||
| 42 | % (self.__class__.__name__, len(reqs), reqs_str)) | ||
| 43 | |||
| 44 | def add_requirement(self, install_req, parent_req_name=None, | ||
| 45 | extras_requested=None): | ||
| 46 | """Add install_req as a requirement to install. | ||
| 47 | |||
| 48 | :param parent_req_name: The name of the requirement that needed this | ||
| 49 | added. The name is used because when multiple unnamed requirements | ||
| 50 | resolve to the same name, we could otherwise end up with dependency | ||
| 51 | links that point outside the Requirements set. parent_req must | ||
| 52 | already be added. Note that None implies that this is a user | ||
| 53 | supplied requirement, vs an inferred one. | ||
| 54 | :param extras_requested: an iterable of extras used to evaluate the | ||
| 55 | environment markers. | ||
| 56 | :return: Additional requirements to scan. That is either [] if | ||
| 57 | the requirement is not applicable, or [install_req] if the | ||
| 58 | requirement is applicable and has just been added. | ||
| 59 | """ | ||
| 60 | name = install_req.name | ||
| 61 | if not install_req.match_markers(extras_requested): | ||
| 62 | logger.info("Ignoring %s: markers '%s' don't match your " | ||
| 63 | "environment", install_req.name, | ||
| 64 | install_req.markers) | ||
| 65 | return [], None | ||
| 66 | |||
| 67 | # This check has to come after we filter requirements with the | ||
| 68 | # environment markers. | ||
| 69 | if install_req.link and install_req.link.is_wheel: | ||
| 70 | wheel = Wheel(install_req.link.filename) | ||
| 71 | if not wheel.supported(): | ||
| 72 | raise InstallationError( | ||
| 73 | "%s is not a supported wheel on this platform." % | ||
| 74 | wheel.filename | ||
| 75 | ) | ||
| 76 | |||
| 77 | # This next bit is really a sanity check. | ||
| 78 | assert install_req.is_direct == (parent_req_name is None), ( | ||
| 79 | "a direct req shouldn't have a parent and also, " | ||
| 80 | "a non direct req should have a parent" | ||
| 81 | ) | ||
| 82 | |||
| 83 | if not name: | ||
| 84 | # url or path requirement w/o an egg fragment | ||
| 85 | self.unnamed_requirements.append(install_req) | ||
| 86 | return [install_req], None | ||
| 87 | else: | ||
| 88 | try: | ||
| 89 | existing_req = self.get_requirement(name) | ||
| 90 | except KeyError: | ||
| 91 | existing_req = None | ||
| 92 | if (parent_req_name is None and existing_req and not | ||
| 93 | existing_req.constraint and | ||
| 94 | existing_req.extras == install_req.extras and not | ||
| 95 | existing_req.req.specifier == install_req.req.specifier): | ||
| 96 | raise InstallationError( | ||
| 97 | 'Double requirement given: %s (already in %s, name=%r)' | ||
| 98 | % (install_req, existing_req, name)) | ||
| 99 | if not existing_req: | ||
| 100 | # Add requirement | ||
| 101 | self.requirements[name] = install_req | ||
| 102 | # FIXME: what about other normalizations? E.g., _ vs. -? | ||
| 103 | if name.lower() != name: | ||
| 104 | self.requirement_aliases[name.lower()] = name | ||
| 105 | result = [install_req] | ||
| 106 | else: | ||
| 107 | # Assume there's no need to scan, and that we've already | ||
| 108 | # encountered this for scanning. | ||
| 109 | result = [] | ||
| 110 | if not install_req.constraint and existing_req.constraint: | ||
| 111 | if (install_req.link and not (existing_req.link and | ||
| 112 | install_req.link.path == existing_req.link.path)): | ||
| 113 | self.reqs_to_cleanup.append(install_req) | ||
| 114 | raise InstallationError( | ||
| 115 | "Could not satisfy constraints for '%s': " | ||
| 116 | "installation from path or url cannot be " | ||
| 117 | "constrained to a version" % name, | ||
| 118 | ) | ||
| 119 | # If we're now installing a constraint, mark the existing | ||
| 120 | # object for real installation. | ||
| 121 | existing_req.constraint = False | ||
| 122 | existing_req.extras = tuple( | ||
| 123 | sorted(set(existing_req.extras).union( | ||
| 124 | set(install_req.extras)))) | ||
| 125 | logger.debug("Setting %s extras to: %s", | ||
| 126 | existing_req, existing_req.extras) | ||
| 127 | # And now we need to scan this. | ||
| 128 | result = [existing_req] | ||
| 129 | # Canonicalise to the already-added object for the backref | ||
| 130 | # check below. | ||
| 131 | install_req = existing_req | ||
| 132 | |||
| 133 | # We return install_req here to allow for the caller to add it to | ||
| 134 | # the dependency information for the parent package. | ||
| 135 | return result, install_req | ||
| 136 | |||
| 137 | def has_requirement(self, project_name): | ||
| 138 | name = project_name.lower() | ||
| 139 | if (name in self.requirements and | ||
| 140 | not self.requirements[name].constraint or | ||
| 141 | name in self.requirement_aliases and | ||
| 142 | not self.requirements[self.requirement_aliases[name]].constraint): | ||
| 143 | return True | ||
| 144 | return False | ||
| 145 | |||
| 146 | @property | ||
| 147 | def has_requirements(self): | ||
| 148 | return list(req for req in self.requirements.values() if not | ||
| 149 | req.constraint) or self.unnamed_requirements | ||
| 150 | |||
| 151 | def get_requirement(self, project_name): | ||
| 152 | for name in project_name, project_name.lower(): | ||
| 153 | if name in self.requirements: | ||
| 154 | return self.requirements[name] | ||
| 155 | if name in self.requirement_aliases: | ||
| 156 | return self.requirements[self.requirement_aliases[name]] | ||
| 157 | raise KeyError("No project with the name %r" % project_name) | ||
| 158 | |||
| 159 | def cleanup_files(self): | ||
| 160 | """Clean up files, remove builds.""" | ||
| 161 | logger.debug('Cleaning up...') | ||
| 162 | with indent_log(): | ||
| 163 | for req in self.reqs_to_cleanup: | ||
| 164 | req.remove_temporary_source() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_uninstall.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_uninstall.py deleted file mode 100644 index a47520f..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_uninstall.py +++ /dev/null | |||
| @@ -1,455 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import csv | ||
| 4 | import functools | ||
| 5 | import logging | ||
| 6 | import os | ||
| 7 | import sys | ||
| 8 | import sysconfig | ||
| 9 | |||
| 10 | from pip._vendor import pkg_resources | ||
| 11 | |||
| 12 | from pip._internal.compat import WINDOWS, cache_from_source, uses_pycache | ||
| 13 | from pip._internal.exceptions import UninstallationError | ||
| 14 | from pip._internal.locations import bin_py, bin_user | ||
| 15 | from pip._internal.utils.logging import indent_log | ||
| 16 | from pip._internal.utils.misc import ( | ||
| 17 | FakeFile, ask, dist_in_usersite, dist_is_local, egg_link_path, is_local, | ||
| 18 | normalize_path, renames, | ||
| 19 | ) | ||
| 20 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 21 | |||
| 22 | logger = logging.getLogger(__name__) | ||
| 23 | |||
| 24 | |||
| 25 | def _script_names(dist, script_name, is_gui): | ||
| 26 | """Create the fully qualified name of the files created by | ||
| 27 | {console,gui}_scripts for the given ``dist``. | ||
| 28 | Returns the list of file names | ||
| 29 | """ | ||
| 30 | if dist_in_usersite(dist): | ||
| 31 | bin_dir = bin_user | ||
| 32 | else: | ||
| 33 | bin_dir = bin_py | ||
| 34 | exe_name = os.path.join(bin_dir, script_name) | ||
| 35 | paths_to_remove = [exe_name] | ||
| 36 | if WINDOWS: | ||
| 37 | paths_to_remove.append(exe_name + '.exe') | ||
| 38 | paths_to_remove.append(exe_name + '.exe.manifest') | ||
| 39 | if is_gui: | ||
| 40 | paths_to_remove.append(exe_name + '-script.pyw') | ||
| 41 | else: | ||
| 42 | paths_to_remove.append(exe_name + '-script.py') | ||
| 43 | return paths_to_remove | ||
| 44 | |||
| 45 | |||
| 46 | def _unique(fn): | ||
| 47 | @functools.wraps(fn) | ||
| 48 | def unique(*args, **kw): | ||
| 49 | seen = set() | ||
| 50 | for item in fn(*args, **kw): | ||
| 51 | if item not in seen: | ||
| 52 | seen.add(item) | ||
| 53 | yield item | ||
| 54 | return unique | ||
| 55 | |||
| 56 | |||
| 57 | @_unique | ||
| 58 | def uninstallation_paths(dist): | ||
| 59 | """ | ||
| 60 | Yield all the uninstallation paths for dist based on RECORD-without-.pyc | ||
| 61 | |||
| 62 | Yield paths to all the files in RECORD. For each .py file in RECORD, add | ||
| 63 | the .pyc in the same directory. | ||
| 64 | |||
| 65 | UninstallPathSet.add() takes care of the __pycache__ .pyc. | ||
| 66 | """ | ||
| 67 | r = csv.reader(FakeFile(dist.get_metadata_lines('RECORD'))) | ||
| 68 | for row in r: | ||
| 69 | path = os.path.join(dist.location, row[0]) | ||
| 70 | yield path | ||
| 71 | if path.endswith('.py'): | ||
| 72 | dn, fn = os.path.split(path) | ||
| 73 | base = fn[:-3] | ||
| 74 | path = os.path.join(dn, base + '.pyc') | ||
| 75 | yield path | ||
| 76 | |||
| 77 | |||
| 78 | def compact(paths): | ||
| 79 | """Compact a path set to contain the minimal number of paths | ||
| 80 | necessary to contain all paths in the set. If /a/path/ and | ||
| 81 | /a/path/to/a/file.txt are both in the set, leave only the | ||
| 82 | shorter path.""" | ||
| 83 | |||
| 84 | sep = os.path.sep | ||
| 85 | short_paths = set() | ||
| 86 | for path in sorted(paths, key=len): | ||
| 87 | should_add = any( | ||
| 88 | path.startswith(shortpath.rstrip("*")) and | ||
| 89 | path[len(shortpath.rstrip("*").rstrip(sep))] == sep | ||
| 90 | for shortpath in short_paths | ||
| 91 | ) | ||
| 92 | if not should_add: | ||
| 93 | short_paths.add(path) | ||
| 94 | return short_paths | ||
| 95 | |||
| 96 | |||
| 97 | def compress_for_output_listing(paths): | ||
| 98 | """Returns a tuple of 2 sets of which paths to display to user | ||
| 99 | |||
| 100 | The first set contains paths that would be deleted. Files of a package | ||
| 101 | are not added and the top-level directory of the package has a '*' added | ||
| 102 | at the end - to signify that all it's contents are removed. | ||
| 103 | |||
| 104 | The second set contains files that would have been skipped in the above | ||
| 105 | folders. | ||
| 106 | """ | ||
| 107 | |||
| 108 | will_remove = list(paths) | ||
| 109 | will_skip = set() | ||
| 110 | |||
| 111 | # Determine folders and files | ||
| 112 | folders = set() | ||
| 113 | files = set() | ||
| 114 | for path in will_remove: | ||
| 115 | if path.endswith(".pyc"): | ||
| 116 | continue | ||
| 117 | if path.endswith("__init__.py") or ".dist-info" in path: | ||
| 118 | folders.add(os.path.dirname(path)) | ||
| 119 | files.add(path) | ||
| 120 | |||
| 121 | folders = compact(folders) | ||
| 122 | |||
| 123 | # This walks the tree using os.walk to not miss extra folders | ||
| 124 | # that might get added. | ||
| 125 | for folder in folders: | ||
| 126 | for dirpath, _, dirfiles in os.walk(folder): | ||
| 127 | for fname in dirfiles: | ||
| 128 | if fname.endswith(".pyc"): | ||
| 129 | continue | ||
| 130 | |||
| 131 | file_ = os.path.normcase(os.path.join(dirpath, fname)) | ||
| 132 | if os.path.isfile(file_) and file_ not in files: | ||
| 133 | # We are skipping this file. Add it to the set. | ||
| 134 | will_skip.add(file_) | ||
| 135 | |||
| 136 | will_remove = files | { | ||
| 137 | os.path.join(folder, "*") for folder in folders | ||
| 138 | } | ||
| 139 | |||
| 140 | return will_remove, will_skip | ||
| 141 | |||
| 142 | |||
| 143 | class UninstallPathSet(object): | ||
| 144 | """A set of file paths to be removed in the uninstallation of a | ||
| 145 | requirement.""" | ||
| 146 | def __init__(self, dist): | ||
| 147 | self.paths = set() | ||
| 148 | self._refuse = set() | ||
| 149 | self.pth = {} | ||
| 150 | self.dist = dist | ||
| 151 | self.save_dir = TempDirectory(kind="uninstall") | ||
| 152 | self._moved_paths = [] | ||
| 153 | |||
| 154 | def _permitted(self, path): | ||
| 155 | """ | ||
| 156 | Return True if the given path is one we are permitted to | ||
| 157 | remove/modify, False otherwise. | ||
| 158 | |||
| 159 | """ | ||
| 160 | return is_local(path) | ||
| 161 | |||
| 162 | def add(self, path): | ||
| 163 | head, tail = os.path.split(path) | ||
| 164 | |||
| 165 | # we normalize the head to resolve parent directory symlinks, but not | ||
| 166 | # the tail, since we only want to uninstall symlinks, not their targets | ||
| 167 | path = os.path.join(normalize_path(head), os.path.normcase(tail)) | ||
| 168 | |||
| 169 | if not os.path.exists(path): | ||
| 170 | return | ||
| 171 | if self._permitted(path): | ||
| 172 | self.paths.add(path) | ||
| 173 | else: | ||
| 174 | self._refuse.add(path) | ||
| 175 | |||
| 176 | # __pycache__ files can show up after 'installed-files.txt' is created, | ||
| 177 | # due to imports | ||
| 178 | if os.path.splitext(path)[1] == '.py' and uses_pycache: | ||
| 179 | self.add(cache_from_source(path)) | ||
| 180 | |||
| 181 | def add_pth(self, pth_file, entry): | ||
| 182 | pth_file = normalize_path(pth_file) | ||
| 183 | if self._permitted(pth_file): | ||
| 184 | if pth_file not in self.pth: | ||
| 185 | self.pth[pth_file] = UninstallPthEntries(pth_file) | ||
| 186 | self.pth[pth_file].add(entry) | ||
| 187 | else: | ||
| 188 | self._refuse.add(pth_file) | ||
| 189 | |||
| 190 | def _stash(self, path): | ||
| 191 | return os.path.join( | ||
| 192 | self.save_dir.path, os.path.splitdrive(path)[1].lstrip(os.path.sep) | ||
| 193 | ) | ||
| 194 | |||
| 195 | def remove(self, auto_confirm=False, verbose=False): | ||
| 196 | """Remove paths in ``self.paths`` with confirmation (unless | ||
| 197 | ``auto_confirm`` is True).""" | ||
| 198 | |||
| 199 | if not self.paths: | ||
| 200 | logger.info( | ||
| 201 | "Can't uninstall '%s'. No files were found to uninstall.", | ||
| 202 | self.dist.project_name, | ||
| 203 | ) | ||
| 204 | return | ||
| 205 | |||
| 206 | dist_name_version = ( | ||
| 207 | self.dist.project_name + "-" + self.dist.version | ||
| 208 | ) | ||
| 209 | logger.info('Uninstalling %s:', dist_name_version) | ||
| 210 | |||
| 211 | with indent_log(): | ||
| 212 | if auto_confirm or self._allowed_to_proceed(verbose): | ||
| 213 | self.save_dir.create() | ||
| 214 | |||
| 215 | for path in sorted(compact(self.paths)): | ||
| 216 | new_path = self._stash(path) | ||
| 217 | logger.debug('Removing file or directory %s', path) | ||
| 218 | self._moved_paths.append(path) | ||
| 219 | renames(path, new_path) | ||
| 220 | for pth in self.pth.values(): | ||
| 221 | pth.remove() | ||
| 222 | |||
| 223 | logger.info('Successfully uninstalled %s', dist_name_version) | ||
| 224 | |||
| 225 | def _allowed_to_proceed(self, verbose): | ||
| 226 | """Display which files would be deleted and prompt for confirmation | ||
| 227 | """ | ||
| 228 | |||
| 229 | def _display(msg, paths): | ||
| 230 | if not paths: | ||
| 231 | return | ||
| 232 | |||
| 233 | logger.info(msg) | ||
| 234 | with indent_log(): | ||
| 235 | for path in sorted(compact(paths)): | ||
| 236 | logger.info(path) | ||
| 237 | |||
| 238 | if not verbose: | ||
| 239 | will_remove, will_skip = compress_for_output_listing(self.paths) | ||
| 240 | else: | ||
| 241 | # In verbose mode, display all the files that are going to be | ||
| 242 | # deleted. | ||
| 243 | will_remove = list(self.paths) | ||
| 244 | will_skip = set() | ||
| 245 | |||
| 246 | _display('Would remove:', will_remove) | ||
| 247 | _display('Would not remove (might be manually added):', will_skip) | ||
| 248 | _display('Would not remove (outside of prefix):', self._refuse) | ||
| 249 | |||
| 250 | return ask('Proceed (y/n)? ', ('y', 'n')) == 'y' | ||
| 251 | |||
| 252 | def rollback(self): | ||
| 253 | """Rollback the changes previously made by remove().""" | ||
| 254 | if self.save_dir.path is None: | ||
| 255 | logger.error( | ||
| 256 | "Can't roll back %s; was not uninstalled", | ||
| 257 | self.dist.project_name, | ||
| 258 | ) | ||
| 259 | return False | ||
| 260 | logger.info('Rolling back uninstall of %s', self.dist.project_name) | ||
| 261 | for path in self._moved_paths: | ||
| 262 | tmp_path = self._stash(path) | ||
| 263 | logger.debug('Replacing %s', path) | ||
| 264 | renames(tmp_path, path) | ||
| 265 | for pth in self.pth.values(): | ||
| 266 | pth.rollback() | ||
| 267 | |||
| 268 | def commit(self): | ||
| 269 | """Remove temporary save dir: rollback will no longer be possible.""" | ||
| 270 | self.save_dir.cleanup() | ||
| 271 | self._moved_paths = [] | ||
| 272 | |||
| 273 | @classmethod | ||
| 274 | def from_dist(cls, dist): | ||
| 275 | dist_path = normalize_path(dist.location) | ||
| 276 | if not dist_is_local(dist): | ||
| 277 | logger.info( | ||
| 278 | "Not uninstalling %s at %s, outside environment %s", | ||
| 279 | dist.key, | ||
| 280 | dist_path, | ||
| 281 | sys.prefix, | ||
| 282 | ) | ||
| 283 | return cls(dist) | ||
| 284 | |||
| 285 | if dist_path in {p for p in {sysconfig.get_path("stdlib"), | ||
| 286 | sysconfig.get_path("platstdlib")} | ||
| 287 | if p}: | ||
| 288 | logger.info( | ||
| 289 | "Not uninstalling %s at %s, as it is in the standard library.", | ||
| 290 | dist.key, | ||
| 291 | dist_path, | ||
| 292 | ) | ||
| 293 | return cls(dist) | ||
| 294 | |||
| 295 | paths_to_remove = cls(dist) | ||
| 296 | develop_egg_link = egg_link_path(dist) | ||
| 297 | develop_egg_link_egg_info = '{}.egg-info'.format( | ||
| 298 | pkg_resources.to_filename(dist.project_name)) | ||
| 299 | egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) | ||
| 300 | # Special case for distutils installed package | ||
| 301 | distutils_egg_info = getattr(dist._provider, 'path', None) | ||
| 302 | |||
| 303 | # Uninstall cases order do matter as in the case of 2 installs of the | ||
| 304 | # same package, pip needs to uninstall the currently detected version | ||
| 305 | if (egg_info_exists and dist.egg_info.endswith('.egg-info') and | ||
| 306 | not dist.egg_info.endswith(develop_egg_link_egg_info)): | ||
| 307 | # if dist.egg_info.endswith(develop_egg_link_egg_info), we | ||
| 308 | # are in fact in the develop_egg_link case | ||
| 309 | paths_to_remove.add(dist.egg_info) | ||
| 310 | if dist.has_metadata('installed-files.txt'): | ||
| 311 | for installed_file in dist.get_metadata( | ||
| 312 | 'installed-files.txt').splitlines(): | ||
| 313 | path = os.path.normpath( | ||
| 314 | os.path.join(dist.egg_info, installed_file) | ||
| 315 | ) | ||
| 316 | paths_to_remove.add(path) | ||
| 317 | # FIXME: need a test for this elif block | ||
| 318 | # occurs with --single-version-externally-managed/--record outside | ||
| 319 | # of pip | ||
| 320 | elif dist.has_metadata('top_level.txt'): | ||
| 321 | if dist.has_metadata('namespace_packages.txt'): | ||
| 322 | namespaces = dist.get_metadata('namespace_packages.txt') | ||
| 323 | else: | ||
| 324 | namespaces = [] | ||
| 325 | for top_level_pkg in [ | ||
| 326 | p for p | ||
| 327 | in dist.get_metadata('top_level.txt').splitlines() | ||
| 328 | if p and p not in namespaces]: | ||
| 329 | path = os.path.join(dist.location, top_level_pkg) | ||
| 330 | paths_to_remove.add(path) | ||
| 331 | paths_to_remove.add(path + '.py') | ||
| 332 | paths_to_remove.add(path + '.pyc') | ||
| 333 | paths_to_remove.add(path + '.pyo') | ||
| 334 | |||
| 335 | elif distutils_egg_info: | ||
| 336 | raise UninstallationError( | ||
| 337 | "Cannot uninstall {!r}. It is a distutils installed project " | ||
| 338 | "and thus we cannot accurately determine which files belong " | ||
| 339 | "to it which would lead to only a partial uninstall.".format( | ||
| 340 | dist.project_name, | ||
| 341 | ) | ||
| 342 | ) | ||
| 343 | |||
| 344 | elif dist.location.endswith('.egg'): | ||
| 345 | # package installed by easy_install | ||
| 346 | # We cannot match on dist.egg_name because it can slightly vary | ||
| 347 | # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg | ||
| 348 | paths_to_remove.add(dist.location) | ||
| 349 | easy_install_egg = os.path.split(dist.location)[1] | ||
| 350 | easy_install_pth = os.path.join(os.path.dirname(dist.location), | ||
| 351 | 'easy-install.pth') | ||
| 352 | paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) | ||
| 353 | |||
| 354 | elif egg_info_exists and dist.egg_info.endswith('.dist-info'): | ||
| 355 | for path in uninstallation_paths(dist): | ||
| 356 | paths_to_remove.add(path) | ||
| 357 | |||
| 358 | elif develop_egg_link: | ||
| 359 | # develop egg | ||
| 360 | with open(develop_egg_link, 'r') as fh: | ||
| 361 | link_pointer = os.path.normcase(fh.readline().strip()) | ||
| 362 | assert (link_pointer == dist.location), ( | ||
| 363 | 'Egg-link %s does not match installed location of %s ' | ||
| 364 | '(at %s)' % (link_pointer, dist.project_name, dist.location) | ||
| 365 | ) | ||
| 366 | paths_to_remove.add(develop_egg_link) | ||
| 367 | easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), | ||
| 368 | 'easy-install.pth') | ||
| 369 | paths_to_remove.add_pth(easy_install_pth, dist.location) | ||
| 370 | |||
| 371 | else: | ||
| 372 | logger.debug( | ||
| 373 | 'Not sure how to uninstall: %s - Check: %s', | ||
| 374 | dist, dist.location, | ||
| 375 | ) | ||
| 376 | |||
| 377 | # find distutils scripts= scripts | ||
| 378 | if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): | ||
| 379 | for script in dist.metadata_listdir('scripts'): | ||
| 380 | if dist_in_usersite(dist): | ||
| 381 | bin_dir = bin_user | ||
| 382 | else: | ||
| 383 | bin_dir = bin_py | ||
| 384 | paths_to_remove.add(os.path.join(bin_dir, script)) | ||
| 385 | if WINDOWS: | ||
| 386 | paths_to_remove.add(os.path.join(bin_dir, script) + '.bat') | ||
| 387 | |||
| 388 | # find console_scripts | ||
| 389 | _scripts_to_remove = [] | ||
| 390 | console_scripts = dist.get_entry_map(group='console_scripts') | ||
| 391 | for name in console_scripts.keys(): | ||
| 392 | _scripts_to_remove.extend(_script_names(dist, name, False)) | ||
| 393 | # find gui_scripts | ||
| 394 | gui_scripts = dist.get_entry_map(group='gui_scripts') | ||
| 395 | for name in gui_scripts.keys(): | ||
| 396 | _scripts_to_remove.extend(_script_names(dist, name, True)) | ||
| 397 | |||
| 398 | for s in _scripts_to_remove: | ||
| 399 | paths_to_remove.add(s) | ||
| 400 | |||
| 401 | return paths_to_remove | ||
| 402 | |||
| 403 | |||
| 404 | class UninstallPthEntries(object): | ||
| 405 | def __init__(self, pth_file): | ||
| 406 | if not os.path.isfile(pth_file): | ||
| 407 | raise UninstallationError( | ||
| 408 | "Cannot remove entries from nonexistent file %s" % pth_file | ||
| 409 | ) | ||
| 410 | self.file = pth_file | ||
| 411 | self.entries = set() | ||
| 412 | self._saved_lines = None | ||
| 413 | |||
| 414 | def add(self, entry): | ||
| 415 | entry = os.path.normcase(entry) | ||
| 416 | # On Windows, os.path.normcase converts the entry to use | ||
| 417 | # backslashes. This is correct for entries that describe absolute | ||
| 418 | # paths outside of site-packages, but all the others use forward | ||
| 419 | # slashes. | ||
| 420 | if WINDOWS and not os.path.splitdrive(entry)[0]: | ||
| 421 | entry = entry.replace('\\', '/') | ||
| 422 | self.entries.add(entry) | ||
| 423 | |||
| 424 | def remove(self): | ||
| 425 | logger.debug('Removing pth entries from %s:', self.file) | ||
| 426 | with open(self.file, 'rb') as fh: | ||
| 427 | # windows uses '\r\n' with py3k, but uses '\n' with py2.x | ||
| 428 | lines = fh.readlines() | ||
| 429 | self._saved_lines = lines | ||
| 430 | if any(b'\r\n' in line for line in lines): | ||
| 431 | endline = '\r\n' | ||
| 432 | else: | ||
| 433 | endline = '\n' | ||
| 434 | # handle missing trailing newline | ||
| 435 | if lines and not lines[-1].endswith(endline.encode("utf-8")): | ||
| 436 | lines[-1] = lines[-1] + endline.encode("utf-8") | ||
| 437 | for entry in self.entries: | ||
| 438 | try: | ||
| 439 | logger.debug('Removing entry: %s', entry) | ||
| 440 | lines.remove((entry + endline).encode("utf-8")) | ||
| 441 | except ValueError: | ||
| 442 | pass | ||
| 443 | with open(self.file, 'wb') as fh: | ||
| 444 | fh.writelines(lines) | ||
| 445 | |||
| 446 | def rollback(self): | ||
| 447 | if self._saved_lines is None: | ||
| 448 | logger.error( | ||
| 449 | 'Cannot roll back changes to %s, none were made', self.file | ||
| 450 | ) | ||
| 451 | return False | ||
| 452 | logger.debug('Rolling %s back to previous state', self.file) | ||
| 453 | with open(self.file, 'wb') as fh: | ||
| 454 | fh.writelines(self._saved_lines) | ||
| 455 | return True | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/resolve.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/resolve.py deleted file mode 100644 index 189827e..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/resolve.py +++ /dev/null | |||
| @@ -1,354 +0,0 @@ | |||
| 1 | """Dependency Resolution | ||
| 2 | |||
| 3 | The dependency resolution in pip is performed as follows: | ||
| 4 | |||
| 5 | for top-level requirements: | ||
| 6 | a. only one spec allowed per project, regardless of conflicts or not. | ||
| 7 | otherwise a "double requirement" exception is raised | ||
| 8 | b. they override sub-dependency requirements. | ||
| 9 | for sub-dependencies | ||
| 10 | a. "first found, wins" (where the order is breadth first) | ||
| 11 | """ | ||
| 12 | |||
| 13 | import logging | ||
| 14 | from collections import defaultdict | ||
| 15 | from itertools import chain | ||
| 16 | |||
| 17 | from pip._internal.exceptions import ( | ||
| 18 | BestVersionAlreadyInstalled, DistributionNotFound, HashError, HashErrors, | ||
| 19 | UnsupportedPythonVersion, | ||
| 20 | ) | ||
| 21 | |||
| 22 | from pip._internal.req.req_install import InstallRequirement | ||
| 23 | from pip._internal.utils.logging import indent_log | ||
| 24 | from pip._internal.utils.misc import dist_in_usersite, ensure_dir | ||
| 25 | from pip._internal.utils.packaging import check_dist_requires_python | ||
| 26 | |||
| 27 | logger = logging.getLogger(__name__) | ||
| 28 | |||
| 29 | |||
| 30 | class Resolver(object): | ||
| 31 | """Resolves which packages need to be installed/uninstalled to perform \ | ||
| 32 | the requested operation without breaking the requirements of any package. | ||
| 33 | """ | ||
| 34 | |||
| 35 | _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} | ||
| 36 | |||
| 37 | def __init__(self, preparer, session, finder, wheel_cache, use_user_site, | ||
| 38 | ignore_dependencies, ignore_installed, ignore_requires_python, | ||
| 39 | force_reinstall, isolated, upgrade_strategy): | ||
| 40 | super(Resolver, self).__init__() | ||
| 41 | assert upgrade_strategy in self._allowed_strategies | ||
| 42 | |||
| 43 | self.preparer = preparer | ||
| 44 | self.finder = finder | ||
| 45 | self.session = session | ||
| 46 | |||
| 47 | # NOTE: This would eventually be replaced with a cache that can give | ||
| 48 | # information about both sdist and wheels transparently. | ||
| 49 | self.wheel_cache = wheel_cache | ||
| 50 | |||
| 51 | self.require_hashes = None # This is set in resolve | ||
| 52 | |||
| 53 | self.upgrade_strategy = upgrade_strategy | ||
| 54 | self.force_reinstall = force_reinstall | ||
| 55 | self.isolated = isolated | ||
| 56 | self.ignore_dependencies = ignore_dependencies | ||
| 57 | self.ignore_installed = ignore_installed | ||
| 58 | self.ignore_requires_python = ignore_requires_python | ||
| 59 | self.use_user_site = use_user_site | ||
| 60 | |||
| 61 | self._discovered_dependencies = defaultdict(list) | ||
| 62 | |||
| 63 | def resolve(self, requirement_set): | ||
| 64 | """Resolve what operations need to be done | ||
| 65 | |||
| 66 | As a side-effect of this method, the packages (and their dependencies) | ||
| 67 | are downloaded, unpacked and prepared for installation. This | ||
| 68 | preparation is done by ``pip.operations.prepare``. | ||
| 69 | |||
| 70 | Once PyPI has static dependency metadata available, it would be | ||
| 71 | possible to move the preparation to become a step separated from | ||
| 72 | dependency resolution. | ||
| 73 | """ | ||
| 74 | # make the wheelhouse | ||
| 75 | if self.preparer.wheel_download_dir: | ||
| 76 | ensure_dir(self.preparer.wheel_download_dir) | ||
| 77 | |||
| 78 | # If any top-level requirement has a hash specified, enter | ||
| 79 | # hash-checking mode, which requires hashes from all. | ||
| 80 | root_reqs = ( | ||
| 81 | requirement_set.unnamed_requirements + | ||
| 82 | list(requirement_set.requirements.values()) | ||
| 83 | ) | ||
| 84 | self.require_hashes = ( | ||
| 85 | requirement_set.require_hashes or | ||
| 86 | any(req.has_hash_options for req in root_reqs) | ||
| 87 | ) | ||
| 88 | |||
| 89 | # Display where finder is looking for packages | ||
| 90 | locations = self.finder.get_formatted_locations() | ||
| 91 | if locations: | ||
| 92 | logger.info(locations) | ||
| 93 | |||
| 94 | # Actually prepare the files, and collect any exceptions. Most hash | ||
| 95 | # exceptions cannot be checked ahead of time, because | ||
| 96 | # req.populate_link() needs to be called before we can make decisions | ||
| 97 | # based on link type. | ||
| 98 | discovered_reqs = [] | ||
| 99 | hash_errors = HashErrors() | ||
| 100 | for req in chain(root_reqs, discovered_reqs): | ||
| 101 | try: | ||
| 102 | discovered_reqs.extend( | ||
| 103 | self._resolve_one(requirement_set, req) | ||
| 104 | ) | ||
| 105 | except HashError as exc: | ||
| 106 | exc.req = req | ||
| 107 | hash_errors.append(exc) | ||
| 108 | |||
| 109 | if hash_errors: | ||
| 110 | raise hash_errors | ||
| 111 | |||
| 112 | def _is_upgrade_allowed(self, req): | ||
| 113 | if self.upgrade_strategy == "to-satisfy-only": | ||
| 114 | return False | ||
| 115 | elif self.upgrade_strategy == "eager": | ||
| 116 | return True | ||
| 117 | else: | ||
| 118 | assert self.upgrade_strategy == "only-if-needed" | ||
| 119 | return req.is_direct | ||
| 120 | |||
| 121 | def _set_req_to_reinstall(self, req): | ||
| 122 | """ | ||
| 123 | Set a requirement to be installed. | ||
| 124 | """ | ||
| 125 | # Don't uninstall the conflict if doing a user install and the | ||
| 126 | # conflict is not a user install. | ||
| 127 | if not self.use_user_site or dist_in_usersite(req.satisfied_by): | ||
| 128 | req.conflicts_with = req.satisfied_by | ||
| 129 | req.satisfied_by = None | ||
| 130 | |||
| 131 | # XXX: Stop passing requirement_set for options | ||
| 132 | def _check_skip_installed(self, req_to_install): | ||
| 133 | """Check if req_to_install should be skipped. | ||
| 134 | |||
| 135 | This will check if the req is installed, and whether we should upgrade | ||
| 136 | or reinstall it, taking into account all the relevant user options. | ||
| 137 | |||
| 138 | After calling this req_to_install will only have satisfied_by set to | ||
| 139 | None if the req_to_install is to be upgraded/reinstalled etc. Any | ||
| 140 | other value will be a dist recording the current thing installed that | ||
| 141 | satisfies the requirement. | ||
| 142 | |||
| 143 | Note that for vcs urls and the like we can't assess skipping in this | ||
| 144 | routine - we simply identify that we need to pull the thing down, | ||
| 145 | then later on it is pulled down and introspected to assess upgrade/ | ||
| 146 | reinstalls etc. | ||
| 147 | |||
| 148 | :return: A text reason for why it was skipped, or None. | ||
| 149 | """ | ||
| 150 | if self.ignore_installed: | ||
| 151 | return None | ||
| 152 | |||
| 153 | req_to_install.check_if_exists(self.use_user_site) | ||
| 154 | if not req_to_install.satisfied_by: | ||
| 155 | return None | ||
| 156 | |||
| 157 | if self.force_reinstall: | ||
| 158 | self._set_req_to_reinstall(req_to_install) | ||
| 159 | return None | ||
| 160 | |||
| 161 | if not self._is_upgrade_allowed(req_to_install): | ||
| 162 | if self.upgrade_strategy == "only-if-needed": | ||
| 163 | return 'not upgraded as not directly required' | ||
| 164 | return 'already satisfied' | ||
| 165 | |||
| 166 | # Check for the possibility of an upgrade. For link-based | ||
| 167 | # requirements we have to pull the tree down and inspect to assess | ||
| 168 | # the version #, so it's handled way down. | ||
| 169 | if not req_to_install.link: | ||
| 170 | try: | ||
| 171 | self.finder.find_requirement(req_to_install, upgrade=True) | ||
| 172 | except BestVersionAlreadyInstalled: | ||
| 173 | # Then the best version is installed. | ||
| 174 | return 'already up-to-date' | ||
| 175 | except DistributionNotFound: | ||
| 176 | # No distribution found, so we squash the error. It will | ||
| 177 | # be raised later when we re-try later to do the install. | ||
| 178 | # Why don't we just raise here? | ||
| 179 | pass | ||
| 180 | |||
| 181 | self._set_req_to_reinstall(req_to_install) | ||
| 182 | return None | ||
| 183 | |||
| 184 | def _get_abstract_dist_for(self, req): | ||
| 185 | """Takes a InstallRequirement and returns a single AbstractDist \ | ||
| 186 | representing a prepared variant of the same. | ||
| 187 | """ | ||
| 188 | assert self.require_hashes is not None, ( | ||
| 189 | "require_hashes should have been set in Resolver.resolve()" | ||
| 190 | ) | ||
| 191 | |||
| 192 | if req.editable: | ||
| 193 | return self.preparer.prepare_editable_requirement( | ||
| 194 | req, self.require_hashes, self.use_user_site, self.finder, | ||
| 195 | ) | ||
| 196 | |||
| 197 | # satisfied_by is only evaluated by calling _check_skip_installed, | ||
| 198 | # so it must be None here. | ||
| 199 | assert req.satisfied_by is None | ||
| 200 | skip_reason = self._check_skip_installed(req) | ||
| 201 | |||
| 202 | if req.satisfied_by: | ||
| 203 | return self.preparer.prepare_installed_requirement( | ||
| 204 | req, self.require_hashes, skip_reason | ||
| 205 | ) | ||
| 206 | |||
| 207 | upgrade_allowed = self._is_upgrade_allowed(req) | ||
| 208 | abstract_dist = self.preparer.prepare_linked_requirement( | ||
| 209 | req, self.session, self.finder, upgrade_allowed, | ||
| 210 | self.require_hashes | ||
| 211 | ) | ||
| 212 | |||
| 213 | # NOTE | ||
| 214 | # The following portion is for determining if a certain package is | ||
| 215 | # going to be re-installed/upgraded or not and reporting to the user. | ||
| 216 | # This should probably get cleaned up in a future refactor. | ||
| 217 | |||
| 218 | # req.req is only avail after unpack for URL | ||
| 219 | # pkgs repeat check_if_exists to uninstall-on-upgrade | ||
| 220 | # (#14) | ||
| 221 | if not self.ignore_installed: | ||
| 222 | req.check_if_exists(self.use_user_site) | ||
| 223 | |||
| 224 | if req.satisfied_by: | ||
| 225 | should_modify = ( | ||
| 226 | self.upgrade_strategy != "to-satisfy-only" or | ||
| 227 | self.force_reinstall or | ||
| 228 | self.ignore_installed or | ||
| 229 | req.link.scheme == 'file' | ||
| 230 | ) | ||
| 231 | if should_modify: | ||
| 232 | self._set_req_to_reinstall(req) | ||
| 233 | else: | ||
| 234 | logger.info( | ||
| 235 | 'Requirement already satisfied (use --upgrade to upgrade):' | ||
| 236 | ' %s', req, | ||
| 237 | ) | ||
| 238 | |||
| 239 | return abstract_dist | ||
| 240 | |||
| 241 | def _resolve_one(self, requirement_set, req_to_install): | ||
| 242 | """Prepare a single requirements file. | ||
| 243 | |||
| 244 | :return: A list of additional InstallRequirements to also install. | ||
| 245 | """ | ||
| 246 | # Tell user what we are doing for this requirement: | ||
| 247 | # obtain (editable), skipping, processing (local url), collecting | ||
| 248 | # (remote url or package name) | ||
| 249 | if req_to_install.constraint or req_to_install.prepared: | ||
| 250 | return [] | ||
| 251 | |||
| 252 | req_to_install.prepared = True | ||
| 253 | |||
| 254 | # register tmp src for cleanup in case something goes wrong | ||
| 255 | requirement_set.reqs_to_cleanup.append(req_to_install) | ||
| 256 | |||
| 257 | abstract_dist = self._get_abstract_dist_for(req_to_install) | ||
| 258 | |||
| 259 | # Parse and return dependencies | ||
| 260 | dist = abstract_dist.dist(self.finder) | ||
| 261 | try: | ||
| 262 | check_dist_requires_python(dist) | ||
| 263 | except UnsupportedPythonVersion as err: | ||
| 264 | if self.ignore_requires_python: | ||
| 265 | logger.warning(err.args[0]) | ||
| 266 | else: | ||
| 267 | raise | ||
| 268 | |||
| 269 | more_reqs = [] | ||
| 270 | |||
| 271 | def add_req(subreq, extras_requested): | ||
| 272 | sub_install_req = InstallRequirement.from_req( | ||
| 273 | str(subreq), | ||
| 274 | req_to_install, | ||
| 275 | isolated=self.isolated, | ||
| 276 | wheel_cache=self.wheel_cache, | ||
| 277 | ) | ||
| 278 | parent_req_name = req_to_install.name | ||
| 279 | to_scan_again, add_to_parent = requirement_set.add_requirement( | ||
| 280 | sub_install_req, | ||
| 281 | parent_req_name=parent_req_name, | ||
| 282 | extras_requested=extras_requested, | ||
| 283 | ) | ||
| 284 | if parent_req_name and add_to_parent: | ||
| 285 | self._discovered_dependencies[parent_req_name].append( | ||
| 286 | add_to_parent | ||
| 287 | ) | ||
| 288 | more_reqs.extend(to_scan_again) | ||
| 289 | |||
| 290 | with indent_log(): | ||
| 291 | # We add req_to_install before its dependencies, so that we | ||
| 292 | # can refer to it when adding dependencies. | ||
| 293 | if not requirement_set.has_requirement(req_to_install.name): | ||
| 294 | # 'unnamed' requirements will get added here | ||
| 295 | req_to_install.is_direct = True | ||
| 296 | requirement_set.add_requirement( | ||
| 297 | req_to_install, parent_req_name=None, | ||
| 298 | ) | ||
| 299 | |||
| 300 | if not self.ignore_dependencies: | ||
| 301 | if req_to_install.extras: | ||
| 302 | logger.debug( | ||
| 303 | "Installing extra requirements: %r", | ||
| 304 | ','.join(req_to_install.extras), | ||
| 305 | ) | ||
| 306 | missing_requested = sorted( | ||
| 307 | set(req_to_install.extras) - set(dist.extras) | ||
| 308 | ) | ||
| 309 | for missing in missing_requested: | ||
| 310 | logger.warning( | ||
| 311 | '%s does not provide the extra \'%s\'', | ||
| 312 | dist, missing | ||
| 313 | ) | ||
| 314 | |||
| 315 | available_requested = sorted( | ||
| 316 | set(dist.extras) & set(req_to_install.extras) | ||
| 317 | ) | ||
| 318 | for subreq in dist.requires(available_requested): | ||
| 319 | add_req(subreq, extras_requested=available_requested) | ||
| 320 | |||
| 321 | if not req_to_install.editable and not req_to_install.satisfied_by: | ||
| 322 | # XXX: --no-install leads this to report 'Successfully | ||
| 323 | # downloaded' for only non-editable reqs, even though we took | ||
| 324 | # action on them. | ||
| 325 | requirement_set.successfully_downloaded.append(req_to_install) | ||
| 326 | |||
| 327 | return more_reqs | ||
| 328 | |||
| 329 | def get_installation_order(self, req_set): | ||
| 330 | """Create the installation order. | ||
| 331 | |||
| 332 | The installation order is topological - requirements are installed | ||
| 333 | before the requiring thing. We break cycles at an arbitrary point, | ||
| 334 | and make no other guarantees. | ||
| 335 | """ | ||
| 336 | # The current implementation, which we may change at any point | ||
| 337 | # installs the user specified things in the order given, except when | ||
| 338 | # dependencies must come earlier to achieve topological order. | ||
| 339 | order = [] | ||
| 340 | ordered_reqs = set() | ||
| 341 | |||
| 342 | def schedule(req): | ||
| 343 | if req.satisfied_by or req in ordered_reqs: | ||
| 344 | return | ||
| 345 | if req.constraint: | ||
| 346 | return | ||
| 347 | ordered_reqs.add(req) | ||
| 348 | for dep in self._discovered_dependencies[req.name]: | ||
| 349 | schedule(dep) | ||
| 350 | order.append(req) | ||
| 351 | |||
| 352 | for install_req in req_set.requirements.values(): | ||
| 353 | schedule(install_req) | ||
| 354 | return order | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/status_codes.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/status_codes.py deleted file mode 100644 index 2b56931..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/status_codes.py +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | SUCCESS = 0 | ||
| 4 | ERROR = 1 | ||
| 5 | UNKNOWN_ERROR = 2 | ||
| 6 | VIRTUALENV_NOT_FOUND = 3 | ||
| 7 | PREVIOUS_BUILD_DIR_ERROR = 4 | ||
| 8 | NO_MATCHES_FOUND = 23 | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/__init__.py +++ /dev/null | |||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/appdirs.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/appdirs.py deleted file mode 100644 index 0eb87ca..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/appdirs.py +++ /dev/null | |||
| @@ -1,258 +0,0 @@ | |||
| 1 | """ | ||
| 2 | This code was taken from https://github.com/ActiveState/appdirs and modified | ||
| 3 | to suit our purposes. | ||
| 4 | """ | ||
| 5 | from __future__ import absolute_import | ||
| 6 | |||
| 7 | import os | ||
| 8 | import sys | ||
| 9 | |||
| 10 | from pip._vendor.six import PY2, text_type | ||
| 11 | |||
| 12 | from pip._internal.compat import WINDOWS, expanduser | ||
| 13 | |||
| 14 | |||
| 15 | def user_cache_dir(appname): | ||
| 16 | r""" | ||
| 17 | Return full path to the user-specific cache dir for this application. | ||
| 18 | |||
| 19 | "appname" is the name of application. | ||
| 20 | |||
| 21 | Typical user cache directories are: | ||
| 22 | macOS: ~/Library/Caches/<AppName> | ||
| 23 | Unix: ~/.cache/<AppName> (XDG default) | ||
| 24 | Windows: C:\Users\<username>\AppData\Local\<AppName>\Cache | ||
| 25 | |||
| 26 | On Windows the only suggestion in the MSDN docs is that local settings go | ||
| 27 | in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the | ||
| 28 | non-roaming app data dir (the default returned by `user_data_dir`). Apps | ||
| 29 | typically put cache data somewhere *under* the given dir here. Some | ||
| 30 | examples: | ||
| 31 | ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache | ||
| 32 | ...\Acme\SuperApp\Cache\1.0 | ||
| 33 | |||
| 34 | OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. | ||
| 35 | """ | ||
| 36 | if WINDOWS: | ||
| 37 | # Get the base path | ||
| 38 | path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) | ||
| 39 | |||
| 40 | # When using Python 2, return paths as bytes on Windows like we do on | ||
| 41 | # other operating systems. See helper function docs for more details. | ||
| 42 | if PY2 and isinstance(path, text_type): | ||
| 43 | path = _win_path_to_bytes(path) | ||
| 44 | |||
| 45 | # Add our app name and Cache directory to it | ||
| 46 | path = os.path.join(path, appname, "Cache") | ||
| 47 | elif sys.platform == "darwin": | ||
| 48 | # Get the base path | ||
| 49 | path = expanduser("~/Library/Caches") | ||
| 50 | |||
| 51 | # Add our app name to it | ||
| 52 | path = os.path.join(path, appname) | ||
| 53 | else: | ||
| 54 | # Get the base path | ||
| 55 | path = os.getenv("XDG_CACHE_HOME", expanduser("~/.cache")) | ||
| 56 | |||
| 57 | # Add our app name to it | ||
| 58 | path = os.path.join(path, appname) | ||
| 59 | |||
| 60 | return path | ||
| 61 | |||
| 62 | |||
| 63 | def user_data_dir(appname, roaming=False): | ||
| 64 | r""" | ||
| 65 | Return full path to the user-specific data dir for this application. | ||
| 66 | |||
| 67 | "appname" is the name of application. | ||
| 68 | If None, just the system directory is returned. | ||
| 69 | "roaming" (boolean, default False) can be set True to use the Windows | ||
| 70 | roaming appdata directory. That means that for users on a Windows | ||
| 71 | network setup for roaming profiles, this user data will be | ||
| 72 | sync'd on login. See | ||
| 73 | <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> | ||
| 74 | for a discussion of issues. | ||
| 75 | |||
| 76 | Typical user data directories are: | ||
| 77 | macOS: ~/Library/Application Support/<AppName> | ||
| 78 | if it exists, else ~/.config/<AppName> | ||
| 79 | Unix: ~/.local/share/<AppName> # or in | ||
| 80 | $XDG_DATA_HOME, if defined | ||
| 81 | Win XP (not roaming): C:\Documents and Settings\<username>\ ... | ||
| 82 | ...Application Data\<AppName> | ||
| 83 | Win XP (roaming): C:\Documents and Settings\<username>\Local ... | ||
| 84 | ...Settings\Application Data\<AppName> | ||
| 85 | Win 7 (not roaming): C:\\Users\<username>\AppData\Local\<AppName> | ||
| 86 | Win 7 (roaming): C:\\Users\<username>\AppData\Roaming\<AppName> | ||
| 87 | |||
| 88 | For Unix, we follow the XDG spec and support $XDG_DATA_HOME. | ||
| 89 | That means, by default "~/.local/share/<AppName>". | ||
| 90 | """ | ||
| 91 | if WINDOWS: | ||
| 92 | const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" | ||
| 93 | path = os.path.join(os.path.normpath(_get_win_folder(const)), appname) | ||
| 94 | elif sys.platform == "darwin": | ||
| 95 | path = os.path.join( | ||
| 96 | expanduser('~/Library/Application Support/'), | ||
| 97 | appname, | ||
| 98 | ) if os.path.isdir(os.path.join( | ||
| 99 | expanduser('~/Library/Application Support/'), | ||
| 100 | appname, | ||
| 101 | ) | ||
| 102 | ) else os.path.join( | ||
| 103 | expanduser('~/.config/'), | ||
| 104 | appname, | ||
| 105 | ) | ||
| 106 | else: | ||
| 107 | path = os.path.join( | ||
| 108 | os.getenv('XDG_DATA_HOME', expanduser("~/.local/share")), | ||
| 109 | appname, | ||
| 110 | ) | ||
| 111 | |||
| 112 | return path | ||
| 113 | |||
| 114 | |||
| 115 | def user_config_dir(appname, roaming=True): | ||
| 116 | """Return full path to the user-specific config dir for this application. | ||
| 117 | |||
| 118 | "appname" is the name of application. | ||
| 119 | If None, just the system directory is returned. | ||
| 120 | "roaming" (boolean, default True) can be set False to not use the | ||
| 121 | Windows roaming appdata directory. That means that for users on a | ||
| 122 | Windows network setup for roaming profiles, this user data will be | ||
| 123 | sync'd on login. See | ||
| 124 | <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> | ||
| 125 | for a discussion of issues. | ||
| 126 | |||
| 127 | Typical user data directories are: | ||
| 128 | macOS: same as user_data_dir | ||
| 129 | Unix: ~/.config/<AppName> | ||
| 130 | Win *: same as user_data_dir | ||
| 131 | |||
| 132 | For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. | ||
| 133 | That means, by default "~/.config/<AppName>". | ||
| 134 | """ | ||
| 135 | if WINDOWS: | ||
| 136 | path = user_data_dir(appname, roaming=roaming) | ||
| 137 | elif sys.platform == "darwin": | ||
| 138 | path = user_data_dir(appname) | ||
| 139 | else: | ||
| 140 | path = os.getenv('XDG_CONFIG_HOME', expanduser("~/.config")) | ||
| 141 | path = os.path.join(path, appname) | ||
| 142 | |||
| 143 | return path | ||
| 144 | |||
| 145 | |||
| 146 | # for the discussion regarding site_config_dirs locations | ||
| 147 | # see <https://github.com/pypa/pip/issues/1733> | ||
| 148 | def site_config_dirs(appname): | ||
| 149 | r"""Return a list of potential user-shared config dirs for this application. | ||
| 150 | |||
| 151 | "appname" is the name of application. | ||
| 152 | |||
| 153 | Typical user config directories are: | ||
| 154 | macOS: /Library/Application Support/<AppName>/ | ||
| 155 | Unix: /etc or $XDG_CONFIG_DIRS[i]/<AppName>/ for each value in | ||
| 156 | $XDG_CONFIG_DIRS | ||
| 157 | Win XP: C:\Documents and Settings\All Users\Application ... | ||
| 158 | ...Data\<AppName>\ | ||
| 159 | Vista: (Fail! "C:\ProgramData" is a hidden *system* directory | ||
| 160 | on Vista.) | ||
| 161 | Win 7: Hidden, but writeable on Win 7: | ||
| 162 | C:\ProgramData\<AppName>\ | ||
| 163 | """ | ||
| 164 | if WINDOWS: | ||
| 165 | path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) | ||
| 166 | pathlist = [os.path.join(path, appname)] | ||
| 167 | elif sys.platform == 'darwin': | ||
| 168 | pathlist = [os.path.join('/Library/Application Support', appname)] | ||
| 169 | else: | ||
| 170 | # try looking in $XDG_CONFIG_DIRS | ||
| 171 | xdg_config_dirs = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') | ||
| 172 | if xdg_config_dirs: | ||
| 173 | pathlist = [ | ||
| 174 | os.path.join(expanduser(x), appname) | ||
| 175 | for x in xdg_config_dirs.split(os.pathsep) | ||
| 176 | ] | ||
| 177 | else: | ||
| 178 | pathlist = [] | ||
| 179 | |||
| 180 | # always look in /etc directly as well | ||
| 181 | pathlist.append('/etc') | ||
| 182 | |||
| 183 | return pathlist | ||
| 184 | |||
| 185 | |||
| 186 | # -- Windows support functions -- | ||
| 187 | |||
| 188 | def _get_win_folder_from_registry(csidl_name): | ||
| 189 | """ | ||
| 190 | This is a fallback technique at best. I'm not sure if using the | ||
| 191 | registry for this guarantees us the correct answer for all CSIDL_* | ||
| 192 | names. | ||
| 193 | """ | ||
| 194 | import _winreg | ||
| 195 | |||
| 196 | shell_folder_name = { | ||
| 197 | "CSIDL_APPDATA": "AppData", | ||
| 198 | "CSIDL_COMMON_APPDATA": "Common AppData", | ||
| 199 | "CSIDL_LOCAL_APPDATA": "Local AppData", | ||
| 200 | }[csidl_name] | ||
| 201 | |||
| 202 | key = _winreg.OpenKey( | ||
| 203 | _winreg.HKEY_CURRENT_USER, | ||
| 204 | r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" | ||
| 205 | ) | ||
| 206 | directory, _type = _winreg.QueryValueEx(key, shell_folder_name) | ||
| 207 | return directory | ||
| 208 | |||
| 209 | |||
| 210 | def _get_win_folder_with_ctypes(csidl_name): | ||
| 211 | csidl_const = { | ||
| 212 | "CSIDL_APPDATA": 26, | ||
| 213 | "CSIDL_COMMON_APPDATA": 35, | ||
| 214 | "CSIDL_LOCAL_APPDATA": 28, | ||
| 215 | }[csidl_name] | ||
| 216 | |||
| 217 | buf = ctypes.create_unicode_buffer(1024) | ||
| 218 | ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) | ||
| 219 | |||
| 220 | # Downgrade to short path name if have highbit chars. See | ||
| 221 | # <http://bugs.activestate.com/show_bug.cgi?id=85099>. | ||
| 222 | has_high_char = False | ||
| 223 | for c in buf: | ||
| 224 | if ord(c) > 255: | ||
| 225 | has_high_char = True | ||
| 226 | break | ||
| 227 | if has_high_char: | ||
| 228 | buf2 = ctypes.create_unicode_buffer(1024) | ||
| 229 | if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): | ||
| 230 | buf = buf2 | ||
| 231 | |||
| 232 | return buf.value | ||
| 233 | |||
| 234 | |||
| 235 | if WINDOWS: | ||
| 236 | try: | ||
| 237 | import ctypes | ||
| 238 | _get_win_folder = _get_win_folder_with_ctypes | ||
| 239 | except ImportError: | ||
| 240 | _get_win_folder = _get_win_folder_from_registry | ||
| 241 | |||
| 242 | |||
| 243 | def _win_path_to_bytes(path): | ||
| 244 | """Encode Windows paths to bytes. Only used on Python 2. | ||
| 245 | |||
| 246 | Motivation is to be consistent with other operating systems where paths | ||
| 247 | are also returned as bytes. This avoids problems mixing bytes and Unicode | ||
| 248 | elsewhere in the codebase. For more details and discussion see | ||
| 249 | <https://github.com/pypa/pip/issues/3463>. | ||
| 250 | |||
| 251 | If encoding using ASCII and MBCS fails, return the original Unicode path. | ||
| 252 | """ | ||
| 253 | for encoding in ('ASCII', 'MBCS'): | ||
| 254 | try: | ||
| 255 | return path.encode(encoding) | ||
| 256 | except (UnicodeEncodeError, LookupError): | ||
| 257 | pass | ||
| 258 | return path | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/deprecation.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/deprecation.py deleted file mode 100644 index c0e3884..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/deprecation.py +++ /dev/null | |||
| @@ -1,77 +0,0 @@ | |||
| 1 | """ | ||
| 2 | A module that implements tooling to enable easy warnings about deprecations. | ||
| 3 | """ | ||
| 4 | from __future__ import absolute_import | ||
| 5 | |||
| 6 | import logging | ||
| 7 | import warnings | ||
| 8 | |||
| 9 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 10 | |||
| 11 | if MYPY_CHECK_RUNNING: | ||
| 12 | from typing import Any | ||
| 13 | |||
| 14 | |||
| 15 | class PipDeprecationWarning(Warning): | ||
| 16 | pass | ||
| 17 | |||
| 18 | |||
| 19 | class Pending(object): | ||
| 20 | pass | ||
| 21 | |||
| 22 | |||
| 23 | class RemovedInPip11Warning(PipDeprecationWarning): | ||
| 24 | pass | ||
| 25 | |||
| 26 | |||
| 27 | class RemovedInPip12Warning(PipDeprecationWarning, Pending): | ||
| 28 | pass | ||
| 29 | |||
| 30 | |||
| 31 | # Warnings <-> Logging Integration | ||
| 32 | |||
| 33 | |||
| 34 | _warnings_showwarning = None # type: Any | ||
| 35 | |||
| 36 | |||
| 37 | def _showwarning(message, category, filename, lineno, file=None, line=None): | ||
| 38 | if file is not None: | ||
| 39 | if _warnings_showwarning is not None: | ||
| 40 | _warnings_showwarning( | ||
| 41 | message, category, filename, lineno, file, line, | ||
| 42 | ) | ||
| 43 | else: | ||
| 44 | if issubclass(category, PipDeprecationWarning): | ||
| 45 | # We use a specially named logger which will handle all of the | ||
| 46 | # deprecation messages for pip. | ||
| 47 | logger = logging.getLogger("pip._internal.deprecations") | ||
| 48 | |||
| 49 | # This is purposely using the % formatter here instead of letting | ||
| 50 | # the logging module handle the interpolation. This is because we | ||
| 51 | # want it to appear as if someone typed this entire message out. | ||
| 52 | log_message = "DEPRECATION: %s" % message | ||
| 53 | |||
| 54 | # PipDeprecationWarnings that are Pending still have at least 2 | ||
| 55 | # versions to go until they are removed so they can just be | ||
| 56 | # warnings. Otherwise, they will be removed in the very next | ||
| 57 | # version of pip. We want these to be more obvious so we use the | ||
| 58 | # ERROR logging level. | ||
| 59 | if issubclass(category, Pending): | ||
| 60 | logger.warning(log_message) | ||
| 61 | else: | ||
| 62 | logger.error(log_message) | ||
| 63 | else: | ||
| 64 | _warnings_showwarning( | ||
| 65 | message, category, filename, lineno, file, line, | ||
| 66 | ) | ||
| 67 | |||
| 68 | |||
| 69 | def install_warning_logger(): | ||
| 70 | # Enable our Deprecation Warnings | ||
| 71 | warnings.simplefilter("default", PipDeprecationWarning, append=True) | ||
| 72 | |||
| 73 | global _warnings_showwarning | ||
| 74 | |||
| 75 | if _warnings_showwarning is None: | ||
| 76 | _warnings_showwarning = warnings.showwarning | ||
| 77 | warnings.showwarning = _showwarning | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/encoding.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/encoding.py deleted file mode 100644 index 831f3f6..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/encoding.py +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | import codecs | ||
| 2 | import locale | ||
| 3 | import re | ||
| 4 | import sys | ||
| 5 | |||
| 6 | BOMS = [ | ||
| 7 | (codecs.BOM_UTF8, 'utf8'), | ||
| 8 | (codecs.BOM_UTF16, 'utf16'), | ||
| 9 | (codecs.BOM_UTF16_BE, 'utf16-be'), | ||
| 10 | (codecs.BOM_UTF16_LE, 'utf16-le'), | ||
| 11 | (codecs.BOM_UTF32, 'utf32'), | ||
| 12 | (codecs.BOM_UTF32_BE, 'utf32-be'), | ||
| 13 | (codecs.BOM_UTF32_LE, 'utf32-le'), | ||
| 14 | ] | ||
| 15 | |||
| 16 | ENCODING_RE = re.compile(br'coding[:=]\s*([-\w.]+)') | ||
| 17 | |||
| 18 | |||
| 19 | def auto_decode(data): | ||
| 20 | """Check a bytes string for a BOM to correctly detect the encoding | ||
| 21 | |||
| 22 | Fallback to locale.getpreferredencoding(False) like open() on Python3""" | ||
| 23 | for bom, encoding in BOMS: | ||
| 24 | if data.startswith(bom): | ||
| 25 | return data[len(bom):].decode(encoding) | ||
| 26 | # Lets check the first two lines as in PEP263 | ||
| 27 | for line in data.split(b'\n')[:2]: | ||
| 28 | if line[0:1] == b'#' and ENCODING_RE.search(line): | ||
| 29 | encoding = ENCODING_RE.search(line).groups()[0].decode('ascii') | ||
| 30 | return data.decode(encoding) | ||
| 31 | return data.decode( | ||
| 32 | locale.getpreferredencoding(False) or sys.getdefaultencoding(), | ||
| 33 | ) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/filesystem.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/filesystem.py deleted file mode 100644 index 94fa2c6..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/filesystem.py +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | import os | ||
| 2 | import os.path | ||
| 3 | |||
| 4 | from pip._internal.compat import get_path_uid | ||
| 5 | |||
| 6 | |||
| 7 | def check_path_owner(path): | ||
| 8 | # If we don't have a way to check the effective uid of this process, then | ||
| 9 | # we'll just assume that we own the directory. | ||
| 10 | if not hasattr(os, "geteuid"): | ||
| 11 | return True | ||
| 12 | |||
| 13 | previous = None | ||
| 14 | while path != previous: | ||
| 15 | if os.path.lexists(path): | ||
| 16 | # Check if path is writable by current user. | ||
| 17 | if os.geteuid() == 0: | ||
| 18 | # Special handling for root user in order to handle properly | ||
| 19 | # cases where users use sudo without -H flag. | ||
| 20 | try: | ||
| 21 | path_uid = get_path_uid(path) | ||
| 22 | except OSError: | ||
| 23 | return False | ||
| 24 | return path_uid == 0 | ||
| 25 | else: | ||
| 26 | return os.access(path, os.W_OK) | ||
| 27 | else: | ||
| 28 | previous, path = path, os.path.dirname(path) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/glibc.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/glibc.py deleted file mode 100644 index 5900a10..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/glibc.py +++ /dev/null | |||
| @@ -1,84 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import ctypes | ||
| 4 | import re | ||
| 5 | import warnings | ||
| 6 | |||
| 7 | |||
| 8 | def glibc_version_string(): | ||
| 9 | "Returns glibc version string, or None if not using glibc." | ||
| 10 | |||
| 11 | # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen | ||
| 12 | # manpage says, "If filename is NULL, then the returned handle is for the | ||
| 13 | # main program". This way we can let the linker do the work to figure out | ||
| 14 | # which libc our process is actually using. | ||
| 15 | process_namespace = ctypes.CDLL(None) | ||
| 16 | try: | ||
| 17 | gnu_get_libc_version = process_namespace.gnu_get_libc_version | ||
| 18 | except AttributeError: | ||
| 19 | # Symbol doesn't exist -> therefore, we are not linked to | ||
| 20 | # glibc. | ||
| 21 | return None | ||
| 22 | |||
| 23 | # Call gnu_get_libc_version, which returns a string like "2.5" | ||
| 24 | gnu_get_libc_version.restype = ctypes.c_char_p | ||
| 25 | version_str = gnu_get_libc_version() | ||
| 26 | # py2 / py3 compatibility: | ||
| 27 | if not isinstance(version_str, str): | ||
| 28 | version_str = version_str.decode("ascii") | ||
| 29 | |||
| 30 | return version_str | ||
| 31 | |||
| 32 | |||
| 33 | # Separated out from have_compatible_glibc for easier unit testing | ||
| 34 | def check_glibc_version(version_str, required_major, minimum_minor): | ||
| 35 | # Parse string and check against requested version. | ||
| 36 | # | ||
| 37 | # We use a regexp instead of str.split because we want to discard any | ||
| 38 | # random junk that might come after the minor version -- this might happen | ||
| 39 | # in patched/forked versions of glibc (e.g. Linaro's version of glibc | ||
| 40 | # uses version strings like "2.20-2014.11"). See gh-3588. | ||
| 41 | m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str) | ||
| 42 | if not m: | ||
| 43 | warnings.warn("Expected glibc version with 2 components major.minor," | ||
| 44 | " got: %s" % version_str, RuntimeWarning) | ||
| 45 | return False | ||
| 46 | return (int(m.group("major")) == required_major and | ||
| 47 | int(m.group("minor")) >= minimum_minor) | ||
| 48 | |||
| 49 | |||
| 50 | def have_compatible_glibc(required_major, minimum_minor): | ||
| 51 | version_str = glibc_version_string() | ||
| 52 | if version_str is None: | ||
| 53 | return False | ||
| 54 | return check_glibc_version(version_str, required_major, minimum_minor) | ||
| 55 | |||
| 56 | |||
| 57 | # platform.libc_ver regularly returns completely nonsensical glibc | ||
| 58 | # versions. E.g. on my computer, platform says: | ||
| 59 | # | ||
| 60 | # ~$ python2.7 -c 'import platform; print(platform.libc_ver())' | ||
| 61 | # ('glibc', '2.7') | ||
| 62 | # ~$ python3.5 -c 'import platform; print(platform.libc_ver())' | ||
| 63 | # ('glibc', '2.9') | ||
| 64 | # | ||
| 65 | # But the truth is: | ||
| 66 | # | ||
| 67 | # ~$ ldd --version | ||
| 68 | # ldd (Debian GLIBC 2.22-11) 2.22 | ||
| 69 | # | ||
| 70 | # This is unfortunate, because it means that the linehaul data on libc | ||
| 71 | # versions that was generated by pip 8.1.2 and earlier is useless and | ||
| 72 | # misleading. Solution: instead of using platform, use our code that actually | ||
| 73 | # works. | ||
| 74 | def libc_ver(): | ||
| 75 | """Try to determine the glibc version | ||
| 76 | |||
| 77 | Returns a tuple of strings (lib, version) which default to empty strings | ||
| 78 | in case the lookup fails. | ||
| 79 | """ | ||
| 80 | glibc_version = glibc_version_string() | ||
| 81 | if glibc_version is None: | ||
| 82 | return ("", "") | ||
| 83 | else: | ||
| 84 | return ("glibc", glibc_version) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/hashes.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/hashes.py deleted file mode 100644 index 8cf6367..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/hashes.py +++ /dev/null | |||
| @@ -1,94 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import hashlib | ||
| 4 | |||
| 5 | from pip._vendor.six import iteritems, iterkeys, itervalues | ||
| 6 | |||
| 7 | from pip._internal.exceptions import ( | ||
| 8 | HashMismatch, HashMissing, InstallationError, | ||
| 9 | ) | ||
| 10 | from pip._internal.utils.misc import read_chunks | ||
| 11 | |||
| 12 | # The recommended hash algo of the moment. Change this whenever the state of | ||
| 13 | # the art changes; it won't hurt backward compatibility. | ||
| 14 | FAVORITE_HASH = 'sha256' | ||
| 15 | |||
| 16 | |||
| 17 | # Names of hashlib algorithms allowed by the --hash option and ``pip hash`` | ||
| 18 | # Currently, those are the ones at least as collision-resistant as sha256. | ||
| 19 | STRONG_HASHES = ['sha256', 'sha384', 'sha512'] | ||
| 20 | |||
| 21 | |||
| 22 | class Hashes(object): | ||
| 23 | """A wrapper that builds multiple hashes at once and checks them against | ||
| 24 | known-good values | ||
| 25 | |||
| 26 | """ | ||
| 27 | def __init__(self, hashes=None): | ||
| 28 | """ | ||
| 29 | :param hashes: A dict of algorithm names pointing to lists of allowed | ||
| 30 | hex digests | ||
| 31 | """ | ||
| 32 | self._allowed = {} if hashes is None else hashes | ||
| 33 | |||
| 34 | def check_against_chunks(self, chunks): | ||
| 35 | """Check good hashes against ones built from iterable of chunks of | ||
| 36 | data. | ||
| 37 | |||
| 38 | Raise HashMismatch if none match. | ||
| 39 | |||
| 40 | """ | ||
| 41 | gots = {} | ||
| 42 | for hash_name in iterkeys(self._allowed): | ||
| 43 | try: | ||
| 44 | gots[hash_name] = hashlib.new(hash_name) | ||
| 45 | except (ValueError, TypeError): | ||
| 46 | raise InstallationError('Unknown hash name: %s' % hash_name) | ||
| 47 | |||
| 48 | for chunk in chunks: | ||
| 49 | for hash in itervalues(gots): | ||
| 50 | hash.update(chunk) | ||
| 51 | |||
| 52 | for hash_name, got in iteritems(gots): | ||
| 53 | if got.hexdigest() in self._allowed[hash_name]: | ||
| 54 | return | ||
| 55 | self._raise(gots) | ||
| 56 | |||
| 57 | def _raise(self, gots): | ||
| 58 | raise HashMismatch(self._allowed, gots) | ||
| 59 | |||
| 60 | def check_against_file(self, file): | ||
| 61 | """Check good hashes against a file-like object | ||
| 62 | |||
| 63 | Raise HashMismatch if none match. | ||
| 64 | |||
| 65 | """ | ||
| 66 | return self.check_against_chunks(read_chunks(file)) | ||
| 67 | |||
| 68 | def check_against_path(self, path): | ||
| 69 | with open(path, 'rb') as file: | ||
| 70 | return self.check_against_file(file) | ||
| 71 | |||
| 72 | def __nonzero__(self): | ||
| 73 | """Return whether I know any known-good hashes.""" | ||
| 74 | return bool(self._allowed) | ||
| 75 | |||
| 76 | def __bool__(self): | ||
| 77 | return self.__nonzero__() | ||
| 78 | |||
| 79 | |||
| 80 | class MissingHashes(Hashes): | ||
| 81 | """A workalike for Hashes used when we're missing a hash for a requirement | ||
| 82 | |||
| 83 | It computes the actual hash of the requirement and raises a HashMissing | ||
| 84 | exception showing it to the user. | ||
| 85 | |||
| 86 | """ | ||
| 87 | def __init__(self): | ||
| 88 | """Don't offer the ``hashes`` kwarg.""" | ||
| 89 | # Pass our favorite hash in to generate a "gotten hash". With the | ||
| 90 | # empty list, it will never match, so an error will always raise. | ||
| 91 | super(MissingHashes, self).__init__(hashes={FAVORITE_HASH: []}) | ||
| 92 | |||
| 93 | def _raise(self, gots): | ||
| 94 | raise HashMissing(gots[FAVORITE_HASH].hexdigest()) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/logging.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/logging.py deleted file mode 100644 index 1fb3e8a..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/logging.py +++ /dev/null | |||
| @@ -1,132 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import contextlib | ||
| 4 | import logging | ||
| 5 | import logging.handlers | ||
| 6 | import os | ||
| 7 | |||
| 8 | from pip._internal.compat import WINDOWS | ||
| 9 | from pip._internal.utils.misc import ensure_dir | ||
| 10 | |||
| 11 | try: | ||
| 12 | import threading | ||
| 13 | except ImportError: | ||
| 14 | import dummy_threading as threading # type: ignore | ||
| 15 | |||
| 16 | |||
| 17 | try: | ||
| 18 | from pip._vendor import colorama | ||
| 19 | # Lots of different errors can come from this, including SystemError and | ||
| 20 | # ImportError. | ||
| 21 | except Exception: | ||
| 22 | colorama = None | ||
| 23 | |||
| 24 | |||
| 25 | _log_state = threading.local() | ||
| 26 | _log_state.indentation = 0 | ||
| 27 | |||
| 28 | |||
| 29 | @contextlib.contextmanager | ||
| 30 | def indent_log(num=2): | ||
| 31 | """ | ||
| 32 | A context manager which will cause the log output to be indented for any | ||
| 33 | log messages emitted inside it. | ||
| 34 | """ | ||
| 35 | _log_state.indentation += num | ||
| 36 | try: | ||
| 37 | yield | ||
| 38 | finally: | ||
| 39 | _log_state.indentation -= num | ||
| 40 | |||
| 41 | |||
| 42 | def get_indentation(): | ||
| 43 | return getattr(_log_state, 'indentation', 0) | ||
| 44 | |||
| 45 | |||
| 46 | class IndentingFormatter(logging.Formatter): | ||
| 47 | |||
| 48 | def format(self, record): | ||
| 49 | """ | ||
| 50 | Calls the standard formatter, but will indent all of the log messages | ||
| 51 | by our current indentation level. | ||
| 52 | """ | ||
| 53 | formatted = logging.Formatter.format(self, record) | ||
| 54 | formatted = "".join([ | ||
| 55 | (" " * get_indentation()) + line | ||
| 56 | for line in formatted.splitlines(True) | ||
| 57 | ]) | ||
| 58 | return formatted | ||
| 59 | |||
| 60 | |||
| 61 | def _color_wrap(*colors): | ||
| 62 | def wrapped(inp): | ||
| 63 | return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) | ||
| 64 | return wrapped | ||
| 65 | |||
| 66 | |||
| 67 | class ColorizedStreamHandler(logging.StreamHandler): | ||
| 68 | |||
| 69 | # Don't build up a list of colors if we don't have colorama | ||
| 70 | if colorama: | ||
| 71 | COLORS = [ | ||
| 72 | # This needs to be in order from highest logging level to lowest. | ||
| 73 | (logging.ERROR, _color_wrap(colorama.Fore.RED)), | ||
| 74 | (logging.WARNING, _color_wrap(colorama.Fore.YELLOW)), | ||
| 75 | ] | ||
| 76 | else: | ||
| 77 | COLORS = [] | ||
| 78 | |||
| 79 | def __init__(self, stream=None, no_color=None): | ||
| 80 | logging.StreamHandler.__init__(self, stream) | ||
| 81 | self._no_color = no_color | ||
| 82 | |||
| 83 | if WINDOWS and colorama: | ||
| 84 | self.stream = colorama.AnsiToWin32(self.stream) | ||
| 85 | |||
| 86 | def should_color(self): | ||
| 87 | # Don't colorize things if we do not have colorama or if told not to | ||
| 88 | if not colorama or self._no_color: | ||
| 89 | return False | ||
| 90 | |||
| 91 | real_stream = ( | ||
| 92 | self.stream if not isinstance(self.stream, colorama.AnsiToWin32) | ||
| 93 | else self.stream.wrapped | ||
| 94 | ) | ||
| 95 | |||
| 96 | # If the stream is a tty we should color it | ||
| 97 | if hasattr(real_stream, "isatty") and real_stream.isatty(): | ||
| 98 | return True | ||
| 99 | |||
| 100 | # If we have an ASNI term we should color it | ||
| 101 | if os.environ.get("TERM") == "ANSI": | ||
| 102 | return True | ||
| 103 | |||
| 104 | # If anything else we should not color it | ||
| 105 | return False | ||
| 106 | |||
| 107 | def format(self, record): | ||
| 108 | msg = logging.StreamHandler.format(self, record) | ||
| 109 | |||
| 110 | if self.should_color(): | ||
| 111 | for level, color in self.COLORS: | ||
| 112 | if record.levelno >= level: | ||
| 113 | msg = color(msg) | ||
| 114 | break | ||
| 115 | |||
| 116 | return msg | ||
| 117 | |||
| 118 | |||
| 119 | class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): | ||
| 120 | |||
| 121 | def _open(self): | ||
| 122 | ensure_dir(os.path.dirname(self.baseFilename)) | ||
| 123 | return logging.handlers.RotatingFileHandler._open(self) | ||
| 124 | |||
| 125 | |||
| 126 | class MaxLevelFilter(logging.Filter): | ||
| 127 | |||
| 128 | def __init__(self, level): | ||
| 129 | self.level = level | ||
| 130 | |||
| 131 | def filter(self, record): | ||
| 132 | return record.levelno < self.level | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/misc.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/misc.py deleted file mode 100644 index db84a7c..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/misc.py +++ /dev/null | |||
| @@ -1,851 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import contextlib | ||
| 4 | import errno | ||
| 5 | import io | ||
| 6 | import locale | ||
| 7 | # we have a submodule named 'logging' which would shadow this if we used the | ||
| 8 | # regular name: | ||
| 9 | import logging as std_logging | ||
| 10 | import os | ||
| 11 | import posixpath | ||
| 12 | import re | ||
| 13 | import shutil | ||
| 14 | import stat | ||
| 15 | import subprocess | ||
| 16 | import sys | ||
| 17 | import tarfile | ||
| 18 | import zipfile | ||
| 19 | from collections import deque | ||
| 20 | |||
| 21 | from pip._vendor import pkg_resources | ||
| 22 | # NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is | ||
| 23 | # why we ignore the type on this import. | ||
| 24 | from pip._vendor.retrying import retry # type: ignore | ||
| 25 | from pip._vendor.six import PY2 | ||
| 26 | from pip._vendor.six.moves import input | ||
| 27 | |||
| 28 | from pip._internal.compat import console_to_str, expanduser, stdlib_pkgs | ||
| 29 | from pip._internal.exceptions import InstallationError | ||
| 30 | from pip._internal.locations import ( | ||
| 31 | running_under_virtualenv, site_packages, user_site, virtualenv_no_global, | ||
| 32 | write_delete_marker_file, | ||
| 33 | ) | ||
| 34 | |||
| 35 | if PY2: | ||
| 36 | from io import BytesIO as StringIO | ||
| 37 | else: | ||
| 38 | from io import StringIO | ||
| 39 | |||
| 40 | __all__ = ['rmtree', 'display_path', 'backup_dir', | ||
| 41 | 'ask', 'splitext', | ||
| 42 | 'format_size', 'is_installable_dir', | ||
| 43 | 'is_svn_page', 'file_contents', | ||
| 44 | 'split_leading_dir', 'has_leading_dir', | ||
| 45 | 'normalize_path', | ||
| 46 | 'renames', 'get_prog', | ||
| 47 | 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess', | ||
| 48 | 'captured_stdout', 'ensure_dir', | ||
| 49 | 'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS', | ||
| 50 | 'get_installed_version'] | ||
| 51 | |||
| 52 | |||
| 53 | logger = std_logging.getLogger(__name__) | ||
| 54 | |||
| 55 | BZ2_EXTENSIONS = ('.tar.bz2', '.tbz') | ||
| 56 | XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', '.tar.lz', '.tar.lzma') | ||
| 57 | ZIP_EXTENSIONS = ('.zip', '.whl') | ||
| 58 | TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar') | ||
| 59 | ARCHIVE_EXTENSIONS = ( | ||
| 60 | ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS) | ||
| 61 | SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS | ||
| 62 | try: | ||
| 63 | import bz2 # noqa | ||
| 64 | SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS | ||
| 65 | except ImportError: | ||
| 66 | logger.debug('bz2 module is not available') | ||
| 67 | |||
| 68 | try: | ||
| 69 | # Only for Python 3.3+ | ||
| 70 | import lzma # noqa | ||
| 71 | SUPPORTED_EXTENSIONS += XZ_EXTENSIONS | ||
| 72 | except ImportError: | ||
| 73 | logger.debug('lzma module is not available') | ||
| 74 | |||
| 75 | |||
| 76 | def import_or_raise(pkg_or_module_string, ExceptionType, *args, **kwargs): | ||
| 77 | try: | ||
| 78 | return __import__(pkg_or_module_string) | ||
| 79 | except ImportError: | ||
| 80 | raise ExceptionType(*args, **kwargs) | ||
| 81 | |||
| 82 | |||
| 83 | def ensure_dir(path): | ||
| 84 | """os.path.makedirs without EEXIST.""" | ||
| 85 | try: | ||
| 86 | os.makedirs(path) | ||
| 87 | except OSError as e: | ||
| 88 | if e.errno != errno.EEXIST: | ||
| 89 | raise | ||
| 90 | |||
| 91 | |||
| 92 | def get_prog(): | ||
| 93 | try: | ||
| 94 | prog = os.path.basename(sys.argv[0]) | ||
| 95 | if prog in ('__main__.py', '-c'): | ||
| 96 | return "%s -m pip" % sys.executable | ||
| 97 | else: | ||
| 98 | return prog | ||
| 99 | except (AttributeError, TypeError, IndexError): | ||
| 100 | pass | ||
| 101 | return 'pip' | ||
| 102 | |||
| 103 | |||
| 104 | # Retry every half second for up to 3 seconds | ||
| 105 | @retry(stop_max_delay=3000, wait_fixed=500) | ||
| 106 | def rmtree(dir, ignore_errors=False): | ||
| 107 | shutil.rmtree(dir, ignore_errors=ignore_errors, | ||
| 108 | onerror=rmtree_errorhandler) | ||
| 109 | |||
| 110 | |||
| 111 | def rmtree_errorhandler(func, path, exc_info): | ||
| 112 | """On Windows, the files in .svn are read-only, so when rmtree() tries to | ||
| 113 | remove them, an exception is thrown. We catch that here, remove the | ||
| 114 | read-only attribute, and hopefully continue without problems.""" | ||
| 115 | # if file type currently read only | ||
| 116 | if os.stat(path).st_mode & stat.S_IREAD: | ||
| 117 | # convert to read/write | ||
| 118 | os.chmod(path, stat.S_IWRITE) | ||
| 119 | # use the original function to repeat the operation | ||
| 120 | func(path) | ||
| 121 | return | ||
| 122 | else: | ||
| 123 | raise | ||
| 124 | |||
| 125 | |||
| 126 | def display_path(path): | ||
| 127 | """Gives the display value for a given path, making it relative to cwd | ||
| 128 | if possible.""" | ||
| 129 | path = os.path.normcase(os.path.abspath(path)) | ||
| 130 | if sys.version_info[0] == 2: | ||
| 131 | path = path.decode(sys.getfilesystemencoding(), 'replace') | ||
| 132 | path = path.encode(sys.getdefaultencoding(), 'replace') | ||
| 133 | if path.startswith(os.getcwd() + os.path.sep): | ||
| 134 | path = '.' + path[len(os.getcwd()):] | ||
| 135 | return path | ||
| 136 | |||
| 137 | |||
| 138 | def backup_dir(dir, ext='.bak'): | ||
| 139 | """Figure out the name of a directory to back up the given dir to | ||
| 140 | (adding .bak, .bak2, etc)""" | ||
| 141 | n = 1 | ||
| 142 | extension = ext | ||
| 143 | while os.path.exists(dir + extension): | ||
| 144 | n += 1 | ||
| 145 | extension = ext + str(n) | ||
| 146 | return dir + extension | ||
| 147 | |||
| 148 | |||
| 149 | def ask_path_exists(message, options): | ||
| 150 | for action in os.environ.get('PIP_EXISTS_ACTION', '').split(): | ||
| 151 | if action in options: | ||
| 152 | return action | ||
| 153 | return ask(message, options) | ||
| 154 | |||
| 155 | |||
| 156 | def ask(message, options): | ||
| 157 | """Ask the message interactively, with the given possible responses""" | ||
| 158 | while 1: | ||
| 159 | if os.environ.get('PIP_NO_INPUT'): | ||
| 160 | raise Exception( | ||
| 161 | 'No input was expected ($PIP_NO_INPUT set); question: %s' % | ||
| 162 | message | ||
| 163 | ) | ||
| 164 | response = input(message) | ||
| 165 | response = response.strip().lower() | ||
| 166 | if response not in options: | ||
| 167 | print( | ||
| 168 | 'Your response (%r) was not one of the expected responses: ' | ||
| 169 | '%s' % (response, ', '.join(options)) | ||
| 170 | ) | ||
| 171 | else: | ||
| 172 | return response | ||
| 173 | |||
| 174 | |||
| 175 | def format_size(bytes): | ||
| 176 | if bytes > 1000 * 1000: | ||
| 177 | return '%.1fMB' % (bytes / 1000.0 / 1000) | ||
| 178 | elif bytes > 10 * 1000: | ||
| 179 | return '%ikB' % (bytes / 1000) | ||
| 180 | elif bytes > 1000: | ||
| 181 | return '%.1fkB' % (bytes / 1000.0) | ||
| 182 | else: | ||
| 183 | return '%ibytes' % bytes | ||
| 184 | |||
| 185 | |||
| 186 | def is_installable_dir(path): | ||
| 187 | """Return True if `path` is a directory containing a setup.py file.""" | ||
| 188 | if not os.path.isdir(path): | ||
| 189 | return False | ||
| 190 | setup_py = os.path.join(path, 'setup.py') | ||
| 191 | if os.path.isfile(setup_py): | ||
| 192 | return True | ||
| 193 | return False | ||
| 194 | |||
| 195 | |||
| 196 | def is_svn_page(html): | ||
| 197 | """ | ||
| 198 | Returns true if the page appears to be the index page of an svn repository | ||
| 199 | """ | ||
| 200 | return (re.search(r'<title>[^<]*Revision \d+:', html) and | ||
| 201 | re.search(r'Powered by (?:<a[^>]*?>)?Subversion', html, re.I)) | ||
| 202 | |||
| 203 | |||
| 204 | def file_contents(filename): | ||
| 205 | with open(filename, 'rb') as fp: | ||
| 206 | return fp.read().decode('utf-8') | ||
| 207 | |||
| 208 | |||
| 209 | def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE): | ||
| 210 | """Yield pieces of data from a file-like object until EOF.""" | ||
| 211 | while True: | ||
| 212 | chunk = file.read(size) | ||
| 213 | if not chunk: | ||
| 214 | break | ||
| 215 | yield chunk | ||
| 216 | |||
| 217 | |||
| 218 | def split_leading_dir(path): | ||
| 219 | path = path.lstrip('/').lstrip('\\') | ||
| 220 | if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) or | ||
| 221 | '\\' not in path): | ||
| 222 | return path.split('/', 1) | ||
| 223 | elif '\\' in path: | ||
| 224 | return path.split('\\', 1) | ||
| 225 | else: | ||
| 226 | return path, '' | ||
| 227 | |||
| 228 | |||
| 229 | def has_leading_dir(paths): | ||
| 230 | """Returns true if all the paths have the same leading path name | ||
| 231 | (i.e., everything is in one subdirectory in an archive)""" | ||
| 232 | common_prefix = None | ||
| 233 | for path in paths: | ||
| 234 | prefix, rest = split_leading_dir(path) | ||
| 235 | if not prefix: | ||
| 236 | return False | ||
| 237 | elif common_prefix is None: | ||
| 238 | common_prefix = prefix | ||
| 239 | elif prefix != common_prefix: | ||
| 240 | return False | ||
| 241 | return True | ||
| 242 | |||
| 243 | |||
| 244 | def normalize_path(path, resolve_symlinks=True): | ||
| 245 | """ | ||
| 246 | Convert a path to its canonical, case-normalized, absolute version. | ||
| 247 | |||
| 248 | """ | ||
| 249 | path = expanduser(path) | ||
| 250 | if resolve_symlinks: | ||
| 251 | path = os.path.realpath(path) | ||
| 252 | else: | ||
| 253 | path = os.path.abspath(path) | ||
| 254 | return os.path.normcase(path) | ||
| 255 | |||
| 256 | |||
| 257 | def splitext(path): | ||
| 258 | """Like os.path.splitext, but take off .tar too""" | ||
| 259 | base, ext = posixpath.splitext(path) | ||
| 260 | if base.lower().endswith('.tar'): | ||
| 261 | ext = base[-4:] + ext | ||
| 262 | base = base[:-4] | ||
| 263 | return base, ext | ||
| 264 | |||
| 265 | |||
| 266 | def renames(old, new): | ||
| 267 | """Like os.renames(), but handles renaming across devices.""" | ||
| 268 | # Implementation borrowed from os.renames(). | ||
| 269 | head, tail = os.path.split(new) | ||
| 270 | if head and tail and not os.path.exists(head): | ||
| 271 | os.makedirs(head) | ||
| 272 | |||
| 273 | shutil.move(old, new) | ||
| 274 | |||
| 275 | head, tail = os.path.split(old) | ||
| 276 | if head and tail: | ||
| 277 | try: | ||
| 278 | os.removedirs(head) | ||
| 279 | except OSError: | ||
| 280 | pass | ||
| 281 | |||
| 282 | |||
| 283 | def is_local(path): | ||
| 284 | """ | ||
| 285 | Return True if path is within sys.prefix, if we're running in a virtualenv. | ||
| 286 | |||
| 287 | If we're not in a virtualenv, all paths are considered "local." | ||
| 288 | |||
| 289 | """ | ||
| 290 | if not running_under_virtualenv(): | ||
| 291 | return True | ||
| 292 | return normalize_path(path).startswith(normalize_path(sys.prefix)) | ||
| 293 | |||
| 294 | |||
| 295 | def dist_is_local(dist): | ||
| 296 | """ | ||
| 297 | Return True if given Distribution object is installed locally | ||
| 298 | (i.e. within current virtualenv). | ||
| 299 | |||
| 300 | Always True if we're not in a virtualenv. | ||
| 301 | |||
| 302 | """ | ||
| 303 | return is_local(dist_location(dist)) | ||
| 304 | |||
| 305 | |||
| 306 | def dist_in_usersite(dist): | ||
| 307 | """ | ||
| 308 | Return True if given Distribution is installed in user site. | ||
| 309 | """ | ||
| 310 | norm_path = normalize_path(dist_location(dist)) | ||
| 311 | return norm_path.startswith(normalize_path(user_site)) | ||
| 312 | |||
| 313 | |||
| 314 | def dist_in_site_packages(dist): | ||
| 315 | """ | ||
| 316 | Return True if given Distribution is installed in | ||
| 317 | sysconfig.get_python_lib(). | ||
| 318 | """ | ||
| 319 | return normalize_path( | ||
| 320 | dist_location(dist) | ||
| 321 | ).startswith(normalize_path(site_packages)) | ||
| 322 | |||
| 323 | |||
| 324 | def dist_is_editable(dist): | ||
| 325 | """Is distribution an editable install?""" | ||
| 326 | for path_item in sys.path: | ||
| 327 | egg_link = os.path.join(path_item, dist.project_name + '.egg-link') | ||
| 328 | if os.path.isfile(egg_link): | ||
| 329 | return True | ||
| 330 | return False | ||
| 331 | |||
| 332 | |||
| 333 | def get_installed_distributions(local_only=True, | ||
| 334 | skip=stdlib_pkgs, | ||
| 335 | include_editables=True, | ||
| 336 | editables_only=False, | ||
| 337 | user_only=False): | ||
| 338 | """ | ||
| 339 | Return a list of installed Distribution objects. | ||
| 340 | |||
| 341 | If ``local_only`` is True (default), only return installations | ||
| 342 | local to the current virtualenv, if in a virtualenv. | ||
| 343 | |||
| 344 | ``skip`` argument is an iterable of lower-case project names to | ||
| 345 | ignore; defaults to stdlib_pkgs | ||
| 346 | |||
| 347 | If ``include_editables`` is False, don't report editables. | ||
| 348 | |||
| 349 | If ``editables_only`` is True , only report editables. | ||
| 350 | |||
| 351 | If ``user_only`` is True , only report installations in the user | ||
| 352 | site directory. | ||
| 353 | |||
| 354 | """ | ||
| 355 | if local_only: | ||
| 356 | local_test = dist_is_local | ||
| 357 | else: | ||
| 358 | def local_test(d): | ||
| 359 | return True | ||
| 360 | |||
| 361 | if include_editables: | ||
| 362 | def editable_test(d): | ||
| 363 | return True | ||
| 364 | else: | ||
| 365 | def editable_test(d): | ||
| 366 | return not dist_is_editable(d) | ||
| 367 | |||
| 368 | if editables_only: | ||
| 369 | def editables_only_test(d): | ||
| 370 | return dist_is_editable(d) | ||
| 371 | else: | ||
| 372 | def editables_only_test(d): | ||
| 373 | return True | ||
| 374 | |||
| 375 | if user_only: | ||
| 376 | user_test = dist_in_usersite | ||
| 377 | else: | ||
| 378 | def user_test(d): | ||
| 379 | return True | ||
| 380 | |||
| 381 | return [d for d in pkg_resources.working_set | ||
| 382 | if local_test(d) and | ||
| 383 | d.key not in skip and | ||
| 384 | editable_test(d) and | ||
| 385 | editables_only_test(d) and | ||
| 386 | user_test(d) | ||
| 387 | ] | ||
| 388 | |||
| 389 | |||
| 390 | def egg_link_path(dist): | ||
| 391 | """ | ||
| 392 | Return the path for the .egg-link file if it exists, otherwise, None. | ||
| 393 | |||
| 394 | There's 3 scenarios: | ||
| 395 | 1) not in a virtualenv | ||
| 396 | try to find in site.USER_SITE, then site_packages | ||
| 397 | 2) in a no-global virtualenv | ||
| 398 | try to find in site_packages | ||
| 399 | 3) in a yes-global virtualenv | ||
| 400 | try to find in site_packages, then site.USER_SITE | ||
| 401 | (don't look in global location) | ||
| 402 | |||
| 403 | For #1 and #3, there could be odd cases, where there's an egg-link in 2 | ||
| 404 | locations. | ||
| 405 | |||
| 406 | This method will just return the first one found. | ||
| 407 | """ | ||
| 408 | sites = [] | ||
| 409 | if running_under_virtualenv(): | ||
| 410 | if virtualenv_no_global(): | ||
| 411 | sites.append(site_packages) | ||
| 412 | else: | ||
| 413 | sites.append(site_packages) | ||
| 414 | if user_site: | ||
| 415 | sites.append(user_site) | ||
| 416 | else: | ||
| 417 | if user_site: | ||
| 418 | sites.append(user_site) | ||
| 419 | sites.append(site_packages) | ||
| 420 | |||
| 421 | for site in sites: | ||
| 422 | egglink = os.path.join(site, dist.project_name) + '.egg-link' | ||
| 423 | if os.path.isfile(egglink): | ||
| 424 | return egglink | ||
| 425 | |||
| 426 | |||
| 427 | def dist_location(dist): | ||
| 428 | """ | ||
| 429 | Get the site-packages location of this distribution. Generally | ||
| 430 | this is dist.location, except in the case of develop-installed | ||
| 431 | packages, where dist.location is the source code location, and we | ||
| 432 | want to know where the egg-link file is. | ||
| 433 | |||
| 434 | """ | ||
| 435 | egg_link = egg_link_path(dist) | ||
| 436 | if egg_link: | ||
| 437 | return egg_link | ||
| 438 | return dist.location | ||
| 439 | |||
| 440 | |||
| 441 | def current_umask(): | ||
| 442 | """Get the current umask which involves having to set it temporarily.""" | ||
| 443 | mask = os.umask(0) | ||
| 444 | os.umask(mask) | ||
| 445 | return mask | ||
| 446 | |||
| 447 | |||
| 448 | def unzip_file(filename, location, flatten=True): | ||
| 449 | """ | ||
| 450 | Unzip the file (with path `filename`) to the destination `location`. All | ||
| 451 | files are written based on system defaults and umask (i.e. permissions are | ||
| 452 | not preserved), except that regular file members with any execute | ||
| 453 | permissions (user, group, or world) have "chmod +x" applied after being | ||
| 454 | written. Note that for windows, any execute changes using os.chmod are | ||
| 455 | no-ops per the python docs. | ||
| 456 | """ | ||
| 457 | ensure_dir(location) | ||
| 458 | zipfp = open(filename, 'rb') | ||
| 459 | try: | ||
| 460 | zip = zipfile.ZipFile(zipfp, allowZip64=True) | ||
| 461 | leading = has_leading_dir(zip.namelist()) and flatten | ||
| 462 | for info in zip.infolist(): | ||
| 463 | name = info.filename | ||
| 464 | data = zip.read(name) | ||
| 465 | fn = name | ||
| 466 | if leading: | ||
| 467 | fn = split_leading_dir(name)[1] | ||
| 468 | fn = os.path.join(location, fn) | ||
| 469 | dir = os.path.dirname(fn) | ||
| 470 | if fn.endswith('/') or fn.endswith('\\'): | ||
| 471 | # A directory | ||
| 472 | ensure_dir(fn) | ||
| 473 | else: | ||
| 474 | ensure_dir(dir) | ||
| 475 | fp = open(fn, 'wb') | ||
| 476 | try: | ||
| 477 | fp.write(data) | ||
| 478 | finally: | ||
| 479 | fp.close() | ||
| 480 | mode = info.external_attr >> 16 | ||
| 481 | # if mode and regular file and any execute permissions for | ||
| 482 | # user/group/world? | ||
| 483 | if mode and stat.S_ISREG(mode) and mode & 0o111: | ||
| 484 | # make dest file have execute for user/group/world | ||
| 485 | # (chmod +x) no-op on windows per python docs | ||
| 486 | os.chmod(fn, (0o777 - current_umask() | 0o111)) | ||
| 487 | finally: | ||
| 488 | zipfp.close() | ||
| 489 | |||
| 490 | |||
| 491 | def untar_file(filename, location): | ||
| 492 | """ | ||
| 493 | Untar the file (with path `filename`) to the destination `location`. | ||
| 494 | All files are written based on system defaults and umask (i.e. permissions | ||
| 495 | are not preserved), except that regular file members with any execute | ||
| 496 | permissions (user, group, or world) have "chmod +x" applied after being | ||
| 497 | written. Note that for windows, any execute changes using os.chmod are | ||
| 498 | no-ops per the python docs. | ||
| 499 | """ | ||
| 500 | ensure_dir(location) | ||
| 501 | if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): | ||
| 502 | mode = 'r:gz' | ||
| 503 | elif filename.lower().endswith(BZ2_EXTENSIONS): | ||
| 504 | mode = 'r:bz2' | ||
| 505 | elif filename.lower().endswith(XZ_EXTENSIONS): | ||
| 506 | mode = 'r:xz' | ||
| 507 | elif filename.lower().endswith('.tar'): | ||
| 508 | mode = 'r' | ||
| 509 | else: | ||
| 510 | logger.warning( | ||
| 511 | 'Cannot determine compression type for file %s', filename, | ||
| 512 | ) | ||
| 513 | mode = 'r:*' | ||
| 514 | tar = tarfile.open(filename, mode) | ||
| 515 | try: | ||
| 516 | # note: python<=2.5 doesn't seem to know about pax headers, filter them | ||
| 517 | leading = has_leading_dir([ | ||
| 518 | member.name for member in tar.getmembers() | ||
| 519 | if member.name != 'pax_global_header' | ||
| 520 | ]) | ||
| 521 | for member in tar.getmembers(): | ||
| 522 | fn = member.name | ||
| 523 | if fn == 'pax_global_header': | ||
| 524 | continue | ||
| 525 | if leading: | ||
| 526 | fn = split_leading_dir(fn)[1] | ||
| 527 | path = os.path.join(location, fn) | ||
| 528 | if member.isdir(): | ||
| 529 | ensure_dir(path) | ||
| 530 | elif member.issym(): | ||
| 531 | try: | ||
| 532 | tar._extract_member(member, path) | ||
| 533 | except Exception as exc: | ||
| 534 | # Some corrupt tar files seem to produce this | ||
| 535 | # (specifically bad symlinks) | ||
| 536 | logger.warning( | ||
| 537 | 'In the tar file %s the member %s is invalid: %s', | ||
| 538 | filename, member.name, exc, | ||
| 539 | ) | ||
| 540 | continue | ||
| 541 | else: | ||
| 542 | try: | ||
| 543 | fp = tar.extractfile(member) | ||
| 544 | except (KeyError, AttributeError) as exc: | ||
| 545 | # Some corrupt tar files seem to produce this | ||
| 546 | # (specifically bad symlinks) | ||
| 547 | logger.warning( | ||
| 548 | 'In the tar file %s the member %s is invalid: %s', | ||
| 549 | filename, member.name, exc, | ||
| 550 | ) | ||
| 551 | continue | ||
| 552 | ensure_dir(os.path.dirname(path)) | ||
| 553 | with open(path, 'wb') as destfp: | ||
| 554 | shutil.copyfileobj(fp, destfp) | ||
| 555 | fp.close() | ||
| 556 | # Update the timestamp (useful for cython compiled files) | ||
| 557 | tar.utime(member, path) | ||
| 558 | # member have any execute permissions for user/group/world? | ||
| 559 | if member.mode & 0o111: | ||
| 560 | # make dest file have execute for user/group/world | ||
| 561 | # no-op on windows per python docs | ||
| 562 | os.chmod(path, (0o777 - current_umask() | 0o111)) | ||
| 563 | finally: | ||
| 564 | tar.close() | ||
| 565 | |||
| 566 | |||
| 567 | def unpack_file(filename, location, content_type, link): | ||
| 568 | filename = os.path.realpath(filename) | ||
| 569 | if (content_type == 'application/zip' or | ||
| 570 | filename.lower().endswith(ZIP_EXTENSIONS) or | ||
| 571 | zipfile.is_zipfile(filename)): | ||
| 572 | unzip_file( | ||
| 573 | filename, | ||
| 574 | location, | ||
| 575 | flatten=not filename.endswith('.whl') | ||
| 576 | ) | ||
| 577 | elif (content_type == 'application/x-gzip' or | ||
| 578 | tarfile.is_tarfile(filename) or | ||
| 579 | filename.lower().endswith( | ||
| 580 | TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS)): | ||
| 581 | untar_file(filename, location) | ||
| 582 | elif (content_type and content_type.startswith('text/html') and | ||
| 583 | is_svn_page(file_contents(filename))): | ||
| 584 | # We don't really care about this | ||
| 585 | from pip._internal.vcs.subversion import Subversion | ||
| 586 | Subversion('svn+' + link.url).unpack(location) | ||
| 587 | else: | ||
| 588 | # FIXME: handle? | ||
| 589 | # FIXME: magic signatures? | ||
| 590 | logger.critical( | ||
| 591 | 'Cannot unpack file %s (downloaded from %s, content-type: %s); ' | ||
| 592 | 'cannot detect archive format', | ||
| 593 | filename, location, content_type, | ||
| 594 | ) | ||
| 595 | raise InstallationError( | ||
| 596 | 'Cannot determine archive format of %s' % location | ||
| 597 | ) | ||
| 598 | |||
| 599 | |||
| 600 | def call_subprocess(cmd, show_stdout=True, cwd=None, | ||
| 601 | on_returncode='raise', | ||
| 602 | command_desc=None, | ||
| 603 | extra_environ=None, unset_environ=None, spinner=None): | ||
| 604 | """ | ||
| 605 | Args: | ||
| 606 | unset_environ: an iterable of environment variable names to unset | ||
| 607 | prior to calling subprocess.Popen(). | ||
| 608 | """ | ||
| 609 | if unset_environ is None: | ||
| 610 | unset_environ = [] | ||
| 611 | # This function's handling of subprocess output is confusing and I | ||
| 612 | # previously broke it terribly, so as penance I will write a long comment | ||
| 613 | # explaining things. | ||
| 614 | # | ||
| 615 | # The obvious thing that affects output is the show_stdout= | ||
| 616 | # kwarg. show_stdout=True means, let the subprocess write directly to our | ||
| 617 | # stdout. Even though it is nominally the default, it is almost never used | ||
| 618 | # inside pip (and should not be used in new code without a very good | ||
| 619 | # reason); as of 2016-02-22 it is only used in a few places inside the VCS | ||
| 620 | # wrapper code. Ideally we should get rid of it entirely, because it | ||
| 621 | # creates a lot of complexity here for a rarely used feature. | ||
| 622 | # | ||
| 623 | # Most places in pip set show_stdout=False. What this means is: | ||
| 624 | # - We connect the child stdout to a pipe, which we read. | ||
| 625 | # - By default, we hide the output but show a spinner -- unless the | ||
| 626 | # subprocess exits with an error, in which case we show the output. | ||
| 627 | # - If the --verbose option was passed (= loglevel is DEBUG), then we show | ||
| 628 | # the output unconditionally. (But in this case we don't want to show | ||
| 629 | # the output a second time if it turns out that there was an error.) | ||
| 630 | # | ||
| 631 | # stderr is always merged with stdout (even if show_stdout=True). | ||
| 632 | if show_stdout: | ||
| 633 | stdout = None | ||
| 634 | else: | ||
| 635 | stdout = subprocess.PIPE | ||
| 636 | if command_desc is None: | ||
| 637 | cmd_parts = [] | ||
| 638 | for part in cmd: | ||
| 639 | if ' ' in part or '\n' in part or '"' in part or "'" in part: | ||
| 640 | part = '"%s"' % part.replace('"', '\\"') | ||
| 641 | cmd_parts.append(part) | ||
| 642 | command_desc = ' '.join(cmd_parts) | ||
| 643 | logger.debug("Running command %s", command_desc) | ||
| 644 | env = os.environ.copy() | ||
| 645 | if extra_environ: | ||
| 646 | env.update(extra_environ) | ||
| 647 | for name in unset_environ: | ||
| 648 | env.pop(name, None) | ||
| 649 | try: | ||
| 650 | proc = subprocess.Popen( | ||
| 651 | cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, | ||
| 652 | stdout=stdout, cwd=cwd, env=env, | ||
| 653 | ) | ||
| 654 | proc.stdin.close() | ||
| 655 | except Exception as exc: | ||
| 656 | logger.critical( | ||
| 657 | "Error %s while executing command %s", exc, command_desc, | ||
| 658 | ) | ||
| 659 | raise | ||
| 660 | all_output = [] | ||
| 661 | if stdout is not None: | ||
| 662 | while True: | ||
| 663 | line = console_to_str(proc.stdout.readline()) | ||
| 664 | if not line: | ||
| 665 | break | ||
| 666 | line = line.rstrip() | ||
| 667 | all_output.append(line + '\n') | ||
| 668 | if logger.getEffectiveLevel() <= std_logging.DEBUG: | ||
| 669 | # Show the line immediately | ||
| 670 | logger.debug(line) | ||
| 671 | else: | ||
| 672 | # Update the spinner | ||
| 673 | if spinner is not None: | ||
| 674 | spinner.spin() | ||
| 675 | try: | ||
| 676 | proc.wait() | ||
| 677 | finally: | ||
| 678 | if proc.stdout: | ||
| 679 | proc.stdout.close() | ||
| 680 | if spinner is not None: | ||
| 681 | if proc.returncode: | ||
| 682 | spinner.finish("error") | ||
| 683 | else: | ||
| 684 | spinner.finish("done") | ||
| 685 | if proc.returncode: | ||
| 686 | if on_returncode == 'raise': | ||
| 687 | if (logger.getEffectiveLevel() > std_logging.DEBUG and | ||
| 688 | not show_stdout): | ||
| 689 | logger.info( | ||
| 690 | 'Complete output from command %s:', command_desc, | ||
| 691 | ) | ||
| 692 | logger.info( | ||
| 693 | ''.join(all_output) + | ||
| 694 | '\n----------------------------------------' | ||
| 695 | ) | ||
| 696 | raise InstallationError( | ||
| 697 | 'Command "%s" failed with error code %s in %s' | ||
| 698 | % (command_desc, proc.returncode, cwd)) | ||
| 699 | elif on_returncode == 'warn': | ||
| 700 | logger.warning( | ||
| 701 | 'Command "%s" had error code %s in %s', | ||
| 702 | command_desc, proc.returncode, cwd, | ||
| 703 | ) | ||
| 704 | elif on_returncode == 'ignore': | ||
| 705 | pass | ||
| 706 | else: | ||
| 707 | raise ValueError('Invalid value: on_returncode=%s' % | ||
| 708 | repr(on_returncode)) | ||
| 709 | if not show_stdout: | ||
| 710 | return ''.join(all_output) | ||
| 711 | |||
| 712 | |||
| 713 | def read_text_file(filename): | ||
| 714 | """Return the contents of *filename*. | ||
| 715 | |||
| 716 | Try to decode the file contents with utf-8, the preferred system encoding | ||
| 717 | (e.g., cp1252 on some Windows machines), and latin1, in that order. | ||
| 718 | Decoding a byte string with latin1 will never raise an error. In the worst | ||
| 719 | case, the returned string will contain some garbage characters. | ||
| 720 | |||
| 721 | """ | ||
| 722 | with open(filename, 'rb') as fp: | ||
| 723 | data = fp.read() | ||
| 724 | |||
| 725 | encodings = ['utf-8', locale.getpreferredencoding(False), 'latin1'] | ||
| 726 | for enc in encodings: | ||
| 727 | try: | ||
| 728 | data = data.decode(enc) | ||
| 729 | except UnicodeDecodeError: | ||
| 730 | continue | ||
| 731 | break | ||
| 732 | |||
| 733 | assert type(data) != bytes # Latin1 should have worked. | ||
| 734 | return data | ||
| 735 | |||
| 736 | |||
| 737 | def _make_build_dir(build_dir): | ||
| 738 | os.makedirs(build_dir) | ||
| 739 | write_delete_marker_file(build_dir) | ||
| 740 | |||
| 741 | |||
| 742 | class FakeFile(object): | ||
| 743 | """Wrap a list of lines in an object with readline() to make | ||
| 744 | ConfigParser happy.""" | ||
| 745 | def __init__(self, lines): | ||
| 746 | self._gen = (l for l in lines) | ||
| 747 | |||
| 748 | def readline(self): | ||
| 749 | try: | ||
| 750 | try: | ||
| 751 | return next(self._gen) | ||
| 752 | except NameError: | ||
| 753 | return self._gen.next() | ||
| 754 | except StopIteration: | ||
| 755 | return '' | ||
| 756 | |||
| 757 | def __iter__(self): | ||
| 758 | return self._gen | ||
| 759 | |||
| 760 | |||
| 761 | class StreamWrapper(StringIO): | ||
| 762 | |||
| 763 | @classmethod | ||
| 764 | def from_stream(cls, orig_stream): | ||
| 765 | cls.orig_stream = orig_stream | ||
| 766 | return cls() | ||
| 767 | |||
| 768 | # compileall.compile_dir() needs stdout.encoding to print to stdout | ||
| 769 | @property | ||
| 770 | def encoding(self): | ||
| 771 | return self.orig_stream.encoding | ||
| 772 | |||
| 773 | |||
| 774 | @contextlib.contextmanager | ||
| 775 | def captured_output(stream_name): | ||
| 776 | """Return a context manager used by captured_stdout/stdin/stderr | ||
| 777 | that temporarily replaces the sys stream *stream_name* with a StringIO. | ||
| 778 | |||
| 779 | Taken from Lib/support/__init__.py in the CPython repo. | ||
| 780 | """ | ||
| 781 | orig_stdout = getattr(sys, stream_name) | ||
| 782 | setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout)) | ||
| 783 | try: | ||
| 784 | yield getattr(sys, stream_name) | ||
| 785 | finally: | ||
| 786 | setattr(sys, stream_name, orig_stdout) | ||
| 787 | |||
| 788 | |||
| 789 | def captured_stdout(): | ||
| 790 | """Capture the output of sys.stdout: | ||
| 791 | |||
| 792 | with captured_stdout() as stdout: | ||
| 793 | print('hello') | ||
| 794 | self.assertEqual(stdout.getvalue(), 'hello\n') | ||
| 795 | |||
| 796 | Taken from Lib/support/__init__.py in the CPython repo. | ||
| 797 | """ | ||
| 798 | return captured_output('stdout') | ||
| 799 | |||
| 800 | |||
| 801 | class cached_property(object): | ||
| 802 | """A property that is only computed once per instance and then replaces | ||
| 803 | itself with an ordinary attribute. Deleting the attribute resets the | ||
| 804 | property. | ||
| 805 | |||
| 806 | Source: https://github.com/bottlepy/bottle/blob/0.11.5/bottle.py#L175 | ||
| 807 | """ | ||
| 808 | |||
| 809 | def __init__(self, func): | ||
| 810 | self.__doc__ = getattr(func, '__doc__') | ||
| 811 | self.func = func | ||
| 812 | |||
| 813 | def __get__(self, obj, cls): | ||
| 814 | if obj is None: | ||
| 815 | # We're being accessed from the class itself, not from an object | ||
| 816 | return self | ||
| 817 | value = obj.__dict__[self.func.__name__] = self.func(obj) | ||
| 818 | return value | ||
| 819 | |||
| 820 | |||
| 821 | def get_installed_version(dist_name, lookup_dirs=None): | ||
| 822 | """Get the installed version of dist_name avoiding pkg_resources cache""" | ||
| 823 | # Create a requirement that we'll look for inside of setuptools. | ||
| 824 | req = pkg_resources.Requirement.parse(dist_name) | ||
| 825 | |||
| 826 | # We want to avoid having this cached, so we need to construct a new | ||
| 827 | # working set each time. | ||
| 828 | if lookup_dirs is None: | ||
| 829 | working_set = pkg_resources.WorkingSet() | ||
| 830 | else: | ||
| 831 | working_set = pkg_resources.WorkingSet(lookup_dirs) | ||
| 832 | |||
| 833 | # Get the installed distribution from our working set | ||
| 834 | dist = working_set.find(req) | ||
| 835 | |||
| 836 | # Check to see if we got an installed distribution or not, if we did | ||
| 837 | # we want to return it's version. | ||
| 838 | return dist.version if dist else None | ||
| 839 | |||
| 840 | |||
| 841 | def consume(iterator): | ||
| 842 | """Consume an iterable at C speed.""" | ||
| 843 | deque(iterator, maxlen=0) | ||
| 844 | |||
| 845 | |||
| 846 | # Simulates an enum | ||
| 847 | def enum(*sequential, **named): | ||
| 848 | enums = dict(zip(sequential, range(len(sequential))), **named) | ||
| 849 | reverse = {value: key for key, value in enums.items()} | ||
| 850 | enums['reverse_mapping'] = reverse | ||
| 851 | return type('Enum', (), enums) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/outdated.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/outdated.py deleted file mode 100644 index f4572ab..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/outdated.py +++ /dev/null | |||
| @@ -1,163 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import datetime | ||
| 4 | import json | ||
| 5 | import logging | ||
| 6 | import os.path | ||
| 7 | import sys | ||
| 8 | |||
| 9 | from pip._vendor import lockfile | ||
| 10 | from pip._vendor.packaging import version as packaging_version | ||
| 11 | |||
| 12 | from pip._internal.compat import WINDOWS | ||
| 13 | from pip._internal.index import PackageFinder | ||
| 14 | from pip._internal.locations import USER_CACHE_DIR, running_under_virtualenv | ||
| 15 | from pip._internal.utils.filesystem import check_path_owner | ||
| 16 | from pip._internal.utils.misc import ensure_dir, get_installed_version | ||
| 17 | |||
| 18 | SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" | ||
| 19 | |||
| 20 | |||
| 21 | logger = logging.getLogger(__name__) | ||
| 22 | |||
| 23 | |||
| 24 | class VirtualenvSelfCheckState(object): | ||
| 25 | def __init__(self): | ||
| 26 | self.statefile_path = os.path.join(sys.prefix, "pip-selfcheck.json") | ||
| 27 | |||
| 28 | # Load the existing state | ||
| 29 | try: | ||
| 30 | with open(self.statefile_path) as statefile: | ||
| 31 | self.state = json.load(statefile) | ||
| 32 | except (IOError, ValueError): | ||
| 33 | self.state = {} | ||
| 34 | |||
| 35 | def save(self, pypi_version, current_time): | ||
| 36 | # Attempt to write out our version check file | ||
| 37 | with open(self.statefile_path, "w") as statefile: | ||
| 38 | json.dump( | ||
| 39 | { | ||
| 40 | "last_check": current_time.strftime(SELFCHECK_DATE_FMT), | ||
| 41 | "pypi_version": pypi_version, | ||
| 42 | }, | ||
| 43 | statefile, | ||
| 44 | sort_keys=True, | ||
| 45 | separators=(",", ":") | ||
| 46 | ) | ||
| 47 | |||
| 48 | |||
| 49 | class GlobalSelfCheckState(object): | ||
| 50 | def __init__(self): | ||
| 51 | self.statefile_path = os.path.join(USER_CACHE_DIR, "selfcheck.json") | ||
| 52 | |||
| 53 | # Load the existing state | ||
| 54 | try: | ||
| 55 | with open(self.statefile_path) as statefile: | ||
| 56 | self.state = json.load(statefile)[sys.prefix] | ||
| 57 | except (IOError, ValueError, KeyError): | ||
| 58 | self.state = {} | ||
| 59 | |||
| 60 | def save(self, pypi_version, current_time): | ||
| 61 | # Check to make sure that we own the directory | ||
| 62 | if not check_path_owner(os.path.dirname(self.statefile_path)): | ||
| 63 | return | ||
| 64 | |||
| 65 | # Now that we've ensured the directory is owned by this user, we'll go | ||
| 66 | # ahead and make sure that all our directories are created. | ||
| 67 | ensure_dir(os.path.dirname(self.statefile_path)) | ||
| 68 | |||
| 69 | # Attempt to write out our version check file | ||
| 70 | with lockfile.LockFile(self.statefile_path): | ||
| 71 | if os.path.exists(self.statefile_path): | ||
| 72 | with open(self.statefile_path) as statefile: | ||
| 73 | state = json.load(statefile) | ||
| 74 | else: | ||
| 75 | state = {} | ||
| 76 | |||
| 77 | state[sys.prefix] = { | ||
| 78 | "last_check": current_time.strftime(SELFCHECK_DATE_FMT), | ||
| 79 | "pypi_version": pypi_version, | ||
| 80 | } | ||
| 81 | |||
| 82 | with open(self.statefile_path, "w") as statefile: | ||
| 83 | json.dump(state, statefile, sort_keys=True, | ||
| 84 | separators=(",", ":")) | ||
| 85 | |||
| 86 | |||
| 87 | def load_selfcheck_statefile(): | ||
| 88 | if running_under_virtualenv(): | ||
| 89 | return VirtualenvSelfCheckState() | ||
| 90 | else: | ||
| 91 | return GlobalSelfCheckState() | ||
| 92 | |||
| 93 | |||
| 94 | def pip_version_check(session, options): | ||
| 95 | """Check for an update for pip. | ||
| 96 | |||
| 97 | Limit the frequency of checks to once per week. State is stored either in | ||
| 98 | the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix | ||
| 99 | of the pip script path. | ||
| 100 | """ | ||
| 101 | installed_version = get_installed_version("pip") | ||
| 102 | if not installed_version: | ||
| 103 | return | ||
| 104 | |||
| 105 | pip_version = packaging_version.parse(installed_version) | ||
| 106 | pypi_version = None | ||
| 107 | |||
| 108 | try: | ||
| 109 | state = load_selfcheck_statefile() | ||
| 110 | |||
| 111 | current_time = datetime.datetime.utcnow() | ||
| 112 | # Determine if we need to refresh the state | ||
| 113 | if "last_check" in state.state and "pypi_version" in state.state: | ||
| 114 | last_check = datetime.datetime.strptime( | ||
| 115 | state.state["last_check"], | ||
| 116 | SELFCHECK_DATE_FMT | ||
| 117 | ) | ||
| 118 | if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: | ||
| 119 | pypi_version = state.state["pypi_version"] | ||
| 120 | |||
| 121 | # Refresh the version if we need to or just see if we need to warn | ||
| 122 | if pypi_version is None: | ||
| 123 | # Lets use PackageFinder to see what the latest pip version is | ||
| 124 | finder = PackageFinder( | ||
| 125 | find_links=options.find_links, | ||
| 126 | index_urls=[options.index_url] + options.extra_index_urls, | ||
| 127 | allow_all_prereleases=False, # Explicitly set to False | ||
| 128 | trusted_hosts=options.trusted_hosts, | ||
| 129 | process_dependency_links=options.process_dependency_links, | ||
| 130 | session=session, | ||
| 131 | ) | ||
| 132 | all_candidates = finder.find_all_candidates("pip") | ||
| 133 | if not all_candidates: | ||
| 134 | return | ||
| 135 | pypi_version = str( | ||
| 136 | max(all_candidates, key=lambda c: c.version).version | ||
| 137 | ) | ||
| 138 | |||
| 139 | # save that we've performed a check | ||
| 140 | state.save(pypi_version, current_time) | ||
| 141 | |||
| 142 | remote_version = packaging_version.parse(pypi_version) | ||
| 143 | |||
| 144 | # Determine if our pypi_version is older | ||
| 145 | if (pip_version < remote_version and | ||
| 146 | pip_version.base_version != remote_version.base_version): | ||
| 147 | # Advise "python -m pip" on Windows to avoid issues | ||
| 148 | # with overwriting pip.exe. | ||
| 149 | if WINDOWS: | ||
| 150 | pip_cmd = "python -m pip" | ||
| 151 | else: | ||
| 152 | pip_cmd = "pip" | ||
| 153 | logger.warning( | ||
| 154 | "You are using pip version %s, however version %s is " | ||
| 155 | "available.\nYou should consider upgrading via the " | ||
| 156 | "'%s install --upgrade pip' command.", | ||
| 157 | pip_version, pypi_version, pip_cmd | ||
| 158 | ) | ||
| 159 | except Exception: | ||
| 160 | logger.debug( | ||
| 161 | "There was an error checking the latest version of pip", | ||
| 162 | exc_info=True, | ||
| 163 | ) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/packaging.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/packaging.py deleted file mode 100644 index d523953..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/packaging.py +++ /dev/null | |||
| @@ -1,70 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import sys | ||
| 5 | from email.parser import FeedParser # type: ignore | ||
| 6 | |||
| 7 | from pip._vendor import pkg_resources | ||
| 8 | from pip._vendor.packaging import specifiers, version | ||
| 9 | |||
| 10 | from pip._internal import exceptions | ||
| 11 | |||
| 12 | logger = logging.getLogger(__name__) | ||
| 13 | |||
| 14 | |||
| 15 | def check_requires_python(requires_python): | ||
| 16 | """ | ||
| 17 | Check if the python version in use match the `requires_python` specifier. | ||
| 18 | |||
| 19 | Returns `True` if the version of python in use matches the requirement. | ||
| 20 | Returns `False` if the version of python in use does not matches the | ||
| 21 | requirement. | ||
| 22 | |||
| 23 | Raises an InvalidSpecifier if `requires_python` have an invalid format. | ||
| 24 | """ | ||
| 25 | if requires_python is None: | ||
| 26 | # The package provides no information | ||
| 27 | return True | ||
| 28 | requires_python_specifier = specifiers.SpecifierSet(requires_python) | ||
| 29 | |||
| 30 | # We only use major.minor.micro | ||
| 31 | python_version = version.parse('.'.join(map(str, sys.version_info[:3]))) | ||
| 32 | return python_version in requires_python_specifier | ||
| 33 | |||
| 34 | |||
| 35 | def get_metadata(dist): | ||
| 36 | if (isinstance(dist, pkg_resources.DistInfoDistribution) and | ||
| 37 | dist.has_metadata('METADATA')): | ||
| 38 | return dist.get_metadata('METADATA') | ||
| 39 | elif dist.has_metadata('PKG-INFO'): | ||
| 40 | return dist.get_metadata('PKG-INFO') | ||
| 41 | |||
| 42 | |||
| 43 | def check_dist_requires_python(dist): | ||
| 44 | metadata = get_metadata(dist) | ||
| 45 | feed_parser = FeedParser() | ||
| 46 | feed_parser.feed(metadata) | ||
| 47 | pkg_info_dict = feed_parser.close() | ||
| 48 | requires_python = pkg_info_dict.get('Requires-Python') | ||
| 49 | try: | ||
| 50 | if not check_requires_python(requires_python): | ||
| 51 | raise exceptions.UnsupportedPythonVersion( | ||
| 52 | "%s requires Python '%s' but the running Python is %s" % ( | ||
| 53 | dist.project_name, | ||
| 54 | requires_python, | ||
| 55 | '.'.join(map(str, sys.version_info[:3])),) | ||
| 56 | ) | ||
| 57 | except specifiers.InvalidSpecifier as e: | ||
| 58 | logger.warning( | ||
| 59 | "Package %s has an invalid Requires-Python entry %s - %s", | ||
| 60 | dist.project_name, requires_python, e, | ||
| 61 | ) | ||
| 62 | return | ||
| 63 | |||
| 64 | |||
| 65 | def get_installer(dist): | ||
| 66 | if dist.has_metadata('INSTALLER'): | ||
| 67 | for line in dist.get_metadata_lines('INSTALLER'): | ||
| 68 | if line.strip(): | ||
| 69 | return line.strip() | ||
| 70 | return '' | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/setuptools_build.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/setuptools_build.py deleted file mode 100644 index 9d32174..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/setuptools_build.py +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | # Shim to wrap setup.py invocation with setuptools | ||
| 2 | SETUPTOOLS_SHIM = ( | ||
| 3 | "import setuptools, tokenize;__file__=%r;" | ||
| 4 | "f=getattr(tokenize, 'open', open)(__file__);" | ||
| 5 | "code=f.read().replace('\\r\\n', '\\n');" | ||
| 6 | "f.close();" | ||
| 7 | "exec(compile(code, __file__, 'exec'))" | ||
| 8 | ) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/temp_dir.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/temp_dir.py deleted file mode 100644 index 25bc0d9..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/temp_dir.py +++ /dev/null | |||
| @@ -1,82 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os.path | ||
| 5 | import tempfile | ||
| 6 | |||
| 7 | from pip._internal.utils.misc import rmtree | ||
| 8 | |||
| 9 | logger = logging.getLogger(__name__) | ||
| 10 | |||
| 11 | |||
| 12 | class TempDirectory(object): | ||
| 13 | """Helper class that owns and cleans up a temporary directory. | ||
| 14 | |||
| 15 | This class can be used as a context manager or as an OO representation of a | ||
| 16 | temporary directory. | ||
| 17 | |||
| 18 | Attributes: | ||
| 19 | path | ||
| 20 | Location to the created temporary directory or None | ||
| 21 | delete | ||
| 22 | Whether the directory should be deleted when exiting | ||
| 23 | (when used as a contextmanager) | ||
| 24 | |||
| 25 | Methods: | ||
| 26 | create() | ||
| 27 | Creates a temporary directory and stores its path in the path | ||
| 28 | attribute. | ||
| 29 | cleanup() | ||
| 30 | Deletes the temporary directory and sets path attribute to None | ||
| 31 | |||
| 32 | When used as a context manager, a temporary directory is created on | ||
| 33 | entering the context and, if the delete attribute is True, on exiting the | ||
| 34 | context the created directory is deleted. | ||
| 35 | """ | ||
| 36 | |||
| 37 | def __init__(self, path=None, delete=None, kind="temp"): | ||
| 38 | super(TempDirectory, self).__init__() | ||
| 39 | |||
| 40 | if path is None and delete is None: | ||
| 41 | # If we were not given an explicit directory, and we were not given | ||
| 42 | # an explicit delete option, then we'll default to deleting. | ||
| 43 | delete = True | ||
| 44 | |||
| 45 | self.path = path | ||
| 46 | self.delete = delete | ||
| 47 | self.kind = kind | ||
| 48 | |||
| 49 | def __repr__(self): | ||
| 50 | return "<{} {!r}>".format(self.__class__.__name__, self.path) | ||
| 51 | |||
| 52 | def __enter__(self): | ||
| 53 | self.create() | ||
| 54 | return self | ||
| 55 | |||
| 56 | def __exit__(self, exc, value, tb): | ||
| 57 | if self.delete: | ||
| 58 | self.cleanup() | ||
| 59 | |||
| 60 | def create(self): | ||
| 61 | """Create a temporary directory and store it's path in self.path | ||
| 62 | """ | ||
| 63 | if self.path is not None: | ||
| 64 | logger.debug( | ||
| 65 | "Skipped creation of temporary directory: {}".format(self.path) | ||
| 66 | ) | ||
| 67 | return | ||
| 68 | # We realpath here because some systems have their default tmpdir | ||
| 69 | # symlinked to another directory. This tends to confuse build | ||
| 70 | # scripts, so we canonicalize the path by traversing potential | ||
| 71 | # symlinks here. | ||
| 72 | self.path = os.path.realpath( | ||
| 73 | tempfile.mkdtemp(prefix="pip-{}-".format(self.kind)) | ||
| 74 | ) | ||
| 75 | logger.debug("Created temporary directory: {}".format(self.path)) | ||
| 76 | |||
| 77 | def cleanup(self): | ||
| 78 | """Remove the temporary directory created and reset state | ||
| 79 | """ | ||
| 80 | if self.path is not None and os.path.exists(self.path): | ||
| 81 | rmtree(self.path) | ||
| 82 | self.path = None | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/typing.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/typing.py deleted file mode 100644 index 4e25ae6..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/typing.py +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | """For neatly implementing static typing in pip. | ||
| 2 | |||
| 3 | `mypy` - the static type analysis tool we use - uses the `typing` module, which | ||
| 4 | provides core functionality fundamental to mypy's functioning. | ||
| 5 | |||
| 6 | Generally, `typing` would be imported at runtime and used in that fashion - | ||
| 7 | it acts as a no-op at runtime and does not have any run-time overhead by | ||
| 8 | design. | ||
| 9 | |||
| 10 | As it turns out, `typing` is not vendorable - it uses separate sources for | ||
| 11 | Python 2/Python 3. Thus, this codebase can not expect it to be present. | ||
| 12 | To work around this, mypy allows the typing import to be behind a False-y | ||
| 13 | optional to prevent it from running at runtime and type-comments can be used | ||
| 14 | to remove the need for the types to be accessible directly during runtime. | ||
| 15 | |||
| 16 | This module provides the False-y guard in a nicely named fashion so that a | ||
| 17 | curious maintainer can reach here to read this. | ||
| 18 | |||
| 19 | In pip, all static-typing related imports should be guarded as follows: | ||
| 20 | |||
| 21 | from pip.utils.typing import MYPY_CHECK_RUNNING | ||
| 22 | |||
| 23 | if MYPY_CHECK_RUNNING: | ||
| 24 | from typing import ... | ||
| 25 | |||
| 26 | Ref: https://github.com/python/mypy/issues/3216 | ||
| 27 | """ | ||
| 28 | |||
| 29 | MYPY_CHECK_RUNNING = False | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/ui.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/ui.py deleted file mode 100644 index d97ea36..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/utils/ui.py +++ /dev/null | |||
| @@ -1,421 +0,0 @@ | |||
| 1 | from __future__ import absolute_import, division | ||
| 2 | |||
| 3 | import contextlib | ||
| 4 | import itertools | ||
| 5 | import logging | ||
| 6 | import sys | ||
| 7 | import time | ||
| 8 | from signal import SIGINT, default_int_handler, signal | ||
| 9 | |||
| 10 | from pip._vendor import six | ||
| 11 | from pip._vendor.progress.bar import ( | ||
| 12 | Bar, ChargingBar, FillingCirclesBar, FillingSquaresBar, IncrementalBar, | ||
| 13 | ShadyBar, | ||
| 14 | ) | ||
| 15 | from pip._vendor.progress.helpers import HIDE_CURSOR, SHOW_CURSOR, WritelnMixin | ||
| 16 | from pip._vendor.progress.spinner import Spinner | ||
| 17 | |||
| 18 | from pip._internal.compat import WINDOWS | ||
| 19 | from pip._internal.utils.logging import get_indentation | ||
| 20 | from pip._internal.utils.misc import format_size | ||
| 21 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 22 | |||
| 23 | if MYPY_CHECK_RUNNING: | ||
| 24 | from typing import Any | ||
| 25 | |||
| 26 | try: | ||
| 27 | from pip._vendor import colorama | ||
| 28 | # Lots of different errors can come from this, including SystemError and | ||
| 29 | # ImportError. | ||
| 30 | except Exception: | ||
| 31 | colorama = None | ||
| 32 | |||
| 33 | logger = logging.getLogger(__name__) | ||
| 34 | |||
| 35 | |||
| 36 | def _select_progress_class(preferred, fallback): | ||
| 37 | encoding = getattr(preferred.file, "encoding", None) | ||
| 38 | |||
| 39 | # If we don't know what encoding this file is in, then we'll just assume | ||
| 40 | # that it doesn't support unicode and use the ASCII bar. | ||
| 41 | if not encoding: | ||
| 42 | return fallback | ||
| 43 | |||
| 44 | # Collect all of the possible characters we want to use with the preferred | ||
| 45 | # bar. | ||
| 46 | characters = [ | ||
| 47 | getattr(preferred, "empty_fill", six.text_type()), | ||
| 48 | getattr(preferred, "fill", six.text_type()), | ||
| 49 | ] | ||
| 50 | characters += list(getattr(preferred, "phases", [])) | ||
| 51 | |||
| 52 | # Try to decode the characters we're using for the bar using the encoding | ||
| 53 | # of the given file, if this works then we'll assume that we can use the | ||
| 54 | # fancier bar and if not we'll fall back to the plaintext bar. | ||
| 55 | try: | ||
| 56 | six.text_type().join(characters).encode(encoding) | ||
| 57 | except UnicodeEncodeError: | ||
| 58 | return fallback | ||
| 59 | else: | ||
| 60 | return preferred | ||
| 61 | |||
| 62 | |||
| 63 | _BaseBar = _select_progress_class(IncrementalBar, Bar) # type: Any | ||
| 64 | |||
| 65 | |||
| 66 | class InterruptibleMixin(object): | ||
| 67 | """ | ||
| 68 | Helper to ensure that self.finish() gets called on keyboard interrupt. | ||
| 69 | |||
| 70 | This allows downloads to be interrupted without leaving temporary state | ||
| 71 | (like hidden cursors) behind. | ||
| 72 | |||
| 73 | This class is similar to the progress library's existing SigIntMixin | ||
| 74 | helper, but as of version 1.2, that helper has the following problems: | ||
| 75 | |||
| 76 | 1. It calls sys.exit(). | ||
| 77 | 2. It discards the existing SIGINT handler completely. | ||
| 78 | 3. It leaves its own handler in place even after an uninterrupted finish, | ||
| 79 | which will have unexpected delayed effects if the user triggers an | ||
| 80 | unrelated keyboard interrupt some time after a progress-displaying | ||
| 81 | download has already completed, for example. | ||
| 82 | """ | ||
| 83 | |||
| 84 | def __init__(self, *args, **kwargs): | ||
| 85 | """ | ||
| 86 | Save the original SIGINT handler for later. | ||
| 87 | """ | ||
| 88 | super(InterruptibleMixin, self).__init__(*args, **kwargs) | ||
| 89 | |||
| 90 | self.original_handler = signal(SIGINT, self.handle_sigint) | ||
| 91 | |||
| 92 | # If signal() returns None, the previous handler was not installed from | ||
| 93 | # Python, and we cannot restore it. This probably should not happen, | ||
| 94 | # but if it does, we must restore something sensible instead, at least. | ||
| 95 | # The least bad option should be Python's default SIGINT handler, which | ||
| 96 | # just raises KeyboardInterrupt. | ||
| 97 | if self.original_handler is None: | ||
| 98 | self.original_handler = default_int_handler | ||
| 99 | |||
| 100 | def finish(self): | ||
| 101 | """ | ||
| 102 | Restore the original SIGINT handler after finishing. | ||
| 103 | |||
| 104 | This should happen regardless of whether the progress display finishes | ||
| 105 | normally, or gets interrupted. | ||
| 106 | """ | ||
| 107 | super(InterruptibleMixin, self).finish() | ||
| 108 | signal(SIGINT, self.original_handler) | ||
| 109 | |||
| 110 | def handle_sigint(self, signum, frame): | ||
| 111 | """ | ||
| 112 | Call self.finish() before delegating to the original SIGINT handler. | ||
| 113 | |||
| 114 | This handler should only be in place while the progress display is | ||
| 115 | active. | ||
| 116 | """ | ||
| 117 | self.finish() | ||
| 118 | self.original_handler(signum, frame) | ||
| 119 | |||
| 120 | |||
| 121 | class SilentBar(Bar): | ||
| 122 | |||
| 123 | def update(self): | ||
| 124 | pass | ||
| 125 | |||
| 126 | |||
| 127 | class BlueEmojiBar(IncrementalBar): | ||
| 128 | |||
| 129 | suffix = "%(percent)d%%" | ||
| 130 | bar_prefix = " " | ||
| 131 | bar_suffix = " " | ||
| 132 | phases = (u"\U0001F539", u"\U0001F537", u"\U0001F535") # type: Any | ||
| 133 | |||
| 134 | |||
| 135 | class DownloadProgressMixin(object): | ||
| 136 | |||
| 137 | def __init__(self, *args, **kwargs): | ||
| 138 | super(DownloadProgressMixin, self).__init__(*args, **kwargs) | ||
| 139 | self.message = (" " * (get_indentation() + 2)) + self.message | ||
| 140 | |||
| 141 | @property | ||
| 142 | def downloaded(self): | ||
| 143 | return format_size(self.index) | ||
| 144 | |||
| 145 | @property | ||
| 146 | def download_speed(self): | ||
| 147 | # Avoid zero division errors... | ||
| 148 | if self.avg == 0.0: | ||
| 149 | return "..." | ||
| 150 | return format_size(1 / self.avg) + "/s" | ||
| 151 | |||
| 152 | @property | ||
| 153 | def pretty_eta(self): | ||
| 154 | if self.eta: | ||
| 155 | return "eta %s" % self.eta_td | ||
| 156 | return "" | ||
| 157 | |||
| 158 | def iter(self, it, n=1): | ||
| 159 | for x in it: | ||
| 160 | yield x | ||
| 161 | self.next(n) | ||
| 162 | self.finish() | ||
| 163 | |||
| 164 | |||
| 165 | class WindowsMixin(object): | ||
| 166 | |||
| 167 | def __init__(self, *args, **kwargs): | ||
| 168 | # The Windows terminal does not support the hide/show cursor ANSI codes | ||
| 169 | # even with colorama. So we'll ensure that hide_cursor is False on | ||
| 170 | # Windows. | ||
| 171 | # This call neds to go before the super() call, so that hide_cursor | ||
| 172 | # is set in time. The base progress bar class writes the "hide cursor" | ||
| 173 | # code to the terminal in its init, so if we don't set this soon | ||
| 174 | # enough, we get a "hide" with no corresponding "show"... | ||
| 175 | if WINDOWS and self.hide_cursor: | ||
| 176 | self.hide_cursor = False | ||
| 177 | |||
| 178 | super(WindowsMixin, self).__init__(*args, **kwargs) | ||
| 179 | |||
| 180 | # Check if we are running on Windows and we have the colorama module, | ||
| 181 | # if we do then wrap our file with it. | ||
| 182 | if WINDOWS and colorama: | ||
| 183 | self.file = colorama.AnsiToWin32(self.file) | ||
| 184 | # The progress code expects to be able to call self.file.isatty() | ||
| 185 | # but the colorama.AnsiToWin32() object doesn't have that, so we'll | ||
| 186 | # add it. | ||
| 187 | self.file.isatty = lambda: self.file.wrapped.isatty() | ||
| 188 | # The progress code expects to be able to call self.file.flush() | ||
| 189 | # but the colorama.AnsiToWin32() object doesn't have that, so we'll | ||
| 190 | # add it. | ||
| 191 | self.file.flush = lambda: self.file.wrapped.flush() | ||
| 192 | |||
| 193 | |||
| 194 | class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, | ||
| 195 | DownloadProgressMixin): | ||
| 196 | |||
| 197 | file = sys.stdout | ||
| 198 | message = "%(percent)d%%" | ||
| 199 | suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s" | ||
| 200 | |||
| 201 | # NOTE: The "type: ignore" comments on the following classes are there to | ||
| 202 | # work around https://github.com/python/typing/issues/241 | ||
| 203 | |||
| 204 | |||
| 205 | class DefaultDownloadProgressBar(BaseDownloadProgressBar, | ||
| 206 | _BaseBar): # type: ignore | ||
| 207 | pass | ||
| 208 | |||
| 209 | |||
| 210 | class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): # type: ignore | ||
| 211 | pass | ||
| 212 | |||
| 213 | |||
| 214 | class DownloadIncrementalBar(BaseDownloadProgressBar, # type: ignore | ||
| 215 | IncrementalBar): | ||
| 216 | pass | ||
| 217 | |||
| 218 | |||
| 219 | class DownloadChargingBar(BaseDownloadProgressBar, # type: ignore | ||
| 220 | ChargingBar): | ||
| 221 | pass | ||
| 222 | |||
| 223 | |||
| 224 | class DownloadShadyBar(BaseDownloadProgressBar, ShadyBar): # type: ignore | ||
| 225 | pass | ||
| 226 | |||
| 227 | |||
| 228 | class DownloadFillingSquaresBar(BaseDownloadProgressBar, # type: ignore | ||
| 229 | FillingSquaresBar): | ||
| 230 | pass | ||
| 231 | |||
| 232 | |||
| 233 | class DownloadFillingCirclesBar(BaseDownloadProgressBar, # type: ignore | ||
| 234 | FillingCirclesBar): | ||
| 235 | pass | ||
| 236 | |||
| 237 | |||
| 238 | class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, # type: ignore | ||
| 239 | BlueEmojiBar): | ||
| 240 | pass | ||
| 241 | |||
| 242 | |||
| 243 | class DownloadProgressSpinner(WindowsMixin, InterruptibleMixin, | ||
| 244 | DownloadProgressMixin, WritelnMixin, Spinner): | ||
| 245 | |||
| 246 | file = sys.stdout | ||
| 247 | suffix = "%(downloaded)s %(download_speed)s" | ||
| 248 | |||
| 249 | def next_phase(self): | ||
| 250 | if not hasattr(self, "_phaser"): | ||
| 251 | self._phaser = itertools.cycle(self.phases) | ||
| 252 | return next(self._phaser) | ||
| 253 | |||
| 254 | def update(self): | ||
| 255 | message = self.message % self | ||
| 256 | phase = self.next_phase() | ||
| 257 | suffix = self.suffix % self | ||
| 258 | line = ''.join([ | ||
| 259 | message, | ||
| 260 | " " if message else "", | ||
| 261 | phase, | ||
| 262 | " " if suffix else "", | ||
| 263 | suffix, | ||
| 264 | ]) | ||
| 265 | |||
| 266 | self.writeln(line) | ||
| 267 | |||
| 268 | |||
| 269 | BAR_TYPES = { | ||
| 270 | "off": (DownloadSilentBar, DownloadSilentBar), | ||
| 271 | "on": (DefaultDownloadProgressBar, DownloadProgressSpinner), | ||
| 272 | "ascii": (DownloadIncrementalBar, DownloadProgressSpinner), | ||
| 273 | "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner), | ||
| 274 | "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner) | ||
| 275 | } | ||
| 276 | |||
| 277 | |||
| 278 | def DownloadProgressProvider(progress_bar, max=None): | ||
| 279 | if max is None or max == 0: | ||
| 280 | return BAR_TYPES[progress_bar][1]().iter | ||
| 281 | else: | ||
| 282 | return BAR_TYPES[progress_bar][0](max=max).iter | ||
| 283 | |||
| 284 | |||
| 285 | ################################################################ | ||
| 286 | # Generic "something is happening" spinners | ||
| 287 | # | ||
| 288 | # We don't even try using progress.spinner.Spinner here because it's actually | ||
| 289 | # simpler to reimplement from scratch than to coerce their code into doing | ||
| 290 | # what we need. | ||
| 291 | ################################################################ | ||
| 292 | |||
| 293 | @contextlib.contextmanager | ||
| 294 | def hidden_cursor(file): | ||
| 295 | # The Windows terminal does not support the hide/show cursor ANSI codes, | ||
| 296 | # even via colorama. So don't even try. | ||
| 297 | if WINDOWS: | ||
| 298 | yield | ||
| 299 | # We don't want to clutter the output with control characters if we're | ||
| 300 | # writing to a file, or if the user is running with --quiet. | ||
| 301 | # See https://github.com/pypa/pip/issues/3418 | ||
| 302 | elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO: | ||
| 303 | yield | ||
| 304 | else: | ||
| 305 | file.write(HIDE_CURSOR) | ||
| 306 | try: | ||
| 307 | yield | ||
| 308 | finally: | ||
| 309 | file.write(SHOW_CURSOR) | ||
| 310 | |||
| 311 | |||
| 312 | class RateLimiter(object): | ||
| 313 | def __init__(self, min_update_interval_seconds): | ||
| 314 | self._min_update_interval_seconds = min_update_interval_seconds | ||
| 315 | self._last_update = 0 | ||
| 316 | |||
| 317 | def ready(self): | ||
| 318 | now = time.time() | ||
| 319 | delta = now - self._last_update | ||
| 320 | return delta >= self._min_update_interval_seconds | ||
| 321 | |||
| 322 | def reset(self): | ||
| 323 | self._last_update = time.time() | ||
| 324 | |||
| 325 | |||
| 326 | class InteractiveSpinner(object): | ||
| 327 | def __init__(self, message, file=None, spin_chars="-\\|/", | ||
| 328 | # Empirically, 8 updates/second looks nice | ||
| 329 | min_update_interval_seconds=0.125): | ||
| 330 | self._message = message | ||
| 331 | if file is None: | ||
| 332 | file = sys.stdout | ||
| 333 | self._file = file | ||
| 334 | self._rate_limiter = RateLimiter(min_update_interval_seconds) | ||
| 335 | self._finished = False | ||
| 336 | |||
| 337 | self._spin_cycle = itertools.cycle(spin_chars) | ||
| 338 | |||
| 339 | self._file.write(" " * get_indentation() + self._message + " ... ") | ||
| 340 | self._width = 0 | ||
| 341 | |||
| 342 | def _write(self, status): | ||
| 343 | assert not self._finished | ||
| 344 | # Erase what we wrote before by backspacing to the beginning, writing | ||
| 345 | # spaces to overwrite the old text, and then backspacing again | ||
| 346 | backup = "\b" * self._width | ||
| 347 | self._file.write(backup + " " * self._width + backup) | ||
| 348 | # Now we have a blank slate to add our status | ||
| 349 | self._file.write(status) | ||
| 350 | self._width = len(status) | ||
| 351 | self._file.flush() | ||
| 352 | self._rate_limiter.reset() | ||
| 353 | |||
| 354 | def spin(self): | ||
| 355 | if self._finished: | ||
| 356 | return | ||
| 357 | if not self._rate_limiter.ready(): | ||
| 358 | return | ||
| 359 | self._write(next(self._spin_cycle)) | ||
| 360 | |||
| 361 | def finish(self, final_status): | ||
| 362 | if self._finished: | ||
| 363 | return | ||
| 364 | self._write(final_status) | ||
| 365 | self._file.write("\n") | ||
| 366 | self._file.flush() | ||
| 367 | self._finished = True | ||
| 368 | |||
| 369 | |||
| 370 | # Used for dumb terminals, non-interactive installs (no tty), etc. | ||
| 371 | # We still print updates occasionally (once every 60 seconds by default) to | ||
| 372 | # act as a keep-alive for systems like Travis-CI that take lack-of-output as | ||
| 373 | # an indication that a task has frozen. | ||
| 374 | class NonInteractiveSpinner(object): | ||
| 375 | def __init__(self, message, min_update_interval_seconds=60): | ||
| 376 | self._message = message | ||
| 377 | self._finished = False | ||
| 378 | self._rate_limiter = RateLimiter(min_update_interval_seconds) | ||
| 379 | self._update("started") | ||
| 380 | |||
| 381 | def _update(self, status): | ||
| 382 | assert not self._finished | ||
| 383 | self._rate_limiter.reset() | ||
| 384 | logger.info("%s: %s", self._message, status) | ||
| 385 | |||
| 386 | def spin(self): | ||
| 387 | if self._finished: | ||
| 388 | return | ||
| 389 | if not self._rate_limiter.ready(): | ||
| 390 | return | ||
| 391 | self._update("still running...") | ||
| 392 | |||
| 393 | def finish(self, final_status): | ||
| 394 | if self._finished: | ||
| 395 | return | ||
| 396 | self._update("finished with status '%s'" % (final_status,)) | ||
| 397 | self._finished = True | ||
| 398 | |||
| 399 | |||
| 400 | @contextlib.contextmanager | ||
| 401 | def open_spinner(message): | ||
| 402 | # Interactive spinner goes directly to sys.stdout rather than being routed | ||
| 403 | # through the logging system, but it acts like it has level INFO, | ||
| 404 | # i.e. it's only displayed if we're at level INFO or better. | ||
| 405 | # Non-interactive spinner goes through the logging system, so it is always | ||
| 406 | # in sync with logging configuration. | ||
| 407 | if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO: | ||
| 408 | spinner = InteractiveSpinner(message) | ||
| 409 | else: | ||
| 410 | spinner = NonInteractiveSpinner(message) | ||
| 411 | try: | ||
| 412 | with hidden_cursor(sys.stdout): | ||
| 413 | yield spinner | ||
| 414 | except KeyboardInterrupt: | ||
| 415 | spinner.finish("canceled") | ||
| 416 | raise | ||
| 417 | except Exception: | ||
| 418 | spinner.finish("error") | ||
| 419 | raise | ||
| 420 | else: | ||
| 421 | spinner.finish("done") | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/__init__.py deleted file mode 100644 index bff94fa..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/__init__.py +++ /dev/null | |||
| @@ -1,471 +0,0 @@ | |||
| 1 | """Handles all VCS (version control) support""" | ||
| 2 | from __future__ import absolute_import | ||
| 3 | |||
| 4 | import copy | ||
| 5 | import errno | ||
| 6 | import logging | ||
| 7 | import os | ||
| 8 | import shutil | ||
| 9 | import sys | ||
| 10 | |||
| 11 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 12 | |||
| 13 | from pip._internal.exceptions import BadCommand | ||
| 14 | from pip._internal.utils.misc import ( | ||
| 15 | display_path, backup_dir, call_subprocess, rmtree, ask_path_exists, | ||
| 16 | ) | ||
| 17 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 18 | |||
| 19 | if MYPY_CHECK_RUNNING: | ||
| 20 | from typing import Dict, Optional, Tuple | ||
| 21 | from pip._internal.basecommand import Command | ||
| 22 | |||
| 23 | __all__ = ['vcs', 'get_src_requirement'] | ||
| 24 | |||
| 25 | |||
| 26 | logger = logging.getLogger(__name__) | ||
| 27 | |||
| 28 | |||
| 29 | class RevOptions(object): | ||
| 30 | |||
| 31 | """ | ||
| 32 | Encapsulates a VCS-specific revision to install, along with any VCS | ||
| 33 | install options. | ||
| 34 | |||
| 35 | Instances of this class should be treated as if immutable. | ||
| 36 | """ | ||
| 37 | |||
| 38 | def __init__(self, vcs, rev=None, extra_args=None): | ||
| 39 | """ | ||
| 40 | Args: | ||
| 41 | vcs: a VersionControl object. | ||
| 42 | rev: the name of the revision to install. | ||
| 43 | extra_args: a list of extra options. | ||
| 44 | """ | ||
| 45 | if extra_args is None: | ||
| 46 | extra_args = [] | ||
| 47 | |||
| 48 | self.extra_args = extra_args | ||
| 49 | self.rev = rev | ||
| 50 | self.vcs = vcs | ||
| 51 | |||
| 52 | def __repr__(self): | ||
| 53 | return '<RevOptions {}: rev={!r}>'.format(self.vcs.name, self.rev) | ||
| 54 | |||
| 55 | @property | ||
| 56 | def arg_rev(self): | ||
| 57 | if self.rev is None: | ||
| 58 | return self.vcs.default_arg_rev | ||
| 59 | |||
| 60 | return self.rev | ||
| 61 | |||
| 62 | def to_args(self): | ||
| 63 | """ | ||
| 64 | Return the VCS-specific command arguments. | ||
| 65 | """ | ||
| 66 | args = [] | ||
| 67 | rev = self.arg_rev | ||
| 68 | if rev is not None: | ||
| 69 | args += self.vcs.get_base_rev_args(rev) | ||
| 70 | args += self.extra_args | ||
| 71 | |||
| 72 | return args | ||
| 73 | |||
| 74 | def to_display(self): | ||
| 75 | if not self.rev: | ||
| 76 | return '' | ||
| 77 | |||
| 78 | return ' (to revision {})'.format(self.rev) | ||
| 79 | |||
| 80 | def make_new(self, rev): | ||
| 81 | """ | ||
| 82 | Make a copy of the current instance, but with a new rev. | ||
| 83 | |||
| 84 | Args: | ||
| 85 | rev: the name of the revision for the new object. | ||
| 86 | """ | ||
| 87 | return self.vcs.make_rev_options(rev, extra_args=self.extra_args) | ||
| 88 | |||
| 89 | |||
| 90 | class VcsSupport(object): | ||
| 91 | _registry = {} # type: Dict[str, Command] | ||
| 92 | schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] | ||
| 93 | |||
| 94 | def __init__(self): | ||
| 95 | # Register more schemes with urlparse for various version control | ||
| 96 | # systems | ||
| 97 | urllib_parse.uses_netloc.extend(self.schemes) | ||
| 98 | # Python >= 2.7.4, 3.3 doesn't have uses_fragment | ||
| 99 | if getattr(urllib_parse, 'uses_fragment', None): | ||
| 100 | urllib_parse.uses_fragment.extend(self.schemes) | ||
| 101 | super(VcsSupport, self).__init__() | ||
| 102 | |||
| 103 | def __iter__(self): | ||
| 104 | return self._registry.__iter__() | ||
| 105 | |||
| 106 | @property | ||
| 107 | def backends(self): | ||
| 108 | return list(self._registry.values()) | ||
| 109 | |||
| 110 | @property | ||
| 111 | def dirnames(self): | ||
| 112 | return [backend.dirname for backend in self.backends] | ||
| 113 | |||
| 114 | @property | ||
| 115 | def all_schemes(self): | ||
| 116 | schemes = [] | ||
| 117 | for backend in self.backends: | ||
| 118 | schemes.extend(backend.schemes) | ||
| 119 | return schemes | ||
| 120 | |||
| 121 | def register(self, cls): | ||
| 122 | if not hasattr(cls, 'name'): | ||
| 123 | logger.warning('Cannot register VCS %s', cls.__name__) | ||
| 124 | return | ||
| 125 | if cls.name not in self._registry: | ||
| 126 | self._registry[cls.name] = cls | ||
| 127 | logger.debug('Registered VCS backend: %s', cls.name) | ||
| 128 | |||
| 129 | def unregister(self, cls=None, name=None): | ||
| 130 | if name in self._registry: | ||
| 131 | del self._registry[name] | ||
| 132 | elif cls in self._registry.values(): | ||
| 133 | del self._registry[cls.name] | ||
| 134 | else: | ||
| 135 | logger.warning('Cannot unregister because no class or name given') | ||
| 136 | |||
| 137 | def get_backend_name(self, location): | ||
| 138 | """ | ||
| 139 | Return the name of the version control backend if found at given | ||
| 140 | location, e.g. vcs.get_backend_name('/path/to/vcs/checkout') | ||
| 141 | """ | ||
| 142 | for vc_type in self._registry.values(): | ||
| 143 | if vc_type.controls_location(location): | ||
| 144 | logger.debug('Determine that %s uses VCS: %s', | ||
| 145 | location, vc_type.name) | ||
| 146 | return vc_type.name | ||
| 147 | return None | ||
| 148 | |||
| 149 | def get_backend(self, name): | ||
| 150 | name = name.lower() | ||
| 151 | if name in self._registry: | ||
| 152 | return self._registry[name] | ||
| 153 | |||
| 154 | def get_backend_from_location(self, location): | ||
| 155 | vc_type = self.get_backend_name(location) | ||
| 156 | if vc_type: | ||
| 157 | return self.get_backend(vc_type) | ||
| 158 | return None | ||
| 159 | |||
| 160 | |||
| 161 | vcs = VcsSupport() | ||
| 162 | |||
| 163 | |||
| 164 | class VersionControl(object): | ||
| 165 | name = '' | ||
| 166 | dirname = '' | ||
| 167 | # List of supported schemes for this Version Control | ||
| 168 | schemes = () # type: Tuple[str, ...] | ||
| 169 | # Iterable of environment variable names to pass to call_subprocess(). | ||
| 170 | unset_environ = () # type: Tuple[str, ...] | ||
| 171 | default_arg_rev = None # type: Optional[str] | ||
| 172 | |||
| 173 | def __init__(self, url=None, *args, **kwargs): | ||
| 174 | self.url = url | ||
| 175 | super(VersionControl, self).__init__(*args, **kwargs) | ||
| 176 | |||
| 177 | def get_base_rev_args(self, rev): | ||
| 178 | """ | ||
| 179 | Return the base revision arguments for a vcs command. | ||
| 180 | |||
| 181 | Args: | ||
| 182 | rev: the name of a revision to install. Cannot be None. | ||
| 183 | """ | ||
| 184 | raise NotImplementedError | ||
| 185 | |||
| 186 | def make_rev_options(self, rev=None, extra_args=None): | ||
| 187 | """ | ||
| 188 | Return a RevOptions object. | ||
| 189 | |||
| 190 | Args: | ||
| 191 | rev: the name of a revision to install. | ||
| 192 | extra_args: a list of extra options. | ||
| 193 | """ | ||
| 194 | return RevOptions(self, rev, extra_args=extra_args) | ||
| 195 | |||
| 196 | def _is_local_repository(self, repo): | ||
| 197 | """ | ||
| 198 | posix absolute paths start with os.path.sep, | ||
| 199 | win32 ones start with drive (like c:\\folder) | ||
| 200 | """ | ||
| 201 | drive, tail = os.path.splitdrive(repo) | ||
| 202 | return repo.startswith(os.path.sep) or drive | ||
| 203 | |||
| 204 | # See issue #1083 for why this method was introduced: | ||
| 205 | # https://github.com/pypa/pip/issues/1083 | ||
| 206 | def translate_egg_surname(self, surname): | ||
| 207 | # For example, Django has branches of the form "stable/1.7.x". | ||
| 208 | return surname.replace('/', '_') | ||
| 209 | |||
| 210 | def export(self, location): | ||
| 211 | """ | ||
| 212 | Export the repository at the url to the destination location | ||
| 213 | i.e. only download the files, without vcs informations | ||
| 214 | """ | ||
| 215 | raise NotImplementedError | ||
| 216 | |||
| 217 | def get_url_rev(self): | ||
| 218 | """ | ||
| 219 | Returns the correct repository URL and revision by parsing the given | ||
| 220 | repository URL | ||
| 221 | """ | ||
| 222 | error_message = ( | ||
| 223 | "Sorry, '%s' is a malformed VCS url. " | ||
| 224 | "The format is <vcs>+<protocol>://<url>, " | ||
| 225 | "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp" | ||
| 226 | ) | ||
| 227 | assert '+' in self.url, error_message % self.url | ||
| 228 | url = self.url.split('+', 1)[1] | ||
| 229 | scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) | ||
| 230 | rev = None | ||
| 231 | if '@' in path: | ||
| 232 | path, rev = path.rsplit('@', 1) | ||
| 233 | url = urllib_parse.urlunsplit((scheme, netloc, path, query, '')) | ||
| 234 | return url, rev | ||
| 235 | |||
| 236 | def get_info(self, location): | ||
| 237 | """ | ||
| 238 | Returns (url, revision), where both are strings | ||
| 239 | """ | ||
| 240 | assert not location.rstrip('/').endswith(self.dirname), \ | ||
| 241 | 'Bad directory: %s' % location | ||
| 242 | return self.get_url(location), self.get_revision(location) | ||
| 243 | |||
| 244 | def normalize_url(self, url): | ||
| 245 | """ | ||
| 246 | Normalize a URL for comparison by unquoting it and removing any | ||
| 247 | trailing slash. | ||
| 248 | """ | ||
| 249 | return urllib_parse.unquote(url).rstrip('/') | ||
| 250 | |||
| 251 | def compare_urls(self, url1, url2): | ||
| 252 | """ | ||
| 253 | Compare two repo URLs for identity, ignoring incidental differences. | ||
| 254 | """ | ||
| 255 | return (self.normalize_url(url1) == self.normalize_url(url2)) | ||
| 256 | |||
| 257 | def obtain(self, dest): | ||
| 258 | """ | ||
| 259 | Called when installing or updating an editable package, takes the | ||
| 260 | source path of the checkout. | ||
| 261 | """ | ||
| 262 | raise NotImplementedError | ||
| 263 | |||
| 264 | def switch(self, dest, url, rev_options): | ||
| 265 | """ | ||
| 266 | Switch the repo at ``dest`` to point to ``URL``. | ||
| 267 | |||
| 268 | Args: | ||
| 269 | rev_options: a RevOptions object. | ||
| 270 | """ | ||
| 271 | raise NotImplementedError | ||
| 272 | |||
| 273 | def update(self, dest, rev_options): | ||
| 274 | """ | ||
| 275 | Update an already-existing repo to the given ``rev_options``. | ||
| 276 | |||
| 277 | Args: | ||
| 278 | rev_options: a RevOptions object. | ||
| 279 | """ | ||
| 280 | raise NotImplementedError | ||
| 281 | |||
| 282 | def is_commit_id_equal(self, dest, name): | ||
| 283 | """ | ||
| 284 | Return whether the id of the current commit equals the given name. | ||
| 285 | |||
| 286 | Args: | ||
| 287 | dest: the repository directory. | ||
| 288 | name: a string name. | ||
| 289 | """ | ||
| 290 | raise NotImplementedError | ||
| 291 | |||
| 292 | def check_destination(self, dest, url, rev_options): | ||
| 293 | """ | ||
| 294 | Prepare a location to receive a checkout/clone. | ||
| 295 | |||
| 296 | Return True if the location is ready for (and requires) a | ||
| 297 | checkout/clone, False otherwise. | ||
| 298 | |||
| 299 | Args: | ||
| 300 | rev_options: a RevOptions object. | ||
| 301 | """ | ||
| 302 | checkout = True | ||
| 303 | prompt = False | ||
| 304 | rev_display = rev_options.to_display() | ||
| 305 | if os.path.exists(dest): | ||
| 306 | checkout = False | ||
| 307 | if os.path.exists(os.path.join(dest, self.dirname)): | ||
| 308 | existing_url = self.get_url(dest) | ||
| 309 | if self.compare_urls(existing_url, url): | ||
| 310 | logger.debug( | ||
| 311 | '%s in %s exists, and has correct URL (%s)', | ||
| 312 | self.repo_name.title(), | ||
| 313 | display_path(dest), | ||
| 314 | url, | ||
| 315 | ) | ||
| 316 | if not self.is_commit_id_equal(dest, rev_options.rev): | ||
| 317 | logger.info( | ||
| 318 | 'Updating %s %s%s', | ||
| 319 | display_path(dest), | ||
| 320 | self.repo_name, | ||
| 321 | rev_display, | ||
| 322 | ) | ||
| 323 | self.update(dest, rev_options) | ||
| 324 | else: | ||
| 325 | logger.info( | ||
| 326 | 'Skipping because already up-to-date.') | ||
| 327 | else: | ||
| 328 | logger.warning( | ||
| 329 | '%s %s in %s exists with URL %s', | ||
| 330 | self.name, | ||
| 331 | self.repo_name, | ||
| 332 | display_path(dest), | ||
| 333 | existing_url, | ||
| 334 | ) | ||
| 335 | prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', | ||
| 336 | ('s', 'i', 'w', 'b')) | ||
| 337 | else: | ||
| 338 | logger.warning( | ||
| 339 | 'Directory %s already exists, and is not a %s %s.', | ||
| 340 | dest, | ||
| 341 | self.name, | ||
| 342 | self.repo_name, | ||
| 343 | ) | ||
| 344 | prompt = ('(i)gnore, (w)ipe, (b)ackup ', ('i', 'w', 'b')) | ||
| 345 | if prompt: | ||
| 346 | logger.warning( | ||
| 347 | 'The plan is to install the %s repository %s', | ||
| 348 | self.name, | ||
| 349 | url, | ||
| 350 | ) | ||
| 351 | response = ask_path_exists('What to do? %s' % prompt[0], | ||
| 352 | prompt[1]) | ||
| 353 | |||
| 354 | if response == 's': | ||
| 355 | logger.info( | ||
| 356 | 'Switching %s %s to %s%s', | ||
| 357 | self.repo_name, | ||
| 358 | display_path(dest), | ||
| 359 | url, | ||
| 360 | rev_display, | ||
| 361 | ) | ||
| 362 | self.switch(dest, url, rev_options) | ||
| 363 | elif response == 'i': | ||
| 364 | # do nothing | ||
| 365 | pass | ||
| 366 | elif response == 'w': | ||
| 367 | logger.warning('Deleting %s', display_path(dest)) | ||
| 368 | rmtree(dest) | ||
| 369 | checkout = True | ||
| 370 | elif response == 'b': | ||
| 371 | dest_dir = backup_dir(dest) | ||
| 372 | logger.warning( | ||
| 373 | 'Backing up %s to %s', display_path(dest), dest_dir, | ||
| 374 | ) | ||
| 375 | shutil.move(dest, dest_dir) | ||
| 376 | checkout = True | ||
| 377 | elif response == 'a': | ||
| 378 | sys.exit(-1) | ||
| 379 | return checkout | ||
| 380 | |||
| 381 | def unpack(self, location): | ||
| 382 | """ | ||
| 383 | Clean up current location and download the url repository | ||
| 384 | (and vcs infos) into location | ||
| 385 | """ | ||
| 386 | if os.path.exists(location): | ||
| 387 | rmtree(location) | ||
| 388 | self.obtain(location) | ||
| 389 | |||
| 390 | def get_src_requirement(self, dist, location): | ||
| 391 | """ | ||
| 392 | Return a string representing the requirement needed to | ||
| 393 | redownload the files currently present in location, something | ||
| 394 | like: | ||
| 395 | {repository_url}@{revision}#egg={project_name}-{version_identifier} | ||
| 396 | """ | ||
| 397 | raise NotImplementedError | ||
| 398 | |||
| 399 | def get_url(self, location): | ||
| 400 | """ | ||
| 401 | Return the url used at location | ||
| 402 | Used in get_info or check_destination | ||
| 403 | """ | ||
| 404 | raise NotImplementedError | ||
| 405 | |||
| 406 | def get_revision(self, location): | ||
| 407 | """ | ||
| 408 | Return the current commit id of the files at the given location. | ||
| 409 | """ | ||
| 410 | raise NotImplementedError | ||
| 411 | |||
| 412 | def run_command(self, cmd, show_stdout=True, cwd=None, | ||
| 413 | on_returncode='raise', | ||
| 414 | command_desc=None, | ||
| 415 | extra_environ=None, spinner=None): | ||
| 416 | """ | ||
| 417 | Run a VCS subcommand | ||
| 418 | This is simply a wrapper around call_subprocess that adds the VCS | ||
| 419 | command name, and checks that the VCS is available | ||
| 420 | """ | ||
| 421 | cmd = [self.name] + cmd | ||
| 422 | try: | ||
| 423 | return call_subprocess(cmd, show_stdout, cwd, | ||
| 424 | on_returncode, | ||
| 425 | command_desc, extra_environ, | ||
| 426 | unset_environ=self.unset_environ, | ||
| 427 | spinner=spinner) | ||
| 428 | except OSError as e: | ||
| 429 | # errno.ENOENT = no such file or directory | ||
| 430 | # In other words, the VCS executable isn't available | ||
| 431 | if e.errno == errno.ENOENT: | ||
| 432 | raise BadCommand( | ||
| 433 | 'Cannot find command %r - do you have ' | ||
| 434 | '%r installed and in your ' | ||
| 435 | 'PATH?' % (self.name, self.name)) | ||
| 436 | else: | ||
| 437 | raise # re-raise exception if a different error occurred | ||
| 438 | |||
| 439 | @classmethod | ||
| 440 | def controls_location(cls, location): | ||
| 441 | """ | ||
| 442 | Check if a location is controlled by the vcs. | ||
| 443 | It is meant to be overridden to implement smarter detection | ||
| 444 | mechanisms for specific vcs. | ||
| 445 | """ | ||
| 446 | logger.debug('Checking in %s for %s (%s)...', | ||
| 447 | location, cls.dirname, cls.name) | ||
| 448 | path = os.path.join(location, cls.dirname) | ||
| 449 | return os.path.exists(path) | ||
| 450 | |||
| 451 | |||
| 452 | def get_src_requirement(dist, location): | ||
| 453 | version_control = vcs.get_backend_from_location(location) | ||
| 454 | if version_control: | ||
| 455 | try: | ||
| 456 | return version_control().get_src_requirement(dist, | ||
| 457 | location) | ||
| 458 | except BadCommand: | ||
| 459 | logger.warning( | ||
| 460 | 'cannot determine version of editable source in %s ' | ||
| 461 | '(%s command not found in path)', | ||
| 462 | location, | ||
| 463 | version_control.name, | ||
| 464 | ) | ||
| 465 | return dist.as_requirement() | ||
| 466 | logger.warning( | ||
| 467 | 'cannot determine version of editable source in %s (is not SVN ' | ||
| 468 | 'checkout, Git clone, Mercurial clone or Bazaar branch)', | ||
| 469 | location, | ||
| 470 | ) | ||
| 471 | return dist.as_requirement() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/bazaar.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/bazaar.py deleted file mode 100644 index 6ed629a..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/bazaar.py +++ /dev/null | |||
| @@ -1,113 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os | ||
| 5 | |||
| 6 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 7 | |||
| 8 | from pip._internal.download import path_to_url | ||
| 9 | from pip._internal.utils.misc import display_path, rmtree | ||
| 10 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 11 | from pip._internal.vcs import VersionControl, vcs | ||
| 12 | |||
| 13 | logger = logging.getLogger(__name__) | ||
| 14 | |||
| 15 | |||
| 16 | class Bazaar(VersionControl): | ||
| 17 | name = 'bzr' | ||
| 18 | dirname = '.bzr' | ||
| 19 | repo_name = 'branch' | ||
| 20 | schemes = ( | ||
| 21 | 'bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', | ||
| 22 | 'bzr+lp', | ||
| 23 | ) | ||
| 24 | |||
| 25 | def __init__(self, url=None, *args, **kwargs): | ||
| 26 | super(Bazaar, self).__init__(url, *args, **kwargs) | ||
| 27 | # This is only needed for python <2.7.5 | ||
| 28 | # Register lp but do not expose as a scheme to support bzr+lp. | ||
| 29 | if getattr(urllib_parse, 'uses_fragment', None): | ||
| 30 | urllib_parse.uses_fragment.extend(['lp']) | ||
| 31 | |||
| 32 | def get_base_rev_args(self, rev): | ||
| 33 | return ['-r', rev] | ||
| 34 | |||
| 35 | def export(self, location): | ||
| 36 | """ | ||
| 37 | Export the Bazaar repository at the url to the destination location | ||
| 38 | """ | ||
| 39 | # Remove the location to make sure Bazaar can export it correctly | ||
| 40 | if os.path.exists(location): | ||
| 41 | rmtree(location) | ||
| 42 | |||
| 43 | with TempDirectory(kind="export") as temp_dir: | ||
| 44 | self.unpack(temp_dir.path) | ||
| 45 | |||
| 46 | self.run_command( | ||
| 47 | ['export', location], | ||
| 48 | cwd=temp_dir.path, show_stdout=False, | ||
| 49 | ) | ||
| 50 | |||
| 51 | def switch(self, dest, url, rev_options): | ||
| 52 | self.run_command(['switch', url], cwd=dest) | ||
| 53 | |||
| 54 | def update(self, dest, rev_options): | ||
| 55 | cmd_args = ['pull', '-q'] + rev_options.to_args() | ||
| 56 | self.run_command(cmd_args, cwd=dest) | ||
| 57 | |||
| 58 | def obtain(self, dest): | ||
| 59 | url, rev = self.get_url_rev() | ||
| 60 | rev_options = self.make_rev_options(rev) | ||
| 61 | if self.check_destination(dest, url, rev_options): | ||
| 62 | rev_display = rev_options.to_display() | ||
| 63 | logger.info( | ||
| 64 | 'Checking out %s%s to %s', | ||
| 65 | url, | ||
| 66 | rev_display, | ||
| 67 | display_path(dest), | ||
| 68 | ) | ||
| 69 | cmd_args = ['branch', '-q'] + rev_options.to_args() + [url, dest] | ||
| 70 | self.run_command(cmd_args) | ||
| 71 | |||
| 72 | def get_url_rev(self): | ||
| 73 | # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it | ||
| 74 | url, rev = super(Bazaar, self).get_url_rev() | ||
| 75 | if url.startswith('ssh://'): | ||
| 76 | url = 'bzr+' + url | ||
| 77 | return url, rev | ||
| 78 | |||
| 79 | def get_url(self, location): | ||
| 80 | urls = self.run_command(['info'], show_stdout=False, cwd=location) | ||
| 81 | for line in urls.splitlines(): | ||
| 82 | line = line.strip() | ||
| 83 | for x in ('checkout of branch: ', | ||
| 84 | 'parent branch: '): | ||
| 85 | if line.startswith(x): | ||
| 86 | repo = line.split(x)[1] | ||
| 87 | if self._is_local_repository(repo): | ||
| 88 | return path_to_url(repo) | ||
| 89 | return repo | ||
| 90 | return None | ||
| 91 | |||
| 92 | def get_revision(self, location): | ||
| 93 | revision = self.run_command( | ||
| 94 | ['revno'], show_stdout=False, cwd=location, | ||
| 95 | ) | ||
| 96 | return revision.splitlines()[-1] | ||
| 97 | |||
| 98 | def get_src_requirement(self, dist, location): | ||
| 99 | repo = self.get_url(location) | ||
| 100 | if not repo: | ||
| 101 | return None | ||
| 102 | if not repo.lower().startswith('bzr:'): | ||
| 103 | repo = 'bzr+' + repo | ||
| 104 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
| 105 | current_rev = self.get_revision(location) | ||
| 106 | return '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) | ||
| 107 | |||
| 108 | def is_commit_id_equal(self, dest, name): | ||
| 109 | """Always assume the versions don't match""" | ||
| 110 | return False | ||
| 111 | |||
| 112 | |||
| 113 | vcs.register(Bazaar) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py deleted file mode 100644 index 7a63dfa..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py +++ /dev/null | |||
| @@ -1,311 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os.path | ||
| 5 | import re | ||
| 6 | |||
| 7 | from pip._vendor.packaging.version import parse as parse_version | ||
| 8 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 9 | from pip._vendor.six.moves.urllib import request as urllib_request | ||
| 10 | |||
| 11 | from pip._internal.compat import samefile | ||
| 12 | from pip._internal.exceptions import BadCommand | ||
| 13 | from pip._internal.utils.misc import display_path | ||
| 14 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 15 | from pip._internal.vcs import VersionControl, vcs | ||
| 16 | |||
| 17 | urlsplit = urllib_parse.urlsplit | ||
| 18 | urlunsplit = urllib_parse.urlunsplit | ||
| 19 | |||
| 20 | |||
| 21 | logger = logging.getLogger(__name__) | ||
| 22 | |||
| 23 | |||
| 24 | HASH_REGEX = re.compile('[a-fA-F0-9]{40}') | ||
| 25 | |||
| 26 | |||
| 27 | def looks_like_hash(sha): | ||
| 28 | return bool(HASH_REGEX.match(sha)) | ||
| 29 | |||
| 30 | |||
| 31 | class Git(VersionControl): | ||
| 32 | name = 'git' | ||
| 33 | dirname = '.git' | ||
| 34 | repo_name = 'clone' | ||
| 35 | schemes = ( | ||
| 36 | 'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', | ||
| 37 | ) | ||
| 38 | # Prevent the user's environment variables from interfering with pip: | ||
| 39 | # https://github.com/pypa/pip/issues/1130 | ||
| 40 | unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') | ||
| 41 | default_arg_rev = 'HEAD' | ||
| 42 | |||
| 43 | def __init__(self, url=None, *args, **kwargs): | ||
| 44 | |||
| 45 | # Works around an apparent Git bug | ||
| 46 | # (see http://article.gmane.org/gmane.comp.version-control.git/146500) | ||
| 47 | if url: | ||
| 48 | scheme, netloc, path, query, fragment = urlsplit(url) | ||
| 49 | if scheme.endswith('file'): | ||
| 50 | initial_slashes = path[:-len(path.lstrip('/'))] | ||
| 51 | newpath = ( | ||
| 52 | initial_slashes + | ||
| 53 | urllib_request.url2pathname(path) | ||
| 54 | .replace('\\', '/').lstrip('/') | ||
| 55 | ) | ||
| 56 | url = urlunsplit((scheme, netloc, newpath, query, fragment)) | ||
| 57 | after_plus = scheme.find('+') + 1 | ||
| 58 | url = scheme[:after_plus] + urlunsplit( | ||
| 59 | (scheme[after_plus:], netloc, newpath, query, fragment), | ||
| 60 | ) | ||
| 61 | |||
| 62 | super(Git, self).__init__(url, *args, **kwargs) | ||
| 63 | |||
| 64 | def get_base_rev_args(self, rev): | ||
| 65 | return [rev] | ||
| 66 | |||
| 67 | def get_git_version(self): | ||
| 68 | VERSION_PFX = 'git version ' | ||
| 69 | version = self.run_command(['version'], show_stdout=False) | ||
| 70 | if version.startswith(VERSION_PFX): | ||
| 71 | version = version[len(VERSION_PFX):].split()[0] | ||
| 72 | else: | ||
| 73 | version = '' | ||
| 74 | # get first 3 positions of the git version becasue | ||
| 75 | # on windows it is x.y.z.windows.t, and this parses as | ||
| 76 | # LegacyVersion which always smaller than a Version. | ||
| 77 | version = '.'.join(version.split('.')[:3]) | ||
| 78 | return parse_version(version) | ||
| 79 | |||
| 80 | def export(self, location): | ||
| 81 | """Export the Git repository at the url to the destination location""" | ||
| 82 | if not location.endswith('/'): | ||
| 83 | location = location + '/' | ||
| 84 | |||
| 85 | with TempDirectory(kind="export") as temp_dir: | ||
| 86 | self.unpack(temp_dir.path) | ||
| 87 | self.run_command( | ||
| 88 | ['checkout-index', '-a', '-f', '--prefix', location], | ||
| 89 | show_stdout=False, cwd=temp_dir.path | ||
| 90 | ) | ||
| 91 | |||
| 92 | def get_revision_sha(self, dest, rev): | ||
| 93 | """ | ||
| 94 | Return a commit hash for the given revision if it names a remote | ||
| 95 | branch or tag. Otherwise, return None. | ||
| 96 | |||
| 97 | Args: | ||
| 98 | dest: the repository directory. | ||
| 99 | rev: the revision name. | ||
| 100 | """ | ||
| 101 | # Pass rev to pre-filter the list. | ||
| 102 | output = self.run_command(['show-ref', rev], cwd=dest, | ||
| 103 | show_stdout=False, on_returncode='ignore') | ||
| 104 | refs = {} | ||
| 105 | for line in output.strip().splitlines(): | ||
| 106 | try: | ||
| 107 | sha, ref = line.split() | ||
| 108 | except ValueError: | ||
| 109 | # Include the offending line to simplify troubleshooting if | ||
| 110 | # this error ever occurs. | ||
| 111 | raise ValueError('unexpected show-ref line: {!r}'.format(line)) | ||
| 112 | |||
| 113 | refs[ref] = sha | ||
| 114 | |||
| 115 | branch_ref = 'refs/remotes/origin/{}'.format(rev) | ||
| 116 | tag_ref = 'refs/tags/{}'.format(rev) | ||
| 117 | |||
| 118 | return refs.get(branch_ref) or refs.get(tag_ref) | ||
| 119 | |||
| 120 | def check_rev_options(self, dest, rev_options): | ||
| 121 | """Check the revision options before checkout. | ||
| 122 | |||
| 123 | Returns a new RevOptions object for the SHA1 of the branch or tag | ||
| 124 | if found. | ||
| 125 | |||
| 126 | Args: | ||
| 127 | rev_options: a RevOptions object. | ||
| 128 | """ | ||
| 129 | rev = rev_options.arg_rev | ||
| 130 | sha = self.get_revision_sha(dest, rev) | ||
| 131 | |||
| 132 | if sha is not None: | ||
| 133 | return rev_options.make_new(sha) | ||
| 134 | |||
| 135 | # Do not show a warning for the common case of something that has | ||
| 136 | # the form of a Git commit hash. | ||
| 137 | if not looks_like_hash(rev): | ||
| 138 | logger.warning( | ||
| 139 | "Did not find branch or tag '%s', assuming revision or ref.", | ||
| 140 | rev, | ||
| 141 | ) | ||
| 142 | return rev_options | ||
| 143 | |||
| 144 | def is_commit_id_equal(self, dest, name): | ||
| 145 | """ | ||
| 146 | Return whether the current commit hash equals the given name. | ||
| 147 | |||
| 148 | Args: | ||
| 149 | dest: the repository directory. | ||
| 150 | name: a string name. | ||
| 151 | """ | ||
| 152 | if not name: | ||
| 153 | # Then avoid an unnecessary subprocess call. | ||
| 154 | return False | ||
| 155 | |||
| 156 | return self.get_revision(dest) == name | ||
| 157 | |||
| 158 | def switch(self, dest, url, rev_options): | ||
| 159 | self.run_command(['config', 'remote.origin.url', url], cwd=dest) | ||
| 160 | cmd_args = ['checkout', '-q'] + rev_options.to_args() | ||
| 161 | self.run_command(cmd_args, cwd=dest) | ||
| 162 | |||
| 163 | self.update_submodules(dest) | ||
| 164 | |||
| 165 | def update(self, dest, rev_options): | ||
| 166 | # First fetch changes from the default remote | ||
| 167 | if self.get_git_version() >= parse_version('1.9.0'): | ||
| 168 | # fetch tags in addition to everything else | ||
| 169 | self.run_command(['fetch', '-q', '--tags'], cwd=dest) | ||
| 170 | else: | ||
| 171 | self.run_command(['fetch', '-q'], cwd=dest) | ||
| 172 | # Then reset to wanted revision (maybe even origin/master) | ||
| 173 | rev_options = self.check_rev_options(dest, rev_options) | ||
| 174 | cmd_args = ['reset', '--hard', '-q'] + rev_options.to_args() | ||
| 175 | self.run_command(cmd_args, cwd=dest) | ||
| 176 | #: update submodules | ||
| 177 | self.update_submodules(dest) | ||
| 178 | |||
| 179 | def obtain(self, dest): | ||
| 180 | url, rev = self.get_url_rev() | ||
| 181 | rev_options = self.make_rev_options(rev) | ||
| 182 | if self.check_destination(dest, url, rev_options): | ||
| 183 | rev_display = rev_options.to_display() | ||
| 184 | logger.info( | ||
| 185 | 'Cloning %s%s to %s', url, rev_display, display_path(dest), | ||
| 186 | ) | ||
| 187 | self.run_command(['clone', '-q', url, dest]) | ||
| 188 | |||
| 189 | if rev: | ||
| 190 | rev_options = self.check_rev_options(dest, rev_options) | ||
| 191 | # Only do a checkout if the current commit id doesn't match | ||
| 192 | # the requested revision. | ||
| 193 | if not self.is_commit_id_equal(dest, rev_options.rev): | ||
| 194 | rev = rev_options.rev | ||
| 195 | # Only fetch the revision if it's a ref | ||
| 196 | if rev.startswith('refs/'): | ||
| 197 | self.run_command( | ||
| 198 | ['fetch', '-q', url] + rev_options.to_args(), | ||
| 199 | cwd=dest, | ||
| 200 | ) | ||
| 201 | # Change the revision to the SHA of the ref we fetched | ||
| 202 | rev = 'FETCH_HEAD' | ||
| 203 | self.run_command(['checkout', '-q', rev], cwd=dest) | ||
| 204 | |||
| 205 | #: repo may contain submodules | ||
| 206 | self.update_submodules(dest) | ||
| 207 | |||
| 208 | def get_url(self, location): | ||
| 209 | """Return URL of the first remote encountered.""" | ||
| 210 | remotes = self.run_command( | ||
| 211 | ['config', '--get-regexp', r'remote\..*\.url'], | ||
| 212 | show_stdout=False, cwd=location, | ||
| 213 | ) | ||
| 214 | remotes = remotes.splitlines() | ||
| 215 | found_remote = remotes[0] | ||
| 216 | for remote in remotes: | ||
| 217 | if remote.startswith('remote.origin.url '): | ||
| 218 | found_remote = remote | ||
| 219 | break | ||
| 220 | url = found_remote.split(' ')[1] | ||
| 221 | return url.strip() | ||
| 222 | |||
| 223 | def get_revision(self, location): | ||
| 224 | current_rev = self.run_command( | ||
| 225 | ['rev-parse', 'HEAD'], show_stdout=False, cwd=location, | ||
| 226 | ) | ||
| 227 | return current_rev.strip() | ||
| 228 | |||
| 229 | def _get_subdirectory(self, location): | ||
| 230 | """Return the relative path of setup.py to the git repo root.""" | ||
| 231 | # find the repo root | ||
| 232 | git_dir = self.run_command(['rev-parse', '--git-dir'], | ||
| 233 | show_stdout=False, cwd=location).strip() | ||
| 234 | if not os.path.isabs(git_dir): | ||
| 235 | git_dir = os.path.join(location, git_dir) | ||
| 236 | root_dir = os.path.join(git_dir, '..') | ||
| 237 | # find setup.py | ||
| 238 | orig_location = location | ||
| 239 | while not os.path.exists(os.path.join(location, 'setup.py')): | ||
| 240 | last_location = location | ||
| 241 | location = os.path.dirname(location) | ||
| 242 | if location == last_location: | ||
| 243 | # We've traversed up to the root of the filesystem without | ||
| 244 | # finding setup.py | ||
| 245 | logger.warning( | ||
| 246 | "Could not find setup.py for directory %s (tried all " | ||
| 247 | "parent directories)", | ||
| 248 | orig_location, | ||
| 249 | ) | ||
| 250 | return None | ||
| 251 | # relative path of setup.py to repo root | ||
| 252 | if samefile(root_dir, location): | ||
| 253 | return None | ||
| 254 | return os.path.relpath(location, root_dir) | ||
| 255 | |||
| 256 | def get_src_requirement(self, dist, location): | ||
| 257 | repo = self.get_url(location) | ||
| 258 | if not repo.lower().startswith('git:'): | ||
| 259 | repo = 'git+' + repo | ||
| 260 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
| 261 | if not repo: | ||
| 262 | return None | ||
| 263 | current_rev = self.get_revision(location) | ||
| 264 | req = '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) | ||
| 265 | subdirectory = self._get_subdirectory(location) | ||
| 266 | if subdirectory: | ||
| 267 | req += '&subdirectory=' + subdirectory | ||
| 268 | return req | ||
| 269 | |||
| 270 | def get_url_rev(self): | ||
| 271 | """ | ||
| 272 | Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. | ||
| 273 | That's required because although they use SSH they sometimes doesn't | ||
| 274 | work with a ssh:// scheme (e.g. Github). But we need a scheme for | ||
| 275 | parsing. Hence we remove it again afterwards and return it as a stub. | ||
| 276 | """ | ||
| 277 | if '://' not in self.url: | ||
| 278 | assert 'file:' not in self.url | ||
| 279 | self.url = self.url.replace('git+', 'git+ssh://') | ||
| 280 | url, rev = super(Git, self).get_url_rev() | ||
| 281 | url = url.replace('ssh://', '') | ||
| 282 | else: | ||
| 283 | url, rev = super(Git, self).get_url_rev() | ||
| 284 | |||
| 285 | return url, rev | ||
| 286 | |||
| 287 | def update_submodules(self, location): | ||
| 288 | if not os.path.exists(os.path.join(location, '.gitmodules')): | ||
| 289 | return | ||
| 290 | self.run_command( | ||
| 291 | ['submodule', 'update', '--init', '--recursive', '-q'], | ||
| 292 | cwd=location, | ||
| 293 | ) | ||
| 294 | |||
| 295 | @classmethod | ||
| 296 | def controls_location(cls, location): | ||
| 297 | if super(Git, cls).controls_location(location): | ||
| 298 | return True | ||
| 299 | try: | ||
| 300 | r = cls().run_command(['rev-parse'], | ||
| 301 | cwd=location, | ||
| 302 | show_stdout=False, | ||
| 303 | on_returncode='ignore') | ||
| 304 | return not r | ||
| 305 | except BadCommand: | ||
| 306 | logger.debug("could not determine if %s is under git control " | ||
| 307 | "because git is not available", location) | ||
| 308 | return False | ||
| 309 | |||
| 310 | |||
| 311 | vcs.register(Git) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/mercurial.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/mercurial.py deleted file mode 100644 index 3936473..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/mercurial.py +++ /dev/null | |||
| @@ -1,105 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os | ||
| 5 | |||
| 6 | from pip._vendor.six.moves import configparser | ||
| 7 | |||
| 8 | from pip._internal.download import path_to_url | ||
| 9 | from pip._internal.utils.misc import display_path | ||
| 10 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 11 | from pip._internal.vcs import VersionControl, vcs | ||
| 12 | |||
| 13 | logger = logging.getLogger(__name__) | ||
| 14 | |||
| 15 | |||
| 16 | class Mercurial(VersionControl): | ||
| 17 | name = 'hg' | ||
| 18 | dirname = '.hg' | ||
| 19 | repo_name = 'clone' | ||
| 20 | schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http') | ||
| 21 | |||
| 22 | def get_base_rev_args(self, rev): | ||
| 23 | return [rev] | ||
| 24 | |||
| 25 | def export(self, location): | ||
| 26 | """Export the Hg repository at the url to the destination location""" | ||
| 27 | with TempDirectory(kind="export") as temp_dir: | ||
| 28 | self.unpack(temp_dir.path) | ||
| 29 | |||
| 30 | self.run_command( | ||
| 31 | ['archive', location], show_stdout=False, cwd=temp_dir.path | ||
| 32 | ) | ||
| 33 | |||
| 34 | def switch(self, dest, url, rev_options): | ||
| 35 | repo_config = os.path.join(dest, self.dirname, 'hgrc') | ||
| 36 | config = configparser.SafeConfigParser() | ||
| 37 | try: | ||
| 38 | config.read(repo_config) | ||
| 39 | config.set('paths', 'default', url) | ||
| 40 | with open(repo_config, 'w') as config_file: | ||
| 41 | config.write(config_file) | ||
| 42 | except (OSError, configparser.NoSectionError) as exc: | ||
| 43 | logger.warning( | ||
| 44 | 'Could not switch Mercurial repository to %s: %s', url, exc, | ||
| 45 | ) | ||
| 46 | else: | ||
| 47 | cmd_args = ['update', '-q'] + rev_options.to_args() | ||
| 48 | self.run_command(cmd_args, cwd=dest) | ||
| 49 | |||
| 50 | def update(self, dest, rev_options): | ||
| 51 | self.run_command(['pull', '-q'], cwd=dest) | ||
| 52 | cmd_args = ['update', '-q'] + rev_options.to_args() | ||
| 53 | self.run_command(cmd_args, cwd=dest) | ||
| 54 | |||
| 55 | def obtain(self, dest): | ||
| 56 | url, rev = self.get_url_rev() | ||
| 57 | rev_options = self.make_rev_options(rev) | ||
| 58 | if self.check_destination(dest, url, rev_options): | ||
| 59 | rev_display = rev_options.to_display() | ||
| 60 | logger.info( | ||
| 61 | 'Cloning hg %s%s to %s', | ||
| 62 | url, | ||
| 63 | rev_display, | ||
| 64 | display_path(dest), | ||
| 65 | ) | ||
| 66 | self.run_command(['clone', '--noupdate', '-q', url, dest]) | ||
| 67 | cmd_args = ['update', '-q'] + rev_options.to_args() | ||
| 68 | self.run_command(cmd_args, cwd=dest) | ||
| 69 | |||
| 70 | def get_url(self, location): | ||
| 71 | url = self.run_command( | ||
| 72 | ['showconfig', 'paths.default'], | ||
| 73 | show_stdout=False, cwd=location).strip() | ||
| 74 | if self._is_local_repository(url): | ||
| 75 | url = path_to_url(url) | ||
| 76 | return url.strip() | ||
| 77 | |||
| 78 | def get_revision(self, location): | ||
| 79 | current_revision = self.run_command( | ||
| 80 | ['parents', '--template={rev}'], | ||
| 81 | show_stdout=False, cwd=location).strip() | ||
| 82 | return current_revision | ||
| 83 | |||
| 84 | def get_revision_hash(self, location): | ||
| 85 | current_rev_hash = self.run_command( | ||
| 86 | ['parents', '--template={node}'], | ||
| 87 | show_stdout=False, cwd=location).strip() | ||
| 88 | return current_rev_hash | ||
| 89 | |||
| 90 | def get_src_requirement(self, dist, location): | ||
| 91 | repo = self.get_url(location) | ||
| 92 | if not repo.lower().startswith('hg:'): | ||
| 93 | repo = 'hg+' + repo | ||
| 94 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
| 95 | if not repo: | ||
| 96 | return None | ||
| 97 | current_rev_hash = self.get_revision_hash(location) | ||
| 98 | return '%s@%s#egg=%s' % (repo, current_rev_hash, egg_project_name) | ||
| 99 | |||
| 100 | def is_commit_id_equal(self, dest, name): | ||
| 101 | """Always assume the versions don't match""" | ||
| 102 | return False | ||
| 103 | |||
| 104 | |||
| 105 | vcs.register(Mercurial) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/subversion.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/subversion.py deleted file mode 100644 index 95e5440..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/subversion.py +++ /dev/null | |||
| @@ -1,271 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os | ||
| 5 | import re | ||
| 6 | |||
| 7 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 8 | |||
| 9 | from pip._internal.index import Link | ||
| 10 | from pip._internal.utils.logging import indent_log | ||
| 11 | from pip._internal.utils.misc import display_path, rmtree | ||
| 12 | from pip._internal.vcs import VersionControl, vcs | ||
| 13 | |||
| 14 | _svn_xml_url_re = re.compile('url="([^"]+)"') | ||
| 15 | _svn_rev_re = re.compile(r'committed-rev="(\d+)"') | ||
| 16 | _svn_url_re = re.compile(r'URL: (.+)') | ||
| 17 | _svn_revision_re = re.compile(r'Revision: (.+)') | ||
| 18 | _svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') | ||
| 19 | _svn_info_xml_url_re = re.compile(r'<url>(.*)</url>') | ||
| 20 | |||
| 21 | |||
| 22 | logger = logging.getLogger(__name__) | ||
| 23 | |||
| 24 | |||
| 25 | class Subversion(VersionControl): | ||
| 26 | name = 'svn' | ||
| 27 | dirname = '.svn' | ||
| 28 | repo_name = 'checkout' | ||
| 29 | schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') | ||
| 30 | |||
| 31 | def get_base_rev_args(self, rev): | ||
| 32 | return ['-r', rev] | ||
| 33 | |||
| 34 | def get_info(self, location): | ||
| 35 | """Returns (url, revision), where both are strings""" | ||
| 36 | assert not location.rstrip('/').endswith(self.dirname), \ | ||
| 37 | 'Bad directory: %s' % location | ||
| 38 | output = self.run_command( | ||
| 39 | ['info', location], | ||
| 40 | show_stdout=False, | ||
| 41 | extra_environ={'LANG': 'C'}, | ||
| 42 | ) | ||
| 43 | match = _svn_url_re.search(output) | ||
| 44 | if not match: | ||
| 45 | logger.warning( | ||
| 46 | 'Cannot determine URL of svn checkout %s', | ||
| 47 | display_path(location), | ||
| 48 | ) | ||
| 49 | logger.debug('Output that cannot be parsed: \n%s', output) | ||
| 50 | return None, None | ||
| 51 | url = match.group(1).strip() | ||
| 52 | match = _svn_revision_re.search(output) | ||
| 53 | if not match: | ||
| 54 | logger.warning( | ||
| 55 | 'Cannot determine revision of svn checkout %s', | ||
| 56 | display_path(location), | ||
| 57 | ) | ||
| 58 | logger.debug('Output that cannot be parsed: \n%s', output) | ||
| 59 | return url, None | ||
| 60 | return url, match.group(1) | ||
| 61 | |||
| 62 | def export(self, location): | ||
| 63 | """Export the svn repository at the url to the destination location""" | ||
| 64 | url, rev = self.get_url_rev() | ||
| 65 | rev_options = get_rev_options(self, url, rev) | ||
| 66 | url = self.remove_auth_from_url(url) | ||
| 67 | logger.info('Exporting svn repository %s to %s', url, location) | ||
| 68 | with indent_log(): | ||
| 69 | if os.path.exists(location): | ||
| 70 | # Subversion doesn't like to check out over an existing | ||
| 71 | # directory --force fixes this, but was only added in svn 1.5 | ||
| 72 | rmtree(location) | ||
| 73 | cmd_args = ['export'] + rev_options.to_args() + [url, location] | ||
| 74 | self.run_command(cmd_args, show_stdout=False) | ||
| 75 | |||
| 76 | def switch(self, dest, url, rev_options): | ||
| 77 | cmd_args = ['switch'] + rev_options.to_args() + [url, dest] | ||
| 78 | self.run_command(cmd_args) | ||
| 79 | |||
| 80 | def update(self, dest, rev_options): | ||
| 81 | cmd_args = ['update'] + rev_options.to_args() + [dest] | ||
| 82 | self.run_command(cmd_args) | ||
| 83 | |||
| 84 | def obtain(self, dest): | ||
| 85 | url, rev = self.get_url_rev() | ||
| 86 | rev_options = get_rev_options(self, url, rev) | ||
| 87 | url = self.remove_auth_from_url(url) | ||
| 88 | if self.check_destination(dest, url, rev_options): | ||
| 89 | rev_display = rev_options.to_display() | ||
| 90 | logger.info( | ||
| 91 | 'Checking out %s%s to %s', | ||
| 92 | url, | ||
| 93 | rev_display, | ||
| 94 | display_path(dest), | ||
| 95 | ) | ||
| 96 | cmd_args = ['checkout', '-q'] + rev_options.to_args() + [url, dest] | ||
| 97 | self.run_command(cmd_args) | ||
| 98 | |||
| 99 | def get_location(self, dist, dependency_links): | ||
| 100 | for url in dependency_links: | ||
| 101 | egg_fragment = Link(url).egg_fragment | ||
| 102 | if not egg_fragment: | ||
| 103 | continue | ||
| 104 | if '-' in egg_fragment: | ||
| 105 | # FIXME: will this work when a package has - in the name? | ||
| 106 | key = '-'.join(egg_fragment.split('-')[:-1]).lower() | ||
| 107 | else: | ||
| 108 | key = egg_fragment | ||
| 109 | if key == dist.key: | ||
| 110 | return url.split('#', 1)[0] | ||
| 111 | return None | ||
| 112 | |||
| 113 | def get_revision(self, location): | ||
| 114 | """ | ||
| 115 | Return the maximum revision for all files under a given location | ||
| 116 | """ | ||
| 117 | # Note: taken from setuptools.command.egg_info | ||
| 118 | revision = 0 | ||
| 119 | |||
| 120 | for base, dirs, files in os.walk(location): | ||
| 121 | if self.dirname not in dirs: | ||
| 122 | dirs[:] = [] | ||
| 123 | continue # no sense walking uncontrolled subdirs | ||
| 124 | dirs.remove(self.dirname) | ||
| 125 | entries_fn = os.path.join(base, self.dirname, 'entries') | ||
| 126 | if not os.path.exists(entries_fn): | ||
| 127 | # FIXME: should we warn? | ||
| 128 | continue | ||
| 129 | |||
| 130 | dirurl, localrev = self._get_svn_url_rev(base) | ||
| 131 | |||
| 132 | if base == location: | ||
| 133 | base = dirurl + '/' # save the root url | ||
| 134 | elif not dirurl or not dirurl.startswith(base): | ||
| 135 | dirs[:] = [] | ||
| 136 | continue # not part of the same svn tree, skip it | ||
| 137 | revision = max(revision, localrev) | ||
| 138 | return revision | ||
| 139 | |||
| 140 | def get_url_rev(self): | ||
| 141 | # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it | ||
| 142 | url, rev = super(Subversion, self).get_url_rev() | ||
| 143 | if url.startswith('ssh://'): | ||
| 144 | url = 'svn+' + url | ||
| 145 | return url, rev | ||
| 146 | |||
| 147 | def get_url(self, location): | ||
| 148 | # In cases where the source is in a subdirectory, not alongside | ||
| 149 | # setup.py we have to look up in the location until we find a real | ||
| 150 | # setup.py | ||
| 151 | orig_location = location | ||
| 152 | while not os.path.exists(os.path.join(location, 'setup.py')): | ||
| 153 | last_location = location | ||
| 154 | location = os.path.dirname(location) | ||
| 155 | if location == last_location: | ||
| 156 | # We've traversed up to the root of the filesystem without | ||
| 157 | # finding setup.py | ||
| 158 | logger.warning( | ||
| 159 | "Could not find setup.py for directory %s (tried all " | ||
| 160 | "parent directories)", | ||
| 161 | orig_location, | ||
| 162 | ) | ||
| 163 | return None | ||
| 164 | |||
| 165 | return self._get_svn_url_rev(location)[0] | ||
| 166 | |||
| 167 | def _get_svn_url_rev(self, location): | ||
| 168 | from pip._internal.exceptions import InstallationError | ||
| 169 | |||
| 170 | entries_path = os.path.join(location, self.dirname, 'entries') | ||
| 171 | if os.path.exists(entries_path): | ||
| 172 | with open(entries_path) as f: | ||
| 173 | data = f.read() | ||
| 174 | else: # subversion >= 1.7 does not have the 'entries' file | ||
| 175 | data = '' | ||
| 176 | |||
| 177 | if (data.startswith('8') or | ||
| 178 | data.startswith('9') or | ||
| 179 | data.startswith('10')): | ||
| 180 | data = list(map(str.splitlines, data.split('\n\x0c\n'))) | ||
| 181 | del data[0][0] # get rid of the '8' | ||
| 182 | url = data[0][3] | ||
| 183 | revs = [int(d[9]) for d in data if len(d) > 9 and d[9]] + [0] | ||
| 184 | elif data.startswith('<?xml'): | ||
| 185 | match = _svn_xml_url_re.search(data) | ||
| 186 | if not match: | ||
| 187 | raise ValueError('Badly formatted data: %r' % data) | ||
| 188 | url = match.group(1) # get repository URL | ||
| 189 | revs = [int(m.group(1)) for m in _svn_rev_re.finditer(data)] + [0] | ||
| 190 | else: | ||
| 191 | try: | ||
| 192 | # subversion >= 1.7 | ||
| 193 | xml = self.run_command( | ||
| 194 | ['info', '--xml', location], | ||
| 195 | show_stdout=False, | ||
| 196 | ) | ||
| 197 | url = _svn_info_xml_url_re.search(xml).group(1) | ||
| 198 | revs = [ | ||
| 199 | int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml) | ||
| 200 | ] | ||
| 201 | except InstallationError: | ||
| 202 | url, revs = None, [] | ||
| 203 | |||
| 204 | if revs: | ||
| 205 | rev = max(revs) | ||
| 206 | else: | ||
| 207 | rev = 0 | ||
| 208 | |||
| 209 | return url, rev | ||
| 210 | |||
| 211 | def get_src_requirement(self, dist, location): | ||
| 212 | repo = self.get_url(location) | ||
| 213 | if repo is None: | ||
| 214 | return None | ||
| 215 | # FIXME: why not project name? | ||
| 216 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
| 217 | rev = self.get_revision(location) | ||
| 218 | return 'svn+%s@%s#egg=%s' % (repo, rev, egg_project_name) | ||
| 219 | |||
| 220 | def is_commit_id_equal(self, dest, name): | ||
| 221 | """Always assume the versions don't match""" | ||
| 222 | return False | ||
| 223 | |||
| 224 | @staticmethod | ||
| 225 | def remove_auth_from_url(url): | ||
| 226 | # Return a copy of url with 'username:password@' removed. | ||
| 227 | # username/pass params are passed to subversion through flags | ||
| 228 | # and are not recognized in the url. | ||
| 229 | |||
| 230 | # parsed url | ||
| 231 | purl = urllib_parse.urlsplit(url) | ||
| 232 | stripped_netloc = \ | ||
| 233 | purl.netloc.split('@')[-1] | ||
| 234 | |||
| 235 | # stripped url | ||
| 236 | url_pieces = ( | ||
| 237 | purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment | ||
| 238 | ) | ||
| 239 | surl = urllib_parse.urlunsplit(url_pieces) | ||
| 240 | return surl | ||
| 241 | |||
| 242 | |||
| 243 | def get_rev_options(vcs, url, rev): | ||
| 244 | """ | ||
| 245 | Return a RevOptions object. | ||
| 246 | """ | ||
| 247 | r = urllib_parse.urlsplit(url) | ||
| 248 | if hasattr(r, 'username'): | ||
| 249 | # >= Python-2.5 | ||
| 250 | username, password = r.username, r.password | ||
| 251 | else: | ||
| 252 | netloc = r[1] | ||
| 253 | if '@' in netloc: | ||
| 254 | auth = netloc.split('@')[0] | ||
| 255 | if ':' in auth: | ||
| 256 | username, password = auth.split(':', 1) | ||
| 257 | else: | ||
| 258 | username, password = auth, None | ||
| 259 | else: | ||
| 260 | username, password = None, None | ||
| 261 | |||
| 262 | extra_args = [] | ||
| 263 | if username: | ||
| 264 | extra_args += ['--username', username] | ||
| 265 | if password: | ||
| 266 | extra_args += ['--password', password] | ||
| 267 | |||
| 268 | return vcs.make_rev_options(rev, extra_args=extra_args) | ||
| 269 | |||
| 270 | |||
| 271 | vcs.register(Subversion) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/wheel.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/wheel.py deleted file mode 100644 index 36459dd..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/wheel.py +++ /dev/null | |||
| @@ -1,817 +0,0 @@ | |||
| 1 | """ | ||
| 2 | Support for installing and building the "wheel" binary package format. | ||
| 3 | """ | ||
| 4 | from __future__ import absolute_import | ||
| 5 | |||
| 6 | import collections | ||
| 7 | import compileall | ||
| 8 | import copy | ||
| 9 | import csv | ||
| 10 | import hashlib | ||
| 11 | import logging | ||
| 12 | import os.path | ||
| 13 | import re | ||
| 14 | import shutil | ||
| 15 | import stat | ||
| 16 | import sys | ||
| 17 | import warnings | ||
| 18 | from base64 import urlsafe_b64encode | ||
| 19 | from email.parser import Parser | ||
| 20 | |||
| 21 | from pip._vendor import pkg_resources | ||
| 22 | from pip._vendor.distlib.scripts import ScriptMaker | ||
| 23 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 24 | from pip._vendor.six import StringIO | ||
| 25 | |||
| 26 | from pip._internal import pep425tags | ||
| 27 | from pip._internal.build_env import BuildEnvironment | ||
| 28 | from pip._internal.download import path_to_url, unpack_url | ||
| 29 | from pip._internal.exceptions import ( | ||
| 30 | InstallationError, InvalidWheelFilename, UnsupportedWheel, | ||
| 31 | ) | ||
| 32 | from pip._internal.locations import ( | ||
| 33 | PIP_DELETE_MARKER_FILENAME, distutils_scheme, | ||
| 34 | ) | ||
| 35 | from pip._internal.utils.logging import indent_log | ||
| 36 | from pip._internal.utils.misc import ( | ||
| 37 | call_subprocess, captured_stdout, ensure_dir, read_chunks, | ||
| 38 | ) | ||
| 39 | from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM | ||
| 40 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 41 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 42 | from pip._internal.utils.ui import open_spinner | ||
| 43 | |||
| 44 | if MYPY_CHECK_RUNNING: | ||
| 45 | from typing import Dict, List, Optional | ||
| 46 | |||
| 47 | wheel_ext = '.whl' | ||
| 48 | |||
| 49 | VERSION_COMPATIBLE = (1, 0) | ||
| 50 | |||
| 51 | |||
| 52 | logger = logging.getLogger(__name__) | ||
| 53 | |||
| 54 | |||
| 55 | def rehash(path, algo='sha256', blocksize=1 << 20): | ||
| 56 | """Return (hash, length) for path using hashlib.new(algo)""" | ||
| 57 | h = hashlib.new(algo) | ||
| 58 | length = 0 | ||
| 59 | with open(path, 'rb') as f: | ||
| 60 | for block in read_chunks(f, size=blocksize): | ||
| 61 | length += len(block) | ||
| 62 | h.update(block) | ||
| 63 | digest = 'sha256=' + urlsafe_b64encode( | ||
| 64 | h.digest() | ||
| 65 | ).decode('latin1').rstrip('=') | ||
| 66 | return (digest, length) | ||
| 67 | |||
| 68 | |||
| 69 | def open_for_csv(name, mode): | ||
| 70 | if sys.version_info[0] < 3: | ||
| 71 | nl = {} | ||
| 72 | bin = 'b' | ||
| 73 | else: | ||
| 74 | nl = {'newline': ''} | ||
| 75 | bin = '' | ||
| 76 | return open(name, mode + bin, **nl) | ||
| 77 | |||
| 78 | |||
| 79 | def fix_script(path): | ||
| 80 | """Replace #!python with #!/path/to/python | ||
| 81 | Return True if file was changed.""" | ||
| 82 | # XXX RECORD hashes will need to be updated | ||
| 83 | if os.path.isfile(path): | ||
| 84 | with open(path, 'rb') as script: | ||
| 85 | firstline = script.readline() | ||
| 86 | if not firstline.startswith(b'#!python'): | ||
| 87 | return False | ||
| 88 | exename = sys.executable.encode(sys.getfilesystemencoding()) | ||
| 89 | firstline = b'#!' + exename + os.linesep.encode("ascii") | ||
| 90 | rest = script.read() | ||
| 91 | with open(path, 'wb') as script: | ||
| 92 | script.write(firstline) | ||
| 93 | script.write(rest) | ||
| 94 | return True | ||
| 95 | |||
| 96 | |||
| 97 | dist_info_re = re.compile(r"""^(?P<namever>(?P<name>.+?)(-(?P<ver>.+?))?) | ||
| 98 | \.dist-info$""", re.VERBOSE) | ||
| 99 | |||
| 100 | |||
| 101 | def root_is_purelib(name, wheeldir): | ||
| 102 | """ | ||
| 103 | Return True if the extracted wheel in wheeldir should go into purelib. | ||
| 104 | """ | ||
| 105 | name_folded = name.replace("-", "_") | ||
| 106 | for item in os.listdir(wheeldir): | ||
| 107 | match = dist_info_re.match(item) | ||
| 108 | if match and match.group('name') == name_folded: | ||
| 109 | with open(os.path.join(wheeldir, item, 'WHEEL')) as wheel: | ||
| 110 | for line in wheel: | ||
| 111 | line = line.lower().rstrip() | ||
| 112 | if line == "root-is-purelib: true": | ||
| 113 | return True | ||
| 114 | return False | ||
| 115 | |||
| 116 | |||
| 117 | def get_entrypoints(filename): | ||
| 118 | if not os.path.exists(filename): | ||
| 119 | return {}, {} | ||
| 120 | |||
| 121 | # This is done because you can pass a string to entry_points wrappers which | ||
| 122 | # means that they may or may not be valid INI files. The attempt here is to | ||
| 123 | # strip leading and trailing whitespace in order to make them valid INI | ||
| 124 | # files. | ||
| 125 | with open(filename) as fp: | ||
| 126 | data = StringIO() | ||
| 127 | for line in fp: | ||
| 128 | data.write(line.strip()) | ||
| 129 | data.write("\n") | ||
| 130 | data.seek(0) | ||
| 131 | |||
| 132 | # get the entry points and then the script names | ||
| 133 | entry_points = pkg_resources.EntryPoint.parse_map(data) | ||
| 134 | console = entry_points.get('console_scripts', {}) | ||
| 135 | gui = entry_points.get('gui_scripts', {}) | ||
| 136 | |||
| 137 | def _split_ep(s): | ||
| 138 | """get the string representation of EntryPoint, remove space and split | ||
| 139 | on '='""" | ||
| 140 | return str(s).replace(" ", "").split("=") | ||
| 141 | |||
| 142 | # convert the EntryPoint objects into strings with module:function | ||
| 143 | console = dict(_split_ep(v) for v in console.values()) | ||
| 144 | gui = dict(_split_ep(v) for v in gui.values()) | ||
| 145 | return console, gui | ||
| 146 | |||
| 147 | |||
| 148 | def message_about_scripts_not_on_PATH(scripts): | ||
| 149 | # type: (List[str]) -> Optional[str] | ||
| 150 | """Determine if any scripts are not on PATH and format a warning. | ||
| 151 | |||
| 152 | Returns a warning message if one or more scripts are not on PATH, | ||
| 153 | otherwise None. | ||
| 154 | """ | ||
| 155 | if not scripts: | ||
| 156 | return None | ||
| 157 | |||
| 158 | # Group scripts by the path they were installed in | ||
| 159 | grouped_by_dir = collections.defaultdict(set) # type: Dict[str, set] | ||
| 160 | for destfile in scripts: | ||
| 161 | parent_dir = os.path.dirname(destfile) | ||
| 162 | script_name = os.path.basename(destfile) | ||
| 163 | grouped_by_dir[parent_dir].add(script_name) | ||
| 164 | |||
| 165 | # We don't want to warn for directories that are on PATH. | ||
| 166 | not_warn_dirs = [ | ||
| 167 | os.path.normcase(i) for i in os.environ["PATH"].split(os.pathsep) | ||
| 168 | ] | ||
| 169 | # If an executable sits with sys.executable, we don't warn for it. | ||
| 170 | # This covers the case of venv invocations without activating the venv. | ||
| 171 | not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable))) | ||
| 172 | warn_for = { | ||
| 173 | parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items() | ||
| 174 | if os.path.normcase(parent_dir) not in not_warn_dirs | ||
| 175 | } | ||
| 176 | if not warn_for: | ||
| 177 | return None | ||
| 178 | |||
| 179 | # Format a message | ||
| 180 | msg_lines = [] | ||
| 181 | for parent_dir, scripts in warn_for.items(): | ||
| 182 | scripts = sorted(scripts) | ||
| 183 | if len(scripts) == 1: | ||
| 184 | start_text = "script {} is".format(scripts[0]) | ||
| 185 | else: | ||
| 186 | start_text = "scripts {} are".format( | ||
| 187 | ", ".join(scripts[:-1]) + " and " + scripts[-1] | ||
| 188 | ) | ||
| 189 | |||
| 190 | msg_lines.append( | ||
| 191 | "The {} installed in '{}' which is not on PATH." | ||
| 192 | .format(start_text, parent_dir) | ||
| 193 | ) | ||
| 194 | |||
| 195 | last_line_fmt = ( | ||
| 196 | "Consider adding {} to PATH or, if you prefer " | ||
| 197 | "to suppress this warning, use --no-warn-script-location." | ||
| 198 | ) | ||
| 199 | if len(msg_lines) == 1: | ||
| 200 | msg_lines.append(last_line_fmt.format("this directory")) | ||
| 201 | else: | ||
| 202 | msg_lines.append(last_line_fmt.format("these directories")) | ||
| 203 | |||
| 204 | # Returns the formatted multiline message | ||
| 205 | return "\n".join(msg_lines) | ||
| 206 | |||
| 207 | |||
| 208 | def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None, | ||
| 209 | pycompile=True, scheme=None, isolated=False, prefix=None, | ||
| 210 | warn_script_location=True): | ||
| 211 | """Install a wheel""" | ||
| 212 | |||
| 213 | if not scheme: | ||
| 214 | scheme = distutils_scheme( | ||
| 215 | name, user=user, home=home, root=root, isolated=isolated, | ||
| 216 | prefix=prefix, | ||
| 217 | ) | ||
| 218 | |||
| 219 | if root_is_purelib(name, wheeldir): | ||
| 220 | lib_dir = scheme['purelib'] | ||
| 221 | else: | ||
| 222 | lib_dir = scheme['platlib'] | ||
| 223 | |||
| 224 | info_dir = [] | ||
| 225 | data_dirs = [] | ||
| 226 | source = wheeldir.rstrip(os.path.sep) + os.path.sep | ||
| 227 | |||
| 228 | # Record details of the files moved | ||
| 229 | # installed = files copied from the wheel to the destination | ||
| 230 | # changed = files changed while installing (scripts #! line typically) | ||
| 231 | # generated = files newly generated during the install (script wrappers) | ||
| 232 | installed = {} | ||
| 233 | changed = set() | ||
| 234 | generated = [] | ||
| 235 | |||
| 236 | # Compile all of the pyc files that we're going to be installing | ||
| 237 | if pycompile: | ||
| 238 | with captured_stdout() as stdout: | ||
| 239 | with warnings.catch_warnings(): | ||
| 240 | warnings.filterwarnings('ignore') | ||
| 241 | compileall.compile_dir(source, force=True, quiet=True) | ||
| 242 | logger.debug(stdout.getvalue()) | ||
| 243 | |||
| 244 | def normpath(src, p): | ||
| 245 | return os.path.relpath(src, p).replace(os.path.sep, '/') | ||
| 246 | |||
| 247 | def record_installed(srcfile, destfile, modified=False): | ||
| 248 | """Map archive RECORD paths to installation RECORD paths.""" | ||
| 249 | oldpath = normpath(srcfile, wheeldir) | ||
| 250 | newpath = normpath(destfile, lib_dir) | ||
| 251 | installed[oldpath] = newpath | ||
| 252 | if modified: | ||
| 253 | changed.add(destfile) | ||
| 254 | |||
| 255 | def clobber(source, dest, is_base, fixer=None, filter=None): | ||
| 256 | ensure_dir(dest) # common for the 'include' path | ||
| 257 | |||
| 258 | for dir, subdirs, files in os.walk(source): | ||
| 259 | basedir = dir[len(source):].lstrip(os.path.sep) | ||
| 260 | destdir = os.path.join(dest, basedir) | ||
| 261 | if is_base and basedir.split(os.path.sep, 1)[0].endswith('.data'): | ||
| 262 | continue | ||
| 263 | for s in subdirs: | ||
| 264 | destsubdir = os.path.join(dest, basedir, s) | ||
| 265 | if is_base and basedir == '' and destsubdir.endswith('.data'): | ||
| 266 | data_dirs.append(s) | ||
| 267 | continue | ||
| 268 | elif (is_base and | ||
| 269 | s.endswith('.dist-info') and | ||
| 270 | canonicalize_name(s).startswith( | ||
| 271 | canonicalize_name(req.name))): | ||
| 272 | assert not info_dir, ('Multiple .dist-info directories: ' + | ||
| 273 | destsubdir + ', ' + | ||
| 274 | ', '.join(info_dir)) | ||
| 275 | info_dir.append(destsubdir) | ||
| 276 | for f in files: | ||
| 277 | # Skip unwanted files | ||
| 278 | if filter and filter(f): | ||
| 279 | continue | ||
| 280 | srcfile = os.path.join(dir, f) | ||
| 281 | destfile = os.path.join(dest, basedir, f) | ||
| 282 | # directory creation is lazy and after the file filtering above | ||
| 283 | # to ensure we don't install empty dirs; empty dirs can't be | ||
| 284 | # uninstalled. | ||
| 285 | ensure_dir(destdir) | ||
| 286 | |||
| 287 | # We use copyfile (not move, copy, or copy2) to be extra sure | ||
| 288 | # that we are not moving directories over (copyfile fails for | ||
| 289 | # directories) as well as to ensure that we are not copying | ||
| 290 | # over any metadata because we want more control over what | ||
| 291 | # metadata we actually copy over. | ||
| 292 | shutil.copyfile(srcfile, destfile) | ||
| 293 | |||
| 294 | # Copy over the metadata for the file, currently this only | ||
| 295 | # includes the atime and mtime. | ||
| 296 | st = os.stat(srcfile) | ||
| 297 | if hasattr(os, "utime"): | ||
| 298 | os.utime(destfile, (st.st_atime, st.st_mtime)) | ||
| 299 | |||
| 300 | # If our file is executable, then make our destination file | ||
| 301 | # executable. | ||
| 302 | if os.access(srcfile, os.X_OK): | ||
| 303 | st = os.stat(srcfile) | ||
| 304 | permissions = ( | ||
| 305 | st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH | ||
| 306 | ) | ||
| 307 | os.chmod(destfile, permissions) | ||
| 308 | |||
| 309 | changed = False | ||
| 310 | if fixer: | ||
| 311 | changed = fixer(destfile) | ||
| 312 | record_installed(srcfile, destfile, changed) | ||
| 313 | |||
| 314 | clobber(source, lib_dir, True) | ||
| 315 | |||
| 316 | assert info_dir, "%s .dist-info directory not found" % req | ||
| 317 | |||
| 318 | # Get the defined entry points | ||
| 319 | ep_file = os.path.join(info_dir[0], 'entry_points.txt') | ||
| 320 | console, gui = get_entrypoints(ep_file) | ||
| 321 | |||
| 322 | def is_entrypoint_wrapper(name): | ||
| 323 | # EP, EP.exe and EP-script.py are scripts generated for | ||
| 324 | # entry point EP by setuptools | ||
| 325 | if name.lower().endswith('.exe'): | ||
| 326 | matchname = name[:-4] | ||
| 327 | elif name.lower().endswith('-script.py'): | ||
| 328 | matchname = name[:-10] | ||
| 329 | elif name.lower().endswith(".pya"): | ||
| 330 | matchname = name[:-4] | ||
| 331 | else: | ||
| 332 | matchname = name | ||
| 333 | # Ignore setuptools-generated scripts | ||
| 334 | return (matchname in console or matchname in gui) | ||
| 335 | |||
| 336 | for datadir in data_dirs: | ||
| 337 | fixer = None | ||
| 338 | filter = None | ||
| 339 | for subdir in os.listdir(os.path.join(wheeldir, datadir)): | ||
| 340 | fixer = None | ||
| 341 | if subdir == 'scripts': | ||
| 342 | fixer = fix_script | ||
| 343 | filter = is_entrypoint_wrapper | ||
| 344 | source = os.path.join(wheeldir, datadir, subdir) | ||
| 345 | dest = scheme[subdir] | ||
| 346 | clobber(source, dest, False, fixer=fixer, filter=filter) | ||
| 347 | |||
| 348 | maker = ScriptMaker(None, scheme['scripts']) | ||
| 349 | |||
| 350 | # Ensure old scripts are overwritten. | ||
| 351 | # See https://github.com/pypa/pip/issues/1800 | ||
| 352 | maker.clobber = True | ||
| 353 | |||
| 354 | # Ensure we don't generate any variants for scripts because this is almost | ||
| 355 | # never what somebody wants. | ||
| 356 | # See https://bitbucket.org/pypa/distlib/issue/35/ | ||
| 357 | maker.variants = {''} | ||
| 358 | |||
| 359 | # This is required because otherwise distlib creates scripts that are not | ||
| 360 | # executable. | ||
| 361 | # See https://bitbucket.org/pypa/distlib/issue/32/ | ||
| 362 | maker.set_mode = True | ||
| 363 | |||
| 364 | # Simplify the script and fix the fact that the default script swallows | ||
| 365 | # every single stack trace. | ||
| 366 | # See https://bitbucket.org/pypa/distlib/issue/34/ | ||
| 367 | # See https://bitbucket.org/pypa/distlib/issue/33/ | ||
| 368 | def _get_script_text(entry): | ||
| 369 | if entry.suffix is None: | ||
| 370 | raise InstallationError( | ||
| 371 | "Invalid script entry point: %s for req: %s - A callable " | ||
| 372 | "suffix is required. Cf https://packaging.python.org/en/" | ||
| 373 | "latest/distributing.html#console-scripts for more " | ||
| 374 | "information." % (entry, req) | ||
| 375 | ) | ||
| 376 | return maker.script_template % { | ||
| 377 | "module": entry.prefix, | ||
| 378 | "import_name": entry.suffix.split(".")[0], | ||
| 379 | "func": entry.suffix, | ||
| 380 | } | ||
| 381 | |||
| 382 | maker._get_script_text = _get_script_text | ||
| 383 | maker.script_template = r"""# -*- coding: utf-8 -*- | ||
| 384 | import re | ||
| 385 | import sys | ||
| 386 | |||
| 387 | from %(module)s import %(import_name)s | ||
| 388 | |||
| 389 | if __name__ == '__main__': | ||
| 390 | sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) | ||
| 391 | sys.exit(%(func)s()) | ||
| 392 | """ | ||
| 393 | |||
| 394 | # Special case pip and setuptools to generate versioned wrappers | ||
| 395 | # | ||
| 396 | # The issue is that some projects (specifically, pip and setuptools) use | ||
| 397 | # code in setup.py to create "versioned" entry points - pip2.7 on Python | ||
| 398 | # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into | ||
| 399 | # the wheel metadata at build time, and so if the wheel is installed with | ||
| 400 | # a *different* version of Python the entry points will be wrong. The | ||
| 401 | # correct fix for this is to enhance the metadata to be able to describe | ||
| 402 | # such versioned entry points, but that won't happen till Metadata 2.0 is | ||
| 403 | # available. | ||
| 404 | # In the meantime, projects using versioned entry points will either have | ||
| 405 | # incorrect versioned entry points, or they will not be able to distribute | ||
| 406 | # "universal" wheels (i.e., they will need a wheel per Python version). | ||
| 407 | # | ||
| 408 | # Because setuptools and pip are bundled with _ensurepip and virtualenv, | ||
| 409 | # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we | ||
| 410 | # override the versioned entry points in the wheel and generate the | ||
| 411 | # correct ones. This code is purely a short-term measure until Metadata 2.0 | ||
| 412 | # is available. | ||
| 413 | # | ||
| 414 | # To add the level of hack in this section of code, in order to support | ||
| 415 | # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment | ||
| 416 | # variable which will control which version scripts get installed. | ||
| 417 | # | ||
| 418 | # ENSUREPIP_OPTIONS=altinstall | ||
| 419 | # - Only pipX.Y and easy_install-X.Y will be generated and installed | ||
| 420 | # ENSUREPIP_OPTIONS=install | ||
| 421 | # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note | ||
| 422 | # that this option is technically if ENSUREPIP_OPTIONS is set and is | ||
| 423 | # not altinstall | ||
| 424 | # DEFAULT | ||
| 425 | # - The default behavior is to install pip, pipX, pipX.Y, easy_install | ||
| 426 | # and easy_install-X.Y. | ||
| 427 | pip_script = console.pop('pip', None) | ||
| 428 | if pip_script: | ||
| 429 | if "ENSUREPIP_OPTIONS" not in os.environ: | ||
| 430 | spec = 'pip = ' + pip_script | ||
| 431 | generated.extend(maker.make(spec)) | ||
| 432 | |||
| 433 | if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": | ||
| 434 | spec = 'pip%s = %s' % (sys.version[:1], pip_script) | ||
| 435 | generated.extend(maker.make(spec)) | ||
| 436 | |||
| 437 | spec = 'pip%s = %s' % (sys.version[:3], pip_script) | ||
| 438 | generated.extend(maker.make(spec)) | ||
| 439 | # Delete any other versioned pip entry points | ||
| 440 | pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)] | ||
| 441 | for k in pip_ep: | ||
| 442 | del console[k] | ||
| 443 | easy_install_script = console.pop('easy_install', None) | ||
| 444 | if easy_install_script: | ||
| 445 | if "ENSUREPIP_OPTIONS" not in os.environ: | ||
| 446 | spec = 'easy_install = ' + easy_install_script | ||
| 447 | generated.extend(maker.make(spec)) | ||
| 448 | |||
| 449 | spec = 'easy_install-%s = %s' % (sys.version[:3], easy_install_script) | ||
| 450 | generated.extend(maker.make(spec)) | ||
| 451 | # Delete any other versioned easy_install entry points | ||
| 452 | easy_install_ep = [ | ||
| 453 | k for k in console if re.match(r'easy_install(-\d\.\d)?$', k) | ||
| 454 | ] | ||
| 455 | for k in easy_install_ep: | ||
| 456 | del console[k] | ||
| 457 | |||
| 458 | # Generate the console and GUI entry points specified in the wheel | ||
| 459 | if len(console) > 0: | ||
| 460 | generated_console_scripts = maker.make_multiple( | ||
| 461 | ['%s = %s' % kv for kv in console.items()] | ||
| 462 | ) | ||
| 463 | generated.extend(generated_console_scripts) | ||
| 464 | |||
| 465 | if warn_script_location: | ||
| 466 | msg = message_about_scripts_not_on_PATH(generated_console_scripts) | ||
| 467 | if msg is not None: | ||
| 468 | logger.warn(msg) | ||
| 469 | |||
| 470 | if len(gui) > 0: | ||
| 471 | generated.extend( | ||
| 472 | maker.make_multiple( | ||
| 473 | ['%s = %s' % kv for kv in gui.items()], | ||
| 474 | {'gui': True} | ||
| 475 | ) | ||
| 476 | ) | ||
| 477 | |||
| 478 | # Record pip as the installer | ||
| 479 | installer = os.path.join(info_dir[0], 'INSTALLER') | ||
| 480 | temp_installer = os.path.join(info_dir[0], 'INSTALLER.pip') | ||
| 481 | with open(temp_installer, 'wb') as installer_file: | ||
| 482 | installer_file.write(b'pip\n') | ||
| 483 | shutil.move(temp_installer, installer) | ||
| 484 | generated.append(installer) | ||
| 485 | |||
| 486 | # Record details of all files installed | ||
| 487 | record = os.path.join(info_dir[0], 'RECORD') | ||
| 488 | temp_record = os.path.join(info_dir[0], 'RECORD.pip') | ||
| 489 | with open_for_csv(record, 'r') as record_in: | ||
| 490 | with open_for_csv(temp_record, 'w+') as record_out: | ||
| 491 | reader = csv.reader(record_in) | ||
| 492 | writer = csv.writer(record_out) | ||
| 493 | for row in reader: | ||
| 494 | row[0] = installed.pop(row[0], row[0]) | ||
| 495 | if row[0] in changed: | ||
| 496 | row[1], row[2] = rehash(row[0]) | ||
| 497 | writer.writerow(row) | ||
| 498 | for f in generated: | ||
| 499 | h, l = rehash(f) | ||
| 500 | writer.writerow((normpath(f, lib_dir), h, l)) | ||
| 501 | for f in installed: | ||
| 502 | writer.writerow((installed[f], '', '')) | ||
| 503 | shutil.move(temp_record, record) | ||
| 504 | |||
| 505 | |||
| 506 | def wheel_version(source_dir): | ||
| 507 | """ | ||
| 508 | Return the Wheel-Version of an extracted wheel, if possible. | ||
| 509 | |||
| 510 | Otherwise, return False if we couldn't parse / extract it. | ||
| 511 | """ | ||
| 512 | try: | ||
| 513 | dist = [d for d in pkg_resources.find_on_path(None, source_dir)][0] | ||
| 514 | |||
| 515 | wheel_data = dist.get_metadata('WHEEL') | ||
| 516 | wheel_data = Parser().parsestr(wheel_data) | ||
| 517 | |||
| 518 | version = wheel_data['Wheel-Version'].strip() | ||
| 519 | version = tuple(map(int, version.split('.'))) | ||
| 520 | return version | ||
| 521 | except: | ||
| 522 | return False | ||
| 523 | |||
| 524 | |||
| 525 | def check_compatibility(version, name): | ||
| 526 | """ | ||
| 527 | Raises errors or warns if called with an incompatible Wheel-Version. | ||
| 528 | |||
| 529 | Pip should refuse to install a Wheel-Version that's a major series | ||
| 530 | ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when | ||
| 531 | installing a version only minor version ahead (e.g 1.2 > 1.1). | ||
| 532 | |||
| 533 | version: a 2-tuple representing a Wheel-Version (Major, Minor) | ||
| 534 | name: name of wheel or package to raise exception about | ||
| 535 | |||
| 536 | :raises UnsupportedWheel: when an incompatible Wheel-Version is given | ||
| 537 | """ | ||
| 538 | if not version: | ||
| 539 | raise UnsupportedWheel( | ||
| 540 | "%s is in an unsupported or invalid wheel" % name | ||
| 541 | ) | ||
| 542 | if version[0] > VERSION_COMPATIBLE[0]: | ||
| 543 | raise UnsupportedWheel( | ||
| 544 | "%s's Wheel-Version (%s) is not compatible with this version " | ||
| 545 | "of pip" % (name, '.'.join(map(str, version))) | ||
| 546 | ) | ||
| 547 | elif version > VERSION_COMPATIBLE: | ||
| 548 | logger.warning( | ||
| 549 | 'Installing from a newer Wheel-Version (%s)', | ||
| 550 | '.'.join(map(str, version)), | ||
| 551 | ) | ||
| 552 | |||
| 553 | |||
| 554 | class Wheel(object): | ||
| 555 | """A wheel file""" | ||
| 556 | |||
| 557 | # TODO: maybe move the install code into this class | ||
| 558 | |||
| 559 | wheel_file_re = re.compile( | ||
| 560 | r"""^(?P<namever>(?P<name>.+?)-(?P<ver>.*?)) | ||
| 561 | ((-(?P<build>\d[^-]*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?) | ||
| 562 | \.whl|\.dist-info)$""", | ||
| 563 | re.VERBOSE | ||
| 564 | ) | ||
| 565 | |||
| 566 | def __init__(self, filename): | ||
| 567 | """ | ||
| 568 | :raises InvalidWheelFilename: when the filename is invalid for a wheel | ||
| 569 | """ | ||
| 570 | wheel_info = self.wheel_file_re.match(filename) | ||
| 571 | if not wheel_info: | ||
| 572 | raise InvalidWheelFilename( | ||
| 573 | "%s is not a valid wheel filename." % filename | ||
| 574 | ) | ||
| 575 | self.filename = filename | ||
| 576 | self.name = wheel_info.group('name').replace('_', '-') | ||
| 577 | # we'll assume "_" means "-" due to wheel naming scheme | ||
| 578 | # (https://github.com/pypa/pip/issues/1150) | ||
| 579 | self.version = wheel_info.group('ver').replace('_', '-') | ||
| 580 | self.build_tag = wheel_info.group('build') | ||
| 581 | self.pyversions = wheel_info.group('pyver').split('.') | ||
| 582 | self.abis = wheel_info.group('abi').split('.') | ||
| 583 | self.plats = wheel_info.group('plat').split('.') | ||
| 584 | |||
| 585 | # All the tag combinations from this file | ||
| 586 | self.file_tags = { | ||
| 587 | (x, y, z) for x in self.pyversions | ||
| 588 | for y in self.abis for z in self.plats | ||
| 589 | } | ||
| 590 | |||
| 591 | def support_index_min(self, tags=None): | ||
| 592 | """ | ||
| 593 | Return the lowest index that one of the wheel's file_tag combinations | ||
| 594 | achieves in the supported_tags list e.g. if there are 8 supported tags, | ||
| 595 | and one of the file tags is first in the list, then return 0. Returns | ||
| 596 | None is the wheel is not supported. | ||
| 597 | """ | ||
| 598 | if tags is None: # for mock | ||
| 599 | tags = pep425tags.get_supported() | ||
| 600 | indexes = [tags.index(c) for c in self.file_tags if c in tags] | ||
| 601 | return min(indexes) if indexes else None | ||
| 602 | |||
| 603 | def supported(self, tags=None): | ||
| 604 | """Is this wheel supported on this system?""" | ||
| 605 | if tags is None: # for mock | ||
| 606 | tags = pep425tags.get_supported() | ||
| 607 | return bool(set(tags).intersection(self.file_tags)) | ||
| 608 | |||
| 609 | |||
| 610 | class WheelBuilder(object): | ||
| 611 | """Build wheels from a RequirementSet.""" | ||
| 612 | |||
| 613 | def __init__(self, finder, preparer, wheel_cache, | ||
| 614 | build_options=None, global_options=None, no_clean=False): | ||
| 615 | self.finder = finder | ||
| 616 | self.preparer = preparer | ||
| 617 | self.wheel_cache = wheel_cache | ||
| 618 | |||
| 619 | self._wheel_dir = preparer.wheel_download_dir | ||
| 620 | |||
| 621 | self.build_options = build_options or [] | ||
| 622 | self.global_options = global_options or [] | ||
| 623 | self.no_clean = no_clean | ||
| 624 | |||
| 625 | def _build_one(self, req, output_dir, python_tag=None): | ||
| 626 | """Build one wheel. | ||
| 627 | |||
| 628 | :return: The filename of the built wheel, or None if the build failed. | ||
| 629 | """ | ||
| 630 | # Install build deps into temporary directory (PEP 518) | ||
| 631 | with req.build_env: | ||
| 632 | return self._build_one_inside_env(req, output_dir, | ||
| 633 | python_tag=python_tag) | ||
| 634 | |||
| 635 | def _build_one_inside_env(self, req, output_dir, python_tag=None): | ||
| 636 | with TempDirectory(kind="wheel") as temp_dir: | ||
| 637 | if self.__build_one(req, temp_dir.path, python_tag=python_tag): | ||
| 638 | try: | ||
| 639 | wheel_name = os.listdir(temp_dir.path)[0] | ||
| 640 | wheel_path = os.path.join(output_dir, wheel_name) | ||
| 641 | shutil.move( | ||
| 642 | os.path.join(temp_dir.path, wheel_name), wheel_path | ||
| 643 | ) | ||
| 644 | logger.info('Stored in directory: %s', output_dir) | ||
| 645 | return wheel_path | ||
| 646 | except: | ||
| 647 | pass | ||
| 648 | # Ignore return, we can't do anything else useful. | ||
| 649 | self._clean_one(req) | ||
| 650 | return None | ||
| 651 | |||
| 652 | def _base_setup_args(self, req): | ||
| 653 | # NOTE: Eventually, we'd want to also -S to the flags here, when we're | ||
| 654 | # isolating. Currently, it breaks Python in virtualenvs, because it | ||
| 655 | # relies on site.py to find parts of the standard library outside the | ||
| 656 | # virtualenv. | ||
| 657 | return [ | ||
| 658 | sys.executable, '-u', '-c', | ||
| 659 | SETUPTOOLS_SHIM % req.setup_py | ||
| 660 | ] + list(self.global_options) | ||
| 661 | |||
| 662 | def __build_one(self, req, tempd, python_tag=None): | ||
| 663 | base_args = self._base_setup_args(req) | ||
| 664 | |||
| 665 | spin_message = 'Running setup.py bdist_wheel for %s' % (req.name,) | ||
| 666 | with open_spinner(spin_message) as spinner: | ||
| 667 | logger.debug('Destination directory: %s', tempd) | ||
| 668 | wheel_args = base_args + ['bdist_wheel', '-d', tempd] \ | ||
| 669 | + self.build_options | ||
| 670 | |||
| 671 | if python_tag is not None: | ||
| 672 | wheel_args += ["--python-tag", python_tag] | ||
| 673 | |||
| 674 | try: | ||
| 675 | call_subprocess(wheel_args, cwd=req.setup_py_dir, | ||
| 676 | show_stdout=False, spinner=spinner) | ||
| 677 | return True | ||
| 678 | except: | ||
| 679 | spinner.finish("error") | ||
| 680 | logger.error('Failed building wheel for %s', req.name) | ||
| 681 | return False | ||
| 682 | |||
| 683 | def _clean_one(self, req): | ||
| 684 | base_args = self._base_setup_args(req) | ||
| 685 | |||
| 686 | logger.info('Running setup.py clean for %s', req.name) | ||
| 687 | clean_args = base_args + ['clean', '--all'] | ||
| 688 | try: | ||
| 689 | call_subprocess(clean_args, cwd=req.source_dir, show_stdout=False) | ||
| 690 | return True | ||
| 691 | except: | ||
| 692 | logger.error('Failed cleaning build dir for %s', req.name) | ||
| 693 | return False | ||
| 694 | |||
| 695 | def build(self, requirements, session, autobuilding=False): | ||
| 696 | """Build wheels. | ||
| 697 | |||
| 698 | :param unpack: If True, replace the sdist we built from with the | ||
| 699 | newly built wheel, in preparation for installation. | ||
| 700 | :return: True if all the wheels built correctly. | ||
| 701 | """ | ||
| 702 | from pip._internal import index | ||
| 703 | |||
| 704 | building_is_possible = self._wheel_dir or ( | ||
| 705 | autobuilding and self.wheel_cache.cache_dir | ||
| 706 | ) | ||
| 707 | assert building_is_possible | ||
| 708 | |||
| 709 | buildset = [] | ||
| 710 | for req in requirements: | ||
| 711 | if req.constraint: | ||
| 712 | continue | ||
| 713 | if req.is_wheel: | ||
| 714 | if not autobuilding: | ||
| 715 | logger.info( | ||
| 716 | 'Skipping %s, due to already being wheel.', req.name, | ||
| 717 | ) | ||
| 718 | elif autobuilding and req.editable: | ||
| 719 | pass | ||
| 720 | elif autobuilding and not req.source_dir: | ||
| 721 | pass | ||
| 722 | elif autobuilding and req.link and not req.link.is_artifact: | ||
| 723 | # VCS checkout. Build wheel just for this run. | ||
| 724 | buildset.append((req, True)) | ||
| 725 | else: | ||
| 726 | ephem_cache = False | ||
| 727 | if autobuilding: | ||
| 728 | link = req.link | ||
| 729 | base, ext = link.splitext() | ||
| 730 | if index.egg_info_matches(base, None, link) is None: | ||
| 731 | # E.g. local directory. Build wheel just for this run. | ||
| 732 | ephem_cache = True | ||
| 733 | if "binary" not in index.fmt_ctl_formats( | ||
| 734 | self.finder.format_control, | ||
| 735 | canonicalize_name(req.name)): | ||
| 736 | logger.info( | ||
| 737 | "Skipping bdist_wheel for %s, due to binaries " | ||
| 738 | "being disabled for it.", req.name, | ||
| 739 | ) | ||
| 740 | continue | ||
| 741 | buildset.append((req, ephem_cache)) | ||
| 742 | |||
| 743 | if not buildset: | ||
| 744 | return True | ||
| 745 | |||
| 746 | # Build the wheels. | ||
| 747 | logger.info( | ||
| 748 | 'Building wheels for collected packages: %s', | ||
| 749 | ', '.join([req.name for (req, _) in buildset]), | ||
| 750 | ) | ||
| 751 | _cache = self.wheel_cache # shorter name | ||
| 752 | with indent_log(): | ||
| 753 | build_success, build_failure = [], [] | ||
| 754 | for req, ephem in buildset: | ||
| 755 | python_tag = None | ||
| 756 | if autobuilding: | ||
| 757 | python_tag = pep425tags.implementation_tag | ||
| 758 | if ephem: | ||
| 759 | output_dir = _cache.get_ephem_path_for_link(req.link) | ||
| 760 | else: | ||
| 761 | output_dir = _cache.get_path_for_link(req.link) | ||
| 762 | try: | ||
| 763 | ensure_dir(output_dir) | ||
| 764 | except OSError as e: | ||
| 765 | logger.warning("Building wheel for %s failed: %s", | ||
| 766 | req.name, e) | ||
| 767 | build_failure.append(req) | ||
| 768 | continue | ||
| 769 | else: | ||
| 770 | output_dir = self._wheel_dir | ||
| 771 | wheel_file = self._build_one( | ||
| 772 | req, output_dir, | ||
| 773 | python_tag=python_tag, | ||
| 774 | ) | ||
| 775 | if wheel_file: | ||
| 776 | build_success.append(req) | ||
| 777 | if autobuilding: | ||
| 778 | # XXX: This is mildly duplicative with prepare_files, | ||
| 779 | # but not close enough to pull out to a single common | ||
| 780 | # method. | ||
| 781 | # The code below assumes temporary source dirs - | ||
| 782 | # prevent it doing bad things. | ||
| 783 | if req.source_dir and not os.path.exists(os.path.join( | ||
| 784 | req.source_dir, PIP_DELETE_MARKER_FILENAME)): | ||
| 785 | raise AssertionError( | ||
| 786 | "bad source dir - missing marker") | ||
| 787 | # Delete the source we built the wheel from | ||
| 788 | req.remove_temporary_source() | ||
| 789 | # set the build directory again - name is known from | ||
| 790 | # the work prepare_files did. | ||
| 791 | req.source_dir = req.build_location( | ||
| 792 | self.preparer.build_dir | ||
| 793 | ) | ||
| 794 | # Update the link for this. | ||
| 795 | req.link = index.Link(path_to_url(wheel_file)) | ||
| 796 | assert req.link.is_wheel | ||
| 797 | # extract the wheel into the dir | ||
| 798 | unpack_url( | ||
| 799 | req.link, req.source_dir, None, False, | ||
| 800 | session=session, | ||
| 801 | ) | ||
| 802 | else: | ||
| 803 | build_failure.append(req) | ||
| 804 | |||
| 805 | # notify success/failure | ||
| 806 | if build_success: | ||
| 807 | logger.info( | ||
| 808 | 'Successfully built %s', | ||
| 809 | ' '.join([req.name for req in build_success]), | ||
| 810 | ) | ||
| 811 | if build_failure: | ||
| 812 | logger.info( | ||
| 813 | 'Failed to build %s', | ||
| 814 | ' '.join([req.name for req in build_failure]), | ||
| 815 | ) | ||
| 816 | # Return True if all builds were successful | ||
| 817 | return len(build_failure) == 0 | ||
