From 0d3f03caba4fc623da76ffe69a7545a36f95907a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sat, 16 Jul 2022 20:08:16 +0200 Subject: [PATCH 01/14] Upgrade colorama to 0.4.5 --- news/colorama.vendor.rst | 1 + src/pip/_vendor/colorama/__init__.py | 2 +- src/pip/_vendor/colorama/ansitowin32.py | 10 +++++++++- src/pip/_vendor/requests/__init__.py | 10 ++++------ src/pip/_vendor/requests/compat.py | 24 ++++++++++++++---------- src/pip/_vendor/requests/help.py | 5 ++++- src/pip/_vendor/requests/packages.py | 22 ++++++++++++++++------ src/pip/_vendor/vendor.txt | 2 +- 8 files changed, 50 insertions(+), 26 deletions(-) create mode 100644 news/colorama.vendor.rst diff --git a/news/colorama.vendor.rst b/news/colorama.vendor.rst new file mode 100644 index 00000000000..a757999b330 --- /dev/null +++ b/news/colorama.vendor.rst @@ -0,0 +1 @@ +Upgrade colorama to 0.4.5 diff --git a/src/pip/_vendor/colorama/__init__.py b/src/pip/_vendor/colorama/__init__.py index b149ed79b0a..9138a8cc8f0 100644 --- a/src/pip/_vendor/colorama/__init__.py +++ b/src/pip/_vendor/colorama/__init__.py @@ -3,4 +3,4 @@ from .ansi import Fore, Back, Style, Cursor from .ansitowin32 import AnsiToWin32 -__version__ = '0.4.4' +__version__ = '0.4.5' diff --git a/src/pip/_vendor/colorama/ansitowin32.py b/src/pip/_vendor/colorama/ansitowin32.py index 6039a054320..3db248baac4 100644 --- a/src/pip/_vendor/colorama/ansitowin32.py +++ b/src/pip/_vendor/colorama/ansitowin32.py @@ -37,6 +37,12 @@ def __enter__(self, *args, **kwargs): def __exit__(self, *args, **kwargs): return self.__wrapped.__exit__(*args, **kwargs) + def __setstate__(self, state): + self.__dict__ = state + + def __getstate__(self): + return self.__dict__ + def write(self, text): self.__convertor.write(text) @@ -57,7 +63,9 @@ def closed(self): stream = self.__wrapped try: return stream.closed - except AttributeError: + # AttributeError in the case that the stream doesn't support being closed + # ValueError for the case that the stream has already been detached when atexit runs + except (AttributeError, ValueError): return True diff --git a/src/pip/_vendor/requests/__init__.py b/src/pip/_vendor/requests/__init__.py index 75a633bf9dc..993046884f7 100644 --- a/src/pip/_vendor/requests/__init__.py +++ b/src/pip/_vendor/requests/__init__.py @@ -44,7 +44,10 @@ import warnings from .exceptions import RequestsDependencyWarning -charset_normalizer_version = None +try: + from charset_normalizer import __version__ as charset_normalizer_version +except ImportError: + charset_normalizer_version = None try: from pip._vendor.chardet import __version__ as chardet_version @@ -104,11 +107,6 @@ def _check_cryptography(cryptography_version): # if the standard library doesn't support SNI or the # 'ssl' library isn't available. try: - # Note: This logic prevents upgrading cryptography on Windows, if imported - # as part of pip. - from pip._internal.utils.compat import WINDOWS - if not WINDOWS: - raise ImportError("pip internals: don't import cryptography on Windows") try: import ssl except ImportError: diff --git a/src/pip/_vendor/requests/compat.py b/src/pip/_vendor/requests/compat.py index f98cc910f9b..6e4982e2bf0 100644 --- a/src/pip/_vendor/requests/compat.py +++ b/src/pip/_vendor/requests/compat.py @@ -8,7 +8,10 @@ Python 3. """ -from pip._vendor import chardet +try: + from pip._vendor import chardet +except ImportError: + import charset_normalizer as chardet import sys @@ -25,14 +28,12 @@ #: Python 3.x? is_py3 = (_ver[0] == 3) -# Note: We've patched out simplejson support in pip because it prevents -# upgrading simplejson on Windows. -# try: -# import simplejson as json -# except (ImportError, SyntaxError): -# # simplejson does not support Python 3.2, it throws a SyntaxError -# # because of u'...' Unicode literals. -import json +has_simplejson = False +try: + import simplejson as json + has_simplejson = True +except ImportError: + import json # --------- # Specifics @@ -67,7 +68,10 @@ # Keep OrderedDict for backwards compatibility. from collections import OrderedDict from collections.abc import Callable, Mapping, MutableMapping - from json import JSONDecodeError + if has_simplejson: + from simplejson import JSONDecodeError + else: + from json import JSONDecodeError builtin_str = str str = str diff --git a/src/pip/_vendor/requests/help.py b/src/pip/_vendor/requests/help.py index 745f0d7b346..3a843404c33 100644 --- a/src/pip/_vendor/requests/help.py +++ b/src/pip/_vendor/requests/help.py @@ -11,7 +11,10 @@ from . import __version__ as requests_version -charset_normalizer = None +try: + import charset_normalizer +except ImportError: + charset_normalizer = None try: from pip._vendor import chardet diff --git a/src/pip/_vendor/requests/packages.py b/src/pip/_vendor/requests/packages.py index 9582fa730f1..0f8ae0d386a 100644 --- a/src/pip/_vendor/requests/packages.py +++ b/src/pip/_vendor/requests/packages.py @@ -1,16 +1,26 @@ import sys +try: + from pip._vendor import chardet +except ImportError: + import charset_normalizer as chardet + import warnings + + warnings.filterwarnings('ignore', 'Trying to detect', module='charset_normalizer') + # This code exists for backwards compatibility reasons. # I don't like it either. Just look the other way. :) -for package in ('urllib3', 'idna', 'chardet'): - vendored_package = "pip._vendor." + package - locals()[package] = __import__(vendored_package) +for package in ('urllib3', 'idna'): + locals()[package] = __import__(package) # This traversal is apparently necessary such that the identities are # preserved (requests.packages.urllib3.* is urllib3.*) for mod in list(sys.modules): - if mod == vendored_package or mod.startswith(vendored_package + '.'): - unprefixed_mod = mod[len("pip._vendor."):] - sys.modules['pip._vendor.requests.packages.' + unprefixed_mod] = sys.modules[mod] + if mod == package or mod.startswith(package + '.'): + sys.modules['requests.packages.' + mod] = sys.modules[mod] +target = chardet.__name__ +for mod in list(sys.modules): + if mod == target or mod.startswith(target + '.'): + sys.modules['requests.packages.' + target.replace(target, 'chardet')] = sys.modules[mod] # Kinda cool, though, right? diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt index 802013b6ad8..a9dd6270b33 100644 --- a/src/pip/_vendor/vendor.txt +++ b/src/pip/_vendor/vendor.txt @@ -1,5 +1,5 @@ CacheControl==0.12.11 # Make sure to update the license in pyproject.toml for this. -colorama==0.4.4 +colorama==0.4.5 distlib==0.3.3 distro==1.7.0 msgpack==1.0.3 From fd0ea6bc5e8cb95e518c23d901c26ca14db17f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sat, 16 Jul 2022 20:08:39 +0200 Subject: [PATCH 02/14] Upgrade distlib to 0.3.5 --- news/distlib.vendor.rst | 1 + src/pip/_vendor/distlib/__init__.py | 2 +- src/pip/_vendor/distlib/_backport/__init__.py | 6 - src/pip/_vendor/distlib/_backport/misc.py | 41 - src/pip/_vendor/distlib/_backport/shutil.py | 764 ----- .../_vendor/distlib/_backport/sysconfig.cfg | 84 - .../_vendor/distlib/_backport/sysconfig.py | 786 ----- src/pip/_vendor/distlib/_backport/tarfile.py | 2607 ----------------- src/pip/_vendor/distlib/compat.py | 28 +- src/pip/_vendor/distlib/database.py | 67 +- src/pip/_vendor/distlib/index.py | 13 +- src/pip/_vendor/distlib/locators.py | 6 +- src/pip/_vendor/distlib/markers.py | 9 +- src/pip/_vendor/distlib/metadata.py | 48 +- src/pip/_vendor/distlib/scripts.py | 10 +- src/pip/_vendor/distlib/t32.exe | Bin 96768 -> 97792 bytes src/pip/_vendor/distlib/t64-arm.exe | Bin 180736 -> 182784 bytes src/pip/_vendor/distlib/t64.exe | Bin 105984 -> 107520 bytes src/pip/_vendor/distlib/util.py | 81 +- src/pip/_vendor/distlib/w32.exe | Bin 90112 -> 91648 bytes src/pip/_vendor/distlib/w64-arm.exe | Bin 166400 -> 168448 bytes src/pip/_vendor/distlib/w64.exe | Bin 99840 -> 101888 bytes src/pip/_vendor/distlib/wheel.py | 51 +- src/pip/_vendor/vendor.txt | 2 +- 24 files changed, 173 insertions(+), 4433 deletions(-) create mode 100644 news/distlib.vendor.rst delete mode 100644 src/pip/_vendor/distlib/_backport/__init__.py delete mode 100644 src/pip/_vendor/distlib/_backport/misc.py delete mode 100644 src/pip/_vendor/distlib/_backport/shutil.py delete mode 100644 src/pip/_vendor/distlib/_backport/sysconfig.cfg delete mode 100644 src/pip/_vendor/distlib/_backport/sysconfig.py delete mode 100644 src/pip/_vendor/distlib/_backport/tarfile.py diff --git a/news/distlib.vendor.rst b/news/distlib.vendor.rst new file mode 100644 index 00000000000..4a1a6739eb4 --- /dev/null +++ b/news/distlib.vendor.rst @@ -0,0 +1 @@ +Upgrade distlib to 0.3.5 diff --git a/src/pip/_vendor/distlib/__init__.py b/src/pip/_vendor/distlib/__init__.py index 11549481074..505556517f8 100644 --- a/src/pip/_vendor/distlib/__init__.py +++ b/src/pip/_vendor/distlib/__init__.py @@ -6,7 +6,7 @@ # import logging -__version__ = '0.3.3' +__version__ = '0.3.5' class DistlibException(Exception): pass diff --git a/src/pip/_vendor/distlib/_backport/__init__.py b/src/pip/_vendor/distlib/_backport/__init__.py deleted file mode 100644 index f7dbf4c9aa8..00000000000 --- a/src/pip/_vendor/distlib/_backport/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Modules copied from Python 3 standard libraries, for internal use only. - -Individual classes and functions are found in d2._backport.misc. Intended -usage is to always import things missing from 3.1 from that module: the -built-in/stdlib objects will be used if found. -""" diff --git a/src/pip/_vendor/distlib/_backport/misc.py b/src/pip/_vendor/distlib/_backport/misc.py deleted file mode 100644 index cfb318d34f7..00000000000 --- a/src/pip/_vendor/distlib/_backport/misc.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Backports for individual classes and functions.""" - -import os -import sys - -__all__ = ['cache_from_source', 'callable', 'fsencode'] - - -try: - from imp import cache_from_source -except ImportError: - def cache_from_source(py_file, debug=__debug__): - ext = debug and 'c' or 'o' - return py_file + ext - - -try: - callable = callable -except NameError: - from collections import Callable - - def callable(obj): - return isinstance(obj, Callable) - - -try: - fsencode = os.fsencode -except AttributeError: - def fsencode(filename): - if isinstance(filename, bytes): - return filename - elif isinstance(filename, str): - return filename.encode(sys.getfilesystemencoding()) - else: - raise TypeError("expect bytes or str, not %s" % - type(filename).__name__) diff --git a/src/pip/_vendor/distlib/_backport/shutil.py b/src/pip/_vendor/distlib/_backport/shutil.py deleted file mode 100644 index 10ed3625397..00000000000 --- a/src/pip/_vendor/distlib/_backport/shutil.py +++ /dev/null @@ -1,764 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Utility functions for copying and archiving files and directory trees. - -XXX The functions here don't copy the resource fork or other metadata on Mac. - -""" - -import os -import sys -import stat -from os.path import abspath -import fnmatch -try: - from collections.abc import Callable -except ImportError: - from collections import Callable -import errno -from . import tarfile - -try: - import bz2 - _BZ2_SUPPORTED = True -except ImportError: - _BZ2_SUPPORTED = False - -try: - from pwd import getpwnam -except ImportError: - getpwnam = None - -try: - from grp import getgrnam -except ImportError: - getgrnam = None - -__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", - "copytree", "move", "rmtree", "Error", "SpecialFileError", - "ExecError", "make_archive", "get_archive_formats", - "register_archive_format", "unregister_archive_format", - "get_unpack_formats", "register_unpack_format", - "unregister_unpack_format", "unpack_archive", "ignore_patterns"] - -class Error(EnvironmentError): - pass - -class SpecialFileError(EnvironmentError): - """Raised when trying to do a kind of operation (e.g. copying) which is - not supported on a special file (e.g. a named pipe)""" - -class ExecError(EnvironmentError): - """Raised when a command could not be executed""" - -class ReadError(EnvironmentError): - """Raised when an archive cannot be read""" - -class RegistryError(Exception): - """Raised when a registry operation with the archiving - and unpacking registries fails""" - - -try: - WindowsError -except NameError: - WindowsError = None - -def copyfileobj(fsrc, fdst, length=16*1024): - """copy data from file-like object fsrc to file-like object fdst""" - while 1: - buf = fsrc.read(length) - if not buf: - break - fdst.write(buf) - -def _samefile(src, dst): - # Macintosh, Unix. - if hasattr(os.path, 'samefile'): - try: - return os.path.samefile(src, dst) - except OSError: - return False - - # All other platforms: check for same pathname. - return (os.path.normcase(os.path.abspath(src)) == - os.path.normcase(os.path.abspath(dst))) - -def copyfile(src, dst): - """Copy data from src to dst""" - if _samefile(src, dst): - raise Error("`%s` and `%s` are the same file" % (src, dst)) - - for fn in [src, dst]: - try: - st = os.stat(fn) - except OSError: - # File most likely does not exist - pass - else: - # XXX What about other special files? (sockets, devices...) - if stat.S_ISFIFO(st.st_mode): - raise SpecialFileError("`%s` is a named pipe" % fn) - - with open(src, 'rb') as fsrc: - with open(dst, 'wb') as fdst: - copyfileobj(fsrc, fdst) - -def copymode(src, dst): - """Copy mode bits from src to dst""" - if hasattr(os, 'chmod'): - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - os.chmod(dst, mode) - -def copystat(src, dst): - """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - if hasattr(os, 'utime'): - os.utime(dst, (st.st_atime, st.st_mtime)) - if hasattr(os, 'chmod'): - os.chmod(dst, mode) - if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - try: - os.chflags(dst, st.st_flags) - except OSError as why: - if (not hasattr(errno, 'EOPNOTSUPP') or - why.errno != errno.EOPNOTSUPP): - raise - -def copy(src, dst): - """Copy data and mode bits ("cp src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copymode(src, dst) - -def copy2(src, dst): - """Copy data and all stat info ("cp -p src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copystat(src, dst) - -def ignore_patterns(*patterns): - """Function that can be used as copytree() ignore parameter. - - Patterns is a sequence of glob-style patterns - that are used to exclude files""" - def _ignore_patterns(path, names): - ignored_names = [] - for pattern in patterns: - ignored_names.extend(fnmatch.filter(names, pattern)) - return set(ignored_names) - return _ignore_patterns - -def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, - ignore_dangling_symlinks=False): - """Recursively copy a directory tree. - - The destination directory must not already exist. - If exception(s) occur, an Error is raised with a list of reasons. - - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. If the file pointed by the symlink doesn't - exist, an exception will be added in the list of errors raised in - an Error exception at the end of the copy process. - - You can set the optional ignore_dangling_symlinks flag to true if you - want to silence this exception. Notice that this has no effect on - platforms that don't support os.symlink. - - The optional ignore argument is a callable. If given, it - is called with the `src` parameter, which is the directory - being visited by copytree(), and `names` which is the list of - `src` contents, as returned by os.listdir(): - - callable(src, names) -> ignored_names - - Since copytree() is called recursively, the callable will be - called once for each directory that is copied. It returns a - list of names relative to the `src` directory that should - not be copied. - - The optional copy_function argument is a callable that will be used - to copy each file. It will be called with the source path and the - destination path as arguments. By default, copy2() is used, but any - function that supports the same signature (like copy()) can be used. - - """ - names = os.listdir(src) - if ignore is not None: - ignored_names = ignore(src, names) - else: - ignored_names = set() - - os.makedirs(dst) - errors = [] - for name in names: - if name in ignored_names: - continue - srcname = os.path.join(src, name) - dstname = os.path.join(dst, name) - try: - if os.path.islink(srcname): - linkto = os.readlink(srcname) - if symlinks: - os.symlink(linkto, dstname) - else: - # ignore dangling symlink if the flag is on - if not os.path.exists(linkto) and ignore_dangling_symlinks: - continue - # otherwise let the copy occurs. copy2 will raise an error - copy_function(srcname, dstname) - elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore, copy_function) - else: - # Will raise a SpecialFileError for unsupported file types - copy_function(srcname, dstname) - # catch the Error from the recursive copytree so that we can - # continue with other files - except Error as err: - errors.extend(err.args[0]) - except EnvironmentError as why: - errors.append((srcname, dstname, str(why))) - try: - copystat(src, dst) - except OSError as why: - if WindowsError is not None and isinstance(why, WindowsError): - # Copying file access times may fail on Windows - pass - else: - errors.extend((src, dst, str(why))) - if errors: - raise Error(errors) - -def rmtree(path, ignore_errors=False, onerror=None): - """Recursively delete a directory tree. - - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, - path, exc_info) where func is os.listdir, os.remove, or os.rmdir; - path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. - - """ - if ignore_errors: - def onerror(*args): - pass - elif onerror is None: - def onerror(*args): - raise - try: - if os.path.islink(path): - # symlinks to directories are forbidden, see bug #1669 - raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns - return - names = [] - try: - names = os.listdir(path) - except os.error: - onerror(os.listdir, path, sys.exc_info()) - for name in names: - fullname = os.path.join(path, name) - try: - mode = os.lstat(fullname).st_mode - except os.error: - mode = 0 - if stat.S_ISDIR(mode): - rmtree(fullname, ignore_errors, onerror) - else: - try: - os.remove(fullname) - except os.error: - onerror(os.remove, fullname, sys.exc_info()) - try: - os.rmdir(path) - except os.error: - onerror(os.rmdir, path, sys.exc_info()) - - -def _basename(path): - # A basename() variant which first strips the trailing slash, if present. - # Thus we always get the last component of the path, even for directories. - return os.path.basename(path.rstrip(os.path.sep)) - -def move(src, dst): - """Recursively move a file or directory to another location. This is - similar to the Unix "mv" command. - - If the destination is a directory or a symlink to a directory, the source - is moved inside the directory. The destination path must not already - exist. - - If the destination already exists but is not a directory, it may be - overwritten depending on os.rename() semantics. - - If the destination is on our current filesystem, then rename() is used. - Otherwise, src is copied to the destination and then removed. - A lot more could be done here... A look at a mv.c shows a lot of - the issues this implementation glosses over. - - """ - real_dst = dst - if os.path.isdir(dst): - if _samefile(src, dst): - # We might be on a case insensitive filesystem, - # perform the rename anyway. - os.rename(src, dst) - return - - real_dst = os.path.join(dst, _basename(src)) - if os.path.exists(real_dst): - raise Error("Destination path '%s' already exists" % real_dst) - try: - os.rename(src, real_dst) - except OSError: - if os.path.isdir(src): - if _destinsrc(src, dst): - raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) - copytree(src, real_dst, symlinks=True) - rmtree(src) - else: - copy2(src, real_dst) - os.unlink(src) - -def _destinsrc(src, dst): - src = abspath(src) - dst = abspath(dst) - if not src.endswith(os.path.sep): - src += os.path.sep - if not dst.endswith(os.path.sep): - dst += os.path.sep - return dst.startswith(src) - -def _get_gid(name): - """Returns a gid, given a group name.""" - if getgrnam is None or name is None: - return None - try: - result = getgrnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _get_uid(name): - """Returns an uid, given a user name.""" - if getpwnam is None or name is None: - return None - try: - result = getpwnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, - owner=None, group=None, logger=None): - """Create a (possibly compressed) tar file from all the files under - 'base_dir'. - - 'compress' must be "gzip" (the default), "bzip2", or None. - - 'owner' and 'group' can be used to define an owner and a group for the - archive that is being built. If not provided, the current owner and group - will be used. - - The output tar file will be named 'base_name' + ".tar", possibly plus - the appropriate compression extension (".gz", or ".bz2"). - - Returns the output filename. - """ - tar_compression = {'gzip': 'gz', None: ''} - compress_ext = {'gzip': '.gz'} - - if _BZ2_SUPPORTED: - tar_compression['bzip2'] = 'bz2' - compress_ext['bzip2'] = '.bz2' - - # flags for compression program, each element of list will be an argument - if compress is not None and compress not in compress_ext: - raise ValueError("bad value for 'compress', or compression format not " - "supported : {0}".format(compress)) - - archive_name = base_name + '.tar' + compress_ext.get(compress, '') - archive_dir = os.path.dirname(archive_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # creating the tarball - if logger is not None: - logger.info('Creating tar archive') - - uid = _get_uid(owner) - gid = _get_gid(group) - - def _set_uid_gid(tarinfo): - if gid is not None: - tarinfo.gid = gid - tarinfo.gname = group - if uid is not None: - tarinfo.uid = uid - tarinfo.uname = owner - return tarinfo - - if not dry_run: - tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) - try: - tar.add(base_dir, filter=_set_uid_gid) - finally: - tar.close() - - return archive_name - -def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): - # XXX see if we want to keep an external call here - if verbose: - zipoptions = "-r" - else: - zipoptions = "-rq" - from distutils.errors import DistutilsExecError - from distutils.spawn import spawn - try: - spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) - except DistutilsExecError: - # XXX really should distinguish between "couldn't find - # external 'zip' command" and "zip failed". - raise ExecError("unable to create zip file '%s': " - "could neither import the 'zipfile' module nor " - "find a standalone zip utility") % zip_filename - -def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): - """Create a zip file from all the files under 'base_dir'. - - The output zip file will be named 'base_name' + ".zip". Uses either the - "zipfile" Python module (if available) or the InfoZIP "zip" utility - (if installed and found on the default search path). If neither tool is - available, raises ExecError. Returns the name of the output zip - file. - """ - zip_filename = base_name + ".zip" - archive_dir = os.path.dirname(base_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # If zipfile module is not available, try spawning an external 'zip' - # command. - try: - import zipfile - except ImportError: - zipfile = None - - if zipfile is None: - _call_external_zip(base_dir, zip_filename, verbose, dry_run) - else: - if logger is not None: - logger.info("creating '%s' and adding '%s' to it", - zip_filename, base_dir) - - if not dry_run: - zip = zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_DEFLATED) - - for dirpath, dirnames, filenames in os.walk(base_dir): - for name in filenames: - path = os.path.normpath(os.path.join(dirpath, name)) - if os.path.isfile(path): - zip.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) - zip.close() - - return zip_filename - -_ARCHIVE_FORMATS = { - 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), - 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [], "ZIP file"), - } - -if _BZ2_SUPPORTED: - _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], - "bzip2'ed tar-file") - -def get_archive_formats(): - """Returns a list of supported formats for archiving and unarchiving. - - Each element of the returned sequence is a tuple (name, description) - """ - formats = [(name, registry[2]) for name, registry in - _ARCHIVE_FORMATS.items()] - formats.sort() - return formats - -def register_archive_format(name, function, extra_args=None, description=''): - """Registers an archive format. - - name is the name of the format. function is the callable that will be - used to create archives. If provided, extra_args is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_archive_formats() function. - """ - if extra_args is None: - extra_args = [] - if not isinstance(function, Callable): - raise TypeError('The %s object is not callable' % function) - if not isinstance(extra_args, (tuple, list)): - raise TypeError('extra_args needs to be a sequence') - for element in extra_args: - if not isinstance(element, (tuple, list)) or len(element) !=2: - raise TypeError('extra_args elements are : (arg_name, value)') - - _ARCHIVE_FORMATS[name] = (function, extra_args, description) - -def unregister_archive_format(name): - del _ARCHIVE_FORMATS[name] - -def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, - dry_run=0, owner=None, group=None, logger=None): - """Create an archive file (eg. zip or tar). - - 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "bztar" - or "gztar". - - 'root_dir' is a directory that will be the root directory of the - archive; ie. we typically chdir into 'root_dir' before creating the - archive. 'base_dir' is the directory where we start archiving from; - ie. 'base_dir' will be the common prefix of all files and - directories in the archive. 'root_dir' and 'base_dir' both default - to the current directory. Returns the name of the archive file. - - 'owner' and 'group' are used when creating a tar archive. By default, - uses the current owner and group. - """ - save_cwd = os.getcwd() - if root_dir is not None: - if logger is not None: - logger.debug("changing into '%s'", root_dir) - base_name = os.path.abspath(base_name) - if not dry_run: - os.chdir(root_dir) - - if base_dir is None: - base_dir = os.curdir - - kwargs = {'dry_run': dry_run, 'logger': logger} - - try: - format_info = _ARCHIVE_FORMATS[format] - except KeyError: - raise ValueError("unknown archive format '%s'" % format) - - func = format_info[0] - for arg, val in format_info[1]: - kwargs[arg] = val - - if format != 'zip': - kwargs['owner'] = owner - kwargs['group'] = group - - try: - filename = func(base_name, base_dir, **kwargs) - finally: - if root_dir is not None: - if logger is not None: - logger.debug("changing back to '%s'", save_cwd) - os.chdir(save_cwd) - - return filename - - -def get_unpack_formats(): - """Returns a list of supported formats for unpacking. - - Each element of the returned sequence is a tuple - (name, extensions, description) - """ - formats = [(name, info[0], info[3]) for name, info in - _UNPACK_FORMATS.items()] - formats.sort() - return formats - -def _check_unpack_options(extensions, function, extra_args): - """Checks what gets registered as an unpacker.""" - # first make sure no other unpacker is registered for this extension - existing_extensions = {} - for name, info in _UNPACK_FORMATS.items(): - for ext in info[0]: - existing_extensions[ext] = name - - for extension in extensions: - if extension in existing_extensions: - msg = '%s is already registered for "%s"' - raise RegistryError(msg % (extension, - existing_extensions[extension])) - - if not isinstance(function, Callable): - raise TypeError('The registered function must be a callable') - - -def register_unpack_format(name, extensions, function, extra_args=None, - description=''): - """Registers an unpack format. - - `name` is the name of the format. `extensions` is a list of extensions - corresponding to the format. - - `function` is the callable that will be - used to unpack archives. The callable will receive archives to unpack. - If it's unable to handle an archive, it needs to raise a ReadError - exception. - - If provided, `extra_args` is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_unpack_formats() function. - """ - if extra_args is None: - extra_args = [] - _check_unpack_options(extensions, function, extra_args) - _UNPACK_FORMATS[name] = extensions, function, extra_args, description - -def unregister_unpack_format(name): - """Removes the pack format from the registry.""" - del _UNPACK_FORMATS[name] - -def _ensure_directory(path): - """Ensure that the parent directory of `path` exists""" - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) - -def _unpack_zipfile(filename, extract_dir): - """Unpack zip `filename` to `extract_dir` - """ - try: - import zipfile - except ImportError: - raise ReadError('zlib not supported, cannot unpack this archive.') - - if not zipfile.is_zipfile(filename): - raise ReadError("%s is not a zip file" % filename) - - zip = zipfile.ZipFile(filename) - try: - for info in zip.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name: - continue - - target = os.path.join(extract_dir, *name.split('/')) - if not target: - continue - - _ensure_directory(target) - if not name.endswith('/'): - # file - data = zip.read(info.filename) - f = open(target, 'wb') - try: - f.write(data) - finally: - f.close() - del data - finally: - zip.close() - -def _unpack_tarfile(filename, extract_dir): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` - """ - try: - tarobj = tarfile.open(filename) - except tarfile.TarError: - raise ReadError( - "%s is not a compressed or uncompressed tar file" % filename) - try: - tarobj.extractall(extract_dir) - finally: - tarobj.close() - -_UNPACK_FORMATS = { - 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), - 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), - 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") - } - -if _BZ2_SUPPORTED: - _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], - "bzip2'ed tar-file") - -def _find_unpack_format(filename): - for name, info in _UNPACK_FORMATS.items(): - for extension in info[0]: - if filename.endswith(extension): - return name - return None - -def unpack_archive(filename, extract_dir=None, format=None): - """Unpack an archive. - - `filename` is the name of the archive. - - `extract_dir` is the name of the target directory, where the archive - is unpacked. If not provided, the current working directory is used. - - `format` is the archive format: one of "zip", "tar", or "gztar". Or any - other registered format. If not provided, unpack_archive will use the - filename extension and see if an unpacker was registered for that - extension. - - In case none is found, a ValueError is raised. - """ - if extract_dir is None: - extract_dir = os.getcwd() - - if format is not None: - try: - format_info = _UNPACK_FORMATS[format] - except KeyError: - raise ValueError("Unknown unpack format '{0}'".format(format)) - - func = format_info[1] - func(filename, extract_dir, **dict(format_info[2])) - else: - # we need to look at the registered unpackers supported extensions - format = _find_unpack_format(filename) - if format is None: - raise ReadError("Unknown archive format '{0}'".format(filename)) - - func = _UNPACK_FORMATS[format][1] - kwargs = dict(_UNPACK_FORMATS[format][2]) - func(filename, extract_dir, **kwargs) diff --git a/src/pip/_vendor/distlib/_backport/sysconfig.cfg b/src/pip/_vendor/distlib/_backport/sysconfig.cfg deleted file mode 100644 index 1746bd01c1a..00000000000 --- a/src/pip/_vendor/distlib/_backport/sysconfig.cfg +++ /dev/null @@ -1,84 +0,0 @@ -[posix_prefix] -# Configuration directories. Some of these come straight out of the -# configure script. They are for implementing the other variables, not to -# be used directly in [resource_locations]. -confdir = /etc -datadir = /usr/share -libdir = /usr/lib -statedir = /var -# User resource directory -local = ~/.local/{distribution.name} - -stdlib = {base}/lib/python{py_version_short} -platstdlib = {platbase}/lib/python{py_version_short} -purelib = {base}/lib/python{py_version_short}/site-packages -platlib = {platbase}/lib/python{py_version_short}/site-packages -include = {base}/include/python{py_version_short}{abiflags} -platinclude = {platbase}/include/python{py_version_short}{abiflags} -data = {base} - -[posix_home] -stdlib = {base}/lib/python -platstdlib = {base}/lib/python -purelib = {base}/lib/python -platlib = {base}/lib/python -include = {base}/include/python -platinclude = {base}/include/python -scripts = {base}/bin -data = {base} - -[nt] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2_home] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[nt_user] -stdlib = {userbase}/Python{py_version_nodot} -platstdlib = {userbase}/Python{py_version_nodot} -purelib = {userbase}/Python{py_version_nodot}/site-packages -platlib = {userbase}/Python{py_version_nodot}/site-packages -include = {userbase}/Python{py_version_nodot}/Include -scripts = {userbase}/Scripts -data = {userbase} - -[posix_user] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[osx_framework_user] -stdlib = {userbase}/lib/python -platstdlib = {userbase}/lib/python -purelib = {userbase}/lib/python/site-packages -platlib = {userbase}/lib/python/site-packages -include = {userbase}/include -scripts = {userbase}/bin -data = {userbase} diff --git a/src/pip/_vendor/distlib/_backport/sysconfig.py b/src/pip/_vendor/distlib/_backport/sysconfig.py deleted file mode 100644 index b470a373c86..00000000000 --- a/src/pip/_vendor/distlib/_backport/sysconfig.py +++ /dev/null @@ -1,786 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Access to Python's configuration information.""" - -import codecs -import os -import re -import sys -from os.path import pardir, realpath -try: - import configparser -except ImportError: - import ConfigParser as configparser - - -__all__ = [ - 'get_config_h_filename', - 'get_config_var', - 'get_config_vars', - 'get_makefile_filename', - 'get_path', - 'get_path_names', - 'get_paths', - 'get_platform', - 'get_python_version', - 'get_scheme_names', - 'parse_config_h', -] - - -def _safe_realpath(path): - try: - return realpath(path) - except OSError: - return path - - -if sys.executable: - _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable)) -else: - # sys.executable can be empty if argv[0] has been changed and Python is - # unable to retrieve the real program name - _PROJECT_BASE = _safe_realpath(os.getcwd()) - -if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir)) -# PC/VS7.1 -if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) -# PC/AMD64 -if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) - - -def is_python_build(): - for fn in ("Setup.dist", "Setup.local"): - if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): - return True - return False - -_PYTHON_BUILD = is_python_build() - -_cfg_read = False - -def _ensure_cfg_read(): - global _cfg_read - if not _cfg_read: - from ..resources import finder - backport_package = __name__.rsplit('.', 1)[0] - _finder = finder(backport_package) - _cfgfile = _finder.find('sysconfig.cfg') - assert _cfgfile, 'sysconfig.cfg exists' - with _cfgfile.as_stream() as s: - _SCHEMES.readfp(s) - if _PYTHON_BUILD: - for scheme in ('posix_prefix', 'posix_home'): - _SCHEMES.set(scheme, 'include', '{srcdir}/Include') - _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.') - - _cfg_read = True - - -_SCHEMES = configparser.RawConfigParser() -_VAR_REPL = re.compile(r'\{([^{]*?)\}') - -def _expand_globals(config): - _ensure_cfg_read() - if config.has_section('globals'): - globals = config.items('globals') - else: - globals = tuple() - - sections = config.sections() - for section in sections: - if section == 'globals': - continue - for option, value in globals: - if config.has_option(section, option): - continue - config.set(section, option, value) - config.remove_section('globals') - - # now expanding local variables defined in the cfg file - # - for section in config.sections(): - variables = dict(config.items(section)) - - def _replacer(matchobj): - name = matchobj.group(1) - if name in variables: - return variables[name] - return matchobj.group(0) - - for option, value in config.items(section): - config.set(section, option, _VAR_REPL.sub(_replacer, value)) - -#_expand_globals(_SCHEMES) - -_PY_VERSION = '%s.%s.%s' % sys.version_info[:3] -_PY_VERSION_SHORT = '%s.%s' % sys.version_info[:2] -_PY_VERSION_SHORT_NO_DOT = '%s%s' % sys.version_info[:2] -_PREFIX = os.path.normpath(sys.prefix) -_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) -_CONFIG_VARS = None -_USER_BASE = None - - -def _subst_vars(path, local_vars): - """In the string `path`, replace tokens like {some.thing} with the - corresponding value from the map `local_vars`. - - If there is no corresponding value, leave the token unchanged. - """ - def _replacer(matchobj): - name = matchobj.group(1) - if name in local_vars: - return local_vars[name] - elif name in os.environ: - return os.environ[name] - return matchobj.group(0) - return _VAR_REPL.sub(_replacer, path) - - -def _extend_dict(target_dict, other_dict): - target_keys = target_dict.keys() - for key, value in other_dict.items(): - if key in target_keys: - continue - target_dict[key] = value - - -def _expand_vars(scheme, vars): - res = {} - if vars is None: - vars = {} - _extend_dict(vars, get_config_vars()) - - for key, value in _SCHEMES.items(scheme): - if os.name in ('posix', 'nt'): - value = os.path.expanduser(value) - res[key] = os.path.normpath(_subst_vars(value, vars)) - return res - - -def format_value(value, vars): - def _replacer(matchobj): - name = matchobj.group(1) - if name in vars: - return vars[name] - return matchobj.group(0) - return _VAR_REPL.sub(_replacer, value) - - -def _get_default_scheme(): - if os.name == 'posix': - # the default scheme for posix is posix_prefix - return 'posix_prefix' - return os.name - - -def _getuserbase(): - env_base = os.environ.get("PYTHONUSERBASE", None) - - def joinuser(*args): - return os.path.expanduser(os.path.join(*args)) - - # what about 'os2emx', 'riscos' ? - if os.name == "nt": - base = os.environ.get("APPDATA") or "~" - if env_base: - return env_base - else: - return joinuser(base, "Python") - - if sys.platform == "darwin": - framework = get_config_var("PYTHONFRAMEWORK") - if framework: - if env_base: - return env_base - else: - return joinuser("~", "Library", framework, "%d.%d" % - sys.version_info[:2]) - - if env_base: - return env_base - else: - return joinuser("~", ".local") - - -def _parse_makefile(filename, vars=None): - """Parse a Makefile-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - # Regexes needed for parsing Makefile (and similar syntaxes, - # like old-style Setup files). - _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") - _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") - _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") - - if vars is None: - vars = {} - done = {} - notdone = {} - - with codecs.open(filename, encoding='utf-8', errors="surrogateescape") as f: - lines = f.readlines() - - for line in lines: - if line.startswith('#') or line.strip() == '': - continue - m = _variable_rx.match(line) - if m: - n, v = m.group(1, 2) - v = v.strip() - # `$$' is a literal `$' in make - tmpv = v.replace('$$', '') - - if "$" in tmpv: - notdone[n] = v - else: - try: - v = int(v) - except ValueError: - # insert literal `$' - done[n] = v.replace('$$', '$') - else: - done[n] = v - - # do variable interpolation here - variables = list(notdone.keys()) - - # Variables with a 'PY_' prefix in the makefile. These need to - # be made available without that prefix through sysconfig. - # Special care is needed to ensure that variable expansion works, even - # if the expansion uses the name without a prefix. - renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') - - while len(variables) > 0: - for name in tuple(variables): - value = notdone[name] - m = _findvar1_rx.search(value) or _findvar2_rx.search(value) - if m is not None: - n = m.group(1) - found = True - if n in done: - item = str(done[n]) - elif n in notdone: - # get it on a subsequent round - found = False - elif n in os.environ: - # do it like make: fall back to environment - item = os.environ[n] - - elif n in renamed_variables: - if (name.startswith('PY_') and - name[3:] in renamed_variables): - item = "" - - elif 'PY_' + n in notdone: - found = False - - else: - item = str(done['PY_' + n]) - - else: - done[n] = item = "" - - if found: - after = value[m.end():] - value = value[:m.start()] + item + after - if "$" in after: - notdone[name] = value - else: - try: - value = int(value) - except ValueError: - done[name] = value.strip() - else: - done[name] = value - variables.remove(name) - - if (name.startswith('PY_') and - name[3:] in renamed_variables): - - name = name[3:] - if name not in done: - done[name] = value - - else: - # bogus variable reference (e.g. "prefix=$/opt/python"); - # just drop it since we can't deal - done[name] = value - variables.remove(name) - - # strip spurious spaces - for k, v in done.items(): - if isinstance(v, str): - done[k] = v.strip() - - # save the results in the global dictionary - vars.update(done) - return vars - - -def get_makefile_filename(): - """Return the path of the Makefile.""" - if _PYTHON_BUILD: - return os.path.join(_PROJECT_BASE, "Makefile") - if hasattr(sys, 'abiflags'): - config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags) - else: - config_dir_name = 'config' - return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') - - -def _init_posix(vars): - """Initialize the module as appropriate for POSIX systems.""" - # load the installed Makefile: - makefile = get_makefile_filename() - try: - _parse_makefile(makefile, vars) - except IOError as e: - msg = "invalid Python installation: unable to open %s" % makefile - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - # load the installed pyconfig.h: - config_h = get_config_h_filename() - try: - with open(config_h) as f: - parse_config_h(f, vars) - except IOError as e: - msg = "invalid Python installation: unable to open %s" % config_h - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - # On AIX, there are wrong paths to the linker scripts in the Makefile - # -- these paths are relative to the Python source, but when installed - # the scripts are in another directory. - if _PYTHON_BUILD: - vars['LDSHARED'] = vars['BLDSHARED'] - - -def _init_non_posix(vars): - """Initialize the module as appropriate for NT""" - # set basic install directories - vars['LIBDEST'] = get_path('stdlib') - vars['BINLIBDEST'] = get_path('platstdlib') - vars['INCLUDEPY'] = get_path('include') - vars['SO'] = '.pyd' - vars['EXE'] = '.exe' - vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT - vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable)) - -# -# public APIs -# - - -def parse_config_h(fp, vars=None): - """Parse a config.h-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - if vars is None: - vars = {} - define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") - undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") - - while True: - line = fp.readline() - if not line: - break - m = define_rx.match(line) - if m: - n, v = m.group(1, 2) - try: - v = int(v) - except ValueError: - pass - vars[n] = v - else: - m = undef_rx.match(line) - if m: - vars[m.group(1)] = 0 - return vars - - -def get_config_h_filename(): - """Return the path of pyconfig.h.""" - if _PYTHON_BUILD: - if os.name == "nt": - inc_dir = os.path.join(_PROJECT_BASE, "PC") - else: - inc_dir = _PROJECT_BASE - else: - inc_dir = get_path('platinclude') - return os.path.join(inc_dir, 'pyconfig.h') - - -def get_scheme_names(): - """Return a tuple containing the schemes names.""" - return tuple(sorted(_SCHEMES.sections())) - - -def get_path_names(): - """Return a tuple containing the paths names.""" - # xxx see if we want a static list - return _SCHEMES.options('posix_prefix') - - -def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): - """Return a mapping containing an install scheme. - - ``scheme`` is the install scheme name. If not provided, it will - return the default scheme for the current platform. - """ - _ensure_cfg_read() - if expand: - return _expand_vars(scheme, vars) - else: - return dict(_SCHEMES.items(scheme)) - - -def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): - """Return a path corresponding to the scheme. - - ``scheme`` is the install scheme name. - """ - return get_paths(scheme, vars, expand)[name] - - -def get_config_vars(*args): - """With no arguments, return a dictionary of all configuration - variables relevant for the current platform. - - On Unix, this means every variable defined in Python's installed Makefile; - On Windows and Mac OS it's a much smaller set. - - With arguments, return a list of values that result from looking up - each argument in the configuration variable dictionary. - """ - global _CONFIG_VARS - if _CONFIG_VARS is None: - _CONFIG_VARS = {} - # Normalized versions of prefix and exec_prefix are handy to have; - # in fact, these are the standard versions used most places in the - # distutils2 module. - _CONFIG_VARS['prefix'] = _PREFIX - _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX - _CONFIG_VARS['py_version'] = _PY_VERSION - _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT - _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2] - _CONFIG_VARS['base'] = _PREFIX - _CONFIG_VARS['platbase'] = _EXEC_PREFIX - _CONFIG_VARS['projectbase'] = _PROJECT_BASE - try: - _CONFIG_VARS['abiflags'] = sys.abiflags - except AttributeError: - # sys.abiflags may not be defined on all platforms. - _CONFIG_VARS['abiflags'] = '' - - if os.name in ('nt', 'os2'): - _init_non_posix(_CONFIG_VARS) - if os.name == 'posix': - _init_posix(_CONFIG_VARS) - # Setting 'userbase' is done below the call to the - # init function to enable using 'get_config_var' in - # the init-function. - if sys.version >= '2.6': - _CONFIG_VARS['userbase'] = _getuserbase() - - if 'srcdir' not in _CONFIG_VARS: - _CONFIG_VARS['srcdir'] = _PROJECT_BASE - else: - _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) - - # Convert srcdir into an absolute path if it appears necessary. - # Normally it is relative to the build directory. However, during - # testing, for example, we might be running a non-installed python - # from a different directory. - if _PYTHON_BUILD and os.name == "posix": - base = _PROJECT_BASE - try: - cwd = os.getcwd() - except OSError: - cwd = None - if (not os.path.isabs(_CONFIG_VARS['srcdir']) and - base != cwd): - # srcdir is relative and we are not in the same directory - # as the executable. Assume executable is in the build - # directory and make srcdir absolute. - srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) - _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) - - if sys.platform == 'darwin': - kernel_version = os.uname()[2] # Kernel version (8.4.3) - major_version = int(kernel_version.split('.')[0]) - - if major_version < 8: - # On Mac OS X before 10.4, check if -arch and -isysroot - # are in CFLAGS or LDFLAGS and remove them if they are. - # This is needed when building extensions on a 10.3 system - # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - flags = _CONFIG_VARS[key] - flags = re.sub(r'-arch\s+\w+\s', ' ', flags) - flags = re.sub('-isysroot [^ \t]*', ' ', flags) - _CONFIG_VARS[key] = flags - else: - # Allow the user to override the architecture flags using - # an environment variable. - # NOTE: This name was introduced by Apple in OSX 10.5 and - # is used by several scripting languages distributed with - # that OS release. - if 'ARCHFLAGS' in os.environ: - arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub(r'-arch\s+\w+\s', ' ', flags) - flags = flags + ' ' + arch - _CONFIG_VARS[key] = flags - - # If we're on OSX 10.5 or later and the user tries to - # compiles an extension using an SDK that is not present - # on the current machine it is better to not use an SDK - # than to fail. - # - # The major usecase for this is users using a Python.org - # binary installer on OSX 10.6: that installer uses - # the 10.4u SDK, but that SDK is not installed by default - # when you install Xcode. - # - CFLAGS = _CONFIG_VARS.get('CFLAGS', '') - m = re.search(r'-isysroot\s+(\S+)', CFLAGS) - if m is not None: - sdk = m.group(1) - if not os.path.exists(sdk): - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub(r'-isysroot\s+\S+(\s|$)', ' ', flags) - _CONFIG_VARS[key] = flags - - if args: - vals = [] - for name in args: - vals.append(_CONFIG_VARS.get(name)) - return vals - else: - return _CONFIG_VARS - - -def get_config_var(name): - """Return the value of a single variable using the dictionary returned by - 'get_config_vars()'. - - Equivalent to get_config_vars().get(name) - """ - return get_config_vars().get(name) - - -def get_platform(): - """Return a string that identifies the current platform. - - This is used mainly to distinguish platform-specific build directories and - platform-specific built distributions. Typically includes the OS name - and version and the architecture (as supplied by 'os.uname()'), - although the exact information included depends on the OS; eg. for IRIX - the architecture isn't particularly important (IRIX only runs on SGI - hardware), but for Linux the kernel version isn't particularly - important. - - Examples of returned values: - linux-i586 - linux-alpha (?) - solaris-2.6-sun4u - irix-5.3 - irix64-6.2 - - Windows will return one of: - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win-ia64 (64bit Windows on Itanium) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. - """ - if os.name == 'nt': - # sniff sys.version for architecture. - prefix = " bit (" - i = sys.version.find(prefix) - if i == -1: - return sys.platform - j = sys.version.find(")", i) - look = sys.version[i+len(prefix):j].lower() - if look == 'amd64': - return 'win-amd64' - if look == 'itanium': - return 'win-ia64' - return sys.platform - - if os.name != "posix" or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. - return sys.platform - - # Try to distinguish various flavours of Unix - osname, host, release, version, machine = os.uname() - - # Convert the OS name to lowercase, remove '/' characters - # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh") - osname = osname.lower().replace('/', '') - machine = machine.replace(' ', '_') - machine = machine.replace('/', '-') - - if osname[:5] == "linux": - # At least on Linux/Intel, 'machine' is the processor -- - # i386, etc. - # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) - elif osname[:5] == "sunos": - if release[0] >= "5": # SunOS 5 == Solaris 2 - osname = "solaris" - release = "%d.%s" % (int(release[0]) - 3, release[2:]) - # fall through to standard osname-release-machine representation - elif osname[:4] == "irix": # could be "irix64"! - return "%s-%s" % (osname, release) - elif osname[:3] == "aix": - return "%s-%s.%s" % (osname, version, release) - elif osname[:6] == "cygwin": - osname = "cygwin" - rel_re = re.compile(r'[\d.]+') - m = rel_re.match(release) - if m: - release = m.group() - elif osname[:6] == "darwin": - # - # For our purposes, we'll assume that the system version from - # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set - # to. This makes the compatibility story a bit more sane because the - # machine is going to compile and link as if it were - # MACOSX_DEPLOYMENT_TARGET. - cfgvars = get_config_vars() - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - - if True: - # Always calculate the release of the running machine, - # needed to determine if we can build fat binaries or not. - - macrelease = macver - # Get the system version. Reading this plist is a documented - # way to get the system version (see the documentation for - # the Gestalt Manager) - try: - f = open('/System/Library/CoreServices/SystemVersion.plist') - except IOError: - # We're on a plain darwin box, fall back to the default - # behaviour. - pass - else: - try: - m = re.search(r'ProductUserVisibleVersion\s*' - r'(.*?)', f.read()) - finally: - f.close() - if m is not None: - macrelease = '.'.join(m.group(1).split('.')[:2]) - # else: fall back to the default behaviour - - if not macver: - macver = macrelease - - if macver: - release = macver - osname = "macosx" - - if ((macrelease + '.') >= '10.4.' and - '-arch' in get_config_vars().get('CFLAGS', '').strip()): - # The universal build will build fat binaries, but not on - # systems before 10.4 - # - # Try to detect 4-way universal builds, those have machine-type - # 'universal' instead of 'fat'. - - machine = 'fat' - cflags = get_config_vars().get('CFLAGS') - - archs = re.findall(r'-arch\s+(\S+)', cflags) - archs = tuple(sorted(set(archs))) - - if len(archs) == 1: - machine = archs[0] - elif archs == ('i386', 'ppc'): - machine = 'fat' - elif archs == ('i386', 'x86_64'): - machine = 'intel' - elif archs == ('i386', 'ppc', 'x86_64'): - machine = 'fat3' - elif archs == ('ppc64', 'x86_64'): - machine = 'fat64' - elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): - machine = 'universal' - else: - raise ValueError( - "Don't know machine value for archs=%r" % (archs,)) - - elif machine == 'i386': - # On OSX the machine type returned by uname is always the - # 32-bit variant, even if the executable architecture is - # the 64-bit variant - if sys.maxsize >= 2**32: - machine = 'x86_64' - - elif machine in ('PowerPC', 'Power_Macintosh'): - # Pick a sane name for the PPC architecture. - # See 'i386' case - if sys.maxsize >= 2**32: - machine = 'ppc64' - else: - machine = 'ppc' - - return "%s-%s-%s" % (osname, release, machine) - - -def get_python_version(): - return _PY_VERSION_SHORT - - -def _print_dict(title, data): - for index, (key, value) in enumerate(sorted(data.items())): - if index == 0: - print('%s: ' % (title)) - print('\t%s = "%s"' % (key, value)) - - -def _main(): - """Display all information sysconfig detains.""" - print('Platform: "%s"' % get_platform()) - print('Python version: "%s"' % get_python_version()) - print('Current installation scheme: "%s"' % _get_default_scheme()) - print() - _print_dict('Paths', get_paths()) - print() - _print_dict('Variables', get_config_vars()) - - -if __name__ == '__main__': - _main() diff --git a/src/pip/_vendor/distlib/_backport/tarfile.py b/src/pip/_vendor/distlib/_backport/tarfile.py deleted file mode 100644 index d66d8566374..00000000000 --- a/src/pip/_vendor/distlib/_backport/tarfile.py +++ /dev/null @@ -1,2607 +0,0 @@ -#------------------------------------------------------------------- -# tarfile.py -#------------------------------------------------------------------- -# Copyright (C) 2002 Lars Gustaebel -# All rights reserved. -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation -# files (the "Software"), to deal in the Software without -# restriction, including without limitation the rights to use, -# copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following -# conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -from __future__ import print_function - -"""Read from and write to tar format archives. -""" - -__version__ = "$Revision$" - -version = "0.9.0" -__author__ = "Lars Gust\u00e4bel (lars@gustaebel.de)" -__date__ = "$Date: 2011-02-25 17:42:01 +0200 (Fri, 25 Feb 2011) $" -__cvsid__ = "$Id: tarfile.py 88586 2011-02-25 15:42:01Z marc-andre.lemburg $" -__credits__ = "Gustavo Niemeyer, Niels Gust\u00e4bel, Richard Townsend." - -#--------- -# Imports -#--------- -import sys -import os -import stat -import errno -import time -import struct -import copy -import re - -try: - import grp, pwd -except ImportError: - grp = pwd = None - -# os.symlink on Windows prior to 6.0 raises NotImplementedError -symlink_exception = (AttributeError, NotImplementedError) -try: - # WindowsError (1314) will be raised if the caller does not hold the - # SeCreateSymbolicLinkPrivilege privilege - symlink_exception += (WindowsError,) -except NameError: - pass - -# from tarfile import * -__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"] - -if sys.version_info[0] < 3: - import __builtin__ as builtins -else: - import builtins - -_open = builtins.open # Since 'open' is TarFile.open - -#--------------------------------------------------------- -# tar constants -#--------------------------------------------------------- -NUL = b"\0" # the null character -BLOCKSIZE = 512 # length of processing blocks -RECORDSIZE = BLOCKSIZE * 20 # length of records -GNU_MAGIC = b"ustar \0" # magic gnu tar string -POSIX_MAGIC = b"ustar\x0000" # magic posix tar string - -LENGTH_NAME = 100 # maximum length of a filename -LENGTH_LINK = 100 # maximum length of a linkname -LENGTH_PREFIX = 155 # maximum length of the prefix field - -REGTYPE = b"0" # regular file -AREGTYPE = b"\0" # regular file -LNKTYPE = b"1" # link (inside tarfile) -SYMTYPE = b"2" # symbolic link -CHRTYPE = b"3" # character special device -BLKTYPE = b"4" # block special device -DIRTYPE = b"5" # directory -FIFOTYPE = b"6" # fifo special device -CONTTYPE = b"7" # contiguous file - -GNUTYPE_LONGNAME = b"L" # GNU tar longname -GNUTYPE_LONGLINK = b"K" # GNU tar longlink -GNUTYPE_SPARSE = b"S" # GNU tar sparse file - -XHDTYPE = b"x" # POSIX.1-2001 extended header -XGLTYPE = b"g" # POSIX.1-2001 global header -SOLARIS_XHDTYPE = b"X" # Solaris extended header - -USTAR_FORMAT = 0 # POSIX.1-1988 (ustar) format -GNU_FORMAT = 1 # GNU tar format -PAX_FORMAT = 2 # POSIX.1-2001 (pax) format -DEFAULT_FORMAT = GNU_FORMAT - -#--------------------------------------------------------- -# tarfile constants -#--------------------------------------------------------- -# File types that tarfile supports: -SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, - SYMTYPE, DIRTYPE, FIFOTYPE, - CONTTYPE, CHRTYPE, BLKTYPE, - GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# File types that will be treated as a regular file. -REGULAR_TYPES = (REGTYPE, AREGTYPE, - CONTTYPE, GNUTYPE_SPARSE) - -# File types that are part of the GNU tar format. -GNU_TYPES = (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# Fields from a pax header that override a TarInfo attribute. -PAX_FIELDS = ("path", "linkpath", "size", "mtime", - "uid", "gid", "uname", "gname") - -# Fields from a pax header that are affected by hdrcharset. -PAX_NAME_FIELDS = set(("path", "linkpath", "uname", "gname")) - -# Fields in a pax header that are numbers, all other fields -# are treated as strings. -PAX_NUMBER_FIELDS = { - "atime": float, - "ctime": float, - "mtime": float, - "uid": int, - "gid": int, - "size": int -} - -#--------------------------------------------------------- -# Bits used in the mode field, values in octal. -#--------------------------------------------------------- -S_IFLNK = 0o120000 # symbolic link -S_IFREG = 0o100000 # regular file -S_IFBLK = 0o060000 # block device -S_IFDIR = 0o040000 # directory -S_IFCHR = 0o020000 # character device -S_IFIFO = 0o010000 # fifo - -TSUID = 0o4000 # set UID on execution -TSGID = 0o2000 # set GID on execution -TSVTX = 0o1000 # reserved - -TUREAD = 0o400 # read by owner -TUWRITE = 0o200 # write by owner -TUEXEC = 0o100 # execute/search by owner -TGREAD = 0o040 # read by group -TGWRITE = 0o020 # write by group -TGEXEC = 0o010 # execute/search by group -TOREAD = 0o004 # read by other -TOWRITE = 0o002 # write by other -TOEXEC = 0o001 # execute/search by other - -#--------------------------------------------------------- -# initialization -#--------------------------------------------------------- -if os.name in ("nt", "ce"): - ENCODING = "utf-8" -else: - ENCODING = sys.getfilesystemencoding() - -#--------------------------------------------------------- -# Some useful functions -#--------------------------------------------------------- - -def stn(s, length, encoding, errors): - """Convert a string to a null-terminated bytes object. - """ - s = s.encode(encoding, errors) - return s[:length] + (length - len(s)) * NUL - -def nts(s, encoding, errors): - """Convert a null-terminated bytes object to a string. - """ - p = s.find(b"\0") - if p != -1: - s = s[:p] - return s.decode(encoding, errors) - -def nti(s): - """Convert a number field to a python number. - """ - # There are two possible encodings for a number field, see - # itn() below. - if s[0] != chr(0o200): - try: - n = int(nts(s, "ascii", "strict") or "0", 8) - except ValueError: - raise InvalidHeaderError("invalid header") - else: - n = 0 - for i in range(len(s) - 1): - n <<= 8 - n += ord(s[i + 1]) - return n - -def itn(n, digits=8, format=DEFAULT_FORMAT): - """Convert a python number to a number field. - """ - # POSIX 1003.1-1988 requires numbers to be encoded as a string of - # octal digits followed by a null-byte, this allows values up to - # (8**(digits-1))-1. GNU tar allows storing numbers greater than - # that if necessary. A leading 0o200 byte indicates this particular - # encoding, the following digits-1 bytes are a big-endian - # representation. This allows values up to (256**(digits-1))-1. - if 0 <= n < 8 ** (digits - 1): - s = ("%0*o" % (digits - 1, n)).encode("ascii") + NUL - else: - if format != GNU_FORMAT or n >= 256 ** (digits - 1): - raise ValueError("overflow in number field") - - if n < 0: - # XXX We mimic GNU tar's behaviour with negative numbers, - # this could raise OverflowError. - n = struct.unpack("L", struct.pack("l", n))[0] - - s = bytearray() - for i in range(digits - 1): - s.insert(0, n & 0o377) - n >>= 8 - s.insert(0, 0o200) - return s - -def calc_chksums(buf): - """Calculate the checksum for a member's header by summing up all - characters except for the chksum field which is treated as if - it was filled with spaces. According to the GNU tar sources, - some tars (Sun and NeXT) calculate chksum with signed char, - which will be different if there are chars in the buffer with - the high bit set. So we calculate two checksums, unsigned and - signed. - """ - unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512])) - signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512])) - return unsigned_chksum, signed_chksum - -def copyfileobj(src, dst, length=None): - """Copy length bytes from fileobj src to fileobj dst. - If length is None, copy the entire content. - """ - if length == 0: - return - if length is None: - while True: - buf = src.read(16*1024) - if not buf: - break - dst.write(buf) - return - - BUFSIZE = 16 * 1024 - blocks, remainder = divmod(length, BUFSIZE) - for b in range(blocks): - buf = src.read(BUFSIZE) - if len(buf) < BUFSIZE: - raise IOError("end of file reached") - dst.write(buf) - - if remainder != 0: - buf = src.read(remainder) - if len(buf) < remainder: - raise IOError("end of file reached") - dst.write(buf) - return - -filemode_table = ( - ((S_IFLNK, "l"), - (S_IFREG, "-"), - (S_IFBLK, "b"), - (S_IFDIR, "d"), - (S_IFCHR, "c"), - (S_IFIFO, "p")), - - ((TUREAD, "r"),), - ((TUWRITE, "w"),), - ((TUEXEC|TSUID, "s"), - (TSUID, "S"), - (TUEXEC, "x")), - - ((TGREAD, "r"),), - ((TGWRITE, "w"),), - ((TGEXEC|TSGID, "s"), - (TSGID, "S"), - (TGEXEC, "x")), - - ((TOREAD, "r"),), - ((TOWRITE, "w"),), - ((TOEXEC|TSVTX, "t"), - (TSVTX, "T"), - (TOEXEC, "x")) -) - -def filemode(mode): - """Convert a file's mode to a string of the form - -rwxrwxrwx. - Used by TarFile.list() - """ - perm = [] - for table in filemode_table: - for bit, char in table: - if mode & bit == bit: - perm.append(char) - break - else: - perm.append("-") - return "".join(perm) - -class TarError(Exception): - """Base exception.""" - pass -class ExtractError(TarError): - """General exception for extract errors.""" - pass -class ReadError(TarError): - """Exception for unreadable tar archives.""" - pass -class CompressionError(TarError): - """Exception for unavailable compression methods.""" - pass -class StreamError(TarError): - """Exception for unsupported operations on stream-like TarFiles.""" - pass -class HeaderError(TarError): - """Base exception for header errors.""" - pass -class EmptyHeaderError(HeaderError): - """Exception for empty headers.""" - pass -class TruncatedHeaderError(HeaderError): - """Exception for truncated headers.""" - pass -class EOFHeaderError(HeaderError): - """Exception for end of file headers.""" - pass -class InvalidHeaderError(HeaderError): - """Exception for invalid headers.""" - pass -class SubsequentHeaderError(HeaderError): - """Exception for missing and invalid extended headers.""" - pass - -#--------------------------- -# internal stream interface -#--------------------------- -class _LowLevelFile(object): - """Low-level file object. Supports reading and writing. - It is used instead of a regular file object for streaming - access. - """ - - def __init__(self, name, mode): - mode = { - "r": os.O_RDONLY, - "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC, - }[mode] - if hasattr(os, "O_BINARY"): - mode |= os.O_BINARY - self.fd = os.open(name, mode, 0o666) - - def close(self): - os.close(self.fd) - - def read(self, size): - return os.read(self.fd, size) - - def write(self, s): - os.write(self.fd, s) - -class _Stream(object): - """Class that serves as an adapter between TarFile and - a stream-like object. The stream-like object only - needs to have a read() or write() method and is accessed - blockwise. Use of gzip or bzip2 compression is possible. - A stream-like object could be for example: sys.stdin, - sys.stdout, a socket, a tape device etc. - - _Stream is intended to be used only internally. - """ - - def __init__(self, name, mode, comptype, fileobj, bufsize): - """Construct a _Stream object. - """ - self._extfileobj = True - if fileobj is None: - fileobj = _LowLevelFile(name, mode) - self._extfileobj = False - - if comptype == '*': - # Enable transparent compression detection for the - # stream interface - fileobj = _StreamProxy(fileobj) - comptype = fileobj.getcomptype() - - self.name = name or "" - self.mode = mode - self.comptype = comptype - self.fileobj = fileobj - self.bufsize = bufsize - self.buf = b"" - self.pos = 0 - self.closed = False - - try: - if comptype == "gz": - try: - import zlib - except ImportError: - raise CompressionError("zlib module is not available") - self.zlib = zlib - self.crc = zlib.crc32(b"") - if mode == "r": - self._init_read_gz() - else: - self._init_write_gz() - - if comptype == "bz2": - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - if mode == "r": - self.dbuf = b"" - self.cmp = bz2.BZ2Decompressor() - else: - self.cmp = bz2.BZ2Compressor() - except: - if not self._extfileobj: - self.fileobj.close() - self.closed = True - raise - - def __del__(self): - if hasattr(self, "closed") and not self.closed: - self.close() - - def _init_write_gz(self): - """Initialize for writing with gzip compression. - """ - self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, - -self.zlib.MAX_WBITS, - self.zlib.DEF_MEM_LEVEL, - 0) - timestamp = struct.pack(" self.bufsize: - self.fileobj.write(self.buf[:self.bufsize]) - self.buf = self.buf[self.bufsize:] - - def close(self): - """Close the _Stream object. No operation should be - done on it afterwards. - """ - if self.closed: - return - - if self.mode == "w" and self.comptype != "tar": - self.buf += self.cmp.flush() - - if self.mode == "w" and self.buf: - self.fileobj.write(self.buf) - self.buf = b"" - if self.comptype == "gz": - # The native zlib crc is an unsigned 32-bit integer, but - # the Python wrapper implicitly casts that to a signed C - # long. So, on a 32-bit box self.crc may "look negative", - # while the same crc on a 64-bit box may "look positive". - # To avoid irksome warnings from the `struct` module, force - # it to look positive on all boxes. - self.fileobj.write(struct.pack("= 0: - blocks, remainder = divmod(pos - self.pos, self.bufsize) - for i in range(blocks): - self.read(self.bufsize) - self.read(remainder) - else: - raise StreamError("seeking backwards is not allowed") - return self.pos - - def read(self, size=None): - """Return the next size number of bytes from the stream. - If size is not defined, return all bytes of the stream - up to EOF. - """ - if size is None: - t = [] - while True: - buf = self._read(self.bufsize) - if not buf: - break - t.append(buf) - buf = "".join(t) - else: - buf = self._read(size) - self.pos += len(buf) - return buf - - def _read(self, size): - """Return size bytes from the stream. - """ - if self.comptype == "tar": - return self.__read(size) - - c = len(self.dbuf) - while c < size: - buf = self.__read(self.bufsize) - if not buf: - break - try: - buf = self.cmp.decompress(buf) - except IOError: - raise ReadError("invalid compressed data") - self.dbuf += buf - c += len(buf) - buf = self.dbuf[:size] - self.dbuf = self.dbuf[size:] - return buf - - def __read(self, size): - """Return size bytes from stream. If internal buffer is empty, - read another block from the stream. - """ - c = len(self.buf) - while c < size: - buf = self.fileobj.read(self.bufsize) - if not buf: - break - self.buf += buf - c += len(buf) - buf = self.buf[:size] - self.buf = self.buf[size:] - return buf -# class _Stream - -class _StreamProxy(object): - """Small proxy class that enables transparent compression - detection for the Stream interface (mode 'r|*'). - """ - - def __init__(self, fileobj): - self.fileobj = fileobj - self.buf = self.fileobj.read(BLOCKSIZE) - - def read(self, size): - self.read = self.fileobj.read - return self.buf - - def getcomptype(self): - if self.buf.startswith(b"\037\213\010"): - return "gz" - if self.buf.startswith(b"BZh91"): - return "bz2" - return "tar" - - def close(self): - self.fileobj.close() -# class StreamProxy - -class _BZ2Proxy(object): - """Small proxy class that enables external file object - support for "r:bz2" and "w:bz2" modes. This is actually - a workaround for a limitation in bz2 module's BZ2File - class which (unlike gzip.GzipFile) has no support for - a file object argument. - """ - - blocksize = 16 * 1024 - - def __init__(self, fileobj, mode): - self.fileobj = fileobj - self.mode = mode - self.name = getattr(self.fileobj, "name", None) - self.init() - - def init(self): - import bz2 - self.pos = 0 - if self.mode == "r": - self.bz2obj = bz2.BZ2Decompressor() - self.fileobj.seek(0) - self.buf = b"" - else: - self.bz2obj = bz2.BZ2Compressor() - - def read(self, size): - x = len(self.buf) - while x < size: - raw = self.fileobj.read(self.blocksize) - if not raw: - break - data = self.bz2obj.decompress(raw) - self.buf += data - x += len(data) - - buf = self.buf[:size] - self.buf = self.buf[size:] - self.pos += len(buf) - return buf - - def seek(self, pos): - if pos < self.pos: - self.init() - self.read(pos - self.pos) - - def tell(self): - return self.pos - - def write(self, data): - self.pos += len(data) - raw = self.bz2obj.compress(data) - self.fileobj.write(raw) - - def close(self): - if self.mode == "w": - raw = self.bz2obj.flush() - self.fileobj.write(raw) -# class _BZ2Proxy - -#------------------------ -# Extraction file object -#------------------------ -class _FileInFile(object): - """A thin wrapper around an existing file object that - provides a part of its data as an individual file - object. - """ - - def __init__(self, fileobj, offset, size, blockinfo=None): - self.fileobj = fileobj - self.offset = offset - self.size = size - self.position = 0 - - if blockinfo is None: - blockinfo = [(0, size)] - - # Construct a map with data and zero blocks. - self.map_index = 0 - self.map = [] - lastpos = 0 - realpos = self.offset - for offset, size in blockinfo: - if offset > lastpos: - self.map.append((False, lastpos, offset, None)) - self.map.append((True, offset, offset + size, realpos)) - realpos += size - lastpos = offset + size - if lastpos < self.size: - self.map.append((False, lastpos, self.size, None)) - - def seekable(self): - if not hasattr(self.fileobj, "seekable"): - # XXX gzip.GzipFile and bz2.BZ2File - return True - return self.fileobj.seekable() - - def tell(self): - """Return the current file position. - """ - return self.position - - def seek(self, position): - """Seek to a position in the file. - """ - self.position = position - - def read(self, size=None): - """Read data from the file. - """ - if size is None: - size = self.size - self.position - else: - size = min(size, self.size - self.position) - - buf = b"" - while size > 0: - while True: - data, start, stop, offset = self.map[self.map_index] - if start <= self.position < stop: - break - else: - self.map_index += 1 - if self.map_index == len(self.map): - self.map_index = 0 - length = min(size, stop - self.position) - if data: - self.fileobj.seek(offset + (self.position - start)) - buf += self.fileobj.read(length) - else: - buf += NUL * length - size -= length - self.position += length - return buf -#class _FileInFile - - -class ExFileObject(object): - """File-like object for reading an archive member. - Is returned by TarFile.extractfile(). - """ - blocksize = 1024 - - def __init__(self, tarfile, tarinfo): - self.fileobj = _FileInFile(tarfile.fileobj, - tarinfo.offset_data, - tarinfo.size, - tarinfo.sparse) - self.name = tarinfo.name - self.mode = "r" - self.closed = False - self.size = tarinfo.size - - self.position = 0 - self.buffer = b"" - - def readable(self): - return True - - def writable(self): - return False - - def seekable(self): - return self.fileobj.seekable() - - def read(self, size=None): - """Read at most size bytes from the file. If size is not - present or None, read all data until EOF is reached. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - buf = b"" - if self.buffer: - if size is None: - buf = self.buffer - self.buffer = b"" - else: - buf = self.buffer[:size] - self.buffer = self.buffer[size:] - - if size is None: - buf += self.fileobj.read() - else: - buf += self.fileobj.read(size - len(buf)) - - self.position += len(buf) - return buf - - # XXX TextIOWrapper uses the read1() method. - read1 = read - - def readline(self, size=-1): - """Read one entire line from the file. If size is present - and non-negative, return a string with at most that - size, which may be an incomplete line. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - pos = self.buffer.find(b"\n") + 1 - if pos == 0: - # no newline found. - while True: - buf = self.fileobj.read(self.blocksize) - self.buffer += buf - if not buf or b"\n" in buf: - pos = self.buffer.find(b"\n") + 1 - if pos == 0: - # no newline found. - pos = len(self.buffer) - break - - if size != -1: - pos = min(size, pos) - - buf = self.buffer[:pos] - self.buffer = self.buffer[pos:] - self.position += len(buf) - return buf - - def readlines(self): - """Return a list with all remaining lines. - """ - result = [] - while True: - line = self.readline() - if not line: break - result.append(line) - return result - - def tell(self): - """Return the current file position. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - return self.position - - def seek(self, pos, whence=os.SEEK_SET): - """Seek to a position in the file. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - if whence == os.SEEK_SET: - self.position = min(max(pos, 0), self.size) - elif whence == os.SEEK_CUR: - if pos < 0: - self.position = max(self.position + pos, 0) - else: - self.position = min(self.position + pos, self.size) - elif whence == os.SEEK_END: - self.position = max(min(self.size + pos, self.size), 0) - else: - raise ValueError("Invalid argument") - - self.buffer = b"" - self.fileobj.seek(self.position) - - def close(self): - """Close the file object. - """ - self.closed = True - - def __iter__(self): - """Get an iterator over the file's lines. - """ - while True: - line = self.readline() - if not line: - break - yield line -#class ExFileObject - -#------------------ -# Exported Classes -#------------------ -class TarInfo(object): - """Informational class which holds the details about an - archive member given by a tar header block. - TarInfo objects are returned by TarFile.getmember(), - TarFile.getmembers() and TarFile.gettarinfo() and are - usually created internally. - """ - - __slots__ = ("name", "mode", "uid", "gid", "size", "mtime", - "chksum", "type", "linkname", "uname", "gname", - "devmajor", "devminor", - "offset", "offset_data", "pax_headers", "sparse", - "tarfile", "_sparse_structs", "_link_target") - - def __init__(self, name=""): - """Construct a TarInfo object. name is the optional name - of the member. - """ - self.name = name # member name - self.mode = 0o644 # file permissions - self.uid = 0 # user id - self.gid = 0 # group id - self.size = 0 # file size - self.mtime = 0 # modification time - self.chksum = 0 # header checksum - self.type = REGTYPE # member type - self.linkname = "" # link name - self.uname = "" # user name - self.gname = "" # group name - self.devmajor = 0 # device major number - self.devminor = 0 # device minor number - - self.offset = 0 # the tar header starts here - self.offset_data = 0 # the file's data starts here - - self.sparse = None # sparse member information - self.pax_headers = {} # pax header information - - # In pax headers the "name" and "linkname" field are called - # "path" and "linkpath". - def _getpath(self): - return self.name - def _setpath(self, name): - self.name = name - path = property(_getpath, _setpath) - - def _getlinkpath(self): - return self.linkname - def _setlinkpath(self, linkname): - self.linkname = linkname - linkpath = property(_getlinkpath, _setlinkpath) - - def __repr__(self): - return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) - - def get_info(self): - """Return the TarInfo's attributes as a dictionary. - """ - info = { - "name": self.name, - "mode": self.mode & 0o7777, - "uid": self.uid, - "gid": self.gid, - "size": self.size, - "mtime": self.mtime, - "chksum": self.chksum, - "type": self.type, - "linkname": self.linkname, - "uname": self.uname, - "gname": self.gname, - "devmajor": self.devmajor, - "devminor": self.devminor - } - - if info["type"] == DIRTYPE and not info["name"].endswith("/"): - info["name"] += "/" - - return info - - def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescape"): - """Return a tar header as a string of 512 byte blocks. - """ - info = self.get_info() - - if format == USTAR_FORMAT: - return self.create_ustar_header(info, encoding, errors) - elif format == GNU_FORMAT: - return self.create_gnu_header(info, encoding, errors) - elif format == PAX_FORMAT: - return self.create_pax_header(info, encoding) - else: - raise ValueError("invalid format") - - def create_ustar_header(self, info, encoding, errors): - """Return the object as a ustar header block. - """ - info["magic"] = POSIX_MAGIC - - if len(info["linkname"]) > LENGTH_LINK: - raise ValueError("linkname is too long") - - if len(info["name"]) > LENGTH_NAME: - info["prefix"], info["name"] = self._posix_split_name(info["name"]) - - return self._create_header(info, USTAR_FORMAT, encoding, errors) - - def create_gnu_header(self, info, encoding, errors): - """Return the object as a GNU header block sequence. - """ - info["magic"] = GNU_MAGIC - - buf = b"" - if len(info["linkname"]) > LENGTH_LINK: - buf += self._create_gnu_long_header(info["linkname"], GNUTYPE_LONGLINK, encoding, errors) - - if len(info["name"]) > LENGTH_NAME: - buf += self._create_gnu_long_header(info["name"], GNUTYPE_LONGNAME, encoding, errors) - - return buf + self._create_header(info, GNU_FORMAT, encoding, errors) - - def create_pax_header(self, info, encoding): - """Return the object as a ustar header block. If it cannot be - represented this way, prepend a pax extended header sequence - with supplement information. - """ - info["magic"] = POSIX_MAGIC - pax_headers = self.pax_headers.copy() - - # Test string fields for values that exceed the field length or cannot - # be represented in ASCII encoding. - for name, hname, length in ( - ("name", "path", LENGTH_NAME), ("linkname", "linkpath", LENGTH_LINK), - ("uname", "uname", 32), ("gname", "gname", 32)): - - if hname in pax_headers: - # The pax header has priority. - continue - - # Try to encode the string as ASCII. - try: - info[name].encode("ascii", "strict") - except UnicodeEncodeError: - pax_headers[hname] = info[name] - continue - - if len(info[name]) > length: - pax_headers[hname] = info[name] - - # Test number fields for values that exceed the field limit or values - # that like to be stored as float. - for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)): - if name in pax_headers: - # The pax header has priority. Avoid overflow. - info[name] = 0 - continue - - val = info[name] - if not 0 <= val < 8 ** (digits - 1) or isinstance(val, float): - pax_headers[name] = str(val) - info[name] = 0 - - # Create a pax extended header if necessary. - if pax_headers: - buf = self._create_pax_generic_header(pax_headers, XHDTYPE, encoding) - else: - buf = b"" - - return buf + self._create_header(info, USTAR_FORMAT, "ascii", "replace") - - @classmethod - def create_pax_global_header(cls, pax_headers): - """Return the object as a pax global header block sequence. - """ - return cls._create_pax_generic_header(pax_headers, XGLTYPE, "utf8") - - def _posix_split_name(self, name): - """Split a name longer than 100 chars into a prefix - and a name part. - """ - prefix = name[:LENGTH_PREFIX + 1] - while prefix and prefix[-1] != "/": - prefix = prefix[:-1] - - name = name[len(prefix):] - prefix = prefix[:-1] - - if not prefix or len(name) > LENGTH_NAME: - raise ValueError("name is too long") - return prefix, name - - @staticmethod - def _create_header(info, format, encoding, errors): - """Return a header block. info is a dictionary with file - information, format must be one of the *_FORMAT constants. - """ - parts = [ - stn(info.get("name", ""), 100, encoding, errors), - itn(info.get("mode", 0) & 0o7777, 8, format), - itn(info.get("uid", 0), 8, format), - itn(info.get("gid", 0), 8, format), - itn(info.get("size", 0), 12, format), - itn(info.get("mtime", 0), 12, format), - b" ", # checksum field - info.get("type", REGTYPE), - stn(info.get("linkname", ""), 100, encoding, errors), - info.get("magic", POSIX_MAGIC), - stn(info.get("uname", ""), 32, encoding, errors), - stn(info.get("gname", ""), 32, encoding, errors), - itn(info.get("devmajor", 0), 8, format), - itn(info.get("devminor", 0), 8, format), - stn(info.get("prefix", ""), 155, encoding, errors) - ] - - buf = struct.pack("%ds" % BLOCKSIZE, b"".join(parts)) - chksum = calc_chksums(buf[-BLOCKSIZE:])[0] - buf = buf[:-364] + ("%06o\0" % chksum).encode("ascii") + buf[-357:] - return buf - - @staticmethod - def _create_payload(payload): - """Return the string payload filled with zero bytes - up to the next 512 byte border. - """ - blocks, remainder = divmod(len(payload), BLOCKSIZE) - if remainder > 0: - payload += (BLOCKSIZE - remainder) * NUL - return payload - - @classmethod - def _create_gnu_long_header(cls, name, type, encoding, errors): - """Return a GNUTYPE_LONGNAME or GNUTYPE_LONGLINK sequence - for name. - """ - name = name.encode(encoding, errors) + NUL - - info = {} - info["name"] = "././@LongLink" - info["type"] = type - info["size"] = len(name) - info["magic"] = GNU_MAGIC - - # create extended header + name blocks. - return cls._create_header(info, USTAR_FORMAT, encoding, errors) + \ - cls._create_payload(name) - - @classmethod - def _create_pax_generic_header(cls, pax_headers, type, encoding): - """Return a POSIX.1-2008 extended or global header sequence - that contains a list of keyword, value pairs. The values - must be strings. - """ - # Check if one of the fields contains surrogate characters and thereby - # forces hdrcharset=BINARY, see _proc_pax() for more information. - binary = False - for keyword, value in pax_headers.items(): - try: - value.encode("utf8", "strict") - except UnicodeEncodeError: - binary = True - break - - records = b"" - if binary: - # Put the hdrcharset field at the beginning of the header. - records += b"21 hdrcharset=BINARY\n" - - for keyword, value in pax_headers.items(): - keyword = keyword.encode("utf8") - if binary: - # Try to restore the original byte representation of `value'. - # Needless to say, that the encoding must match the string. - value = value.encode(encoding, "surrogateescape") - else: - value = value.encode("utf8") - - l = len(keyword) + len(value) + 3 # ' ' + '=' + '\n' - n = p = 0 - while True: - n = l + len(str(p)) - if n == p: - break - p = n - records += bytes(str(p), "ascii") + b" " + keyword + b"=" + value + b"\n" - - # We use a hardcoded "././@PaxHeader" name like star does - # instead of the one that POSIX recommends. - info = {} - info["name"] = "././@PaxHeader" - info["type"] = type - info["size"] = len(records) - info["magic"] = POSIX_MAGIC - - # Create pax header + record blocks. - return cls._create_header(info, USTAR_FORMAT, "ascii", "replace") + \ - cls._create_payload(records) - - @classmethod - def frombuf(cls, buf, encoding, errors): - """Construct a TarInfo object from a 512 byte bytes object. - """ - if len(buf) == 0: - raise EmptyHeaderError("empty header") - if len(buf) != BLOCKSIZE: - raise TruncatedHeaderError("truncated header") - if buf.count(NUL) == BLOCKSIZE: - raise EOFHeaderError("end of file header") - - chksum = nti(buf[148:156]) - if chksum not in calc_chksums(buf): - raise InvalidHeaderError("bad checksum") - - obj = cls() - obj.name = nts(buf[0:100], encoding, errors) - obj.mode = nti(buf[100:108]) - obj.uid = nti(buf[108:116]) - obj.gid = nti(buf[116:124]) - obj.size = nti(buf[124:136]) - obj.mtime = nti(buf[136:148]) - obj.chksum = chksum - obj.type = buf[156:157] - obj.linkname = nts(buf[157:257], encoding, errors) - obj.uname = nts(buf[265:297], encoding, errors) - obj.gname = nts(buf[297:329], encoding, errors) - obj.devmajor = nti(buf[329:337]) - obj.devminor = nti(buf[337:345]) - prefix = nts(buf[345:500], encoding, errors) - - # Old V7 tar format represents a directory as a regular - # file with a trailing slash. - if obj.type == AREGTYPE and obj.name.endswith("/"): - obj.type = DIRTYPE - - # The old GNU sparse format occupies some of the unused - # space in the buffer for up to 4 sparse structures. - # Save the them for later processing in _proc_sparse(). - if obj.type == GNUTYPE_SPARSE: - pos = 386 - structs = [] - for i in range(4): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - structs.append((offset, numbytes)) - pos += 24 - isextended = bool(buf[482]) - origsize = nti(buf[483:495]) - obj._sparse_structs = (structs, isextended, origsize) - - # Remove redundant slashes from directories. - if obj.isdir(): - obj.name = obj.name.rstrip("/") - - # Reconstruct a ustar longname. - if prefix and obj.type not in GNU_TYPES: - obj.name = prefix + "/" + obj.name - return obj - - @classmethod - def fromtarfile(cls, tarfile): - """Return the next TarInfo object from TarFile object - tarfile. - """ - buf = tarfile.fileobj.read(BLOCKSIZE) - obj = cls.frombuf(buf, tarfile.encoding, tarfile.errors) - obj.offset = tarfile.fileobj.tell() - BLOCKSIZE - return obj._proc_member(tarfile) - - #-------------------------------------------------------------------------- - # The following are methods that are called depending on the type of a - # member. The entry point is _proc_member() which can be overridden in a - # subclass to add custom _proc_*() methods. A _proc_*() method MUST - # implement the following - # operations: - # 1. Set self.offset_data to the position where the data blocks begin, - # if there is data that follows. - # 2. Set tarfile.offset to the position where the next member's header will - # begin. - # 3. Return self or another valid TarInfo object. - def _proc_member(self, tarfile): - """Choose the right processing method depending on - the type and call it. - """ - if self.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK): - return self._proc_gnulong(tarfile) - elif self.type == GNUTYPE_SPARSE: - return self._proc_sparse(tarfile) - elif self.type in (XHDTYPE, XGLTYPE, SOLARIS_XHDTYPE): - return self._proc_pax(tarfile) - else: - return self._proc_builtin(tarfile) - - def _proc_builtin(self, tarfile): - """Process a builtin type or an unknown type which - will be treated as a regular file. - """ - self.offset_data = tarfile.fileobj.tell() - offset = self.offset_data - if self.isreg() or self.type not in SUPPORTED_TYPES: - # Skip the following data blocks. - offset += self._block(self.size) - tarfile.offset = offset - - # Patch the TarInfo object with saved global - # header information. - self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors) - - return self - - def _proc_gnulong(self, tarfile): - """Process the blocks that hold a GNU longname - or longlink member. - """ - buf = tarfile.fileobj.read(self._block(self.size)) - - # Fetch the next header and process it. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - # Patch the TarInfo object from the next header with - # the longname information. - next.offset = self.offset - if self.type == GNUTYPE_LONGNAME: - next.name = nts(buf, tarfile.encoding, tarfile.errors) - elif self.type == GNUTYPE_LONGLINK: - next.linkname = nts(buf, tarfile.encoding, tarfile.errors) - - return next - - def _proc_sparse(self, tarfile): - """Process a GNU sparse header plus extra headers. - """ - # We already collected some sparse structures in frombuf(). - structs, isextended, origsize = self._sparse_structs - del self._sparse_structs - - # Collect sparse structures from extended header blocks. - while isextended: - buf = tarfile.fileobj.read(BLOCKSIZE) - pos = 0 - for i in range(21): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - if offset and numbytes: - structs.append((offset, numbytes)) - pos += 24 - isextended = bool(buf[504]) - self.sparse = structs - - self.offset_data = tarfile.fileobj.tell() - tarfile.offset = self.offset_data + self._block(self.size) - self.size = origsize - return self - - def _proc_pax(self, tarfile): - """Process an extended or global header as described in - POSIX.1-2008. - """ - # Read the header information. - buf = tarfile.fileobj.read(self._block(self.size)) - - # A pax header stores supplemental information for either - # the following file (extended) or all following files - # (global). - if self.type == XGLTYPE: - pax_headers = tarfile.pax_headers - else: - pax_headers = tarfile.pax_headers.copy() - - # Check if the pax header contains a hdrcharset field. This tells us - # the encoding of the path, linkpath, uname and gname fields. Normally, - # these fields are UTF-8 encoded but since POSIX.1-2008 tar - # implementations are allowed to store them as raw binary strings if - # the translation to UTF-8 fails. - match = re.search(br"\d+ hdrcharset=([^\n]+)\n", buf) - if match is not None: - pax_headers["hdrcharset"] = match.group(1).decode("utf8") - - # For the time being, we don't care about anything other than "BINARY". - # The only other value that is currently allowed by the standard is - # "ISO-IR 10646 2000 UTF-8" in other words UTF-8. - hdrcharset = pax_headers.get("hdrcharset") - if hdrcharset == "BINARY": - encoding = tarfile.encoding - else: - encoding = "utf8" - - # Parse pax header information. A record looks like that: - # "%d %s=%s\n" % (length, keyword, value). length is the size - # of the complete record including the length field itself and - # the newline. keyword and value are both UTF-8 encoded strings. - regex = re.compile(br"(\d+) ([^=]+)=") - pos = 0 - while True: - match = regex.match(buf, pos) - if not match: - break - - length, keyword = match.groups() - length = int(length) - value = buf[match.end(2) + 1:match.start(1) + length - 1] - - # Normally, we could just use "utf8" as the encoding and "strict" - # as the error handler, but we better not take the risk. For - # example, GNU tar <= 1.23 is known to store filenames it cannot - # translate to UTF-8 as raw strings (unfortunately without a - # hdrcharset=BINARY header). - # We first try the strict standard encoding, and if that fails we - # fall back on the user's encoding and error handler. - keyword = self._decode_pax_field(keyword, "utf8", "utf8", - tarfile.errors) - if keyword in PAX_NAME_FIELDS: - value = self._decode_pax_field(value, encoding, tarfile.encoding, - tarfile.errors) - else: - value = self._decode_pax_field(value, "utf8", "utf8", - tarfile.errors) - - pax_headers[keyword] = value - pos += length - - # Fetch the next header. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - # Process GNU sparse information. - if "GNU.sparse.map" in pax_headers: - # GNU extended sparse format version 0.1. - self._proc_gnusparse_01(next, pax_headers) - - elif "GNU.sparse.size" in pax_headers: - # GNU extended sparse format version 0.0. - self._proc_gnusparse_00(next, pax_headers, buf) - - elif pax_headers.get("GNU.sparse.major") == "1" and pax_headers.get("GNU.sparse.minor") == "0": - # GNU extended sparse format version 1.0. - self._proc_gnusparse_10(next, pax_headers, tarfile) - - if self.type in (XHDTYPE, SOLARIS_XHDTYPE): - # Patch the TarInfo object with the extended header info. - next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) - next.offset = self.offset - - if "size" in pax_headers: - # If the extended header replaces the size field, - # we need to recalculate the offset where the next - # header starts. - offset = next.offset_data - if next.isreg() or next.type not in SUPPORTED_TYPES: - offset += next._block(next.size) - tarfile.offset = offset - - return next - - def _proc_gnusparse_00(self, next, pax_headers, buf): - """Process a GNU tar extended sparse header, version 0.0. - """ - offsets = [] - for match in re.finditer(br"\d+ GNU.sparse.offset=(\d+)\n", buf): - offsets.append(int(match.group(1))) - numbytes = [] - for match in re.finditer(br"\d+ GNU.sparse.numbytes=(\d+)\n", buf): - numbytes.append(int(match.group(1))) - next.sparse = list(zip(offsets, numbytes)) - - def _proc_gnusparse_01(self, next, pax_headers): - """Process a GNU tar extended sparse header, version 0.1. - """ - sparse = [int(x) for x in pax_headers["GNU.sparse.map"].split(",")] - next.sparse = list(zip(sparse[::2], sparse[1::2])) - - def _proc_gnusparse_10(self, next, pax_headers, tarfile): - """Process a GNU tar extended sparse header, version 1.0. - """ - fields = None - sparse = [] - buf = tarfile.fileobj.read(BLOCKSIZE) - fields, buf = buf.split(b"\n", 1) - fields = int(fields) - while len(sparse) < fields * 2: - if b"\n" not in buf: - buf += tarfile.fileobj.read(BLOCKSIZE) - number, buf = buf.split(b"\n", 1) - sparse.append(int(number)) - next.offset_data = tarfile.fileobj.tell() - next.sparse = list(zip(sparse[::2], sparse[1::2])) - - def _apply_pax_info(self, pax_headers, encoding, errors): - """Replace fields with supplemental information from a previous - pax extended or global header. - """ - for keyword, value in pax_headers.items(): - if keyword == "GNU.sparse.name": - setattr(self, "path", value) - elif keyword == "GNU.sparse.size": - setattr(self, "size", int(value)) - elif keyword == "GNU.sparse.realsize": - setattr(self, "size", int(value)) - elif keyword in PAX_FIELDS: - if keyword in PAX_NUMBER_FIELDS: - try: - value = PAX_NUMBER_FIELDS[keyword](value) - except ValueError: - value = 0 - if keyword == "path": - value = value.rstrip("/") - setattr(self, keyword, value) - - self.pax_headers = pax_headers.copy() - - def _decode_pax_field(self, value, encoding, fallback_encoding, fallback_errors): - """Decode a single field from a pax record. - """ - try: - return value.decode(encoding, "strict") - except UnicodeDecodeError: - return value.decode(fallback_encoding, fallback_errors) - - def _block(self, count): - """Round up a byte count by BLOCKSIZE and return it, - e.g. _block(834) => 1024. - """ - blocks, remainder = divmod(count, BLOCKSIZE) - if remainder: - blocks += 1 - return blocks * BLOCKSIZE - - def isreg(self): - return self.type in REGULAR_TYPES - def isfile(self): - return self.isreg() - def isdir(self): - return self.type == DIRTYPE - def issym(self): - return self.type == SYMTYPE - def islnk(self): - return self.type == LNKTYPE - def ischr(self): - return self.type == CHRTYPE - def isblk(self): - return self.type == BLKTYPE - def isfifo(self): - return self.type == FIFOTYPE - def issparse(self): - return self.sparse is not None - def isdev(self): - return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) -# class TarInfo - -class TarFile(object): - """The TarFile Class provides an interface to tar archives. - """ - - debug = 0 # May be set from 0 (no msgs) to 3 (all msgs) - - dereference = False # If true, add content of linked file to the - # tar file, else the link. - - ignore_zeros = False # If true, skips empty or invalid blocks and - # continues processing. - - errorlevel = 1 # If 0, fatal errors only appear in debug - # messages (if debug >= 0). If > 0, errors - # are passed to the caller as exceptions. - - format = DEFAULT_FORMAT # The format to use when creating an archive. - - encoding = ENCODING # Encoding for 8-bit character strings. - - errors = None # Error handler for unicode conversion. - - tarinfo = TarInfo # The default TarInfo class to use. - - fileobject = ExFileObject # The default ExFileObject class to use. - - def __init__(self, name=None, mode="r", fileobj=None, format=None, - tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, - errors="surrogateescape", pax_headers=None, debug=None, errorlevel=None): - """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to - read from an existing archive, 'a' to append data to an existing - file or 'w' to create a new file overwriting an existing one. `mode' - defaults to 'r'. - If `fileobj' is given, it is used for reading or writing data. If it - can be determined, `mode' is overridden by `fileobj's mode. - `fileobj' is not closed, when TarFile is closed. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - self.mode = mode - self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] - - if not fileobj: - if self.mode == "a" and not os.path.exists(name): - # Create nonexistent files in append mode. - self.mode = "w" - self._mode = "wb" - fileobj = bltn_open(name, self._mode) - self._extfileobj = False - else: - if name is None and hasattr(fileobj, "name"): - name = fileobj.name - if hasattr(fileobj, "mode"): - self._mode = fileobj.mode - self._extfileobj = True - self.name = os.path.abspath(name) if name else None - self.fileobj = fileobj - - # Init attributes. - if format is not None: - self.format = format - if tarinfo is not None: - self.tarinfo = tarinfo - if dereference is not None: - self.dereference = dereference - if ignore_zeros is not None: - self.ignore_zeros = ignore_zeros - if encoding is not None: - self.encoding = encoding - self.errors = errors - - if pax_headers is not None and self.format == PAX_FORMAT: - self.pax_headers = pax_headers - else: - self.pax_headers = {} - - if debug is not None: - self.debug = debug - if errorlevel is not None: - self.errorlevel = errorlevel - - # Init datastructures. - self.closed = False - self.members = [] # list of members as TarInfo objects - self._loaded = False # flag if all members have been read - self.offset = self.fileobj.tell() - # current position in the archive file - self.inodes = {} # dictionary caching the inodes of - # archive members already added - - try: - if self.mode == "r": - self.firstmember = None - self.firstmember = self.next() - - if self.mode == "a": - # Move to the end of the archive, - # before the first empty block. - while True: - self.fileobj.seek(self.offset) - try: - tarinfo = self.tarinfo.fromtarfile(self) - self.members.append(tarinfo) - except EOFHeaderError: - self.fileobj.seek(self.offset) - break - except HeaderError as e: - raise ReadError(str(e)) - - if self.mode in "aw": - self._loaded = True - - if self.pax_headers: - buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) - self.fileobj.write(buf) - self.offset += len(buf) - except: - if not self._extfileobj: - self.fileobj.close() - self.closed = True - raise - - #-------------------------------------------------------------------------- - # Below are the classmethods which act as alternate constructors to the - # TarFile class. The open() method is the only one that is needed for - # public use; it is the "super"-constructor and is able to select an - # adequate "sub"-constructor for a particular compression using the mapping - # from OPEN_METH. - # - # This concept allows one to subclass TarFile without losing the comfort of - # the super-constructor. A sub-constructor is registered and made available - # by adding it to the mapping in OPEN_METH. - - @classmethod - def open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs): - """Open a tar archive for reading, writing or appending. Return - an appropriate TarFile class. - - mode: - 'r' or 'r:*' open for reading with transparent compression - 'r:' open for reading exclusively uncompressed - 'r:gz' open for reading with gzip compression - 'r:bz2' open for reading with bzip2 compression - 'a' or 'a:' open for appending, creating the file if necessary - 'w' or 'w:' open for writing without compression - 'w:gz' open for writing with gzip compression - 'w:bz2' open for writing with bzip2 compression - - 'r|*' open a stream of tar blocks with transparent compression - 'r|' open an uncompressed stream of tar blocks for reading - 'r|gz' open a gzip compressed stream of tar blocks - 'r|bz2' open a bzip2 compressed stream of tar blocks - 'w|' open an uncompressed stream for writing - 'w|gz' open a gzip compressed stream for writing - 'w|bz2' open a bzip2 compressed stream for writing - """ - - if not name and not fileobj: - raise ValueError("nothing to open") - - if mode in ("r", "r:*"): - # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - if fileobj is not None: - saved_pos = fileobj.tell() - try: - return func(name, "r", fileobj, **kwargs) - except (ReadError, CompressionError) as e: - if fileobj is not None: - fileobj.seek(saved_pos) - continue - raise ReadError("file could not be opened successfully") - - elif ":" in mode: - filemode, comptype = mode.split(":", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - # Select the *open() function according to - # given compression. - if comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - else: - raise CompressionError("unknown compression type %r" % comptype) - return func(name, filemode, fileobj, **kwargs) - - elif "|" in mode: - filemode, comptype = mode.split("|", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - if filemode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - stream = _Stream(name, filemode, comptype, fileobj, bufsize) - try: - t = cls(name, filemode, stream, **kwargs) - except: - stream.close() - raise - t._extfileobj = False - return t - - elif mode in "aw": - return cls.taropen(name, mode, fileobj, **kwargs) - - raise ValueError("undiscernible mode") - - @classmethod - def taropen(cls, name, mode="r", fileobj=None, **kwargs): - """Open uncompressed tar archive name for reading or writing. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - return cls(name, mode, fileobj, **kwargs) - - @classmethod - def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open gzip compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - try: - import gzip - gzip.GzipFile - except (ImportError, AttributeError): - raise CompressionError("gzip module is not available") - - extfileobj = fileobj is not None - try: - fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) - t = cls.taropen(name, mode, fileobj, **kwargs) - except IOError: - if not extfileobj and fileobj is not None: - fileobj.close() - if fileobj is None: - raise - raise ReadError("not a gzip file") - except: - if not extfileobj and fileobj is not None: - fileobj.close() - raise - t._extfileobj = extfileobj - return t - - @classmethod - def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open bzip2 compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'.") - - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - - if fileobj is not None: - fileobj = _BZ2Proxy(fileobj, mode) - else: - fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel) - - try: - t = cls.taropen(name, mode, fileobj, **kwargs) - except (IOError, EOFError): - fileobj.close() - raise ReadError("not a bzip2 file") - t._extfileobj = False - return t - - # All *open() methods are registered here. - OPEN_METH = { - "tar": "taropen", # uncompressed tar - "gz": "gzopen", # gzip compressed tar - "bz2": "bz2open" # bzip2 compressed tar - } - - #-------------------------------------------------------------------------- - # The public methods which TarFile provides: - - def close(self): - """Close the TarFile. In write-mode, two finishing zero blocks are - appended to the archive. - """ - if self.closed: - return - - if self.mode in "aw": - self.fileobj.write(NUL * (BLOCKSIZE * 2)) - self.offset += (BLOCKSIZE * 2) - # fill up the end with zero-blocks - # (like option -b20 for tar does) - blocks, remainder = divmod(self.offset, RECORDSIZE) - if remainder > 0: - self.fileobj.write(NUL * (RECORDSIZE - remainder)) - - if not self._extfileobj: - self.fileobj.close() - self.closed = True - - def getmember(self, name): - """Return a TarInfo object for member `name'. If `name' can not be - found in the archive, KeyError is raised. If a member occurs more - than once in the archive, its last occurrence is assumed to be the - most up-to-date version. - """ - tarinfo = self._getmember(name) - if tarinfo is None: - raise KeyError("filename %r not found" % name) - return tarinfo - - def getmembers(self): - """Return the members of the archive as a list of TarInfo objects. The - list has the same order as the members in the archive. - """ - self._check() - if not self._loaded: # if we want to obtain a list of - self._load() # all members, we first have to - # scan the whole archive. - return self.members - - def getnames(self): - """Return the members of the archive as a list of their names. It has - the same order as the list returned by getmembers(). - """ - return [tarinfo.name for tarinfo in self.getmembers()] - - def gettarinfo(self, name=None, arcname=None, fileobj=None): - """Create a TarInfo object for either the file `name' or the file - object `fileobj' (using os.fstat on its file descriptor). You can - modify some of the TarInfo's attributes before you add it using - addfile(). If given, `arcname' specifies an alternative name for the - file in the archive. - """ - self._check("aw") - - # When fileobj is given, replace name by - # fileobj's real name. - if fileobj is not None: - name = fileobj.name - - # Building the name of the member in the archive. - # Backward slashes are converted to forward slashes, - # Absolute paths are turned to relative paths. - if arcname is None: - arcname = name - drv, arcname = os.path.splitdrive(arcname) - arcname = arcname.replace(os.sep, "/") - arcname = arcname.lstrip("/") - - # Now, fill the TarInfo object with - # information specific for the file. - tarinfo = self.tarinfo() - tarinfo.tarfile = self - - # Use os.stat or os.lstat, depending on platform - # and if symlinks shall be resolved. - if fileobj is None: - if hasattr(os, "lstat") and not self.dereference: - statres = os.lstat(name) - else: - statres = os.stat(name) - else: - statres = os.fstat(fileobj.fileno()) - linkname = "" - - stmd = statres.st_mode - if stat.S_ISREG(stmd): - inode = (statres.st_ino, statres.st_dev) - if not self.dereference and statres.st_nlink > 1 and \ - inode in self.inodes and arcname != self.inodes[inode]: - # Is it a hardlink to an already - # archived file? - type = LNKTYPE - linkname = self.inodes[inode] - else: - # The inode is added only if its valid. - # For win32 it is always 0. - type = REGTYPE - if inode[0]: - self.inodes[inode] = arcname - elif stat.S_ISDIR(stmd): - type = DIRTYPE - elif stat.S_ISFIFO(stmd): - type = FIFOTYPE - elif stat.S_ISLNK(stmd): - type = SYMTYPE - linkname = os.readlink(name) - elif stat.S_ISCHR(stmd): - type = CHRTYPE - elif stat.S_ISBLK(stmd): - type = BLKTYPE - else: - return None - - # Fill the TarInfo object with all - # information we can get. - tarinfo.name = arcname - tarinfo.mode = stmd - tarinfo.uid = statres.st_uid - tarinfo.gid = statres.st_gid - if type == REGTYPE: - tarinfo.size = statres.st_size - else: - tarinfo.size = 0 - tarinfo.mtime = statres.st_mtime - tarinfo.type = type - tarinfo.linkname = linkname - if pwd: - try: - tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0] - except KeyError: - pass - if grp: - try: - tarinfo.gname = grp.getgrgid(tarinfo.gid)[0] - except KeyError: - pass - - if type in (CHRTYPE, BLKTYPE): - if hasattr(os, "major") and hasattr(os, "minor"): - tarinfo.devmajor = os.major(statres.st_rdev) - tarinfo.devminor = os.minor(statres.st_rdev) - return tarinfo - - def list(self, verbose=True): - """Print a table of contents to sys.stdout. If `verbose' is False, only - the names of the members are printed. If it is True, an `ls -l'-like - output is produced. - """ - self._check() - - for tarinfo in self: - if verbose: - print(filemode(tarinfo.mode), end=' ') - print("%s/%s" % (tarinfo.uname or tarinfo.uid, - tarinfo.gname or tarinfo.gid), end=' ') - if tarinfo.ischr() or tarinfo.isblk(): - print("%10s" % ("%d,%d" \ - % (tarinfo.devmajor, tarinfo.devminor)), end=' ') - else: - print("%10d" % tarinfo.size, end=' ') - print("%d-%02d-%02d %02d:%02d:%02d" \ - % time.localtime(tarinfo.mtime)[:6], end=' ') - - print(tarinfo.name + ("/" if tarinfo.isdir() else ""), end=' ') - - if verbose: - if tarinfo.issym(): - print("->", tarinfo.linkname, end=' ') - if tarinfo.islnk(): - print("link to", tarinfo.linkname, end=' ') - print() - - def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): - """Add the file `name' to the archive. `name' may be any type of file - (directory, fifo, symbolic link, etc.). If given, `arcname' - specifies an alternative name for the file in the archive. - Directories are added recursively by default. This can be avoided by - setting `recursive' to False. `exclude' is a function that should - return True for each filename to be excluded. `filter' is a function - that expects a TarInfo object argument and returns the changed - TarInfo object, if it returns None the TarInfo object will be - excluded from the archive. - """ - self._check("aw") - - if arcname is None: - arcname = name - - # Exclude pathnames. - if exclude is not None: - import warnings - warnings.warn("use the filter argument instead", - DeprecationWarning, 2) - if exclude(name): - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Skip if somebody tries to archive the archive... - if self.name is not None and os.path.abspath(name) == self.name: - self._dbg(2, "tarfile: Skipped %r" % name) - return - - self._dbg(1, name) - - # Create a TarInfo object from the file. - tarinfo = self.gettarinfo(name, arcname) - - if tarinfo is None: - self._dbg(1, "tarfile: Unsupported type %r" % name) - return - - # Change or exclude the TarInfo object. - if filter is not None: - tarinfo = filter(tarinfo) - if tarinfo is None: - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Append the tar header and data to the archive. - if tarinfo.isreg(): - f = bltn_open(name, "rb") - self.addfile(tarinfo, f) - f.close() - - elif tarinfo.isdir(): - self.addfile(tarinfo) - if recursive: - for f in os.listdir(name): - self.add(os.path.join(name, f), os.path.join(arcname, f), - recursive, exclude, filter=filter) - - else: - self.addfile(tarinfo) - - def addfile(self, tarinfo, fileobj=None): - """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is - given, tarinfo.size bytes are read from it and added to the archive. - You can create TarInfo objects using gettarinfo(). - On Windows platforms, `fileobj' should always be opened with mode - 'rb' to avoid irritation about the file size. - """ - self._check("aw") - - tarinfo = copy.copy(tarinfo) - - buf = tarinfo.tobuf(self.format, self.encoding, self.errors) - self.fileobj.write(buf) - self.offset += len(buf) - - # If there's data to follow, append it. - if fileobj is not None: - copyfileobj(fileobj, self.fileobj, tarinfo.size) - blocks, remainder = divmod(tarinfo.size, BLOCKSIZE) - if remainder > 0: - self.fileobj.write(NUL * (BLOCKSIZE - remainder)) - blocks += 1 - self.offset += blocks * BLOCKSIZE - - self.members.append(tarinfo) - - def extractall(self, path=".", members=None): - """Extract all members from the archive to the current working - directory and set owner, modification time and permissions on - directories afterwards. `path' specifies a different directory - to extract to. `members' is optional and must be a subset of the - list returned by getmembers(). - """ - directories = [] - - if members is None: - members = self - - for tarinfo in members: - if tarinfo.isdir(): - # Extract directories with a safe mode. - directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 0o700 - # Do not set_attrs directories, as we will do that further down - self.extract(tarinfo, path, set_attrs=not tarinfo.isdir()) - - # Reverse sort directories. - directories.sort(key=lambda a: a.name) - directories.reverse() - - # Set correct owner, mtime and filemode on directories. - for tarinfo in directories: - dirpath = os.path.join(path, tarinfo.name) - try: - self.chown(tarinfo, dirpath) - self.utime(tarinfo, dirpath) - self.chmod(tarinfo, dirpath) - except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extract(self, member, path="", set_attrs=True): - """Extract a member from the archive to the current working directory, - using its full name. Its file information is extracted as accurately - as possible. `member' may be a filename or a TarInfo object. You can - specify a different directory using `path'. File attributes (owner, - mtime, mode) are set unless `set_attrs' is False. - """ - self._check("r") - - if isinstance(member, str): - tarinfo = self.getmember(member) - else: - tarinfo = member - - # Prepare the link target for makelink(). - if tarinfo.islnk(): - tarinfo._link_target = os.path.join(path, tarinfo.linkname) - - try: - self._extract_member(tarinfo, os.path.join(path, tarinfo.name), - set_attrs=set_attrs) - except EnvironmentError as e: - if self.errorlevel > 0: - raise - else: - if e.filename is None: - self._dbg(1, "tarfile: %s" % e.strerror) - else: - self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) - except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extractfile(self, member): - """Extract a member from the archive as a file object. `member' may be - a filename or a TarInfo object. If `member' is a regular file, a - file-like object is returned. If `member' is a link, a file-like - object is constructed from the link's target. If `member' is none of - the above, None is returned. - The file-like object is read-only and provides the following - methods: read(), readline(), readlines(), seek() and tell() - """ - self._check("r") - - if isinstance(member, str): - tarinfo = self.getmember(member) - else: - tarinfo = member - - if tarinfo.isreg(): - return self.fileobject(self, tarinfo) - - elif tarinfo.type not in SUPPORTED_TYPES: - # If a member's type is unknown, it is treated as a - # regular file. - return self.fileobject(self, tarinfo) - - elif tarinfo.islnk() or tarinfo.issym(): - if isinstance(self.fileobj, _Stream): - # A small but ugly workaround for the case that someone tries - # to extract a (sym)link as a file-object from a non-seekable - # stream of tar blocks. - raise StreamError("cannot extract (sym)link as file object") - else: - # A (sym)link's file object is its target's file object. - return self.extractfile(self._find_link_target(tarinfo)) - else: - # If there's no data associated with the member (directory, chrdev, - # blkdev, etc.), return None instead of a file object. - return None - - def _extract_member(self, tarinfo, targetpath, set_attrs=True): - """Extract the TarInfo object tarinfo to a physical - file called targetpath. - """ - # Fetch the TarInfo object for the given name - # and build the destination pathname, replacing - # forward slashes to platform specific separators. - targetpath = targetpath.rstrip("/") - targetpath = targetpath.replace("/", os.sep) - - # Create all upper directories. - upperdirs = os.path.dirname(targetpath) - if upperdirs and not os.path.exists(upperdirs): - # Create directories that are not part of the archive with - # default permissions. - os.makedirs(upperdirs) - - if tarinfo.islnk() or tarinfo.issym(): - self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) - else: - self._dbg(1, tarinfo.name) - - if tarinfo.isreg(): - self.makefile(tarinfo, targetpath) - elif tarinfo.isdir(): - self.makedir(tarinfo, targetpath) - elif tarinfo.isfifo(): - self.makefifo(tarinfo, targetpath) - elif tarinfo.ischr() or tarinfo.isblk(): - self.makedev(tarinfo, targetpath) - elif tarinfo.islnk() or tarinfo.issym(): - self.makelink(tarinfo, targetpath) - elif tarinfo.type not in SUPPORTED_TYPES: - self.makeunknown(tarinfo, targetpath) - else: - self.makefile(tarinfo, targetpath) - - if set_attrs: - self.chown(tarinfo, targetpath) - if not tarinfo.issym(): - self.chmod(tarinfo, targetpath) - self.utime(tarinfo, targetpath) - - #-------------------------------------------------------------------------- - # Below are the different file methods. They are called via - # _extract_member() when extract() is called. They can be replaced in a - # subclass to implement other functionality. - - def makedir(self, tarinfo, targetpath): - """Make a directory called targetpath. - """ - try: - # Use a safe mode for the directory, the real mode is set - # later in _extract_member(). - os.mkdir(targetpath, 0o700) - except EnvironmentError as e: - if e.errno != errno.EEXIST: - raise - - def makefile(self, tarinfo, targetpath): - """Make a file called targetpath. - """ - source = self.fileobj - source.seek(tarinfo.offset_data) - target = bltn_open(targetpath, "wb") - if tarinfo.sparse is not None: - for offset, size in tarinfo.sparse: - target.seek(offset) - copyfileobj(source, target, size) - else: - copyfileobj(source, target, tarinfo.size) - target.seek(tarinfo.size) - target.truncate() - target.close() - - def makeunknown(self, tarinfo, targetpath): - """Make a file from a TarInfo object with an unknown type - at targetpath. - """ - self.makefile(tarinfo, targetpath) - self._dbg(1, "tarfile: Unknown file type %r, " \ - "extracted as regular file." % tarinfo.type) - - def makefifo(self, tarinfo, targetpath): - """Make a fifo called targetpath. - """ - if hasattr(os, "mkfifo"): - os.mkfifo(targetpath) - else: - raise ExtractError("fifo not supported by system") - - def makedev(self, tarinfo, targetpath): - """Make a character or block device called targetpath. - """ - if not hasattr(os, "mknod") or not hasattr(os, "makedev"): - raise ExtractError("special devices not supported by system") - - mode = tarinfo.mode - if tarinfo.isblk(): - mode |= stat.S_IFBLK - else: - mode |= stat.S_IFCHR - - os.mknod(targetpath, mode, - os.makedev(tarinfo.devmajor, tarinfo.devminor)) - - def makelink(self, tarinfo, targetpath): - """Make a (symbolic) link called targetpath. If it cannot be created - (platform limitation), we try to make a copy of the referenced file - instead of a link. - """ - try: - # For systems that support symbolic and hard links. - if tarinfo.issym(): - os.symlink(tarinfo.linkname, targetpath) - else: - # See extract(). - if os.path.exists(tarinfo._link_target): - os.link(tarinfo._link_target, targetpath) - else: - self._extract_member(self._find_link_target(tarinfo), - targetpath) - except symlink_exception: - if tarinfo.issym(): - linkpath = os.path.join(os.path.dirname(tarinfo.name), - tarinfo.linkname) - else: - linkpath = tarinfo.linkname - else: - try: - self._extract_member(self._find_link_target(tarinfo), - targetpath) - except KeyError: - raise ExtractError("unable to resolve link inside archive") - - def chown(self, tarinfo, targetpath): - """Set owner of targetpath according to tarinfo. - """ - if pwd and hasattr(os, "geteuid") and os.geteuid() == 0: - # We have to be root to do so. - try: - g = grp.getgrnam(tarinfo.gname)[2] - except KeyError: - g = tarinfo.gid - try: - u = pwd.getpwnam(tarinfo.uname)[2] - except KeyError: - u = tarinfo.uid - try: - if tarinfo.issym() and hasattr(os, "lchown"): - os.lchown(targetpath, u, g) - else: - if sys.platform != "os2emx": - os.chown(targetpath, u, g) - except EnvironmentError as e: - raise ExtractError("could not change owner") - - def chmod(self, tarinfo, targetpath): - """Set file permissions of targetpath according to tarinfo. - """ - if hasattr(os, 'chmod'): - try: - os.chmod(targetpath, tarinfo.mode) - except EnvironmentError as e: - raise ExtractError("could not change mode") - - def utime(self, tarinfo, targetpath): - """Set modification time of targetpath according to tarinfo. - """ - if not hasattr(os, 'utime'): - return - try: - os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) - except EnvironmentError as e: - raise ExtractError("could not change modification time") - - #-------------------------------------------------------------------------- - def next(self): - """Return the next member of the archive as a TarInfo object, when - TarFile is opened for reading. Return None if there is no more - available. - """ - self._check("ra") - if self.firstmember is not None: - m = self.firstmember - self.firstmember = None - return m - - # Read the next block. - self.fileobj.seek(self.offset) - tarinfo = None - while True: - try: - tarinfo = self.tarinfo.fromtarfile(self) - except EOFHeaderError as e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - except InvalidHeaderError as e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - elif self.offset == 0: - raise ReadError(str(e)) - except EmptyHeaderError: - if self.offset == 0: - raise ReadError("empty file") - except TruncatedHeaderError as e: - if self.offset == 0: - raise ReadError(str(e)) - except SubsequentHeaderError as e: - raise ReadError(str(e)) - break - - if tarinfo is not None: - self.members.append(tarinfo) - else: - self._loaded = True - - return tarinfo - - #-------------------------------------------------------------------------- - # Little helper methods: - - def _getmember(self, name, tarinfo=None, normalize=False): - """Find an archive member by name from bottom to top. - If tarinfo is given, it is used as the starting point. - """ - # Ensure that all members have been loaded. - members = self.getmembers() - - # Limit the member search list up to tarinfo. - if tarinfo is not None: - members = members[:members.index(tarinfo)] - - if normalize: - name = os.path.normpath(name) - - for member in reversed(members): - if normalize: - member_name = os.path.normpath(member.name) - else: - member_name = member.name - - if name == member_name: - return member - - def _load(self): - """Read through the entire archive file and look for readable - members. - """ - while True: - tarinfo = self.next() - if tarinfo is None: - break - self._loaded = True - - def _check(self, mode=None): - """Check if TarFile is still open, and if the operation's mode - corresponds to TarFile's mode. - """ - if self.closed: - raise IOError("%s is closed" % self.__class__.__name__) - if mode is not None and self.mode not in mode: - raise IOError("bad operation for mode %r" % self.mode) - - def _find_link_target(self, tarinfo): - """Find the target member of a symlink or hardlink member in the - archive. - """ - if tarinfo.issym(): - # Always search the entire archive. - linkname = os.path.dirname(tarinfo.name) + "/" + tarinfo.linkname - limit = None - else: - # Search the archive before the link, because a hard link is - # just a reference to an already archived file. - linkname = tarinfo.linkname - limit = tarinfo - - member = self._getmember(linkname, tarinfo=limit, normalize=True) - if member is None: - raise KeyError("linkname %r not found" % linkname) - return member - - def __iter__(self): - """Provide an iterator object. - """ - if self._loaded: - return iter(self.members) - else: - return TarIter(self) - - def _dbg(self, level, msg): - """Write debugging output to sys.stderr. - """ - if level <= self.debug: - print(msg, file=sys.stderr) - - def __enter__(self): - self._check() - return self - - def __exit__(self, type, value, traceback): - if type is None: - self.close() - else: - # An exception occurred. We must not call close() because - # it would try to write end-of-archive blocks and padding. - if not self._extfileobj: - self.fileobj.close() - self.closed = True -# class TarFile - -class TarIter(object): - """Iterator Class. - - for tarinfo in TarFile(...): - suite... - """ - - def __init__(self, tarfile): - """Construct a TarIter object. - """ - self.tarfile = tarfile - self.index = 0 - def __iter__(self): - """Return iterator object. - """ - return self - - def __next__(self): - """Return the next item using TarFile's next() method. - When all members have been read, set TarFile as _loaded. - """ - # Fix for SF #1100429: Under rare circumstances it can - # happen that getmembers() is called during iteration, - # which will cause TarIter to stop prematurely. - if not self.tarfile._loaded: - tarinfo = self.tarfile.next() - if not tarinfo: - self.tarfile._loaded = True - raise StopIteration - else: - try: - tarinfo = self.tarfile.members[self.index] - except IndexError: - raise StopIteration - self.index += 1 - return tarinfo - - next = __next__ # for Python 2.x - -#-------------------- -# exported functions -#-------------------- -def is_tarfile(name): - """Return True if name points to a tar archive that we - are able to handle, else return False. - """ - try: - t = open(name) - t.close() - return True - except TarError: - return False - -bltn_open = open -open = TarFile.open diff --git a/src/pip/_vendor/distlib/compat.py b/src/pip/_vendor/distlib/compat.py index e594106956f..1fe3d225acb 100644 --- a/src/pip/_vendor/distlib/compat.py +++ b/src/pip/_vendor/distlib/compat.py @@ -22,7 +22,6 @@ from types import FileType as file_type import __builtin__ as builtins import ConfigParser as configparser - from ._backport import shutil from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit from urllib import (urlretrieve, quote as _quote, unquote, url2pathname, pathname2url, ContentTooShortError, splittype) @@ -313,10 +312,8 @@ def python_implementation(): return 'IronPython' return 'CPython' -try: - import sysconfig -except ImportError: # pragma: no cover - from ._backport import sysconfig +import shutil +import sysconfig try: callable = callable @@ -618,18 +615,15 @@ def clear(self): try: from importlib.util import cache_from_source # Python >= 3.4 except ImportError: # pragma: no cover - try: - from imp import cache_from_source - except ImportError: # pragma: no cover - def cache_from_source(path, debug_override=None): - assert path.endswith('.py') - if debug_override is None: - debug_override = __debug__ - if debug_override: - suffix = 'c' - else: - suffix = 'o' - return path + suffix + def cache_from_source(path, debug_override=None): + assert path.endswith('.py') + if debug_override is None: + debug_override = __debug__ + if debug_override: + suffix = 'c' + else: + suffix = 'o' + return path + suffix try: from collections import OrderedDict diff --git a/src/pip/_vendor/distlib/database.py b/src/pip/_vendor/distlib/database.py index 0a90c300ba8..5db5d7f507c 100644 --- a/src/pip/_vendor/distlib/database.py +++ b/src/pip/_vendor/distlib/database.py @@ -132,29 +132,35 @@ def _yield_distributions(self): r = finder.find(entry) if not r or r.path in seen: continue - if self._include_dist and entry.endswith(DISTINFO_EXT): - possible_filenames = [METADATA_FILENAME, - WHEEL_METADATA_FILENAME, - LEGACY_METADATA_FILENAME] - for metadata_filename in possible_filenames: - metadata_path = posixpath.join(entry, metadata_filename) - pydist = finder.find(metadata_path) - if pydist: - break - else: - continue + try: + if self._include_dist and entry.endswith(DISTINFO_EXT): + possible_filenames = [METADATA_FILENAME, + WHEEL_METADATA_FILENAME, + LEGACY_METADATA_FILENAME] + for metadata_filename in possible_filenames: + metadata_path = posixpath.join(entry, metadata_filename) + pydist = finder.find(metadata_path) + if pydist: + break + else: + continue - with contextlib.closing(pydist.as_stream()) as stream: - metadata = Metadata(fileobj=stream, scheme='legacy') - logger.debug('Found %s', r.path) - seen.add(r.path) - yield new_dist_class(r.path, metadata=metadata, - env=self) - elif self._include_egg and entry.endswith(('.egg-info', - '.egg')): - logger.debug('Found %s', r.path) - seen.add(r.path) - yield old_dist_class(r.path, self) + with contextlib.closing(pydist.as_stream()) as stream: + metadata = Metadata(fileobj=stream, scheme='legacy') + logger.debug('Found %s', r.path) + seen.add(r.path) + yield new_dist_class(r.path, metadata=metadata, + env=self) + elif self._include_egg and entry.endswith(('.egg-info', + '.egg')): + logger.debug('Found %s', r.path) + seen.add(r.path) + yield old_dist_class(r.path, self) + except Exception as e: + msg = 'Unable to read distribution at %s, perhaps due to bad metadata: %s' + logger.warning(msg, r.path, e) + import warnings + warnings.warn(msg % (r.path, e), stacklevel=2) def _generate_cache(self): """ @@ -379,8 +385,9 @@ def provides(self): def _get_requirements(self, req_attr): md = self.metadata - logger.debug('Getting requirements from metadata %r', md.todict()) reqts = getattr(md, req_attr) + logger.debug('%s: got requirements %r from metadata: %r', self.name, req_attr, + reqts) return set(md.get_requirements(reqts, extras=self.extras, env=self.context)) @@ -1308,22 +1315,26 @@ def get_required_dists(dists, dist): :param dists: a list of distributions :param dist: a distribution, member of *dists* for which we are interested + in finding the dependencies. """ if dist not in dists: raise DistlibException('given distribution %r is not a member ' 'of the list' % dist.name) graph = make_graph(dists) - req = [] # required distributions + req = set() # required distributions todo = graph.adjacency_list[dist] # list of nodes we should inspect + seen = set(t[0] for t in todo) # already added to todo while todo: d = todo.pop()[0] - req.append(d) - for pred in graph.adjacency_list[d]: - if pred not in req: + req.add(d) + pred_list = graph.adjacency_list[d] + for pred in pred_list: + d = pred[0] + if d not in req and d not in seen: + seen.add(d) todo.append(pred) - return req diff --git a/src/pip/_vendor/distlib/index.py b/src/pip/_vendor/distlib/index.py index b1fbbf8e8d2..9b6d129ed69 100644 --- a/src/pip/_vendor/distlib/index.py +++ b/src/pip/_vendor/distlib/index.py @@ -12,7 +12,7 @@ import tempfile try: from threading import Thread -except ImportError: +except ImportError: # pragma: no cover from dummy_threading import Thread from . import DistlibException @@ -104,7 +104,7 @@ def check_credentials(self): pm.add_password(self.realm, netloc, self.username, self.password) self.password_handler = HTTPBasicAuthHandler(pm) - def register(self, metadata): + def register(self, metadata): # pragma: no cover """ Register a distribution on PyPI, using the provided metadata. @@ -142,8 +142,7 @@ def _reader(self, name, stream, outbuf): logger.debug('%s: %s' % (name, s)) stream.close() - def get_sign_command(self, filename, signer, sign_password, - keystore=None): + def get_sign_command(self, filename, signer, sign_password, keystore=None): # pragma: no cover """ Return a suitable command for signing a file. @@ -206,7 +205,7 @@ def run_command(self, cmd, input_data=None): t2.join() return p.returncode, stdout, stderr - def sign_file(self, filename, signer, sign_password, keystore=None): + def sign_file(self, filename, signer, sign_password, keystore=None): # pragma: no cover """ Sign a file. @@ -286,7 +285,7 @@ def upload_file(self, metadata, filename, signer=None, sign_password=None, request = self.encode_request(d.items(), files) return self.send_request(request) - def upload_documentation(self, metadata, doc_dir): + def upload_documentation(self, metadata, doc_dir): # pragma: no cover """ Upload documentation to the index. @@ -499,7 +498,7 @@ def encode_request(self, fields, files): } return Request(self.url, body, headers) - def search(self, terms, operator=None): + def search(self, terms, operator=None): # pragma: no cover if isinstance(terms, string_types): terms = {'name': terms} rpc_proxy = ServerProxy(self.url, timeout=3.0) diff --git a/src/pip/_vendor/distlib/locators.py b/src/pip/_vendor/distlib/locators.py index 0c7d6391438..966ebc0e37d 100644 --- a/src/pip/_vendor/distlib/locators.py +++ b/src/pip/_vendor/distlib/locators.py @@ -633,7 +633,7 @@ def _prepare_threads(self): self._threads = [] for i in range(self.num_workers): t = threading.Thread(target=self._fetch) - t.setDaemon(True) + t.daemon = True t.start() self._threads.append(t) @@ -1053,9 +1053,9 @@ def get_distribution_names(self): # We use a legacy scheme simply because most of the dists on PyPI use legacy -# versions which don't conform to PEP 426 / PEP 440. +# versions which don't conform to PEP 440. default_locator = AggregatingLocator( - JSONLocator(), + # JSONLocator(), # don't use as PEP 426 is withdrawn SimpleScrapingLocator('https://pypi.org/simple/', timeout=3.0), scheme='legacy') diff --git a/src/pip/_vendor/distlib/markers.py b/src/pip/_vendor/distlib/markers.py index b43136fa11e..9dc68410337 100644 --- a/src/pip/_vendor/distlib/markers.py +++ b/src/pip/_vendor/distlib/markers.py @@ -90,6 +90,8 @@ def evaluate(self, expr, context): result = self.operations[op](lhs, rhs) return result +_DIGITS = re.compile(r'\d+\.\d+') + def default_context(): def format_full_version(info): version = '%s.%s.%s' % (info.major, info.minor, info.micro) @@ -105,6 +107,9 @@ def format_full_version(info): implementation_version = '0' implementation_name = '' + ppv = platform.python_version() + m = _DIGITS.match(ppv) + pv = m.group(0) result = { 'implementation_name': implementation_name, 'implementation_version': implementation_version, @@ -115,8 +120,8 @@ def format_full_version(info): 'platform_system': platform.system(), 'platform_version': platform.version(), 'platform_in_venv': str(in_venv()), - 'python_full_version': platform.python_version(), - 'python_version': platform.python_version()[:3], + 'python_full_version': ppv, + 'python_version': pv, 'sys_platform': sys.platform, } return result diff --git a/src/pip/_vendor/distlib/metadata.py b/src/pip/_vendor/distlib/metadata.py index 6a26b0ab232..c329e1977fd 100644 --- a/src/pip/_vendor/distlib/metadata.py +++ b/src/pip/_vendor/distlib/metadata.py @@ -5,7 +5,7 @@ # """Implementation of the Metadata for Python packages PEPs. -Supports all metadata formats (1.0, 1.1, 1.2, 1.3/2.1 and withdrawn 2.0). +Supports all metadata formats (1.0, 1.1, 1.2, 1.3/2.1 and 2.2). """ from __future__ import unicode_literals @@ -100,12 +100,17 @@ class MetadataInvalidError(DistlibException): _566_MARKERS = ('Description-Content-Type',) +_643_MARKERS = ('Dynamic', 'License-File') + +_643_FIELDS = _566_FIELDS + _643_MARKERS + _ALL_FIELDS = set() _ALL_FIELDS.update(_241_FIELDS) _ALL_FIELDS.update(_314_FIELDS) _ALL_FIELDS.update(_345_FIELDS) _ALL_FIELDS.update(_426_FIELDS) _ALL_FIELDS.update(_566_FIELDS) +_ALL_FIELDS.update(_643_FIELDS) EXTRA_RE = re.compile(r'''extra\s*==\s*("([^"]+)"|'([^']+)')''') @@ -121,7 +126,10 @@ def _version2fieldlist(version): # avoid adding field names if already there return _345_FIELDS + tuple(f for f in _566_FIELDS if f not in _345_FIELDS) elif version == '2.0': - return _426_FIELDS + raise ValueError('Metadata 2.0 is withdrawn and not supported') + # return _426_FIELDS + elif version == '2.2': + return _643_FIELDS raise MetadataUnrecognizedVersionError(version) @@ -139,7 +147,7 @@ def _has_marker(keys, markers): continue keys.append(key) - possible_versions = ['1.0', '1.1', '1.2', '1.3', '2.0', '2.1'] + possible_versions = ['1.0', '1.1', '1.2', '1.3', '2.1', '2.2'] # 2.0 removed # first let's try to see if a field is not part of one of the version for key in keys: @@ -159,9 +167,12 @@ def _has_marker(keys, markers): if key != 'Description': # In 2.1, description allowed after headers possible_versions.remove('2.1') logger.debug('Removed 2.1 due to %s', key) - if key not in _426_FIELDS and '2.0' in possible_versions: - possible_versions.remove('2.0') - logger.debug('Removed 2.0 due to %s', key) + if key not in _643_FIELDS and '2.2' in possible_versions: + possible_versions.remove('2.2') + logger.debug('Removed 2.2 due to %s', key) + # if key not in _426_FIELDS and '2.0' in possible_versions: + # possible_versions.remove('2.0') + # logger.debug('Removed 2.0 due to %s', key) # possible_version contains qualified versions if len(possible_versions) == 1: @@ -174,16 +185,18 @@ def _has_marker(keys, markers): is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) is_2_1 = '2.1' in possible_versions and _has_marker(keys, _566_MARKERS) - is_2_0 = '2.0' in possible_versions and _has_marker(keys, _426_MARKERS) - if int(is_1_1) + int(is_1_2) + int(is_2_1) + int(is_2_0) > 1: - raise MetadataConflictError('You used incompatible 1.1/1.2/2.0/2.1 fields') + # is_2_0 = '2.0' in possible_versions and _has_marker(keys, _426_MARKERS) + is_2_2 = '2.2' in possible_versions and _has_marker(keys, _643_MARKERS) + if int(is_1_1) + int(is_1_2) + int(is_2_1) + int(is_2_2) > 1: + raise MetadataConflictError('You used incompatible 1.1/1.2/2.1/2.2 fields') - # we have the choice, 1.0, or 1.2, or 2.0 + # we have the choice, 1.0, or 1.2, 2.1 or 2.2 # - 1.0 has a broken Summary field but works with all tools # - 1.1 is to avoid # - 1.2 fixes Summary but has little adoption - # - 2.0 adds more features and is very new - if not is_1_1 and not is_1_2 and not is_2_1 and not is_2_0: + # - 2.1 adds more features + # - 2.2 is the latest + if not is_1_1 and not is_1_2 and not is_2_1 and not is_2_2: # we couldn't find any specific marker if PKG_INFO_PREFERRED_VERSION in possible_versions: return PKG_INFO_PREFERRED_VERSION @@ -193,8 +206,10 @@ def _has_marker(keys, markers): return '1.2' if is_2_1: return '2.1' + # if is_2_2: + # return '2.2' - return '2.0' + return '2.2' # This follows the rules about transforming keys as described in # https://www.python.org/dev/peps/pep-0566/#id17 @@ -210,7 +225,7 @@ def _has_marker(keys, markers): 'Requires', 'Provides', 'Obsoletes-Dist', 'Provides-Dist', 'Requires-Dist', 'Requires-External', 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist', - 'Provides-Extra', 'Extension') + 'Provides-Extra', 'Extension', 'License-File') _LISTTUPLEFIELDS = ('Project-URL',) _ELEMENTSFIELD = ('Keywords',) @@ -602,7 +617,7 @@ def __repr__(self): class Metadata(object): """ - The metadata of a release. This implementation uses 2.0 (JSON) + The metadata of a release. This implementation uses 2.1 metadata where possible. If not possible, it wraps a LegacyMetadata instance which handles the key-value metadata format. """ @@ -611,6 +626,8 @@ class Metadata(object): NAME_MATCHER = re.compile('^[0-9A-Z]([0-9A-Z_.-]*[0-9A-Z])?$', re.I) + FIELDNAME_MATCHER = re.compile('^[A-Z]([0-9A-Z-]*[0-9A-Z])?$', re.I) + VERSION_MATCHER = PEP440_VERSION_RE SUMMARY_MATCHER = re.compile('.{1,2047}') @@ -638,6 +655,7 @@ class Metadata(object): 'name': (NAME_MATCHER, ('legacy',)), 'version': (VERSION_MATCHER, ('legacy',)), 'summary': (SUMMARY_MATCHER, ('legacy',)), + 'dynamic': (FIELDNAME_MATCHER, ('legacy',)), } __slots__ = ('_legacy', '_data', 'scheme') diff --git a/src/pip/_vendor/distlib/scripts.py b/src/pip/_vendor/distlib/scripts.py index 913912c7b8e..d2706242b8a 100644 --- a/src/pip/_vendor/distlib/scripts.py +++ b/src/pip/_vendor/distlib/scripts.py @@ -10,6 +10,8 @@ import re import struct import sys +import time +from zipfile import ZipInfo from .compat import sysconfig, detect_encoding, ZipFile from .resources import finder @@ -249,7 +251,13 @@ def _write_script(self, names, shebang, script_bytes, filenames, ext): launcher = self._get_launcher('w') stream = BytesIO() with ZipFile(stream, 'w') as zf: - zf.writestr('__main__.py', script_bytes) + source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH') + if source_date_epoch: + date_time = time.gmtime(int(source_date_epoch))[:6] + zinfo = ZipInfo(filename='__main__.py', date_time=date_time) + zf.writestr(zinfo, script_bytes) + else: + zf.writestr('__main__.py', script_bytes) zip_data = stream.getvalue() script_bytes = launcher + shebang + zip_data for name in names: diff --git a/src/pip/_vendor/distlib/t32.exe b/src/pip/_vendor/distlib/t32.exe index 8932a18e4596952373a38c60b81b7116d4ef9ee8..0aaa386d75662d2f874aab78460dcd39b2ee43b0 100644 GIT binary patch delta 24811 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 delta 23612 zcmd_SeO#2q_cwm+t<@YYg!W8in*?s zI+|9N5>{4LCZ=X-7$!cZnWd#Aeez?&XZ;qXDJ6N`@40rt>ifNazuzDC>;C6Q&CZ!K zXJ*dKoO5R8%v>&O4_J09VBPYm@10(B{M;)k9bwYTnJFib{-UsJN{bk0r8J4LEag4K zM|LVx&LBR1t}f*{5ij@C>-}+#7>}Dh(}p_NUybftHQ>+5od2(x<0aiC-8k+mAh!FE zT~s7SlHNtvE+G#}QhF%DC0rKEDU)zJEbIG($r~ixs;(gah2!GZ_lb?Lgh)8EudMI4 zmE%e_4@;LsMIfE-s95Yk9CHCbp$K1*KO_kmJ<z`46m_=8<{1|NPNZGL3)>wE@q@$2k9pfB59Xy z`jR#&c(qH4=-F_xK47S7axlla^KNAr$iyF_r_qI1K^uK}i^Hni+In&v6I)}^r7&J8T2f)oF@yT0S-ofxsV zaKu|}HWC~(a8R%v~Em}RTLPU70nRE5$?7UrK=d2dAZxJH$f%LRi-*(D{2s0yS z3v^0GpxhLZ(@GiV>{V;a8^(dZu67P3;y|TtF#GbawJpCs~c=l z=%Iy%wF|=XHOZ@(L@L+_i6tGrl5&)^=|wtk6=ceuJJpJMHN_UHnj(&u+mW2=(Pn|p zep~p;g3NMy>z*JqNs~*&a(ht>mHy_-w9$*cOoy1c*_V0CmpO+X^kuFSGoSEfN^D<- znYpIis^rNWWI%|>MPq0uiZzyIDK3Tx6c-B)a3w^9BG1_5%=V3P@duog8%x1ZaeVzSL#AWJR6tc0w z#s#yHcnrC|dXCCbm8+2lhxQO#K5~obBSGXuaO_ZDiq(0GHJ zs#!dPoam7h`7I#NC3QpfWpv4QKx8MrjR-x4%Fc<2>vu>-NSdr&OzgQs>>gF$K_Je5E2tv(vhnZbA4F_q%}lQx&~Pmdh0eDA4Byea9}&Y zsM(l)2dq70Qc&7jvVK>pg)bXqLg~Ork3~i`ehgpQ2m?!}ld-+RYBYS!?pz(Pug9;nSVp1@dF_rcdI@EqEZykYSaLWl ziC?TI&0+od0U1OVp1`k6C#m5hg5yEt?_@&^c`|%KuOXQn7qY*VjW4W)g~n$RA>1Uf z5K}}hG4eD`o9YcOqVpI5RRPz;$x*AiVbYYw z16pclumvoJ_OQkcxF15O~ERQz*EhE4lQ!=$t zef|Shk2j!p#|UyVvOm8pkNg^$9y4<|$1TfV%DUwUphFP}T2>QxDJHm(%)jg&Xn&Xq_K7d-%B;eC2 zv(nf+k{mrwvxT*M9IJ!7u+4bN*_$#=YvKlB4C!yM3LdWI9l(Y{*}|Tp37}Ua$eYnA zs+U;7qsB%@ToZTtG}N!Bg|@K87O1XG+_&FCyc=Ym!Zy#P>dR2nRS`rI6PE zThAhqkA2-mt@N~d<H52F+(hUu6WB-BXyo zs+1Y;GIP)f0oUKJ<8n_jIX<>mBMfD!drJH5k#e(hUNOxbP2BPEOpbQO52#v(?SVJo zz~aHfxZCFBWsY$A8WvoC??wT164a4dq31vY7GUw+ROXDBdhXp3Es#H;^$2gC+CH6A7`y#(MHXp%3A-1xu!%fi(ct z4JR6{9w$tOBiK_Yt3Kh3_psmIwBbJCOn~H2(k^wtecVoVY&b5oR6yvg*a74-?n|+c zHcXRZLqAQ5t+zN(c$-YhbA{eWUrv31oI(HUIs1@^arXigj$< z&*ON5)hFf=6Lez_yCMI=2necbl|e08;Wm}-5FwBU>roKb=^+<14t34m;hsj<$E`qmTyu0-=^hpApFA@1CX_q z<8g*Uh`PD%NgM&Ld%W`-Hcyh9vhI3M&CLVLr+1=PsedIfoGh` zv1w6^CvcW4YjL-1XHTrr*f4%d>INmN&#_J&!;{*#WTKr|b8at{;PP<59d3XOH4y z+8udlsZfiSd}<0=l%cPVAWx+n3t|La!$`!&6s)n22dgXv4Ar;PE%W^1{YYH!#Zs=b z0tP9Z4nekm3eMqh(7nlf0R}SdYs6?N|Y_sSZX%W=F7C1-3PVQLxcUvs=mg zX~~7FTmLe{H!yiTR#4Lrab=><4DQ$&Y)-{sVA->W+d_My^`}v{`nEy49WvqUZpHB* zYwBXMGQF@W6+1x8xy&9%r(io(O3$SD5uvm|L`=LSE>=}nd0ie)U_&O{Q^UqL;2 zSKN8cuF7j1qko^#e~BOeZV^_8E)2qm($nC$Wz)SX96i`haruqZF6crVb|dcKTkJQY zmHo!wV82?nOL1pk!|$v$5upke1xv*!zF9;DToI#`OJX$S0-~+Y2FO6-$>ZwUk@VzA z>o}xq@?>>#hOchMxvo!BKt3`h_^+1b*0p00n*v(#+f~XnGzHuuk0}z1R<>{>rB${5y8?no7w(+Csio#q(oYNE@P|Eu^Lr4CSlSST9YSd z+Y$@CFq@RAwL=w5?n*$SzATnL&kOR$bD_!>=$Ym*rFlf@pg8a`*>&C^)!+RlP8!_x~1=7 zKQ+d-9V=-^QQt0b4F;mRLBu)3&;b4O->4ty-Y6Bf+Z&5Ue3We02|QV*(ZsoUNR6lR z8v5aazWGfJ_M&y+Dsm(tB_<12wAA$~n^ewTfI}VtxRR(db3@{LRcr$7*r5Ant)}`C zaxp1v-k^PkOnwyP=o-d#J}4xo3o|%UQKtPurWx9qnVi+|53;RYYgfCC%iCjJ|!hVAwfF zl8wdm3s?=;Q7N{oA)W~k$#Fu&mJ#G|hPl_xtA8*3!&MTh%j0(&NwKaZaxU=vu(JB} z2SOy$U*QZO!-l6zvdH}5gQXi;a@+7+K41#Dy0SNEAKqP>%5dFtwUS53u-u`^AKyY3 z4^i+Tlscr(} zdGduJ^kFh1FQw=GBPwK1<;vbmw&Xe3kzm9^$#$}Q#2CqUQEe*l5TKE6Ua6QMe}}w);^!pllL`A0B75P)Ra*XH=f#Ah|W_dJ3yK zq>OGa|_xV#|-@F15Pxqwt&jeS)PL7p|jlbyj1e92Zu-bYYYSLWK3dlFJL??Pb2f=W%wD~WTCc?7GVosWa45b+T(;$1_mpv@&cE#Z+340CL1 zW9=LeuoF-ub~y#aXh}>yiY!;KSg>U`Rw}#9wwpEa)-`w-3w~ou`*HG=#VpxDKDIm{ znNIkzeIfiQW3`feGHGmV^f^|+7^&b6^met}lz73H)O`aW_Qgw;dRSxrq9WgeY zE85U+&j`3O+1Bg8F%Wx3r1?^B`cfKSYO61mwF;IUJE1)rD~)BeXu#W-uwXP=@BttFp~ORYN2 z29No*x>C)b%v(DRCu;2lU~Q`~KE=XUwxuktGeZNAm@g)BeF>YG$QKjX9wFvDS~eYZ z1%Mrqu53mKN0}>|5pgh`4bJ3RHidO8r}k(Sz@`AP?jkcbf{aWoEJU!WuVYik4s|Pz zU}!Pn$hHVyu|13^%CAZomKFDC*MVO6%17hpR`Av5;}$Z(D)(_Kwn49V4`<7@W2PsY zt?0If38+GAChbM((IVYN;T*DKannW9u*N`zBF>TF4p)QK2*^S zYoQRqP^EO-Xqdaj*nir}@I!0a;=_E6U$=|1unJo?YXrYy1lerW$ycFP;VaK2K?}q;*5rXp!O`-{YpW0~>^9`XyVy%&oDyxP1v3Xf z&diQ-4!OF)!v5&E%WQ5gC~!NC_OccYveG6bYNUBgSUkrEe`fFU`R}%)s9^BdMG6b8 zhl#~y1FAh_`v};>;n;h_b<|(PgD2;!!uwJfaNv4PCW_LCsAng#B69E4BKFs^1oLOV zB}8PADWyj3r)+X?Wg$Zm3l`8zV7znL3O*z*TV3c;X4o+vjtGp!{>kJ_siMbjxSst^ zbV0kDbe}j>a*Y@#rpTDT&aHLi5!=L6=BC;(ad?6QxXMR9UV+GNwkOfk7*=uHHr5pY z%9|7OL5Ah z0IWf1MDo!82l6#jq5_k8K`k8Q%_*^uFt>Z7dc`a|T!X$g`y$iZpxk_K{VT3^iE-D$}ZN|MTA`7sAb zc3EEh9CS(ax7Zj1H5V8IBiW_cWkY-t*;Z!ay4W&Mn6KnQi{T}&(YqgA@^3%2!v zYmb9V+S}c2@&*;t87%9c1JR#kPd5bGP=4wZ5;q`8lO`5r4ncaB=`j4E>yWtb4~>RD zG=c`)C);_RoSR-G*+-IR3=MXojDIs8b)J;XQ1sMyVp^VIwWgBV8Ie_YkHVN9f+G5z znotq-zMjzp^T$6yM>7FwhPD%kzv{U{vDf9>{6XlJATPF5c zphy%-cLC{lcs|4^j|J&Qw>O9$Qn8EE{~>^?gW}Be5sCA1Q5_ zIGf$^`>{bC*j!+J_h`&Bj8 hBpr%-{n{n>;gt&8iq+%299^WI)6Vm0g+ry;!o<_$Lt4EQu54-tWtz@EYZ}(e1MeK$v zSQ0%uhyQsdnK*kj|HDageRcsKF_UQQgJaDgvd~pH0F=54ZwNSx;b6(Ouc7adC+r9R zR!PnyXGpl^xf;)IO> z2=1Vp=Flmm$D`3xo&d(@;7$PKIp)oW&SQUTaLO0-v|=*Z%yi4~E%!~(6yIFI4a+tF zBJGEuUD$&vSWSMv_#S&?32Zu9{b>JgbI^a>*0$U(CkG$3kl7#i<=6a1YChJHjdP8C z9(WTT1|BBDGeM(yArtksxNbh-l*`jQmm&~H+^H%W_o~rlG zi{PdGvAZD;HAYLLu#Y8u79>b-!);MNe8FG|zjivAzi=J@NE+cC3;6E_lSPiJl9YO@ zGo9z}460xGc)Ucif!sI|MLt>_C2bgqnvzaNlAjj$l4!}OlY>dxl0^Q!Nu+Q|x-^>Q zRxKGM^U>oeViA-!6&gUwWCeFBx0q+A2Ckes-FH& zGy$BFIZyVJKXjk4n7sI8Oh_XTKH;0idPBO-?L)$s_Kq2amD!ai<6S19)EVN+8H5hy zcp9nl5XoD*q|a&$79EXyQJ*hNoOvUX{+a)7Ke@W}UH(%~{kqB+o?};br4@8oj>NY;Ro)}h6=CAG{ zn^%tDEirI{^_4E%gIVjIJBSQ@#>jWuL*_h_#6Pf}tbL|@K*Y0b0&7NblU-(R@^Uk` z7NG?}`?Q%GhVTr+Q!Wy{Drx40U7fr>4iKCRRV~+{7i`%=Z(``4`xFy8DH=gh{4pao zUR@MH*WRa50&IB}*|?r$x9{()BU@L^>@l{0sTywYopF@kMS|Vh2Q4b7lr^M!J&4&o z8`?VXRwp-;0Q$IDfqYM)y!wRWDt4zrmBAUhD4f>ZCsn*fYTRojCJD%MO!mtN0v8zBfZXCQ?yt6?Qctw_7 zTC-T<=!@s4^cHplD9{C>I?RfvhZD9#BG@U%Im*>2ttLrTyCbwlZ-X;TL`3gU$%T`ZC@9>hy8JO%Kbd+zQOgwxEM62Xxro*}00Xxz6U z4+gHCsZi6jNmCo)_@!JQHl}j#_51gCR_e_4ugaEMs8Cy4Le*$s>=NAA4P#ljxOBu> zsg}V|$^z7gp0G7YR8Qz6&Ry$=W60SeD=H!mm)8@q!j>M(RY*CUAn<cABZ&i~k@Ba7(~Y#7*?$emrzq)u?0^3_n}Ra>bA1(q>^ zD`5hMC&mQSpbdh+kcw+Z7Cl%ikw{g1D~Ex-hH+Y-#wq4e|FSh)?;S?edt5~W52_pnd~IL zDn1;K0EGxCoCLM(@)Ji|GGbjGf9xcwS(n_8U0k}wOHACkcfsIb8{K*DCNB~t`@*^b z5*cY4Td0B%6zt%liUqv{?bUYa>E0W ztx#!ql&gn8zX0UhNj$!te7E6rWRK3QU$%8*ZQ4c}$Uw<>@*h&5`PPUrJp~6O-thFH z4iG_<-3hc9P!osSWsVjA#B-=J0a2dJlO0Fw8|~ur9iL*=K$w>$-RpRY_ub1F47vxu zINay8wak(-Yub!cyH8njJsJO9IsaCNr`1Zguv)}oqK@BozD=hA)x_bE3FqDJB1M~` z!yeN^(E~l_T+N9`{s{1dZ-ULJ+LXXHC)+j+(Jo}JQ+7Hx-gQRP?_R=NZM_S{9Tp*j zF2cT{MYxClR$PLCsmZ&&{xHHb6;Xl+5d9JHu$j=&<6WaX~ z$7wuYK#A{w==TXw#>S8pYf+!QOHJN2R@db-Waj3vk&kth2w5>2L+C3tnVj4_KsNVR zHdODtNPgcO7dHsEbz++#D?Y(4>{#AC-fI$@2>qTYw!l?iFNV0EjkvR z-I5|HAir%%%#VYxU>Y?YGx7Qh=zkzyxnX#I5Aeuq*m>qib6`!bM4Ye;8pWPnwA5m& zhDrIXgNRIiK3civd6;rI1ZXcP;9}I&@kZ4d)$s&0jCKd!CvWdQPhNYzj5oYMWH0pX z#TvTb%3icWvR;@$w!g3?NESAXV;7V;FCOZquZ6|J-uB7^Byekg-noRNZ&mZ=S~7F% z(=7UN>lnj==Q@lp^DS04U^@@j61MZbXmMv2{bLgh?stFdDw+F|dgy2z!Ad`5Z_JqI zKHW+U41sgCqpy_?0gP3m^Q0I589Db-;-GeB!2IN`K3F8b2KcY!7tVk@k_>&h>!A9- z6nXtGMPB?z5ziSifjj_<@7m*2d4`$0CCQ!^`YF>hlvM)(=0N{)(t*N*MYXwf!XXxd}*fvaDn_cWN zqKs{af*j=Ay4s8$hyObR6P>6G3iFpYkaz&;I9MaivDook{hKDTcSm2%d>8>VUPQYs z?r8HyXPfWL{~y}?W&!E;YHn4`0w@pGycf;Nh=hJGl3lIRp*As|Ov}W$jFyOTIkkwfjpmE-9BLNh`BX2)4yq92#WYon zm(nD}Rg8&!%a}dx#nAiMHiQO=;3@{TW9)=|YZ&;82r^d|y)J?q8F*O)w=nRW2ySKI zry{tWfd@r!2Ls;~!JQ1;A%Y)OG5C2AZeZYA5j@I3mk1tb;9?Pk#BuadfFjT5SZbP> z!QAR}ya--m;3yHi!a$PJKJj+>XmzWXCz}k6LtZsZ7$I<6RbQA+U zA{fWOWg?iwK&J>MGte%AsSKPZf@usKFM;CKb z`Y_?ffC4`z*oTQS23Y)3s%(FgBt}$S#A5-bWV2& z@UDM#as4h^F!1K9Lh>eV4>|l+WJ36RSP+wILid=tb%-}2xh@$$76iw8|!t{_}MIE`==;Uk2-?~$i><%cs$kHBhTLZon51+V_yB-cIDV){|{-r?Tk8+lmxMfz~aEN)XBr zYzXra79%V}AoV2So&0cLBfEgui*OX-QayR%o#*AL*bdNZE8vEhP)icuP12mk^DO!& z5REqTUhomYE?(fu%5ws zGIMuo@U>U*cqs20Q<7)jC0llv^T%Ey_jafAN$-&K_tH#1KFtnt>~$i0W@bh~|Fs%R z=H5@@+cuAu-47QFTHj@-c-6V(y*_;PVDjO6eXE2wpb*S49$7OS+sp+f3;TMq#gBCi zJtFXy8qER!P>FTmxR@>8SYKpcp-HX6#kv(Z?4W7pw!(tTmUgRMiaWarVm;V%|E0W0 zjMHI&J*s4C??!x)iTfe;h{wi;b=`7I*Unn9a8F;^F2IfSnOgGFo~*Q%7h#GjZs09r zKKh4so;oXSd%LoEN%{p+h7Cc;3T99}*%wGaeZLuuOt^?EciRe371b4Vrfp){(vhw! z0fZA}sLjGM#4>f`fvaUdoyH{yhA0c>oa3nwZ=T^7${!u;|cpY zcis)u7F}y0SL>tk7~}W)WPZhTlDIcUJ{P9mr_{ZwNZ#HNd|VZ&*=vx0|5OLQ`YCdL zuZth|6e)f`rHZ}dozhs#B6qMaL3@MNFHi?7F(#tBx8sv0XLoklVJOF>PVs+V!0tcr zNP9X^ICd5mdleXb$q4v<|MKlqG8;nnmZIYWA+weK`;|hJL095k_nH@-veGYKL7Hws zqa7avG5-dA28jD#OX-j*#ha6V(RqKvCsvaDeJOlqC7HJ`p5N1-tlgI!{XSb>@HgA z3G)1c8+i;0zPmmWvZ9Q~1@A8oxxOZc5v{NwEkvY}U-$ov)B3*-q)IN4?jMxkxBP?Y z{H}ha>4U+1RX=j;gKvR5fADMk?)va7XqSGZ=*=$7F|6_~@28?R<9Ai3yzJ{^()f`% z$)6YDsb+buS99^pxvTYvd_?^Y4Tzhvh>ZxlBBK=m-3o7x@IIrYvlo$BhmwQiMFKcS zIGVDEY(A8j;w@&|Uwf!+m1w+>-|35L!S0$3+h-}nmDrK$jWUZG2?{7Vf@}0%l#MXl4zc|2p(H|V0 z&94OL{pK&%DOV3ijVK94&En%BIKBem_)-?p%j`iBoEi$uA1qsU-faQ0vx?hwzZ-8pm|u%vXZ zksSTl*k>k3Wy$@h3vxCNnn|;R%EWgkO<& znw&e8S5*srzy}iWpgMcf2@iKnnWxEf(K}jncejtlzcYY2VOJeEqk%BYH!ViS;dIA);<=xnFR zF<)yO2|E)XJo0``56vRkXA=7E14jJ%W+E%$Td#$HW*Bqv!7SZgLn_Z?q;#y~)?#=d zN_`%Pg=0lNL!n z`U&#TAbq`)9CUy4p~TRa{WPvl8rmPA_e)>jd_JRT%!AY%cso~ykv!v(%EXr%ludCh zi18Vqr-?Cr$2S#SG~&&9Q{FW!_4tCoFjeN%+Pl%0*Rf@1N;^wO|LwI;_mnizp;(iv zXLoJvjRyNDcm^tOR9{B@C|&j}N_TFk{^siG@M^KL{)Z${Hd#2>yF3#^z&_l;YnCha z?o`DpfxVG2LpB}k0oTlM?iBX#cwBM`=8zgA+o5O3J$}61n`Z18fPdk`Z zP9E!@6k}hFOk4moL&c`o$i+6@67liWTm8jv16%s{4}NI|#sQpeuK_jLbLQhfJ*2E| z4te~uVX>`n%=-2#8v)_=7`uij=B(+JN51$hHDUuCd04>dtH||#;QB%t2|b%2e}a|l z%Rc!|C?lC?3$gUAIvbA%s;`|*;+wXR<7W-(DUAD4Ppc;n?@gZSj-6)|9VO!MiB=4_ z#%ox7jxAnNvk$G=12oOK{yo^;kTgHRUA`B2 z?AD9ESdZnQVF^A=>n=i$F|^B6^7`jV>DAR3i8^)(fg<0y6$an8d0}=bwToH4x*Z?8 z6`uGx{M zsUC&=-|!8YL@F<+dHHu_&xQ0vKW!Ok)t6gVvgtZL5gh3QoZabL6Nzvkr9gU95JVrj z_|`TT%`>rh`#1Cm&6J?%olCI|cP`~W@6K!O_lbMLEf6{f(gIZE^Z3*80L2X~ng3-X z|NO6H{g-LX`~C5k@0s+aosx37gegM_1T1(mHvMk=I~;yfJJ$D-$+8~yvhyWVG;J>- z?|c=@Uo9c0zRFEqkOR&e@U00RC(RP!&c{iA909i&3Or7l@hj0?9Lg8{i`XuzVwjoe z{Eiv>*N7sveH}~hwvxRU2l1D`C(RcJ@Gm`4-}RDA63iZ%LThC9Ncz%wlJIq8_Uq%t z`NIoL72L46J@x;~2Y5A7YVGV;`vg!i>y44alLY@ihhQO(eI0>^bkBU<4{H0?*U34D z@Rq~>8RiKC6E}9HaMzKDVz_gSC=lC1H>92>uUvdNN_kW*o(b8P^ugaOiD&l+b-SSr zjkWBTxx(@3>ph%w*}src_s#GwTUyQg$99waD5*LcA>qy=TtoO3K^`gL5)f1f`3U6* z%Mdmo>_j+>@C`yMg0#1U3r9#s$U+!{@N2AuYeqPSun%D;aC;FN5H2CKBJgm&g(D1# zl2maf022`wBdkH#i*OX-0zxywPY8b?^om9S1Py{2VI0C#ggFRLAgn;xg0K_eFv2;6 zD+oU!v?KJ0k#PMH(h*DuqY);@R7to+0M;SAhVT)>R|wY;+7TkrgJc8^!UG875Xuo2 zBdkK$fp8Cj{VhY!>O<<3!53P5MfIQdi6X0IVsFze*KYeCq)y*ovg779p$sAVpiP3-7G5VnFZDvM`1|zzAx1)9he>$)X&aLvj@1e^7rvZI3=>HJ{eTeR; zs-l28{yG}L2jE;A@Uj^aj-n^md>LG8xr9pvz9Stq3(J=5e!5|va2&ReeLvYZ5gXnnKNdjZ?E( zvrBVAb6xYBri(UFJ5W19TdbX{b!eZ`uGT)UeObF(dsy43?VT|wqco#2AL`#FbmF6I1~a|=(Axg?Go&jeNxs_3og zuTUv+6f+f0g-fwT@rvTO;;y2bGEAvc&Qj*7E^437xSjE5Mxw62?mgWJ-7v%Zh6$PR zStGJWXP?YIpZ!Dj&)Gqy=_dA1C|0q{W0_)^;#I{S#m9tHQlv?w4=1Uv}d)yXxp`_j0ZC2WK>pVtj<`UQJYbp zaUesci_!g|lj?iwAJSX(Gxf9eujxP0|6AXtR~p6`UNJ1qT!DexpV`BxH4ZZtVB8wA zDzj&qoF?|~c5!CBG(z;YvQ?F-S+03ob5^q>Biaye=wnDR3^WWeC=FUeuEAn>&al<+ zn!%X4IP=-eD!~|6l65NUTGmfllI)c1$=U0(cVvf~l%^+4 zEhbq`WsW;%YtB14CvrZ|`8uaHhqH+GitDOKQKTz0ifqLLim{5tidu~3F-0%sbmbe$ zKa~xtpH#Ed%hc=DC)IzbC7NJO7-TI)ldjQJX|gq=G!JQtHB&URHS;t}H7hl1G|y=c zXwGPEYSdbTcBXc=cAmCc`w|2$JEJVap7Bb?n;ADVe$NQeh3n#UeRTtMLvvHDO$q#@DJ-;i%OWcbu@$?yXt^$&wIvukEb=FrT%OiQLc)0tVBS(8aJcVvDG z=?yl98`CivWkx$2X;s?Yi$t10VlmMl9ydrbBt+55Bqoh>&-n-Wc< zO!F{Z+f3I?UK5uyGG}a6&eEKXIeT)x%Hhg5jyDV~R9zoYoK;wQx) z3bisznXjx?u2sIEtXE!8eyfzKda5E-$tpqBS3N{+QEyXUSO1s#j=HNRi4819bgJfY zjYqRy^8#eyb4^ce1xE20RMn$v)!)$vWX5Ig$*lSz)0UNxotk|m+nYTD+~wws$@wXV zt!?>WCQUI_u~N~jT%w9oXR6Ea?2rrD-P zO^=ygGu4~EF#VS)5&h$q;lnS~qg2ExHPEK%npd^W8U1t*=^oQfG<<42QDr=1{M`7Z z@oVF^#_x@C4AdP+be(CB={F2ex189V{y7iiJe9L6rzPhmvjgimZUv(55Vl#0wTjuw zdCE^zpR2m6!_?!|)6}!oPpGTad0MM>spNU}kitK67;Dl+1aV?`EFO+>w1OTgdKj8ey`S9yYBp zy=$7xnAk2Z{+vzmsG>^olHxtZenpycz49exglectuUewos@kWzsQO*?fZC(Z(mbHa z*OX{xYBp)RWF+Vw)^YlC`q73*(b_Ln*%l2b`l zGL>AlKvk*QqS~g~q1vh1r8=X!qZ+7Is5NT6I!kR<=c@D7RR!wj)LYft)jQNX)x$MU zXqIWJHAJ&T^OEKj%^uD7njbYkYcjM(tyBAicDZ(?wnn=_yIm{E=#~+hu_fbm4CdjC zV;LDbBh;@*w@CM-ZW+|ARTrjD&?oCP(5%t=arzSd482XiK)+c3wBDnCPXD5Q2iAoT z^tYr%!fIQ>KZSxCV~PMeikw%Zj&@SCqdh z)v9r-pH+R-qtuO%`C!d(EL%a^H?_yLKWWFoLafW!Y1o#j$Xb}S4K}ilS;uoYoFWRr z*!5P%Dif9clmnE5l~vm?WS=U3P$sHILX7&UGt?v1bJVY6RXnf$Rh_4K6b9)Pn9_DM zpw$l77HHRC{rg5MXyqB2j9D3TGj?Tc*S)ISr@x?|VQ|BCoH0C`xhb)|A RkhJ|TEt1R(+Hg7Te*r5FG7|s* diff --git a/src/pip/_vendor/distlib/t64-arm.exe b/src/pip/_vendor/distlib/t64-arm.exe index c5df4869da5ee0970ef4f652d967caa80d5ec63d..a759e270d0bf784d1cbd03acc9492cc25f7e4669 100644 GIT binary patch delta 42378 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 diff --git a/src/pip/_vendor/distlib/t64.exe b/src/pip/_vendor/distlib/t64.exe index 325b8057c08cf7113d4fd889991fa5638d443793..82fe2d99e115fe361782ac4e84f8a4e67a243768 100644 GIT binary patch delta 30687 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
2J@eT_;Prc$CoDN`w_Dh1CN++I{E9aTyq zC?=H>q*78qnXXb?REh{nwn}+0LTSNNP-dG|(lwP-08*|>IjvF_fHGF4>{BR;QUNhj zC4R0F(IgJU6qWdzN+dM{V!TQ$AtEfZarhF1_9Yp3(3$r(eakJ_u$zpr8M!QeTa2)9 z$(HPGO9ZoREy-F&3WXf*_O=rZob22VG3DzN^q2|W-V-<~+6?DAfsFTYWCyBWwxDlY zL{YTdt+fi;s2~~ua?pvyKoncl2gpp{&KMsF@2@G+cNBfmI+cz8wzoNXVe_%;E;gTr z6qo~VGUSrn)&kV8gm56eu96r)1HR1{wM>mKqWDaC!K>5|I^GmH(K)0LYfqFaHc-Q) z!^RxlJy=5B$Jm=Zab@DJd?BgMUbNdQCNck=t$pp)!XD$IO?h{ZyOwO5VQm~6y)&?7 z85|Qwu<<(KU1HBoY}w8sE&WiMbfO&JmXmZI8SK)|2w!<11o=^(#9+mj+ed=m5&Z9d zzyfzoNvwx2ZXdcyf$H!mCn4)VU)kdw61^ICO*TXKj*z!pcl|8|oPUdbyQ^#H9Sl+h zdgDD%ZHAj2&>d18;*t{oxdZdq-CEGKVcmC!3uia5=XU#xyEdRqSd=}*J$RL64ZN>d z#iNiFr8^;CI(;X8fD%VKeYv-Xns^x=#B}KwxK7T?@oU+4yEDww3y_VT5aB!8sgi7z z{xC}QvJuuF-XC=j8it98lbpWvGD|=y?B?{NN_tgOx(^U| zheUoVJAMYCiSJe{Qp2AEjdCZhxGfaqO6;)ns@K ze1IP2yKP6Z%@7gGYO3%Jnt|+ARi~EQV3{_p-GXtf!yZwXY+?)cWVAFqlk&q@c4E&0 z;pKTOV{ce^=n@DYCh2?u%iUU0%u^nP)1~GkaUaW8?Tya=AQOviI=&QNwzN2WQ=MtS_ltx1IqB-4lm&>4im9u)(Iy&*d+h=)L zH-8tM$vr`lcNen2eE~7=6w(yO{C*UzoI%nN$Ag#Ca#>TtWi=tLkWJp##Xl8f?Yge2 zAvsPsmaupSnnr>q`z}FGAwiIFAgJ?CVnRra3wl z>r1xK7S*^?nd^95HXhotN}1<637p->cny?X>(V7xz5bPbHiJ)FvUBw%OOOlZaEp|Z zyZRE^Qf-Dm(ZaCBk$CC;GZxbLek|qtaG~9+Ecg4}A$!|sw;uYELCTWAb7=aRgHVzv z^A(nQz)$GWhK)baO?bfAs|Uh_Us|(m2PO!UgPHHaFrjxaOF9@Wv}G*sV3gmNk!Vz#bhPfRI7Y0PJ!PPs3rK^=#UL@;u=&0~p1mh3K2-y{^ z!(l(4%m~G3cd^48*tDc4=4}m5a2kZM35UD*_nSd|OlLoNEKqzeX4?bWBvyy9&khF; zsR>v6VGI14a2bnuR=*K_oe0+Y1z@BHeOb^IZzyZVevi`IDJGZH;w7BFzN9l)qAHe!QNI-74z4(a28q-x=7~XWkE(E~;?P{9DpELP zhDe_B&8f{Ye=t~?)Bo~?hSHNS8kJwHVIR$FEwtUFxt4>4KPKVgq;EuO3cA!4rKrzt zH>l3!hf}Cnx&xBG8iY#>e^zl+Kj^ifXD?1dj1b;x7(SCOP7eIj#Yq7e|2G#WnL+I4 z(SN!)Nqbu7<4on^r0=mwAyt9+F32T)1AhPEu$Z$4Zwac>bE-tU>i+s~N?O#hea9ZS z-k3$or$$aVi;?_pzJdLGyo2!mEL^K}6P#RF{}Ts<^)qp$GDXNZz2*6nxJUHn1;G#|mRNu)5O`{;Tg{eE!3Y$zR=A(3w!-p@H>2lO(L_f_ss3{=!LU zk^gWfvg|EZ@Kal1)LUEL_{oWP+w)xWm@G_Vn` z>B~aSh3U8D(eRyBUz*P;VS~^0VcjqG4XzmXbdMAJC=)&xzt@t2Ur4Ew-(#;|jBm9M zH&Aj9@Ezn}oN{tU_^L0)xjx2W+Bz{D3ukL83#gkbtZcf8T;JTZ_F4ScUu`5}xOa6lUN;dXVsBqVVExt6-t<#w1Zol4}$(Jx6neNvR_mZik zn;)m@UpXiyb$M|rOZYX~P_~qs3#&@CIIUs}`Q}14_t(z7bYQ1%vT65@y5FXti*2TK z+U(Qh8DAk^xvp^%+Rz4fLU{7=f;{p|W$!GI+mB|Ke(jPxs90fIgq)NMb|V~NT^1|R zyG5bu3%s@}Q@+OZmdZ403LAF0vv6-STYfoCxSh|oUv4X$>AA+^ zjG`Ac6r$uQ`K<4iArr@|M16?}Z=#rk->QhL#xGe^J7t!4fXshk^wPS|j9g$UqA%YK z+HAA!7El;gssnz_q?H+&&?6{y1f_RCy7Jo@c)a1|Am2%6cdmp-zvrsxzm}LZaszam zI-KN!D{l|ggpP8d%!^s_Z$Zu{lVEpKbOg)&Etdb3t^V!x+%8yg_+=hi4yLR$>j3;% z8+_*>pem$fQTkbofw^#AziJPp!;d4mpxNKiw;QaZU~S10@kP$zqBLCKl`U;j~0a)+ViUBqeKX_(4MnCmc z6eWK%jO1~nfvN$j7)}o0#1B`10l(&jQcyTvK%%Ul|FVTBP1l#)!??v))e}&50wbx> zpr8fp{cAt?zdp2idJpSvvuz`t-{36i2F+wE<>jeN#|q1?GW+Z8!aKl-#VHb}QaSz%>c(Vq-mdIk z35ed+bsEdEt{Z0b?t(7~*-`)PDWtm}I>q9K&re>J)!YdKx{>VoULYN1jnW=iy;z`O?Vx;10|-U(d{UV zC`XiDt~)uJ>f0}>->*Y;dlUj5qq~wAcoS&&PN%R$@3Tb(LSS1|u<~~_{-%t8*rB3y z9lq2o`S%z)L&86R-_mSnBVdPU;uP-(JjC{q7fDviNB(K+1BxTm0U&Ma6 z;g?+X-#OlYCh1=UgNEVc(nT!dX1FkE5gTwb$YrRBM$7B4T-uJ!xf#~h`AL^k`pax?#n4-bq8eFWwRT^Bc!7nvfrNN^b zJg31cW({f7pnxAEppUx-gEbhf!9)!X(%@JP&eUMB23KnEEe(F7!QC1>szLKP4Y{E~ zhi<9>p&IO}L8AuqH8@{`D>e9m2EWqaehr?~;IA6|Q-e?);HNRfX>oroUgfH02+-nLTAa?e%14U_Ytd~kDu0L;Z**4U zp<29Hi-#%k;phk_m0^L#P@u(M(BfHI9B(R>Pn;Hiq{XAPxJ`>YIc@b9_*Sm^oWi_G zrfG9#hvrY3HZw1`GNL8l&pd0=jA^r{gw8YNPMaM%ZT8f>!fB>SlV|2>Ox)A-IYp-b z#GuvklrOKa@PFVNf!D*6xXIj1E{_Z4OqCZ~^69}jb7q?g=gbV9I%#(9%)G+Td3h!i zNu>(9wY8pq(az)Xh}FB|GomtfuK9X&TJoJIj+I}x;^*al+81BhgAj$G9QP`M`$JWt z*MWcjOx(lYp7ZbQU0}%eilaO<=Uzjn??Y&(<>CFDIX{yd=a=is`3-mB{1Ol^G*neC z_T)nar^S_TdGZ6ZnsTp$>+c^3X-&ED#Ke9w$9V+mxWGQXRcc)v*Tg@%J;!->cq$?9 zEO5@99pWlKHSoR;PK!CNPFMN67w_MyDaW38j;ld9_OSALAm5>x{&yFS3+T#m6CPH! z3*v*riJ$tw5AP3B5MIzEsshiXM6~l^zS5XZ0>Ac5+(U2A=@T3|eP@?~rh?;pb6he)Q^6h{4x9%%(WA3ll}mwh zb`#&C6pnivfxcTppBB#coO418&UvVVPjg{qsT|j)5A0P4(56pi9|J$Mxd%QFIqpC@ z$2mT#JZa!Nn|UuM&MOyTxFhG4;J|rxb}#Vj*n$f-ea!{ue#HeRY~h0W&76A{$5Brg zz~1suDs`kWXs+{{aUAD1p5wwFse0uLSr8h^K{%z2rl9f6 z0{#lZf@cNmEM$3j+H;;51<%gpE*n)L|6d`RU9KiB%ULwK4AjF^7Dn0~$x6qySA;#|0p zgb%n7em&>j*s|{F#8Icy;a}rY*W$Qi zm9D@(+b&CpqeX$WiLXP_6oGa?Z;*zlj1J@johUUl0J0VP@m@We%Jr+`xD14*-u!P` zqX9e}FOk-$d_9m4r#9^ld`52TO^(}xQ2V%YdJx}HuZZ9R5u7=FAw*ag#EZdxu>$AM zmn&Kz4jrY&Tks@WoKt1HV7`B4v=<*3=@;+9g`4vD@Z4NJJRye<=O^&WRM1pN9ZZnQ zf?z(h8)dD)QIFR~E{=Z3Tl<_*tS6qU)ogzvd&8*RB*0cOnE$6E0kQsHJ`tF?|KUhL z_5WW!5tyNuGzoETADjp( zSA_9X`z^5_mS++b+bw-|{+z;DikS&5ryDhCnyLSs!eKDxX66l^JUuVR#I^WO)P4&p zyM^=C%0Hs`R{E8~fIQRiyjcZVlT1@bah3bR`7W8SP$k1mxoSN)p73Dm4?}kN3k7*x z5~cQ?Gke~gnR$Ipg)>#ILT;QwFDfj|n{7&)R*3rN6uy8W!y@>vD<4Jh6_tA<`OsEJ z?T6ydnP$V#fI@0?k)&_d(1*?Fm4l>JcC%n`Gn zpEf(U--4}|B6&N0t9@&JI$!x>8-Cf=f<%5k-zsIUYR4;Gj6W%Jx3-GrUvv%{?WiUU z*IVAlwWzP2j9Y6mZMho{}r0G&lRMr?EfW7}4xqgc$CZGGU<{7v8-T|GCI)icOyGcK?yC@- zWDp^^8-WTv4tNV8I|79Q{t$})%?J2#z=$xlvNXWc2pd4J1vG?XpGU>MfMXCypz(l@ zHJppU-X4j%!0!vV8R13;c(w@1k5XF<_X(HPTFp%Gc?1$@0pNL!egV*}jmonQ(9)LU zE}+m7z+(vZ5TX|FZv=PXj{xIw67>b10C*lD4)_JY2WI@qCMLjkm@HF)#{#ZFpw_$s zxC4QN*bk_WY81ZW3HWYze6OS} z&us*}-2;sQ{ZGJFNvaTDfCmt${A$2HJu&{pU`p!=moNfNIxZO}gkGo+bbG)#2sD-j zfY%YI#Ww(l_QuKr&u~EZ6qQc!M+7faa0)P^556Y@+z2=Uff|qv_%V(+*`R;g*9?QX zA0(v+U^%Q~`u|;40$xtXA#d^q&O14;;=zE)9Vy zFiqyTn>p&xGy)FDRfQ7)cOh&5{}I632*m#<;755d+(7>nFfLyej^J}h%;1&)43b5}? zoO{5t81P*LWyk>A&%yW?BOz`MF6I%a1&aZ{Kp>{gfXfOwZX@s#Kw%zQ2HYNSxrUbk zx|vkEJK#D58Zv@?iZI^bPXpYAKoh(Q&~?7nU^9^W2ppD;{qq<-C%96SWyMIgPh5zuk5S{a>$q7bN&(SW50=FP}Z1*GK? zw16rAeDg&}3Vbu*>*%36;OhZ@FV^M(pl2D!T>;$-uwyyK5_lZoRs?G0Hozwc)Qj8- zc>fTTUI9#d6l=&Z33NO z+(xxEMnI4EIc_KDUV!Nzs6Al>Jb^$8=MSNwv^Ozz#oh++xt<00$rtzX+Ih8r~Vu37$qEA!-3XJfq^9 z0A&Q?m(O5UfBTa<0e1rSsa5ebz>OENc2N*POC81xcnRRROHielz2gBtL!e2z8PI$~ zoz=yFhMVfp_yRseFoFLO;Nag?A+i9y8lgSSNFXE{fySHQQ3P7Y#{s23u@i!4C7|P9 z5Ds`C;8%Ac9B_im?qPU4Ob`=Mj8C$9)m^1c5S>_ny4*e`0bGB;PvW1ScSD!gfrMJlsSl_=<+V21w3oq7x)1 zH2BR5LQZ5#AV}^>!U>X(mT-dPk0qQSxlRcuI8VdLeM*i|q7x*yCE)}wYB;$rg~uwL zVCdsaHA3#YK3W1n34vNekQ{1M5J7T@6HbsEVuTaCt>U;(J7l)!=wr{>;cpx!e@nmx zfbM`5fWCm600ESb%J0bWh*g0u0Al(TQ+~{VVoG;{v84kH1#|$!ZD6q@U=|>N@=?p- zE6pOW>ooP>6S#b^75@i1RlKh9O_BGp-weERgUEZ?S2bhDo3XlPtg#v6Ag-Fjy%`H_ z!h|@XazZ-qZB79t>s>53z$>btT;ltfbttDPp8Ww%6HZU#PG3M(q0vq01z#aO>S^5f z9OCHIru3@o;78d_@#tHKqiKlyC>>M*f)jeRiDBIzTmMey2W6U_>=M8*68~|?MEvc? z4F#6Y4dw^8_vcWi?fv2Kqd3l2GOXNH-0Y%>F+rv>#@391gnQ}YfFias%fz;!)KAbq{0O|^pl7a3YXFk(L6W0~J(E({x zDIAhG#$k^DK1JcAz9~SjP&=le-6rt-J1vxp2DL4E~1K0sq>e|EW9E(0U$IcoM2^ z60>=lAuSRU6!s%hX)gV*6$3q!2y_}BBJMd^Hn42>n9i8Nr~onvR8&1!^kUJ6ML!k^ gES6ZDusCBeg8;A>0TiFEG>cJ-QDeLJEXJ+O0B!ye=>Px# delta 29432 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 delta 23856 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 YAzmKZNUN2m2|0&sxBazwEI8*s0V2R_$p8QV delta 41105 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 OjC9xS&Xf4Jg#QJu{VkIK diff --git a/src/pip/_vendor/distlib/wheel.py b/src/pip/_vendor/distlib/wheel.py index 48abfde5b52..028c2d99b57 100644 --- a/src/pip/_vendor/distlib/wheel.py +++ b/src/pip/_vendor/distlib/wheel.py @@ -11,7 +11,6 @@ import datetime from email import message_from_file import hashlib -import imp import json import logging import os @@ -61,10 +60,18 @@ def _derive_abi(): parts = ['cp', VER_SUFFIX] if sysconfig.get_config_var('Py_DEBUG'): parts.append('d') - if sysconfig.get_config_var('WITH_PYMALLOC'): - parts.append('m') - if sysconfig.get_config_var('Py_UNICODE_SIZE') == 4: - parts.append('u') + if IMP_PREFIX == 'cp': + vi = sys.version_info[:2] + if vi < (3, 8): + wpm = sysconfig.get_config_var('WITH_PYMALLOC') + if wpm is None: + wpm = True + if wpm: + parts.append('m') + if vi < (3, 3): + us = sysconfig.get_config_var('Py_UNICODE_SIZE') + if us == 4 or (us is None and sys.maxunicode == 0x10FFFF): + parts.append('u') return ''.join(parts) ABI = _derive_abi() del _derive_abi @@ -95,6 +102,29 @@ def _derive_abi(): else: to_posix = lambda o: o.replace(os.sep, '/') +if sys.version_info[0] < 3: + import imp +else: + imp = None + import importlib.machinery + import importlib.util + +def _get_suffixes(): + if imp: + return [s[0] for s in imp.get_suffixes()] + else: + return importlib.machinery.EXTENSION_SUFFIXES + +def _load_dynamic(name, path): + # https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly + if imp: + return imp.load_dynamic(name, path) + else: + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) + return module class Mounter(object): def __init__(self): @@ -124,7 +154,7 @@ def load_module(self, fullname): else: if fullname not in self.libs: raise ImportError('unable to find extension for %s' % fullname) - result = imp.load_dynamic(fullname, self.libs[fullname]) + result = _load_dynamic(fullname, self.libs[fullname]) result.__loader__ = self parts = fullname.rsplit('.', 1) if len(parts) > 1: @@ -301,10 +331,9 @@ def get_hash(self, data, hash_kind=None): result = base64.urlsafe_b64encode(result).rstrip(b'=').decode('ascii') return hash_kind, result - def write_record(self, records, record_path, base): + def write_record(self, records, record_path, archive_record_path): records = list(records) # make a copy, as mutated - p = to_posix(os.path.relpath(record_path, base)) - records.append((p, '', '')) + records.append((archive_record_path, '', '')) with CSVWriter(record_path) as writer: for row in records: writer.writerow(row) @@ -321,8 +350,8 @@ def write_records(self, info, libdir, archive_paths): records.append((ap, digest, size)) p = os.path.join(distinfo, 'RECORD') - self.write_record(records, p, libdir) ap = to_posix(os.path.join(info_dir, 'RECORD')) + self.write_record(records, p, ap) archive_paths.append((ap, p)) def build_zip(self, pathname, archive_paths): @@ -965,7 +994,7 @@ def compatible_tags(): versions.append(''.join([major, str(minor)])) abis = [] - for suffix, _, _ in imp.get_suffixes(): + for suffix in _get_suffixes(): if suffix.startswith('.abi'): abis.append(suffix.split('.', 2)[1]) abis.sort() diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt index a9dd6270b33..33523db3f22 100644 --- a/src/pip/_vendor/vendor.txt +++ b/src/pip/_vendor/vendor.txt @@ -1,6 +1,6 @@ CacheControl==0.12.11 # Make sure to update the license in pyproject.toml for this. colorama==0.4.5 -distlib==0.3.3 +distlib==0.3.5 distro==1.7.0 msgpack==1.0.3 packaging==21.3 From f341a3b9acd29359fb8a8a31631d2cdc023f7c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sat, 16 Jul 2022 20:08:57 +0200 Subject: [PATCH 03/14] Upgrade msgpack to 1.0.4 --- news/msgpack.vendor.rst | 1 + src/pip/_vendor/msgpack/__init__.py | 5 ++++- src/pip/_vendor/msgpack/_version.py | 1 - src/pip/_vendor/msgpack/ext.py | 8 ++++---- src/pip/_vendor/msgpack/fallback.py | 18 ++++++++---------- src/pip/_vendor/vendor.txt | 2 +- 6 files changed, 18 insertions(+), 17 deletions(-) create mode 100644 news/msgpack.vendor.rst delete mode 100644 src/pip/_vendor/msgpack/_version.py diff --git a/news/msgpack.vendor.rst b/news/msgpack.vendor.rst new file mode 100644 index 00000000000..523b26dca37 --- /dev/null +++ b/news/msgpack.vendor.rst @@ -0,0 +1 @@ +Upgrade msgpack to 1.0.4 diff --git a/src/pip/_vendor/msgpack/__init__.py b/src/pip/_vendor/msgpack/__init__.py index d6705e22b79..50710218987 100644 --- a/src/pip/_vendor/msgpack/__init__.py +++ b/src/pip/_vendor/msgpack/__init__.py @@ -1,5 +1,4 @@ # coding: utf-8 -from ._version import version from .exceptions import * from .ext import ExtType, Timestamp @@ -7,6 +6,10 @@ import sys +version = (1, 0, 4) +__version__ = "1.0.4" + + if os.environ.get("MSGPACK_PUREPYTHON") or sys.version_info[0] == 2: from .fallback import Packer, unpackb, Unpacker else: diff --git a/src/pip/_vendor/msgpack/_version.py b/src/pip/_vendor/msgpack/_version.py deleted file mode 100644 index fb878b353de..00000000000 --- a/src/pip/_vendor/msgpack/_version.py +++ /dev/null @@ -1 +0,0 @@ -version = (1, 0, 3) diff --git a/src/pip/_vendor/msgpack/ext.py b/src/pip/_vendor/msgpack/ext.py index 4eb9dd65adc..25544c55564 100644 --- a/src/pip/_vendor/msgpack/ext.py +++ b/src/pip/_vendor/msgpack/ext.py @@ -59,7 +59,7 @@ def __init__(self, seconds, nanoseconds=0): raise TypeError("seconds must be an interger") if not isinstance(nanoseconds, int_types): raise TypeError("nanoseconds must be an integer") - if not (0 <= nanoseconds < 10 ** 9): + if not (0 <= nanoseconds < 10**9): raise ValueError( "nanoseconds must be a non-negative integer less than 999999999." ) @@ -143,7 +143,7 @@ def from_unix(unix_sec): :type unix_float: int or float. """ seconds = int(unix_sec // 1) - nanoseconds = int((unix_sec % 1) * 10 ** 9) + nanoseconds = int((unix_sec % 1) * 10**9) return Timestamp(seconds, nanoseconds) def to_unix(self): @@ -161,7 +161,7 @@ def from_unix_nano(unix_ns): :param int unix_ns: Posix timestamp in nanoseconds. :rtype: Timestamp """ - return Timestamp(*divmod(unix_ns, 10 ** 9)) + return Timestamp(*divmod(unix_ns, 10**9)) def to_unix_nano(self): """Get the timestamp as a unixtime in nanoseconds. @@ -169,7 +169,7 @@ def to_unix_nano(self): :returns: posix timestamp in nanoseconds :rtype: int """ - return self.seconds * 10 ** 9 + self.nanoseconds + return self.seconds * 10**9 + self.nanoseconds def to_datetime(self): """Get the timestamp as a UTC datetime. diff --git a/src/pip/_vendor/msgpack/fallback.py b/src/pip/_vendor/msgpack/fallback.py index b27acb29515..f560c7b5509 100644 --- a/src/pip/_vendor/msgpack/fallback.py +++ b/src/pip/_vendor/msgpack/fallback.py @@ -11,7 +11,6 @@ def dict_iteritems(d): return d.iteritems() - else: int_types = int unicode = str @@ -32,7 +31,6 @@ def _is_recursionerror(e): and e.args[0].startswith("maximum recursion depth exceeded") ) - else: def _is_recursionerror(e): @@ -68,7 +66,6 @@ def write(self, s): def getvalue(self): return self.builder.build() - else: USING_STRINGBUILDER = False from io import BytesIO as StringIO @@ -143,7 +140,6 @@ def _unpack_from(f, b, o=0): """Explicit type cast for legacy struct.unpack_from""" return struct.unpack_from(f, bytes(b), o) - else: _unpack_from = struct.unpack_from @@ -322,7 +318,7 @@ def __init__( self._buf_checkpoint = 0 if not max_buffer_size: - max_buffer_size = 2 ** 31 - 1 + max_buffer_size = 2**31 - 1 if max_str_len == -1: max_str_len = max_buffer_size if max_bin_len == -1: @@ -427,6 +423,8 @@ def _reserve(self, n, raise_outofdata=True): # Read from file remain_bytes = -remain_bytes + if remain_bytes + len(self._buffer) > self._max_buffer_size: + raise BufferFull while remain_bytes > 0: to_read_bytes = max(self._read_size, remain_bytes) read_data = self.file_like.read(to_read_bytes) @@ -804,20 +802,20 @@ def _pack( raise OverflowError("Integer value out of range") if check(obj, (bytes, bytearray)): n = len(obj) - if n >= 2 ** 32: + if n >= 2**32: raise ValueError("%s is too large" % type(obj).__name__) self._pack_bin_header(n) return self._buffer.write(obj) if check(obj, unicode): obj = obj.encode("utf-8", self._unicode_errors) n = len(obj) - if n >= 2 ** 32: + if n >= 2**32: raise ValueError("String is too large") self._pack_raw_header(n) return self._buffer.write(obj) if check(obj, memoryview): n = len(obj) * obj.itemsize - if n >= 2 ** 32: + if n >= 2**32: raise ValueError("Memoryview is too large") self._pack_bin_header(n) return self._buffer.write(obj) @@ -899,7 +897,7 @@ def pack_map_pairs(self, pairs): return ret def pack_array_header(self, n): - if n >= 2 ** 32: + if n >= 2**32: raise ValueError self._pack_array_header(n) if self._autoreset: @@ -908,7 +906,7 @@ def pack_array_header(self, n): return ret def pack_map_header(self, n): - if n >= 2 ** 32: + if n >= 2**32: raise ValueError self._pack_map_header(n) if self._autoreset: diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt index 33523db3f22..ccec77a4213 100644 --- a/src/pip/_vendor/vendor.txt +++ b/src/pip/_vendor/vendor.txt @@ -2,7 +2,7 @@ CacheControl==0.12.11 # Make sure to update the license in pyproject.toml for t colorama==0.4.5 distlib==0.3.5 distro==1.7.0 -msgpack==1.0.3 +msgpack==1.0.4 packaging==21.3 pep517==0.12.0 platformdirs==2.5.2 From b3dc8435bae5bb02ab5680d4bc7ad390c55bb044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sat, 16 Jul 2022 20:09:19 +0200 Subject: [PATCH 04/14] Upgrade pyparsing to 3.0.9 --- news/pyparsing.vendor.rst | 1 + src/pip/_vendor/pyparsing/__init__.py | 4 +- src/pip/_vendor/pyparsing/actions.py | 2 +- src/pip/_vendor/pyparsing/core.py | 130 +++++++++--------- src/pip/_vendor/pyparsing/diagram/__init__.py | 61 ++++++-- .../_vendor/pyparsing/diagram/template.jinja2 | 26 ---- src/pip/_vendor/pyparsing/exceptions.py | 4 +- src/pip/_vendor/pyparsing/helpers.py | 27 ++-- src/pip/_vendor/pyparsing/results.py | 8 +- src/pip/_vendor/pyparsing/testing.py | 10 +- src/pip/_vendor/pyparsing/unicode.py | 30 +++- src/pip/_vendor/vendor.txt | 2 +- 12 files changed, 169 insertions(+), 136 deletions(-) create mode 100644 news/pyparsing.vendor.rst delete mode 100644 src/pip/_vendor/pyparsing/diagram/template.jinja2 diff --git a/news/pyparsing.vendor.rst b/news/pyparsing.vendor.rst new file mode 100644 index 00000000000..f42555ba535 --- /dev/null +++ b/news/pyparsing.vendor.rst @@ -0,0 +1 @@ +Upgrade pyparsing to 3.0.9 diff --git a/src/pip/_vendor/pyparsing/__init__.py b/src/pip/_vendor/pyparsing/__init__.py index 24ba1b9b087..75372500ed9 100644 --- a/src/pip/_vendor/pyparsing/__init__.py +++ b/src/pip/_vendor/pyparsing/__init__.py @@ -128,8 +128,8 @@ def __repr__(self): ) -__version_info__ = version_info(3, 0, 8, "final", 0) -__version_time__ = "09 Apr 2022 23:29 UTC" +__version_info__ = version_info(3, 0, 9, "final", 0) +__version_time__ = "05 May 2022 07:02 UTC" __version__ = __version_info__.__version__ __versionTime__ = __version_time__ __author__ = "Paul McGuire " diff --git a/src/pip/_vendor/pyparsing/actions.py b/src/pip/_vendor/pyparsing/actions.py index 2bcc5502b07..f72c66e7431 100644 --- a/src/pip/_vendor/pyparsing/actions.py +++ b/src/pip/_vendor/pyparsing/actions.py @@ -55,7 +55,7 @@ def replace_with(repl_str): na = one_of("N/A NA").set_parse_action(replace_with(math.nan)) term = na | num - OneOrMore(term).parse_string("324 234 N/A 234") # -> [324, 234, nan, 234] + term[1, ...].parse_string("324 234 N/A 234") # -> [324, 234, nan, 234] """ return lambda s, l, t: [repl_str] diff --git a/src/pip/_vendor/pyparsing/core.py b/src/pip/_vendor/pyparsing/core.py index 5afbfd0bdc6..6ff3c766f7d 100644 --- a/src/pip/_vendor/pyparsing/core.py +++ b/src/pip/_vendor/pyparsing/core.py @@ -2,9 +2,8 @@ # core.py # import os +import typing from typing import ( - Optional as OptionalType, - Iterable as IterableType, NamedTuple, Union, Callable, @@ -14,7 +13,6 @@ List, TextIO, Set, - Dict as DictType, Sequence, ) from abc import ABC, abstractmethod @@ -192,7 +190,7 @@ def enable_all_warnings() -> None: def _should_enable_warnings( - cmd_line_warn_options: IterableType[str], warn_env_var: OptionalType[str] + cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str] ) -> bool: enable = bool(warn_env_var) for warn_opt in cmd_line_warn_options: @@ -404,7 +402,7 @@ class ParserElement(ABC): DEFAULT_WHITE_CHARS: str = " \n\t\r" verbose_stacktrace: bool = False - _literalStringClass: OptionalType[type] = None + _literalStringClass: typing.Optional[type] = None @staticmethod def set_default_whitespace_chars(chars: str) -> None: @@ -414,11 +412,11 @@ def set_default_whitespace_chars(chars: str) -> None: Example:: # default whitespace chars are space, and newline - OneOrMore(Word(alphas)).parse_string("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] + Word(alphas)[1, ...].parse_string("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] # change to just treat newline as significant ParserElement.set_default_whitespace_chars(" \t") - OneOrMore(Word(alphas)).parse_string("abc def\nghi jkl") # -> ['abc', 'def'] + Word(alphas)[1, ...].parse_string("abc def\nghi jkl") # -> ['abc', 'def'] """ ParserElement.DEFAULT_WHITE_CHARS = chars @@ -450,13 +448,13 @@ def inline_literals_using(cls: type) -> None: ParserElement._literalStringClass = cls class DebugActions(NamedTuple): - debug_try: OptionalType[DebugStartAction] - debug_match: OptionalType[DebugSuccessAction] - debug_fail: OptionalType[DebugExceptionAction] + debug_try: typing.Optional[DebugStartAction] + debug_match: typing.Optional[DebugSuccessAction] + debug_fail: typing.Optional[DebugExceptionAction] def __init__(self, savelist: bool = False): self.parseAction: List[ParseAction] = list() - self.failAction: OptionalType[ParseFailAction] = None + self.failAction: typing.Optional[ParseFailAction] = None self.customName = None self._defaultName = None self.resultsName = None @@ -510,7 +508,7 @@ def copy(self) -> "ParserElement": integerK = integer.copy().add_parse_action(lambda toks: toks[0] * 1024) + Suppress("K") integerM = integer.copy().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M") - print(OneOrMore(integerK | integerM | integer).parse_string("5K 100 640K 256M")) + print((integerK | integerM | integer)[1, ...].parse_string("5K 100 640K 256M")) prints:: @@ -895,7 +893,7 @@ def can_parse_next(self, instring: str, loc: int) -> bool: # cache for left-recursion in Forward references recursion_lock = RLock() - recursion_memos: DictType[ + recursion_memos: typing.Dict[ Tuple[int, "Forward", bool], Tuple[int, Union[ParseResults, Exception]] ] = {} @@ -985,7 +983,7 @@ def disable_memoization() -> None: @staticmethod def enable_left_recursion( - cache_size_limit: OptionalType[int] = None, *, force=False + cache_size_limit: typing.Optional[int] = None, *, force=False ) -> None: """ Enables "bounded recursion" parsing, which allows for both direct and indirect @@ -1738,7 +1736,7 @@ def ignore(self, other: "ParserElement") -> "ParserElement": Example:: - patt = OneOrMore(Word(alphas)) + patt = Word(alphas)[1, ...] patt.parse_string('ablaj /* comment */ lskjd') # -> ['ablaj'] @@ -1798,7 +1796,7 @@ def set_debug(self, flag: bool = True) -> "ParserElement": # turn on debugging for wd wd.set_debug() - OneOrMore(term).parse_string("abc 123 xyz 890") + term[1, ...].parse_string("abc 123 xyz 890") prints:: @@ -1953,12 +1951,12 @@ def run_tests( self, tests: Union[str, List[str]], parse_all: bool = True, - comment: OptionalType[Union["ParserElement", str]] = "#", + comment: typing.Optional[Union["ParserElement", str]] = "#", full_dump: bool = True, print_results: bool = True, failure_tests: bool = False, post_parse: Callable[[str, ParseResults], str] = None, - file: OptionalType[TextIO] = None, + file: typing.Optional[TextIO] = None, with_line_numbers: bool = False, *, parseAll: bool = True, @@ -2385,11 +2383,11 @@ class Keyword(Token): def __init__( self, match_string: str = "", - ident_chars: OptionalType[str] = None, + ident_chars: typing.Optional[str] = None, caseless: bool = False, *, matchString: str = "", - identChars: OptionalType[str] = None, + identChars: typing.Optional[str] = None, ): super().__init__() identChars = identChars or ident_chars @@ -2479,7 +2477,7 @@ class CaselessLiteral(Literal): Example:: - OneOrMore(CaselessLiteral("CMD")).parse_string("cmd CMD Cmd10") + CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] (Contrast with example for :class:`CaselessKeyword`.) @@ -2504,7 +2502,7 @@ class CaselessKeyword(Keyword): Example:: - OneOrMore(CaselessKeyword("CMD")).parse_string("cmd CMD Cmd10") + CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10") # -> ['CMD', 'CMD'] (Contrast with example for :class:`CaselessLiteral`.) @@ -2513,10 +2511,10 @@ class CaselessKeyword(Keyword): def __init__( self, match_string: str = "", - ident_chars: OptionalType[str] = None, + ident_chars: typing.Optional[str] = None, *, matchString: str = "", - identChars: OptionalType[str] = None, + identChars: typing.Optional[str] = None, ): identChars = identChars or ident_chars match_string = matchString or match_string @@ -2680,17 +2678,17 @@ class Word(Token): def __init__( self, init_chars: str = "", - body_chars: OptionalType[str] = None, + body_chars: typing.Optional[str] = None, min: int = 1, max: int = 0, exact: int = 0, as_keyword: bool = False, - exclude_chars: OptionalType[str] = None, + exclude_chars: typing.Optional[str] = None, *, - initChars: OptionalType[str] = None, - bodyChars: OptionalType[str] = None, + initChars: typing.Optional[str] = None, + bodyChars: typing.Optional[str] = None, asKeyword: bool = False, - excludeChars: OptionalType[str] = None, + excludeChars: typing.Optional[str] = None, ): initChars = initChars or init_chars bodyChars = bodyChars or body_chars @@ -2872,10 +2870,10 @@ def __init__( self, charset: str, as_keyword: bool = False, - exclude_chars: OptionalType[str] = None, + exclude_chars: typing.Optional[str] = None, *, asKeyword: bool = False, - excludeChars: OptionalType[str] = None, + excludeChars: typing.Optional[str] = None, ): asKeyword = asKeyword or as_keyword excludeChars = excludeChars or exclude_chars @@ -3088,18 +3086,18 @@ class QuotedString(Token): def __init__( self, quote_char: str = "", - esc_char: OptionalType[str] = None, - esc_quote: OptionalType[str] = None, + esc_char: typing.Optional[str] = None, + esc_quote: typing.Optional[str] = None, multiline: bool = False, unquote_results: bool = True, - end_quote_char: OptionalType[str] = None, + end_quote_char: typing.Optional[str] = None, convert_whitespace_escapes: bool = True, *, quoteChar: str = "", - escChar: OptionalType[str] = None, - escQuote: OptionalType[str] = None, + escChar: typing.Optional[str] = None, + escQuote: typing.Optional[str] = None, unquoteResults: bool = True, - endQuoteChar: OptionalType[str] = None, + endQuoteChar: typing.Optional[str] = None, convertWhitespaceEscapes: bool = True, ): super().__init__() @@ -3600,7 +3598,7 @@ class ParseExpression(ParserElement): post-processing parsed tokens. """ - def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False): + def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): super().__init__(savelist) self.exprs: List[ParserElement] if isinstance(exprs, _generatorType): @@ -3767,7 +3765,7 @@ class And(ParseExpression): Example:: integer = Word(nums) - name_expr = OneOrMore(Word(alphas)) + name_expr = Word(alphas)[1, ...] expr = And([integer("id"), name_expr("name"), integer("age")]) # more easily written as: @@ -3782,7 +3780,9 @@ def __init__(self, *args, **kwargs): def _generateDefaultName(self): return "-" - def __init__(self, exprs_arg: IterableType[ParserElement], savelist: bool = True): + def __init__( + self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True + ): exprs: List[ParserElement] = list(exprs_arg) if exprs and Ellipsis in exprs: tmp = [] @@ -3926,7 +3926,7 @@ class Or(ParseExpression): [['123'], ['3.1416'], ['789']] """ - def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False): + def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): super().__init__(exprs, savelist) if self.exprs: self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) @@ -4081,7 +4081,7 @@ class MatchFirst(ParseExpression): print(number.search_string("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] """ - def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False): + def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): super().__init__(exprs, savelist) if self.exprs: self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) @@ -4232,7 +4232,7 @@ class Each(ParseExpression): - size: 20 """ - def __init__(self, exprs: IterableType[ParserElement], savelist: bool = True): + def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True): super().__init__(exprs, savelist) if self.exprs: self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) @@ -4568,7 +4568,7 @@ class FollowedBy(ParseElementEnhance): label = data_word + FollowedBy(':') attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - OneOrMore(attr_expr).parse_string("shape: SQUARE color: BLACK posn: upper left").pprint() + attr_expr[1, ...].parse_string("shape: SQUARE color: BLACK posn: upper left").pprint() prints:: @@ -4619,7 +4619,7 @@ class PrecededBy(ParseElementEnhance): """ def __init__( - self, expr: Union[ParserElement, str], retreat: OptionalType[int] = None + self, expr: Union[ParserElement, str], retreat: typing.Optional[int] = None ): super().__init__(expr) self.expr = self.expr().leave_whitespace() @@ -4730,7 +4730,7 @@ class NotAny(ParseElementEnhance): # very crude boolean expression - to support parenthesis groups and # operation hierarchy, use infix_notation - boolean_expr = boolean_term + ZeroOrMore((AND | OR) + boolean_term) + boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...] # integers that are followed by "." are actually floats integer = Word(nums) + ~Char(".") @@ -4758,9 +4758,9 @@ class _MultipleMatch(ParseElementEnhance): def __init__( self, expr: ParserElement, - stop_on: OptionalType[Union[ParserElement, str]] = None, + stop_on: typing.Optional[Union[ParserElement, str]] = None, *, - stopOn: OptionalType[Union[ParserElement, str]] = None, + stopOn: typing.Optional[Union[ParserElement, str]] = None, ): super().__init__(expr) stopOn = stopOn or stop_on @@ -4849,7 +4849,7 @@ class OneOrMore(_MultipleMatch): attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).set_parse_action(' '.join)) text = "shape: SQUARE posn: upper left color: BLACK" - OneOrMore(attr_expr).parse_string(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] + attr_expr[1, ...].parse_string(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] # use stop_on attribute for OneOrMore to avoid reading label string as part of the data attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) @@ -4879,9 +4879,9 @@ class ZeroOrMore(_MultipleMatch): def __init__( self, expr: ParserElement, - stop_on: OptionalType[Union[ParserElement, str]] = None, + stop_on: typing.Optional[Union[ParserElement, str]] = None, *, - stopOn: OptionalType[Union[ParserElement, str]] = None, + stopOn: typing.Optional[Union[ParserElement, str]] = None, ): super().__init__(expr, stopOn=stopOn or stop_on) self.mayReturnEmpty = True @@ -5046,7 +5046,7 @@ def __init__( other: Union[ParserElement, str], include: bool = False, ignore: bool = None, - fail_on: OptionalType[Union[ParserElement, str]] = None, + fail_on: typing.Optional[Union[ParserElement, str]] = None, *, failOn: Union[ParserElement, str] = None, ): @@ -5143,7 +5143,7 @@ class Forward(ParseElementEnhance): parser created using ``Forward``. """ - def __init__(self, other: OptionalType[Union[ParserElement, str]] = None): + def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None): self.caller_frame = traceback.extract_stack(limit=2)[0] super().__init__(other, savelist=False) self.lshift_line = None @@ -5395,7 +5395,7 @@ def __init__( join_string: str = "", adjacent: bool = True, *, - joinString: OptionalType[str] = None, + joinString: typing.Optional[str] = None, ): super().__init__(expr) joinString = joinString if joinString is not None else join_string @@ -5482,10 +5482,10 @@ class Dict(TokenConverter): attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) # print attributes as plain groups - print(OneOrMore(attr_expr).parse_string(text).dump()) + print(attr_expr[1, ...].parse_string(text).dump()) - # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names - result = Dict(OneOrMore(Group(attr_expr))).parse_string(text) + # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) - Dict will auto-assign names + result = Dict(Group(attr_expr)[1, ...]).parse_string(text) print(result.dump()) # access named fields as dict entries, or output as dict @@ -5558,12 +5558,12 @@ class Suppress(TokenConverter): source = "a, b, c,d" wd = Word(alphas) - wd_list1 = wd + ZeroOrMore(',' + wd) + wd_list1 = wd + (',' + wd)[...] print(wd_list1.parse_string(source)) # often, delimiters that are useful during parsing are just in the # way afterward - use Suppress to keep them out of the parsed output - wd_list2 = wd + ZeroOrMore(Suppress(',') + wd) + wd_list2 = wd + (Suppress(',') + wd)[...] print(wd_list2.parse_string(source)) # Skipped text (using '...') can be suppressed as well @@ -5622,7 +5622,7 @@ def trace_parse_action(f: ParseAction) -> ParseAction: def remove_duplicate_chars(tokens): return ''.join(sorted(set(''.join(tokens)))) - wds = OneOrMore(wd).set_parse_action(remove_duplicate_chars) + wds = wd[1, ...].set_parse_action(remove_duplicate_chars) print(wds.parse_string("slkdjs sld sldd sdlf sdljf")) prints:: @@ -5728,18 +5728,18 @@ def token_map(func, *args) -> ParseAction: Example (compare the last to example in :class:`ParserElement.transform_string`:: - hex_ints = OneOrMore(Word(hexnums)).set_parse_action(token_map(int, 16)) + hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16)) hex_ints.run_tests(''' 00 11 22 aa FF 0a 0d 1a ''') upperword = Word(alphas).set_parse_action(token_map(str.upper)) - OneOrMore(upperword).run_tests(''' + upperword[1, ...].run_tests(''' my kingdom for a horse ''') wd = Word(alphas).set_parse_action(token_map(str.title)) - OneOrMore(wd).set_parse_action(' '.join).run_tests(''' + wd[1, ...].set_parse_action(' '.join).run_tests(''' now is the winter of our discontent made glorious summer by this sun of york ''') @@ -5795,7 +5795,9 @@ def autoname_elements() -> None: # build list of built-in expressions, for future reference if a global default value # gets updated -_builtin_exprs = [v for v in vars().values() if isinstance(v, ParserElement)] +_builtin_exprs: List[ParserElement] = [ + v for v in vars().values() if isinstance(v, ParserElement) +] # backward compatibility names tokenMap = token_map diff --git a/src/pip/_vendor/pyparsing/diagram/__init__.py b/src/pip/_vendor/pyparsing/diagram/__init__.py index 93c8c081e0f..1506d66bf4e 100644 --- a/src/pip/_vendor/pyparsing/diagram/__init__.py +++ b/src/pip/_vendor/pyparsing/diagram/__init__.py @@ -1,9 +1,8 @@ import railroad from pip._vendor import pyparsing -from pip._vendor.pkg_resources import resource_filename +import typing from typing import ( List, - Optional, NamedTuple, Generic, TypeVar, @@ -17,13 +16,41 @@ import inspect -with open(resource_filename(__name__, "template.jinja2"), encoding="utf-8") as fp: - template = Template(fp.read()) +jinja2_template_source = """\ + + + + {% if not head %} + + {% else %} + {{ head | safe }} + {% endif %} + + +{{ body | safe }} +{% for diagram in diagrams %} +
+

{{ diagram.title }}

+
{{ diagram.text }}
+
+ {{ diagram.svg }} +
+
+{% endfor %} + + +""" + +template = Template(jinja2_template_source) # Note: ideally this would be a dataclass, but we're supporting Python 3.5+ so we can't do this yet NamedDiagram = NamedTuple( "NamedDiagram", - [("name", str), ("diagram", Optional[railroad.DiagramItem]), ("index", int)], + [("name", str), ("diagram", typing.Optional[railroad.DiagramItem]), ("index", int)], ) """ A simple structure for associating a name with a railroad diagram @@ -107,6 +134,8 @@ def railroad_to_html(diagrams: List[NamedDiagram], **kwargs) -> str: """ data = [] for diagram in diagrams: + if diagram.diagram is None: + continue io = StringIO() diagram.diagram.writeSvg(io.write) title = diagram.name @@ -135,7 +164,7 @@ def resolve_partial(partial: "EditablePartial[T]") -> T: def to_railroad( element: pyparsing.ParserElement, - diagram_kwargs: Optional[dict] = None, + diagram_kwargs: typing.Optional[dict] = None, vertical: int = 3, show_results_names: bool = False, show_groups: bool = False, @@ -216,12 +245,12 @@ def __init__( parent: EditablePartial, number: int, name: str = None, - parent_index: Optional[int] = None, + parent_index: typing.Optional[int] = None, ): #: The pyparsing element that this represents self.element: pyparsing.ParserElement = element #: The name of the element - self.name: str = name + self.name: typing.Optional[str] = name #: The output Railroad element in an unconverted state self.converted: EditablePartial = converted #: The parent Railroad element, which we store so that we can extract this if it's duplicated @@ -229,7 +258,7 @@ def __init__( #: The order in which we found this element, used for sorting diagrams if this is extracted into a diagram self.number: int = number #: The index of this inside its parent - self.parent_index: Optional[int] = parent_index + self.parent_index: typing.Optional[int] = parent_index #: If true, we should extract this out into a subdiagram self.extract: bool = False #: If true, all of this element's children have been filled out @@ -270,7 +299,7 @@ class ConverterState: Stores some state that persists between recursions into the element tree """ - def __init__(self, diagram_kwargs: Optional[dict] = None): + def __init__(self, diagram_kwargs: typing.Optional[dict] = None): #: A dictionary mapping ParserElements to state relating to them self._element_diagram_states: Dict[int, ElementState] = {} #: A dictionary mapping ParserElement IDs to subdiagrams generated from them @@ -361,14 +390,14 @@ def _apply_diagram_item_enhancements(fn): def _inner( element: pyparsing.ParserElement, - parent: Optional[EditablePartial], + parent: typing.Optional[EditablePartial], lookup: ConverterState = None, vertical: int = None, index: int = 0, name_hint: str = None, show_results_names: bool = False, show_groups: bool = False, - ) -> Optional[EditablePartial]: + ) -> typing.Optional[EditablePartial]: ret = fn( element, @@ -412,14 +441,14 @@ def _visible_exprs(exprs: Iterable[pyparsing.ParserElement]): @_apply_diagram_item_enhancements def _to_diagram_element( element: pyparsing.ParserElement, - parent: Optional[EditablePartial], + parent: typing.Optional[EditablePartial], lookup: ConverterState = None, vertical: int = None, index: int = 0, name_hint: str = None, show_results_names: bool = False, show_groups: bool = False, -) -> Optional[EditablePartial]: +) -> typing.Optional[EditablePartial]: """ Recursively converts a PyParsing Element to a railroad Element :param lookup: The shared converter state that keeps track of useful things @@ -526,7 +555,9 @@ def _to_diagram_element( else: ret = EditablePartial.from_call(railroad.Group, label="", item="") elif isinstance(element, pyparsing.TokenConverter): - ret = EditablePartial.from_call(AnnotatedItem, label=type(element).__name__.lower(), item="") + ret = EditablePartial.from_call( + AnnotatedItem, label=type(element).__name__.lower(), item="" + ) elif isinstance(element, pyparsing.Opt): ret = EditablePartial.from_call(railroad.Optional, item="") elif isinstance(element, pyparsing.OneOrMore): diff --git a/src/pip/_vendor/pyparsing/diagram/template.jinja2 b/src/pip/_vendor/pyparsing/diagram/template.jinja2 deleted file mode 100644 index d2219fb0115..00000000000 --- a/src/pip/_vendor/pyparsing/diagram/template.jinja2 +++ /dev/null @@ -1,26 +0,0 @@ - - - - {% if not head %} - - {% else %} - {{ hear | safe }} - {% endif %} - - -{{ body | safe }} -{% for diagram in diagrams %} -
-

{{ diagram.title }}

-
{{ diagram.text }}
-
- {{ diagram.svg }} -
-
-{% endfor %} - - diff --git a/src/pip/_vendor/pyparsing/exceptions.py b/src/pip/_vendor/pyparsing/exceptions.py index e06513eb00f..a38447bb05b 100644 --- a/src/pip/_vendor/pyparsing/exceptions.py +++ b/src/pip/_vendor/pyparsing/exceptions.py @@ -2,7 +2,7 @@ import re import sys -from typing import Optional +import typing from .util import col, line, lineno, _collapse_string_to_ranges from .unicode import pyparsing_unicode as ppu @@ -25,7 +25,7 @@ def __init__( self, pstr: str, loc: int = 0, - msg: Optional[str] = None, + msg: typing.Optional[str] = None, elem=None, ): self.loc = loc diff --git a/src/pip/_vendor/pyparsing/helpers.py b/src/pip/_vendor/pyparsing/helpers.py index be8a3657884..9588b3b7801 100644 --- a/src/pip/_vendor/pyparsing/helpers.py +++ b/src/pip/_vendor/pyparsing/helpers.py @@ -1,6 +1,7 @@ # helpers.py import html.entities import re +import typing from . import __diag__ from .core import * @@ -14,8 +15,8 @@ def delimited_list( expr: Union[str, ParserElement], delim: Union[str, ParserElement] = ",", combine: bool = False, - min: OptionalType[int] = None, - max: OptionalType[int] = None, + min: typing.Optional[int] = None, + max: typing.Optional[int] = None, *, allow_trailing_delim: bool = False, ) -> ParserElement: @@ -69,9 +70,9 @@ def delimited_list( def counted_array( expr: ParserElement, - int_expr: OptionalType[ParserElement] = None, + int_expr: typing.Optional[ParserElement] = None, *, - intExpr: OptionalType[ParserElement] = None, + intExpr: typing.Optional[ParserElement] = None, ) -> ParserElement: """Helper to define a counted list of expressions. @@ -197,7 +198,7 @@ def must_match_these_tokens(s, l, t): def one_of( - strs: Union[IterableType[str], str], + strs: Union[typing.Iterable[str], str], caseless: bool = False, use_regex: bool = True, as_keyword: bool = False, @@ -337,7 +338,7 @@ def dict_of(key: ParserElement, value: ParserElement) -> ParserElement: text = "shape: SQUARE posn: upper left color: light blue texture: burlap" attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - print(OneOrMore(attr_expr).parse_string(text).dump()) + print(attr_expr[1, ...].parse_string(text).dump()) attr_label = label attr_value = Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join) @@ -461,7 +462,7 @@ def locatedExpr(expr: ParserElement) -> ParserElement: def nested_expr( opener: Union[str, ParserElement] = "(", closer: Union[str, ParserElement] = ")", - content: OptionalType[ParserElement] = None, + content: typing.Optional[ParserElement] = None, ignore_expr: ParserElement = quoted_string(), *, ignoreExpr: ParserElement = quoted_string(), @@ -682,6 +683,8 @@ def make_xml_tags( return _makeTags(tag_str, True) +any_open_tag: ParserElement +any_close_tag: ParserElement any_open_tag, any_close_tag = make_html_tags( Word(alphas, alphanums + "_:").set_name("any tag") ) @@ -710,7 +713,7 @@ class OpAssoc(Enum): InfixNotationOperatorArgType, int, OpAssoc, - OptionalType[ParseAction], + typing.Optional[ParseAction], ], Tuple[ InfixNotationOperatorArgType, @@ -840,7 +843,7 @@ def parseImpl(self, instring, loc, doActions=True): if rightLeftAssoc not in (OpAssoc.LEFT, OpAssoc.RIGHT): raise ValueError("operator must indicate right or left associativity") - thisExpr = Forward().set_name(term_name) + thisExpr: Forward = Forward().set_name(term_name) if rightLeftAssoc is OpAssoc.LEFT: if arity == 1: matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + opExpr[1, ...]) @@ -945,7 +948,7 @@ def eggs(z): assignment = Group(identifier + "=" + rvalue) stmt << (funcDef | assignment | identifier) - module_body = OneOrMore(stmt) + module_body = stmt[1, ...] parseTree = module_body.parseString(data) parseTree.pprint() @@ -1055,7 +1058,9 @@ def checkUnindent(s, l, t): # build list of built-in expressions, for future reference if a global default value # gets updated -_builtin_exprs = [v for v in vars().values() if isinstance(v, ParserElement)] +_builtin_exprs: List[ParserElement] = [ + v for v in vars().values() if isinstance(v, ParserElement) +] # pre-PEP8 compatible names diff --git a/src/pip/_vendor/pyparsing/results.py b/src/pip/_vendor/pyparsing/results.py index bb444df4e5b..00c9421d3b0 100644 --- a/src/pip/_vendor/pyparsing/results.py +++ b/src/pip/_vendor/pyparsing/results.py @@ -287,7 +287,7 @@ def remove_first(tokens): print(numlist.parse_string("0 123 321")) # -> ['123', '321'] label = Word(alphas) - patt = label("LABEL") + OneOrMore(Word(nums)) + patt = label("LABEL") + Word(nums)[1, ...] print(patt.parse_string("AAB 123 321").dump()) # Use pop() in a parse action to remove named result (note that corresponding value is not @@ -394,7 +394,7 @@ def extend(self, itemseq): Example:: - patt = OneOrMore(Word(alphas)) + patt = Word(alphas)[1, ...] # use a parse action to append the reverse of the matched strings, to make a palindrome def make_palindrome(tokens): @@ -487,7 +487,7 @@ def as_list(self) -> list: Example:: - patt = OneOrMore(Word(alphas)) + patt = Word(alphas)[1, ...] result = patt.parse_string("sldkj lsdkj sldkj") # even though the result prints in string-like form, it is actually a pyparsing ParseResults print(type(result), result) # -> ['sldkj', 'lsdkj', 'sldkj'] @@ -554,7 +554,7 @@ def get_name(self): user_data = (Group(house_number_expr)("house_number") | Group(ssn_expr)("ssn") | Group(integer)("age")) - user_info = OneOrMore(user_data) + user_info = user_data[1, ...] result = user_info.parse_string("22 111-22-3333 #221B") for item in result: diff --git a/src/pip/_vendor/pyparsing/testing.py b/src/pip/_vendor/pyparsing/testing.py index 991972f3fb2..84a0ef17078 100644 --- a/src/pip/_vendor/pyparsing/testing.py +++ b/src/pip/_vendor/pyparsing/testing.py @@ -1,7 +1,7 @@ # testing.py from contextlib import contextmanager -from typing import Optional +import typing from .core import ( ParserElement, @@ -237,12 +237,12 @@ def assertRaisesParseException(self, exc_type=ParseException, msg=None): @staticmethod def with_line_numbers( s: str, - start_line: Optional[int] = None, - end_line: Optional[int] = None, + start_line: typing.Optional[int] = None, + end_line: typing.Optional[int] = None, expand_tabs: bool = True, eol_mark: str = "|", - mark_spaces: Optional[str] = None, - mark_control: Optional[str] = None, + mark_spaces: typing.Optional[str] = None, + mark_control: typing.Optional[str] = None, ) -> str: """ Helpful method for debugging a parser - prints a string with line and column numbers. diff --git a/src/pip/_vendor/pyparsing/unicode.py b/src/pip/_vendor/pyparsing/unicode.py index 92261487c7a..06526203911 100644 --- a/src/pip/_vendor/pyparsing/unicode.py +++ b/src/pip/_vendor/pyparsing/unicode.py @@ -120,7 +120,18 @@ class pyparsing_unicode(unicode_set): A namespace class for defining common language unicode_sets. """ - _ranges: UnicodeRangeList = [(32, sys.maxunicode)] + # fmt: off + + # define ranges in language character sets + _ranges: UnicodeRangeList = [ + (0x0020, sys.maxunicode), + ] + + class BasicMultilingualPlane(unicode_set): + "Unicode set for the Basic Multilingual Plane" + _ranges: UnicodeRangeList = [ + (0x0020, 0xFFFF), + ] class Latin1(unicode_set): "Unicode set for Latin-1 Unicode Character Range" @@ -278,11 +289,13 @@ class Hangul(unicode_set): class CJK(Chinese, Japanese, Hangul): "Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range" - pass class Thai(unicode_set): "Unicode set for Thai Unicode Character Range" - _ranges: UnicodeRangeList = [(0x0E01, 0x0E3A), (0x0E3F, 0x0E5B)] + _ranges: UnicodeRangeList = [ + (0x0E01, 0x0E3A), + (0x0E3F, 0x0E5B) + ] class Arabic(unicode_set): "Unicode set for Arabic Unicode Character Range" @@ -308,7 +321,12 @@ class Hebrew(unicode_set): class Devanagari(unicode_set): "Unicode set for Devanagari Unicode Character Range" - _ranges: UnicodeRangeList = [(0x0900, 0x097F), (0xA8E0, 0xA8FF)] + _ranges: UnicodeRangeList = [ + (0x0900, 0x097F), + (0xA8E0, 0xA8FF) + ] + + # fmt: on pyparsing_unicode.Japanese._ranges = ( @@ -317,7 +335,9 @@ class Devanagari(unicode_set): + pyparsing_unicode.Japanese.Katakana._ranges ) -# define ranges in language character sets +pyparsing_unicode.BMP = pyparsing_unicode.BasicMultilingualPlane + +# add language identifiers using language Unicode pyparsing_unicode.العربية = pyparsing_unicode.Arabic pyparsing_unicode.中文 = pyparsing_unicode.Chinese pyparsing_unicode.кириллица = pyparsing_unicode.Cyrillic diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt index ccec77a4213..f716be64deb 100644 --- a/src/pip/_vendor/vendor.txt +++ b/src/pip/_vendor/vendor.txt @@ -6,7 +6,7 @@ msgpack==1.0.4 packaging==21.3 pep517==0.12.0 platformdirs==2.5.2 -pyparsing==3.0.8 +pyparsing==3.0.9 requests==2.27.1 certifi==2021.10.08 chardet==4.0.0 From 73290afb56080af919eadc92085c6e2cd68568b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sat, 16 Jul 2022 20:21:49 +0200 Subject: [PATCH 05/14] Upgrade urllib3 to 1.26.10 --- news/urllib3.vendor.rst | 1 + src/pip/_vendor/urllib3/_version.py | 2 +- src/pip/_vendor/urllib3/connection.py | 2 +- src/pip/_vendor/urllib3/connectionpool.py | 2 ++ src/pip/_vendor/urllib3/contrib/pyopenssl.py | 1 - src/pip/_vendor/urllib3/contrib/securetransport.py | 1 - src/pip/_vendor/urllib3/packages/six.py | 1 - src/pip/_vendor/urllib3/util/url.py | 5 ++++- src/pip/_vendor/urllib3/util/wait.py | 1 - src/pip/_vendor/vendor.txt | 2 +- 10 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 news/urllib3.vendor.rst diff --git a/news/urllib3.vendor.rst b/news/urllib3.vendor.rst new file mode 100644 index 00000000000..a637370403b --- /dev/null +++ b/news/urllib3.vendor.rst @@ -0,0 +1 @@ +Upgrade urllib3 to 1.26.10 diff --git a/src/pip/_vendor/urllib3/_version.py b/src/pip/_vendor/urllib3/_version.py index d905b69755a..c8ac29d0824 100644 --- a/src/pip/_vendor/urllib3/_version.py +++ b/src/pip/_vendor/urllib3/_version.py @@ -1,2 +1,2 @@ # This file is protected via CODEOWNERS -__version__ = "1.26.9" +__version__ = "1.26.10" diff --git a/src/pip/_vendor/urllib3/connection.py b/src/pip/_vendor/urllib3/connection.py index 7bf395bdac1..10fb36c4e35 100644 --- a/src/pip/_vendor/urllib3/connection.py +++ b/src/pip/_vendor/urllib3/connection.py @@ -68,7 +68,7 @@ class BrokenPipeError(Exception): # When it comes time to update this value as a part of regular maintenance # (ie test_recent_date is failing) update it to ~6 months before the current date. -RECENT_DATE = datetime.date(2020, 7, 1) +RECENT_DATE = datetime.date(2022, 1, 1) _CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") diff --git a/src/pip/_vendor/urllib3/connectionpool.py b/src/pip/_vendor/urllib3/connectionpool.py index 15bffcb23a9..96339e90af1 100644 --- a/src/pip/_vendor/urllib3/connectionpool.py +++ b/src/pip/_vendor/urllib3/connectionpool.py @@ -767,6 +767,8 @@ def _is_ssl_error_message_from_http_proxy(ssl_error): isinstance(e, BaseSSLError) and self.proxy and _is_ssl_error_message_from_http_proxy(e) + and conn.proxy + and conn.proxy.scheme == "https" ): e = ProxyError( "Your proxy appears to only use HTTP and not HTTPS, " diff --git a/src/pip/_vendor/urllib3/contrib/pyopenssl.py b/src/pip/_vendor/urllib3/contrib/pyopenssl.py index 3130f51ac06..5f1d2d0b7af 100644 --- a/src/pip/_vendor/urllib3/contrib/pyopenssl.py +++ b/src/pip/_vendor/urllib3/contrib/pyopenssl.py @@ -406,7 +406,6 @@ def makefile(self, mode, bufsize=-1): self._makefile_refs += 1 return _fileobject(self, mode, bufsize, close=True) - else: # Platform-specific: Python 3 makefile = backport_makefile diff --git a/src/pip/_vendor/urllib3/contrib/securetransport.py b/src/pip/_vendor/urllib3/contrib/securetransport.py index b4ca80b88be..4a06bc69d5c 100644 --- a/src/pip/_vendor/urllib3/contrib/securetransport.py +++ b/src/pip/_vendor/urllib3/contrib/securetransport.py @@ -770,7 +770,6 @@ def makefile(self, mode, bufsize=-1): self._makefile_refs += 1 return _fileobject(self, mode, bufsize, close=True) - else: # Platform-specific: Python 3 def makefile(self, mode="r", buffering=None, *args, **kwargs): diff --git a/src/pip/_vendor/urllib3/packages/six.py b/src/pip/_vendor/urllib3/packages/six.py index ba50acb0624..f099a3dcd28 100644 --- a/src/pip/_vendor/urllib3/packages/six.py +++ b/src/pip/_vendor/urllib3/packages/six.py @@ -772,7 +772,6 @@ def reraise(tp, value, tb=None): value = None tb = None - else: def exec_(_code_, _globs_=None, _locs_=None): diff --git a/src/pip/_vendor/urllib3/util/url.py b/src/pip/_vendor/urllib3/util/url.py index 3651c43182a..86bd8b48ab0 100644 --- a/src/pip/_vendor/urllib3/util/url.py +++ b/src/pip/_vendor/urllib3/util/url.py @@ -279,6 +279,9 @@ def _normalize_host(host, scheme): if scheme in NORMALIZABLE_SCHEMES: is_ipv6 = IPV6_ADDRZ_RE.match(host) if is_ipv6: + # IPv6 hosts of the form 'a::b%zone' are encoded in a URL as + # such per RFC 6874: 'a::b%25zone'. Unquote the ZoneID + # separator as necessary to return a valid RFC 4007 scoped IP. match = ZONE_ID_RE.search(host) if match: start, end = match.span(1) @@ -331,7 +334,7 @@ def parse_url(url): """ Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is performed to parse incomplete urls. Fields not provided will be None. - This parser is RFC 3986 compliant. + This parser is RFC 3986 and RFC 6874 compliant. The parser logic and helper functions are based heavily on work done in the ``rfc3986`` module. diff --git a/src/pip/_vendor/urllib3/util/wait.py b/src/pip/_vendor/urllib3/util/wait.py index c280646c7be..21b4590b3dc 100644 --- a/src/pip/_vendor/urllib3/util/wait.py +++ b/src/pip/_vendor/urllib3/util/wait.py @@ -42,7 +42,6 @@ class NoWayToWaitForSocketError(Exception): def _retry_on_intr(fn, timeout): return fn(timeout) - else: # Old and broken Pythons. def _retry_on_intr(fn, timeout): diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt index f716be64deb..e87f50ccbb1 100644 --- a/src/pip/_vendor/vendor.txt +++ b/src/pip/_vendor/vendor.txt @@ -11,7 +11,7 @@ requests==2.27.1 certifi==2021.10.08 chardet==4.0.0 idna==3.3 - urllib3==1.26.9 + urllib3==1.26.10 rich==12.2.0 pygments==2.11.2 typing_extensions==4.2.0 From 373fca928e012413f502ffc911b8746af24532a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Sat, 16 Jul 2022 20:22:03 +0200 Subject: [PATCH 06/14] Upgrade rich to 12.5.1 --- news/rich.vendor.rst | 1 + src/pip/_vendor/rich/__init__.py | 8 +- src/pip/_vendor/rich/_export_format.py | 78 +++ src/pip/_vendor/rich/_inspect.py | 84 +++- src/pip/_vendor/rich/_lru_cache.py | 38 -- src/pip/_vendor/rich/_win32_console.py | 36 +- src/pip/_vendor/rich/_windows_renderer.py | 3 + src/pip/_vendor/rich/_wrap.py | 11 +- src/pip/_vendor/rich/box.py | 34 ++ src/pip/_vendor/rich/cells.py | 34 +- src/pip/_vendor/rich/console.py | 581 ++++++++++++---------- src/pip/_vendor/rich/control.py | 60 ++- src/pip/_vendor/rich/default_styles.py | 5 + src/pip/_vendor/rich/diagnose.py | 2 + src/pip/_vendor/rich/file_proxy.py | 10 +- src/pip/_vendor/rich/highlighter.py | 59 +++ src/pip/_vendor/rich/jupyter.py | 11 +- src/pip/_vendor/rich/live.py | 10 +- src/pip/_vendor/rich/markup.py | 3 +- src/pip/_vendor/rich/measure.py | 4 +- src/pip/_vendor/rich/pretty.py | 31 +- src/pip/_vendor/rich/progress.py | 167 +++++-- src/pip/_vendor/rich/progress_bar.py | 24 +- src/pip/_vendor/rich/rule.py | 37 +- src/pip/_vendor/rich/segment.py | 70 ++- src/pip/_vendor/rich/spinner.py | 6 +- src/pip/_vendor/rich/style.py | 90 ++-- src/pip/_vendor/rich/syntax.py | 205 +++++++- src/pip/_vendor/rich/table.py | 2 +- src/pip/_vendor/rich/terminal_theme.py | 50 +- src/pip/_vendor/rich/text.py | 17 +- src/pip/_vendor/rich/traceback.py | 6 +- src/pip/_vendor/rich/tree.py | 2 +- src/pip/_vendor/vendor.txt | 2 +- 34 files changed, 1224 insertions(+), 557 deletions(-) create mode 100644 news/rich.vendor.rst create mode 100644 src/pip/_vendor/rich/_export_format.py delete mode 100644 src/pip/_vendor/rich/_lru_cache.py diff --git a/news/rich.vendor.rst b/news/rich.vendor.rst new file mode 100644 index 00000000000..536d6ea28f8 --- /dev/null +++ b/news/rich.vendor.rst @@ -0,0 +1 @@ +Upgrade rich to 12.5.1 diff --git a/src/pip/_vendor/rich/__init__.py b/src/pip/_vendor/rich/__init__.py index 657811b5ebb..d35875dbb81 100644 --- a/src/pip/_vendor/rich/__init__.py +++ b/src/pip/_vendor/rich/__init__.py @@ -1,7 +1,7 @@ """Rich text and beautiful formatting in the terminal.""" import os -from typing import Callable, IO, TYPE_CHECKING, Any, Optional, Union +from typing import IO, TYPE_CHECKING, Any, Callable, Optional, Union from ._extension import load_ipython_extension # noqa: F401 @@ -13,7 +13,11 @@ # Global console used by alternative print _console: Optional["Console"] = None -_IMPORT_CWD = os.path.abspath(os.getcwd()) +try: + _IMPORT_CWD = os.path.abspath(os.getcwd()) +except FileNotFoundError: + # Can happen if the cwd has been deleted + _IMPORT_CWD = "" def get_console() -> "Console": diff --git a/src/pip/_vendor/rich/_export_format.py b/src/pip/_vendor/rich/_export_format.py new file mode 100644 index 00000000000..b79c13069b9 --- /dev/null +++ b/src/pip/_vendor/rich/_export_format.py @@ -0,0 +1,78 @@ +CONSOLE_HTML_FORMAT = """\ + + + + + + + + +
{code}
+
+ + +""" + +CONSOLE_SVG_FORMAT = """\ + + + + + + + + + {lines} + + + {chrome} + + {backgrounds} + + {matrix} + + + +""" + +_SVG_FONT_FAMILY = "Rich Fira Code" +_SVG_CLASSES_PREFIX = "rich-svg" diff --git a/src/pip/_vendor/rich/_inspect.py b/src/pip/_vendor/rich/_inspect.py index 01713e57673..30446ceb3f0 100644 --- a/src/pip/_vendor/rich/_inspect.py +++ b/src/pip/_vendor/rich/_inspect.py @@ -2,9 +2,10 @@ import inspect from inspect import cleandoc, getdoc, getfile, isclass, ismodule, signature -from typing import Any, Iterable, Optional, Tuple +from typing import Any, Collection, Iterable, Optional, Tuple, Type, Union from .console import Group, RenderableType +from .control import escape_control_codes from .highlighter import ReprHighlighter from .jupyter import JupyterMixin from .panel import Panel @@ -19,12 +20,6 @@ def _first_paragraph(doc: str) -> str: return paragraph -def _reformat_doc(doc: str) -> str: - """Reformat docstring.""" - doc = cleandoc(doc).strip() - return doc - - class Inspect(JupyterMixin): """A renderable to inspect any Python Object. @@ -112,11 +107,13 @@ def _get_signature(self, name: str, obj: Any) -> Optional[Text]: # If obj is a module, there may be classes (which are callable) to display if inspect.isclass(obj): prefix = "class" + elif inspect.iscoroutinefunction(obj): + prefix = "async def" else: prefix = "def" qual_signature = Text.assemble( - (f"{prefix} ", f"inspect.{prefix}"), + (f"{prefix} ", f"inspect.{prefix.replace(' ', '_')}"), (qualname, "inspect.callable"), signature_text, ) @@ -161,11 +158,9 @@ def safe_getattr(attr_name: str) -> Tuple[Any, Any]: yield "" if self.docs: - _doc = getdoc(obj) + _doc = self._get_formatted_doc(obj) if _doc is not None: - if not self.help: - _doc = _first_paragraph(_doc) - doc_text = Text(_reformat_doc(_doc), style="inspect.help") + doc_text = Text(_doc, style="inspect.help") doc_text = highlighter(doc_text) yield doc_text yield "" @@ -200,13 +195,10 @@ def safe_getattr(attr_name: str) -> Tuple[Any, Any]: add_row(key_text, Pretty(value, highlighter=highlighter)) else: if self.docs: - docs = getdoc(value) + docs = self._get_formatted_doc(value) if docs is not None: - _doc = _reformat_doc(str(docs)) - if not self.help: - _doc = _first_paragraph(_doc) - _signature_text.append("\n" if "\n" in _doc else " ") - doc = highlighter(_doc) + _signature_text.append("\n" if "\n" in docs else " ") + doc = highlighter(docs) doc.stylize("inspect.doc") _signature_text.append(doc) @@ -220,3 +212,59 @@ def safe_getattr(attr_name: str) -> Tuple[Any, Any]: f"[b cyan]{not_shown_count}[/][i] attribute(s) not shown.[/i] " f"Run [b][magenta]inspect[/]([not b]inspect[/])[/b] for options." ) + + def _get_formatted_doc(self, object_: Any) -> Optional[str]: + """ + Extract the docstring of an object, process it and returns it. + The processing consists in cleaning up the doctring's indentation, + taking only its 1st paragraph if `self.help` is not True, + and escape its control codes. + + Args: + object_ (Any): the object to get the docstring from. + + Returns: + Optional[str]: the processed docstring, or None if no docstring was found. + """ + docs = getdoc(object_) + if docs is None: + return None + docs = cleandoc(docs).strip() + if not self.help: + docs = _first_paragraph(docs) + return escape_control_codes(docs) + + +def get_object_types_mro(obj: Union[object, Type[Any]]) -> Tuple[type, ...]: + """Returns the MRO of an object's class, or of the object itself if it's a class.""" + if not hasattr(obj, "__mro__"): + # N.B. we cannot use `if type(obj) is type` here because it doesn't work with + # some types of classes, such as the ones that use abc.ABCMeta. + obj = type(obj) + return getattr(obj, "__mro__", ()) + + +def get_object_types_mro_as_strings(obj: object) -> Collection[str]: + """ + Returns the MRO of an object's class as full qualified names, or of the object itself if it's a class. + + Examples: + `object_types_mro_as_strings(JSONDecoder)` will return `['json.decoder.JSONDecoder', 'builtins.object']` + """ + return [ + f'{getattr(type_, "__module__", "")}.{getattr(type_, "__qualname__", "")}' + for type_ in get_object_types_mro(obj) + ] + + +def is_object_one_of_types( + obj: object, fully_qualified_types_names: Collection[str] +) -> bool: + """ + Returns `True` if the given object's class (or the object itself, if it's a class) has one of the + fully qualified names in its MRO. + """ + for type_name in get_object_types_mro_as_strings(obj): + if type_name in fully_qualified_types_names: + return True + return False diff --git a/src/pip/_vendor/rich/_lru_cache.py b/src/pip/_vendor/rich/_lru_cache.py deleted file mode 100644 index 10c818743be..00000000000 --- a/src/pip/_vendor/rich/_lru_cache.py +++ /dev/null @@ -1,38 +0,0 @@ -from typing import Dict, Generic, TypeVar, TYPE_CHECKING -import sys - -CacheKey = TypeVar("CacheKey") -CacheValue = TypeVar("CacheValue") - -if sys.version_info < (3, 9): - from pip._vendor.typing_extensions import OrderedDict -else: - from collections import OrderedDict - - -class LRUCache(OrderedDict[CacheKey, CacheValue]): - """ - A dictionary-like container that stores a given maximum items. - - If an additional item is added when the LRUCache is full, the least - recently used key is discarded to make room for the new item. - - """ - - def __init__(self, cache_size: int) -> None: - self.cache_size = cache_size - super().__init__() - - def __setitem__(self, key: CacheKey, value: CacheValue) -> None: - """Store a new views, potentially discarding an old value.""" - if key not in self: - if len(self) >= self.cache_size: - self.popitem(last=False) - super().__setitem__(key, value) - - def __getitem__(self, key: CacheKey) -> CacheValue: - """Gets the item, but also makes it most recent.""" - value: CacheValue = super().__getitem__(key) - super().__delitem__(key) - super().__setitem__(key, value) - return value diff --git a/src/pip/_vendor/rich/_win32_console.py b/src/pip/_vendor/rich/_win32_console.py index d42cd791607..81b10829053 100644 --- a/src/pip/_vendor/rich/_win32_console.py +++ b/src/pip/_vendor/rich/_win32_console.py @@ -263,6 +263,30 @@ def SetConsoleCursorPosition( return bool(_SetConsoleCursorPosition(std_handle, coords)) +_GetConsoleCursorInfo = windll.kernel32.GetConsoleCursorInfo +_GetConsoleCursorInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(CONSOLE_CURSOR_INFO), +] +_GetConsoleCursorInfo.restype = wintypes.BOOL + + +def GetConsoleCursorInfo( + std_handle: wintypes.HANDLE, cursor_info: CONSOLE_CURSOR_INFO +) -> bool: + """Get the cursor info - used to get cursor visibility and width + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + cursor_info (CONSOLE_CURSOR_INFO): CONSOLE_CURSOR_INFO ctype struct that receives information + about the console's cursor. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_GetConsoleCursorInfo(std_handle, byref(cursor_info))) + + _SetConsoleCursorInfo = windll.kernel32.SetConsoleCursorInfo _SetConsoleCursorInfo.argtypes = [ wintypes.HANDLE, @@ -523,12 +547,14 @@ def move_cursor_backward(self) -> None: def hide_cursor(self) -> None: """Hide the cursor""" - invisible_cursor = CONSOLE_CURSOR_INFO(dwSize=100, bVisible=0) + current_cursor_size = self._get_cursor_size() + invisible_cursor = CONSOLE_CURSOR_INFO(dwSize=current_cursor_size, bVisible=0) SetConsoleCursorInfo(self._handle, cursor_info=invisible_cursor) def show_cursor(self) -> None: """Show the cursor""" - visible_cursor = CONSOLE_CURSOR_INFO(dwSize=100, bVisible=1) + current_cursor_size = self._get_cursor_size() + visible_cursor = CONSOLE_CURSOR_INFO(dwSize=current_cursor_size, bVisible=1) SetConsoleCursorInfo(self._handle, cursor_info=visible_cursor) def set_title(self, title: str) -> None: @@ -540,6 +566,12 @@ def set_title(self, title: str) -> None: assert len(title) < 255, "Console title must be less than 255 characters" SetConsoleTitle(title) + def _get_cursor_size(self) -> int: + """Get the percentage of the character cell that is filled by the cursor""" + cursor_info = CONSOLE_CURSOR_INFO() + GetConsoleCursorInfo(self._handle, cursor_info=cursor_info) + return int(cursor_info.dwSize) + if __name__ == "__main__": handle = GetStdHandle() diff --git a/src/pip/_vendor/rich/_windows_renderer.py b/src/pip/_vendor/rich/_windows_renderer.py index 066e585ddc0..5ece05649e7 100644 --- a/src/pip/_vendor/rich/_windows_renderer.py +++ b/src/pip/_vendor/rich/_windows_renderer.py @@ -51,3 +51,6 @@ def legacy_windows_render(buffer: Iterable[Segment], term: LegacyWindowsTerm) -> term.erase_start_of_line() elif mode == 2: term.erase_line() + elif control_type == ControlType.SET_WINDOW_TITLE: + _, title = cast(Tuple[ControlType, str], control_code) + term.set_title(title) diff --git a/src/pip/_vendor/rich/_wrap.py b/src/pip/_vendor/rich/_wrap.py index b537757a573..c45f193f74a 100644 --- a/src/pip/_vendor/rich/_wrap.py +++ b/src/pip/_vendor/rich/_wrap.py @@ -1,8 +1,8 @@ import re from typing import Iterable, List, Tuple -from .cells import cell_len, chop_cells from ._loop import loop_last +from .cells import cell_len, chop_cells re_word = re.compile(r"\s*\S+\s*") @@ -27,14 +27,15 @@ def divide_line(text: str, width: int, fold: bool = True) -> List[int]: if line_position + word_length > width: if word_length > width: if fold: - for last, line in loop_last( - chop_cells(word, width, position=line_position) - ): + chopped_words = chop_cells(word, max_size=width, position=0) + for last, line in loop_last(chopped_words): + if start: + append(start) + if last: line_position = _cell_len(line) else: start += len(line) - append(start) else: if start: append(start) diff --git a/src/pip/_vendor/rich/box.py b/src/pip/_vendor/rich/box.py index aec2926bea2..d0b07cf57e0 100644 --- a/src/pip/_vendor/rich/box.py +++ b/src/pip/_vendor/rich/box.py @@ -88,6 +88,16 @@ def substitute(self, options: "ConsoleOptions", safe: bool = True) -> "Box": box = ASCII return box + def get_plain_headed_box(self) -> "Box": + """If this box uses special characters for the borders of the header, then + return the equivalent box that does not. + + Returns: + Box: The most similar Box that doesn't use header-specific box characters. + If the current Box already satisfies this criterion, then it's returned. + """ + return PLAIN_HEADED_SUBSTITUTIONS.get(self, self) + def get_top(self, widths: Iterable[int]) -> str: """Get the top of a simple box. @@ -419,6 +429,20 @@ def get_bottom(self, widths: Iterable[int]) -> str: """ ) +MARKDOWN: Box = Box( + """\ + +| || +|-|| +| || +|-|| +|-|| +| || + +""", + ascii=True, +) + # Map Boxes that don't render with raster fonts on to equivalent that do LEGACY_WINDOWS_SUBSTITUTIONS = { ROUNDED: SQUARE, @@ -429,6 +453,15 @@ def get_bottom(self, widths: Iterable[int]) -> str: HEAVY_HEAD: SQUARE, } +# Map headed boxes to their headerless equivalents +PLAIN_HEADED_SUBSTITUTIONS = { + HEAVY_HEAD: SQUARE, + SQUARE_DOUBLE_HEAD: SQUARE, + MINIMAL_DOUBLE_HEAD: MINIMAL, + MINIMAL_HEAVY_HEAD: MINIMAL, + ASCII_DOUBLE_HEAD: ASCII2, +} + if __name__ == "__main__": # pragma: no cover @@ -461,6 +494,7 @@ def get_bottom(self, widths: Iterable[int]) -> str: "HEAVY_HEAD", "DOUBLE", "DOUBLE_EDGE", + "MARKDOWN", ] console.print(Panel("[bold green]Box Constants", style="green"), justify="center") diff --git a/src/pip/_vendor/rich/cells.py b/src/pip/_vendor/rich/cells.py index d7adf5a046d..139b949f7f2 100644 --- a/src/pip/_vendor/rich/cells.py +++ b/src/pip/_vendor/rich/cells.py @@ -1,31 +1,44 @@ import re from functools import lru_cache -from typing import Dict, List +from typing import Callable, List from ._cell_widths import CELL_WIDTHS -from ._lru_cache import LRUCache # Regex to match sequence of the most common character ranges _is_single_cell_widths = re.compile("^[\u0020-\u006f\u00a0\u02ff\u0370-\u0482]*$").match -def cell_len(text: str, _cache: Dict[str, int] = LRUCache(1024 * 4)) -> int: +@lru_cache(4096) +def cached_cell_len(text: str) -> int: """Get the number of cells required to display text. + This method always caches, which may use up a lot of memory. It is recommended to use + `cell_len` over this method. + Args: text (str): Text to display. Returns: int: Get the number of cells required to display text. """ - cached_result = _cache.get(text, None) - if cached_result is not None: - return cached_result + _get_size = get_character_cell_size + total_size = sum(_get_size(character) for character in text) + return total_size + + +def cell_len(text: str, _cell_len: Callable[[str], int] = cached_cell_len) -> int: + """Get the number of cells required to display text. + Args: + text (str): Text to display. + + Returns: + int: Get the number of cells required to display text. + """ + if len(text) < 512: + return _cell_len(text) _get_size = get_character_cell_size total_size = sum(_get_size(character) for character in text) - if len(text) <= 512: - _cache[text] = total_size return total_size @@ -80,7 +93,7 @@ def set_cell_size(text: str, total: int) -> str: return text + " " * (total - size) return text[:total] - if not total: + if total <= 0: return "" cell_size = cell_len(text) if cell_size == total: @@ -109,7 +122,8 @@ def set_cell_size(text: str, total: int) -> str: # TODO: This is inefficient # TODO: This might not work with CWJ type characters def chop_cells(text: str, max_size: int, position: int = 0) -> List[str]: - """Break text in to equal (cell) length strings.""" + """Break text in to equal (cell) length strings, returning the characters in reverse + order""" _get_character_cell_size = get_character_cell_size characters = [ (character, _get_character_cell_size(character)) for character in text diff --git a/src/pip/_vendor/rich/console.py b/src/pip/_vendor/rich/console.py index 8c305712dc7..93a10b0b500 100644 --- a/src/pip/_vendor/rich/console.py +++ b/src/pip/_vendor/rich/console.py @@ -4,6 +4,7 @@ import platform import sys import threading +import zlib from abc import ABC, abstractmethod from dataclasses import dataclass, field from datetime import datetime @@ -12,6 +13,7 @@ from html import escape from inspect import isclass from itertools import islice +from math import ceil from time import monotonic from types import FrameType, ModuleType, TracebackType from typing import ( @@ -43,9 +45,10 @@ from . import errors, themes from ._emoji_replace import _emoji_replace +from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT from ._log_render import FormatTimeCallable, LogRender from .align import Align, AlignMethod -from .color import ColorSystem +from .color import ColorSystem, blend_rgb from .control import Control from .emoji import EmojiVariant from .highlighter import NullHighlighter, ReprHighlighter @@ -69,6 +72,8 @@ from .live import Live from .status import Status +JUPYTER_DEFAULT_COLUMNS = 115 +JUPYTER_DEFAULT_LINES = 100 WINDOWS = platform.system() == "Windows" HighlighterType = Callable[[Union[str, "Text"]], "Text"] @@ -82,159 +87,22 @@ class NoChange: NO_CHANGE = NoChange() +try: + _STDIN_FILENO = sys.__stdin__.fileno() +except Exception: + _STDIN_FILENO = 0 try: _STDOUT_FILENO = sys.__stdout__.fileno() except Exception: _STDOUT_FILENO = 1 - try: _STDERR_FILENO = sys.__stderr__.fileno() except Exception: _STDERR_FILENO = 2 -_STD_STREAMS = (_STDOUT_FILENO, _STDERR_FILENO) - -CONSOLE_HTML_FORMAT = """\ - - - - - - - - -
{code}
-
- - -""" - -CONSOLE_SVG_FORMAT = """\ - - - - -
-
-
- - - - - -
{title}
-
-
- {code} -
-
-
- -
-
-""" +_STD_STREAMS = (_STDIN_FILENO, _STDOUT_FILENO, _STDERR_FILENO) +_STD_STREAMS_OUTPUT = (_STDOUT_FILENO, _STDERR_FILENO) + _TERM_COLORS = {"256color": ColorSystem.EIGHT_BIT, "16color": ColorSystem.STANDARD} @@ -790,12 +658,19 @@ def __init__( self.is_jupyter = _is_jupyter() if force_jupyter is None else force_jupyter if self.is_jupyter: - width = width or 93 - height = height or 100 + if width is None: + jupyter_columns = self._environ.get("JUPYTER_COLUMNS") + if jupyter_columns is not None and jupyter_columns.isdigit(): + width = int(jupyter_columns) + else: + width = JUPYTER_DEFAULT_COLUMNS + if height is None: + jupyter_lines = self._environ.get("JUPYTER_LINES") + if jupyter_lines is not None and jupyter_lines.isdigit(): + height = int(jupyter_lines) + else: + height = JUPYTER_DEFAULT_LINES - self.soft_wrap = soft_wrap - self._width = width - self._height = height self.tab_size = tab_size self.record = record self._markup = markup @@ -807,6 +682,7 @@ def __init__( if legacy_windows is None else legacy_windows ) + if width is None: columns = self._environ.get("COLUMNS") if columns is not None and columns.isdigit(): @@ -1045,6 +921,13 @@ def is_terminal(self) -> bool: """ if self._force_terminal is not None: return self._force_terminal + + if hasattr(sys.stdin, "__module__") and sys.stdin.__module__.startswith( + "idlelib" + ): + # Return False for Idle which claims to be a tty but can't handle ansi codes + return False + isatty: Optional[Callable[[], bool]] = getattr(self.file, "isatty", None) try: return False if isatty is None else isatty() @@ -1099,16 +982,16 @@ def size(self) -> ConsoleDimensions: if WINDOWS: # pragma: no cover try: width, height = os.get_terminal_size() - except OSError: # Probably not a terminal + except (AttributeError, ValueError, OSError): # Probably not a terminal pass else: - try: - width, height = os.get_terminal_size(sys.__stdin__.fileno()) - except (AttributeError, ValueError, OSError): + for file_descriptor in _STD_STREAMS: try: - width, height = os.get_terminal_size(sys.__stdout__.fileno()) + width, height = os.get_terminal_size(file_descriptor) except (AttributeError, ValueError, OSError): pass + else: + break columns = self._environ.get("COLUMNS") if columns is not None and columns.isdigit(): @@ -1311,6 +1194,38 @@ def is_alt_screen(self) -> bool: """ return self._is_alt_screen + def set_window_title(self, title: str) -> bool: + """Set the title of the console terminal window. + + Warning: There is no means within Rich of "resetting" the window title to its + previous value, meaning the title you set will persist even after your application + exits. + + ``fish`` shell resets the window title before and after each command by default, + negating this issue. Windows Terminal and command prompt will also reset the title for you. + Most other shells and terminals, however, do not do this. + + Some terminals may require configuration changes before you can set the title. + Some terminals may not support setting the title at all. + + Other software (including the terminal itself, the shell, custom prompts, plugins, etc.) + may also set the terminal window title. This could result in whatever value you write + using this method being overwritten. + + Args: + title (str): The new title of the terminal window. + + Returns: + bool: True if the control code to change the terminal title was + written, otherwise False. Note that a return value of True + does not guarantee that the window title has actually changed, + since the feature may be unsupported/disabled in some terminals. + """ + if self.is_terminal: + self.control(Control.title(title)) + return True + return False + def screen( self, hide_cursor: bool = True, style: Optional[StyleType] = None ) -> "ScreenContext": @@ -1422,6 +1337,11 @@ def render_lines( _rendered = self.render(renderable, render_options) if style: _rendered = Segment.apply_style(_rendered, style) + + render_height = render_options.height + if render_height is not None: + render_height = max(0, render_height) + lines = list( islice( Segment.split_and_crop_lines( @@ -1429,9 +1349,10 @@ def render_lines( render_options.max_width, include_new_lines=new_lines, pad=pad, + style=style, ), None, - render_options.height, + render_height, ) ) if render_options.height is not None: @@ -1901,7 +1822,7 @@ def print_exception( """Prints a rich render of the last exception and traceback. Args: - width (Optional[int], optional): Number of characters used to render code. Defaults to 88. + width (Optional[int], optional): Number of characters used to render code. Defaults to 100. extra_lines (int, optional): Additional lines of code to render. Defaults to 3. theme (str, optional): Override pygments theme used in traceback word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. @@ -1947,7 +1868,7 @@ def _caller_frame_info( frame = currentframe() if frame is not None: # Use the faster currentframe where implemented - while offset and frame: + while offset and frame is not None: frame = frame.f_back offset -= 1 assert frame is not None @@ -2049,11 +1970,11 @@ def _check_buffer(self) -> None: del self._buffer[:] return with self._lock: - if self._buffer_index == 0: + if self.record: + with self._record_buffer_lock: + self._record_buffer.extend(self._buffer[:]) - if self.record: - with self._record_buffer_lock: - self._record_buffer.extend(self._buffer[:]) + if self._buffer_index == 0: if self.is_jupyter: # pragma: no cover from .jupyter import display @@ -2066,7 +1987,7 @@ def _check_buffer(self) -> None: if self.legacy_windows: try: use_legacy_windows_render = ( - self.file.fileno() in _STD_STREAMS + self.file.fileno() in _STD_STREAMS_OUTPUT ) except (ValueError, io.UnsupportedOperation): pass @@ -2318,135 +2239,240 @@ def export_svg( clear: bool = True, code_format: str = CONSOLE_SVG_FORMAT, ) -> str: - """Generate an SVG string from the console contents (requires record=True in Console constructor) + """ + Generate an SVG from the console contents (requires record=True in Console constructor). Args: + path (str): The path to write the SVG to. title (str): The title of the tab in the output image theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal clear (bool, optional): Clear record buffer after exporting. Defaults to ``True`` code_format (str): Format string used to generate the SVG. Rich will inject a number of variables into the string in order to form the final SVG output. The default template used and the variables injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable. - - Returns: - str: The string representation of the SVG. That is, the ``code_format`` template with content injected. """ - assert ( - self.record - ), "To export console contents set record=True in the constructor or instance" - _theme = theme or SVG_EXPORT_THEME + from pip._vendor.rich.cells import cell_len - with self._record_buffer_lock: - segments = Segment.simplify(self._record_buffer) - segments = Segment.filter_control(segments) - parts = [(text, style or Style.null()) for text, style, _ in segments] - terminal_text = Text.assemble(*parts) - lines = terminal_text.wrap(self, width=self.width, overflow="fold") - segments = self.render(lines, options=self.options) - segment_lines = list( - Segment.split_and_crop_lines( - segments, length=self.width, include_new_lines=False - ) - ) - - fragments: List[str] = [] - theme_foreground_color = _theme.foreground_color.hex - theme_background_color = _theme.background_color.hex - - theme_foreground_css = f"color: {theme_foreground_color}; text-decoration-color: {theme_foreground_color};" - theme_background_css = f"background-color: {theme_background_color};" + style_cache: Dict[Style, str] = {} - theme_css = theme_foreground_css + theme_background_css - - styles: Dict[str, int] = {} - styles[theme_css] = 1 + def get_svg_style(style: Style) -> str: + """Convert a Style to CSS rules for SVG.""" + if style in style_cache: + return style_cache[style] + css_rules = [] + color = ( + _theme.foreground_color + if (style.color is None or style.color.is_default) + else style.color.get_truecolor(_theme) + ) + bgcolor = ( + _theme.background_color + if (style.bgcolor is None or style.bgcolor.is_default) + else style.bgcolor.get_truecolor(_theme) + ) + if style.reverse: + color, bgcolor = bgcolor, color + if style.dim: + color = blend_rgb(color, bgcolor, 0.4) + css_rules.append(f"fill: {color.hex}") + if style.bold: + css_rules.append("font-weight: bold") + if style.italic: + css_rules.append("font-style: italic;") + if style.underline: + css_rules.append("text-decoration: underline;") + if style.strike: + css_rules.append("text-decoration: line-through;") + + css = ";".join(css_rules) + style_cache[style] = css + return css - for line in segment_lines: - line_spans = [] - for segment in line: - text, style, _ = segment - text = escape(text) - if style: - rules = style.get_html_style(_theme) - if style.link: - text = f'{text}' + _theme = theme or SVG_EXPORT_THEME - if style.blink or style.blink2: - text = f'{text}' + width = self.width + char_height = 20 + char_width = char_height * 0.61 + line_height = char_height * 1.22 + + margin_top = 1 + margin_right = 1 + margin_bottom = 1 + margin_left = 1 + + padding_top = 40 + padding_right = 8 + padding_bottom = 8 + padding_left = 8 + + padding_width = padding_left + padding_right + padding_height = padding_top + padding_bottom + margin_width = margin_left + margin_right + margin_height = margin_top + margin_bottom + + text_backgrounds: List[str] = [] + text_group: List[str] = [] + classes: Dict[str, int] = {} + style_no = 1 + + def escape_text(text: str) -> str: + """HTML escape text and replace spaces with nbsp.""" + return escape(text).replace(" ", " ") + + def make_tag( + name: str, content: Optional[str] = None, **attribs: object + ) -> str: + """Make a tag from name, content, and attributes.""" + + def stringify(value: object) -> str: + if isinstance(value, (float)): + return format(value, "g") + return str(value) + + tag_attribs = " ".join( + f'{k.lstrip("_").replace("_", "-")}="{stringify(v)}"' + for k, v in attribs.items() + ) + return ( + f"<{name} {tag_attribs}>{content}" + if content + else f"<{name} {tag_attribs}/>" + ) - # If the style doesn't contain a color, we still - # need to make sure we output the default foreground color - # from the TerminalTheme. - if not style.reverse: - foreground_css = theme_foreground_css - background_css = theme_background_css - else: - foreground_css = f"color: {theme_background_color}; text-decoration-color: {theme_background_color};" - background_css = ( - f"background-color: {theme_foreground_color};" - ) + with self._record_buffer_lock: + segments = list(Segment.filter_control(self._record_buffer)) + if clear: + self._record_buffer.clear() - if style.color is None: - rules += f";{foreground_css}" - if style.bgcolor is None: - rules += f";{background_css}" + unique_id = "terminal-" + str( + zlib.adler32( + ("".join(segment.text for segment in segments)).encode( + "utf-8", "ignore" + ) + + title.encode("utf-8", "ignore") + ) + ) + y = 0 + for y, line in enumerate(Segment.split_and_crop_lines(segments, length=width)): + x = 0 + for text, style, _control in line: + style = style or Style() + rules = get_svg_style(style) + if rules not in classes: + classes[rules] = style_no + style_no += 1 + class_name = f"r{classes[rules]}" + + if style.reverse: + has_background = True + background = ( + _theme.foreground_color.hex + if style.color is None + else style.color.get_truecolor(_theme).hex + ) + else: + bgcolor = style.bgcolor + has_background = bgcolor is not None and not bgcolor.is_default + background = ( + _theme.background_color.hex + if style.bgcolor is None + else style.bgcolor.get_truecolor(_theme).hex + ) - style_number = styles.setdefault(rules, len(styles) + 1) - text = f'{text}' - else: - text = f'{text}' - line_spans.append(text) + text_length = cell_len(text) + if has_background: + text_backgrounds.append( + make_tag( + "rect", + fill=background, + x=x * char_width, + y=y * line_height + 1.5, + width=char_width * text_length, + height=line_height + 0.25, + shape_rendering="crispEdges", + ) + ) - fragments.append(f"
{''.join(line_spans)}
") + if text != " " * len(text): + text_group.append( + make_tag( + "text", + escape_text(text), + _class=f"{unique_id}-{class_name}", + x=x * char_width, + y=y * line_height + char_height, + textLength=char_width * len(text), + clip_path=f"url(#{unique_id}-line-{y})", + ) + ) + x += cell_len(text) + + line_offsets = [line_no * line_height + 1.5 for line_no in range(y)] + lines = "\n".join( + f""" + {make_tag("rect", x=0, y=offset, width=char_width * width, height=line_height + 0.25)} + """ + for line_no, offset in enumerate(line_offsets) + ) - stylesheet_rules = [] - for style_rule, style_number in styles.items(): - if style_rule: - stylesheet_rules.append(f".r{style_number} {{{ style_rule }}}") - stylesheet = "\n".join(stylesheet_rules) + styles = "\n".join( + f".{unique_id}-r{rule_no} {{ {css} }}" for css, rule_no in classes.items() + ) + backgrounds = "".join(text_backgrounds) + matrix = "".join(text_group) + + terminal_width = ceil(width * char_width + padding_width) + terminal_height = (y + 1) * line_height + padding_height + chrome = make_tag( + "rect", + fill=_theme.background_color.hex, + stroke="rgba(255,255,255,0.35)", + stroke_width="1", + x=margin_left, + y=margin_top, + width=terminal_width, + height=terminal_height, + rx=8, + ) - if clear: - self._record_buffer.clear() + title_color = _theme.foreground_color.hex + if title: + chrome += make_tag( + "text", + escape_text(title), + _class=f"{unique_id}-title", + fill=title_color, + text_anchor="middle", + x=terminal_width // 2, + y=margin_top + char_height + 6, + ) + chrome += f""" + + + + + + """ - # These values are the ones that I found to work well after experimentation. - # Many of them can be tweaked, but too much variation from these values could - # result in visually broken output/clipping issues. - terminal_padding = 12 - font_size = 18 - line_height = font_size + 4 - code_start_y = 60 - required_code_height = line_height * len(lines) - margin = 140 - - # Monospace fonts are generally around 0.5-0.55 width/height ratio, but I've - # added extra width to ensure that the output SVG is big enough. - monospace_font_width_scale = 0.60 - - # This works out as a good heuristic for the final size of the drawn terminal. - terminal_height = required_code_height + code_start_y - terminal_width = ( - self.width * monospace_font_width_scale * font_size - + 2 * terminal_padding - + self.width - ) - total_height = terminal_height + 2 * margin - total_width = terminal_width + 2 * margin - - rendered_code = code_format.format( - code="\n".join(fragments), - total_height=total_height, - total_width=total_width, - theme_foreground_color=theme_foreground_color, - theme_background_color=theme_background_color, - margin=margin, - font_size=font_size, + svg = code_format.format( + unique_id=unique_id, + char_width=char_width, + char_height=char_height, line_height=line_height, - title=title, - stylesheet=stylesheet, + terminal_width=char_width * width - 1, + terminal_height=(y + 1) * line_height - 1, + width=terminal_width + margin_width, + height=terminal_height + margin_height, + terminal_x=margin_left + padding_left, + terminal_y=margin_top + padding_top, + styles=styles, + chrome=chrome, + backgrounds=backgrounds, + matrix=matrix, + lines=lines, ) - - return rendered_code + return svg def save_svg( self, @@ -2469,12 +2495,27 @@ def save_svg( injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable. """ svg = self.export_svg( - title=title, theme=theme, clear=clear, code_format=code_format + title=title, + theme=theme, + clear=clear, + code_format=code_format, ) with open(path, "wt", encoding="utf-8") as write_file: write_file.write(svg) +def _svg_hash(svg_main_code: str) -> str: + """Returns a unique hash for the given SVG main code. + + Args: + svg_main_code (str): The content we're going to inject in the SVG envelope. + + Returns: + str: a hash of the given content + """ + return str(zlib.adler32(svg_main_code.encode())) + + if __name__ == "__main__": # pragma: no cover console = Console(record=True) diff --git a/src/pip/_vendor/rich/control.py b/src/pip/_vendor/rich/control.py index e17b2c6349c..88fcb929516 100644 --- a/src/pip/_vendor/rich/control.py +++ b/src/pip/_vendor/rich/control.py @@ -1,18 +1,35 @@ -from typing import Callable, Dict, Iterable, List, TYPE_CHECKING, Union +import sys +import time +from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Union + +if sys.version_info >= (3, 8): + from typing import Final +else: + from pip._vendor.typing_extensions import Final # pragma: no cover from .segment import ControlCode, ControlType, Segment if TYPE_CHECKING: from .console import Console, ConsoleOptions, RenderResult -STRIP_CONTROL_CODES = [ +STRIP_CONTROL_CODES: Final = [ + 7, # Bell 8, # Backspace 11, # Vertical tab 12, # Form feed 13, # Carriage return ] -_CONTROL_TRANSLATE = {_codepoint: None for _codepoint in STRIP_CONTROL_CODES} +_CONTROL_STRIP_TRANSLATE: Final = { + _codepoint: None for _codepoint in STRIP_CONTROL_CODES +} +CONTROL_ESCAPE: Final = { + 7: "\\a", + 8: "\\b", + 11: "\\v", + 12: "\\f", + 13: "\\r", +} CONTROL_CODES_FORMAT: Dict[int, Callable[..., str]] = { ControlType.BELL: lambda: "\x07", @@ -30,6 +47,7 @@ ControlType.CURSOR_MOVE_TO_COLUMN: lambda param: f"\x1b[{param+1}G", ControlType.ERASE_IN_LINE: lambda param: f"\x1b[{param}K", ControlType.CURSOR_MOVE_TO: lambda x, y: f"\x1b[{y+1};{x+1}H", + ControlType.SET_WINDOW_TITLE: lambda title: f"\x1b]0;{title}\x07", } @@ -147,6 +165,15 @@ def alt_screen(cls, enable: bool) -> "Control": else: return cls(ControlType.DISABLE_ALT_SCREEN) + @classmethod + def title(cls, title: str) -> "Control": + """Set the terminal window title + + Args: + title (str): The new terminal window title + """ + return cls((ControlType.SET_WINDOW_TITLE, title)) + def __str__(self) -> str: return self.segment.text @@ -158,7 +185,7 @@ def __rich_console__( def strip_control_codes( - text: str, _translate_table: Dict[int, None] = _CONTROL_TRANSLATE + text: str, _translate_table: Dict[int, None] = _CONTROL_STRIP_TRANSLATE ) -> str: """Remove control codes from text. @@ -171,5 +198,28 @@ def strip_control_codes( return text.translate(_translate_table) +def escape_control_codes( + text: str, + _translate_table: Dict[int, str] = CONTROL_ESCAPE, +) -> str: + """Replace control codes with their "escaped" equivalent in the given text. + (e.g. "\b" becomes "\\b") + + Args: + text (str): A string possibly containing control codes. + + Returns: + str: String with control codes replaced with their escaped version. + """ + return text.translate(_translate_table) + + if __name__ == "__main__": # pragma: no cover - print(strip_control_codes("hello\rWorld")) + from pip._vendor.rich.console import Console + + console = Console() + console.print("Look at the title of your terminal window ^") + # console.print(Control((ControlType.SET_WINDOW_TITLE, "Hello, world!"))) + for i in range(10): + console.set_window_title("🚀 Loading" + "." * i) + time.sleep(0.5) diff --git a/src/pip/_vendor/rich/default_styles.py b/src/pip/_vendor/rich/default_styles.py index cb7bfc19253..46e9ea52c54 100644 --- a/src/pip/_vendor/rich/default_styles.py +++ b/src/pip/_vendor/rich/default_styles.py @@ -39,6 +39,7 @@ "inspect.attr": Style(color="yellow", italic=True), "inspect.attr.dunder": Style(color="yellow", italic=True, dim=True), "inspect.callable": Style(bold=True, color="red"), + "inspect.async_def": Style(italic=True, color="bright_cyan"), "inspect.def": Style(italic=True, color="bright_cyan"), "inspect.class": Style(italic=True, color="bright_cyan"), "inspect.error": Style(bold=True, color="red"), @@ -78,6 +79,7 @@ "repr.attrib_equal": Style(bold=True), "repr.attrib_value": Style(color="magenta", italic=False), "repr.number": Style(color="cyan", bold=True, italic=False), + "repr.number_complex": Style(color="cyan", bold=True, italic=False), # same "repr.bool_true": Style(color="bright_green", italic=True), "repr.bool_false": Style(color="bright_red", italic=True), "repr.none": Style(color="magenta", italic=True), @@ -156,6 +158,9 @@ "markdown.h7": Style(italic=True, dim=True), "markdown.link": Style(color="bright_blue"), "markdown.link_url": Style(color="blue"), + "iso8601.date": Style(color="blue"), + "iso8601.time": Style(color="magenta"), + "iso8601.timezone": Style(color="yellow"), } diff --git a/src/pip/_vendor/rich/diagnose.py b/src/pip/_vendor/rich/diagnose.py index 518586ea876..ad36183898e 100644 --- a/src/pip/_vendor/rich/diagnose.py +++ b/src/pip/_vendor/rich/diagnose.py @@ -22,6 +22,8 @@ def report() -> None: # pragma: no cover "TERM_PROGRAM", "COLUMNS", "LINES", + "JUPYTER_COLUMNS", + "JUPYTER_LINES", "JPY_PARENT_PID", "VSCODE_VERBOSE_LOGGING", ) diff --git a/src/pip/_vendor/rich/file_proxy.py b/src/pip/_vendor/rich/file_proxy.py index 3ec593a5a48..cc69f22f3cc 100644 --- a/src/pip/_vendor/rich/file_proxy.py +++ b/src/pip/_vendor/rich/file_proxy.py @@ -1,5 +1,5 @@ import io -from typing import List, Any, IO, TYPE_CHECKING +from typing import IO, TYPE_CHECKING, Any, List from .ansi import AnsiDecoder from .text import Text @@ -48,7 +48,7 @@ def write(self, text: str) -> int: return len(text) def flush(self) -> None: - buffer = self.__buffer - if buffer: - self.__console.print("".join(buffer)) - del buffer[:] + output = "".join(self.__buffer) + if output: + self.__console.print(output) + del self.__buffer[:] diff --git a/src/pip/_vendor/rich/highlighter.py b/src/pip/_vendor/rich/highlighter.py index 7bee4167e43..82293dffc49 100644 --- a/src/pip/_vendor/rich/highlighter.py +++ b/src/pip/_vendor/rich/highlighter.py @@ -94,6 +94,7 @@ class ReprHighlighter(RegexHighlighter): r"(?P[\w.]*?)\(", r"\b(?PTrue)\b|\b(?PFalse)\b|\b(?PNone)\b", r"(?P\.\.\.)", + r"(?P(?(?\B(/[-\w._+]+)*\/)(?P[-\w._+]*)?", r"(?b?'''.*?(? None: break +class ISO8601Highlighter(RegexHighlighter): + """Highlights the ISO8601 date time strings. + Regex reference: https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html + """ + + base_style = "iso8601." + highlights = [ + # + # Dates + # + # Calendar month (e.g. 2008-08). The hyphen is required + r"^(?P[0-9]{4})-(?P1[0-2]|0[1-9])$", + # Calendar date w/o hyphens (e.g. 20080830) + r"^(?P(?P[0-9]{4})(?P1[0-2]|0[1-9])(?P3[01]|0[1-9]|[12][0-9]))$", + # Ordinal date (e.g. 2008-243). The hyphen is optional + r"^(?P(?P[0-9]{4})-?(?P36[0-6]|3[0-5][0-9]|[12][0-9]{2}|0[1-9][0-9]|00[1-9]))$", + # + # Weeks + # + # Week of the year (e.g., 2008-W35). The hyphen is optional + r"^(?P(?P[0-9]{4})-?W(?P5[0-3]|[1-4][0-9]|0[1-9]))$", + # Week date (e.g., 2008-W35-6). The hyphens are optional + r"^(?P(?P[0-9]{4})-?W(?P5[0-3]|[1-4][0-9]|0[1-9])-?(?P[1-7]))$", + # + # Times + # + # Hours and minutes (e.g., 17:21). The colon is optional + r"^(?P