summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Stufft <donald@stufft.io>2016-11-02 12:40:37 -0400
committerGitHub <noreply@github.com>2016-11-02 12:40:37 -0400
commitd6a41466c8eec86ef403ac891df9528dde77e245 (patch)
tree68295878d4c9626d38dd9784c101adc5d070bce6
parentcc3e98c6501fd2f118f80371387bcbc9af0c0d10 (diff)
downloadpip-d6a41466c8eec86ef403ac891df9528dde77e245.tar.gz
Upgrade pkg_resources to setuptools 27.3.0 (#4054)
-rw-r--r--pip/_vendor/README.rst2
-rw-r--r--pip/_vendor/appdirs.py552
-rw-r--r--pip/_vendor/pkg_resources/__init__.py321
-rw-r--r--pip/_vendor/vendor.txt1
4 files changed, 751 insertions, 125 deletions
diff --git a/pip/_vendor/README.rst b/pip/_vendor/README.rst
index 855b174f7..fc2386182 100644
--- a/pip/_vendor/README.rst
+++ b/pip/_vendor/README.rst
@@ -95,7 +95,7 @@ such as OS packages.
pkg_resources
-------------
-pkg_resources has been pulled in from setuptools 21.0.0
+pkg_resources has been pulled in from setuptools 27.3.0
Modifications
diff --git a/pip/_vendor/appdirs.py b/pip/_vendor/appdirs.py
new file mode 100644
index 000000000..f4dba0953
--- /dev/null
+++ b/pip/_vendor/appdirs.py
@@ -0,0 +1,552 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2005-2010 ActiveState Software Inc.
+# Copyright (c) 2013 Eddy Petrișor
+
+"""Utilities for determining application-specific dirs.
+
+See <http://github.com/ActiveState/appdirs> for details and usage.
+"""
+# Dev Notes:
+# - MSDN on where to store app data files:
+# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
+# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
+# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+
+__version_info__ = (1, 4, 0)
+__version__ = '.'.join(map(str, __version_info__))
+
+
+import sys
+import os
+
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+ unicode = str
+
+if sys.platform.startswith('java'):
+ import platform
+ os_name = platform.java_ver()[3][0]
+ if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
+ system = 'win32'
+ elif os_name.startswith('Mac'): # "Mac OS X", etc.
+ system = 'darwin'
+ else: # "Linux", "SunOS", "FreeBSD", etc.
+ # Setting this to "linux2" is not ideal, but only Windows or Mac
+ # are actually checked for and the rest of the module expects
+ # *sys.platform* style strings.
+ system = 'linux2'
+else:
+ system = sys.platform
+
+
+
+def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
+ r"""Return full path to the user-specific data dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be "<major>.<minor>".
+ Only applied when appname is present.
+ "roaming" (boolean, default False) can be set True to use the Windows
+ roaming appdata directory. That means that for users on a Windows
+ network setup for roaming profiles, this user data will be
+ sync'd on login. See
+ <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
+ for a discussion of issues.
+
+ Typical user data directories are:
+ Mac OS X: ~/Library/Application Support/<AppName>
+ Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined
+ Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
+ Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
+ Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>
+ Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>
+
+ For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
+ That means, by default "~/.local/share/<AppName>".
+ """
+ if system == "win32":
+ if appauthor is None:
+ appauthor = appname
+ const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
+ path = os.path.normpath(_get_win_folder(const))
+ if appname:
+ if appauthor is not False:
+ path = os.path.join(path, appauthor, appname)
+ else:
+ path = os.path.join(path, appname)
+ elif system == 'darwin':
+ path = os.path.expanduser('~/Library/Application Support/')
+ if appname:
+ path = os.path.join(path, appname)
+ else:
+ path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
+ if appname:
+ path = os.path.join(path, appname)
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
+ """Return full path to the user-shared data dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be "<major>.<minor>".
+ Only applied when appname is present.
+ "multipath" is an optional parameter only applicable to *nix
+ which indicates that the entire list of data dirs should be
+ returned. By default, the first item from XDG_DATA_DIRS is
+ returned, or '/usr/local/share/<AppName>',
+ if XDG_DATA_DIRS is not set
+
+ Typical user data directories are:
+ Mac OS X: /Library/Application Support/<AppName>
+ Unix: /usr/local/share/<AppName> or /usr/share/<AppName>
+ Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
+ Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
+ Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7.
+
+ For Unix, this is using the $XDG_DATA_DIRS[0] default.
+
+ WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
+ """
+ if system == "win32":
+ if appauthor is None:
+ appauthor = appname
+ path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
+ if appname:
+ if appauthor is not False:
+ path = os.path.join(path, appauthor, appname)
+ else:
+ path = os.path.join(path, appname)
+ elif system == 'darwin':
+ path = os.path.expanduser('/Library/Application Support')
+ if appname:
+ path = os.path.join(path, appname)
+ else:
+ # XDG default for $XDG_DATA_DIRS
+ # only first, if multipath is False
+ path = os.getenv('XDG_DATA_DIRS',
+ os.pathsep.join(['/usr/local/share', '/usr/share']))
+ pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
+ if appname:
+ if version:
+ appname = os.path.join(appname, version)
+ pathlist = [os.sep.join([x, appname]) for x in pathlist]
+
+ if multipath:
+ path = os.pathsep.join(pathlist)
+ else:
+ path = pathlist[0]
+ return path
+
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
+ r"""Return full path to the user-specific config dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be "<major>.<minor>".
+ Only applied when appname is present.
+ "roaming" (boolean, default False) can be set True to use the Windows
+ roaming appdata directory. That means that for users on a Windows
+ network setup for roaming profiles, this user data will be
+ sync'd on login. See
+ <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
+ for a discussion of issues.
+
+ Typical user data directories are:
+ Mac OS X: same as user_data_dir
+ Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined
+ Win *: same as user_data_dir
+
+ For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
+ That means, by deafult "~/.config/<AppName>".
+ """
+ if system in ["win32", "darwin"]:
+ path = user_data_dir(appname, appauthor, None, roaming)
+ else:
+ path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
+ if appname:
+ path = os.path.join(path, appname)
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
+ """Return full path to the user-shared data dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be "<major>.<minor>".
+ Only applied when appname is present.
+ "multipath" is an optional parameter only applicable to *nix
+ which indicates that the entire list of config dirs should be
+ returned. By default, the first item from XDG_CONFIG_DIRS is
+ returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
+
+ Typical user data directories are:
+ Mac OS X: same as site_data_dir
+ Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
+ $XDG_CONFIG_DIRS
+ Win *: same as site_data_dir
+ Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
+
+ For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
+
+ WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
+ """
+ if system in ["win32", "darwin"]:
+ path = site_data_dir(appname, appauthor)
+ if appname and version:
+ path = os.path.join(path, version)
+ else:
+ # XDG default for $XDG_CONFIG_DIRS
+ # only first, if multipath is False
+ path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
+ pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
+ if appname:
+ if version:
+ appname = os.path.join(appname, version)
+ pathlist = [os.sep.join([x, appname]) for x in pathlist]
+
+ if multipath:
+ path = os.pathsep.join(pathlist)
+ else:
+ path = pathlist[0]
+ return path
+
+
+def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
+ r"""Return full path to the user-specific cache dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be "<major>.<minor>".
+ Only applied when appname is present.
+ "opinion" (boolean) can be False to disable the appending of
+ "Cache" to the base app data dir for Windows. See
+ discussion below.
+
+ Typical user cache directories are:
+ Mac OS X: ~/Library/Caches/<AppName>
+ Unix: ~/.cache/<AppName> (XDG default)
+ Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache
+ Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache
+
+ On Windows the only suggestion in the MSDN docs is that local settings go in
+ the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
+ app data dir (the default returned by `user_data_dir` above). Apps typically
+ put cache data somewhere *under* the given dir here. Some examples:
+ ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
+ ...\Acme\SuperApp\Cache\1.0
+ OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
+ This can be disabled with the `opinion=False` option.
+ """
+ if system == "win32":
+ if appauthor is None:
+ appauthor = appname
+ path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
+ if appname:
+ if appauthor is not False:
+ path = os.path.join(path, appauthor, appname)
+ else:
+ path = os.path.join(path, appname)
+ if opinion:
+ path = os.path.join(path, "Cache")
+ elif system == 'darwin':
+ path = os.path.expanduser('~/Library/Caches')
+ if appname:
+ path = os.path.join(path, appname)
+ else:
+ path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
+ if appname:
+ path = os.path.join(path, appname)
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
+ r"""Return full path to the user-specific log dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be "<major>.<minor>".
+ Only applied when appname is present.
+ "opinion" (boolean) can be False to disable the appending of
+ "Logs" to the base app data dir for Windows, and "log" to the
+ base cache dir for Unix. See discussion below.
+
+ Typical user cache directories are:
+ Mac OS X: ~/Library/Logs/<AppName>
+ Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined
+ Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
+ Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs
+
+ On Windows the only suggestion in the MSDN docs is that local settings
+ go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
+ examples of what some windows apps use for a logs dir.)
+
+ OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
+ value for Windows and appends "log" to the user cache dir for Unix.
+ This can be disabled with the `opinion=False` option.
+ """
+ if system == "darwin":
+ path = os.path.join(
+ os.path.expanduser('~/Library/Logs'),
+ appname)
+ elif system == "win32":
+ path = user_data_dir(appname, appauthor, version)
+ version = False
+ if opinion:
+ path = os.path.join(path, "Logs")
+ else:
+ path = user_cache_dir(appname, appauthor, version)
+ version = False
+ if opinion:
+ path = os.path.join(path, "log")
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+class AppDirs(object):
+ """Convenience wrapper for getting application dirs."""
+ def __init__(self, appname, appauthor=None, version=None, roaming=False,
+ multipath=False):
+ self.appname = appname
+ self.appauthor = appauthor
+ self.version = version
+ self.roaming = roaming
+ self.multipath = multipath
+
+ @property
+ def user_data_dir(self):
+ return user_data_dir(self.appname, self.appauthor,
+ version=self.version, roaming=self.roaming)
+
+ @property
+ def site_data_dir(self):
+ return site_data_dir(self.appname, self.appauthor,
+ version=self.version, multipath=self.multipath)
+
+ @property
+ def user_config_dir(self):
+ return user_config_dir(self.appname, self.appauthor,
+ version=self.version, roaming=self.roaming)
+
+ @property
+ def site_config_dir(self):
+ return site_config_dir(self.appname, self.appauthor,
+ version=self.version, multipath=self.multipath)
+
+ @property
+ def user_cache_dir(self):
+ return user_cache_dir(self.appname, self.appauthor,
+ version=self.version)
+
+ @property
+ def user_log_dir(self):
+ return user_log_dir(self.appname, self.appauthor,
+ version=self.version)
+
+
+#---- internal support stuff
+
+def _get_win_folder_from_registry(csidl_name):
+ """This is a fallback technique at best. I'm not sure if using the
+ registry for this guarantees us the correct answer for all CSIDL_*
+ names.
+ """
+ import _winreg
+
+ shell_folder_name = {
+ "CSIDL_APPDATA": "AppData",
+ "CSIDL_COMMON_APPDATA": "Common AppData",
+ "CSIDL_LOCAL_APPDATA": "Local AppData",
+ }[csidl_name]
+
+ key = _winreg.OpenKey(
+ _winreg.HKEY_CURRENT_USER,
+ r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
+ )
+ dir, type = _winreg.QueryValueEx(key, shell_folder_name)
+ return dir
+
+
+def _get_win_folder_with_pywin32(csidl_name):
+ from win32com.shell import shellcon, shell
+ dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)
+ # Try to make this a unicode path because SHGetFolderPath does
+ # not return unicode strings when there is unicode data in the
+ # path.
+ try:
+ dir = unicode(dir)
+
+ # Downgrade to short path name if have highbit chars. See
+ # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
+ has_high_char = False
+ for c in dir:
+ if ord(c) > 255:
+ has_high_char = True
+ break
+ if has_high_char:
+ try:
+ import win32api
+ dir = win32api.GetShortPathName(dir)
+ except ImportError:
+ pass
+ except UnicodeError:
+ pass
+ return dir
+
+
+def _get_win_folder_with_ctypes(csidl_name):
+ import ctypes
+
+ csidl_const = {
+ "CSIDL_APPDATA": 26,
+ "CSIDL_COMMON_APPDATA": 35,
+ "CSIDL_LOCAL_APPDATA": 28,
+ }[csidl_name]
+
+ buf = ctypes.create_unicode_buffer(1024)
+ ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
+
+ # Downgrade to short path name if have highbit chars. See
+ # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
+ has_high_char = False
+ for c in buf:
+ if ord(c) > 255:
+ has_high_char = True
+ break
+ if has_high_char:
+ buf2 = ctypes.create_unicode_buffer(1024)
+ if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
+ buf = buf2
+
+ return buf.value
+
+def _get_win_folder_with_jna(csidl_name):
+ import array
+ from com.sun import jna
+ from com.sun.jna.platform import win32
+
+ buf_size = win32.WinDef.MAX_PATH * 2
+ buf = array.zeros('c', buf_size)
+ shell = win32.Shell32.INSTANCE
+ shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)
+ dir = jna.Native.toString(buf.tostring()).rstrip("\0")
+
+ # Downgrade to short path name if have highbit chars. See
+ # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
+ has_high_char = False
+ for c in dir:
+ if ord(c) > 255:
+ has_high_char = True
+ break
+ if has_high_char:
+ buf = array.zeros('c', buf_size)
+ kernel = win32.Kernel32.INSTANCE
+ if kernal.GetShortPathName(dir, buf, buf_size):
+ dir = jna.Native.toString(buf.tostring()).rstrip("\0")
+
+ return dir
+
+if system == "win32":
+ try:
+ import win32com.shell
+ _get_win_folder = _get_win_folder_with_pywin32
+ except ImportError:
+ try:
+ from ctypes import windll
+ _get_win_folder = _get_win_folder_with_ctypes
+ except ImportError:
+ try:
+ import com.sun.jna
+ _get_win_folder = _get_win_folder_with_jna
+ except ImportError:
+ _get_win_folder = _get_win_folder_from_registry
+
+
+#---- self test code
+
+if __name__ == "__main__":
+ appname = "MyApp"
+ appauthor = "MyCompany"
+
+ props = ("user_data_dir", "site_data_dir",
+ "user_config_dir", "site_config_dir",
+ "user_cache_dir", "user_log_dir")
+
+ print("-- app dirs (with optional 'version')")
+ dirs = AppDirs(appname, appauthor, version="1.0")
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
+
+ print("\n-- app dirs (without optional 'version')")
+ dirs = AppDirs(appname, appauthor)
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
+
+ print("\n-- app dirs (without optional 'appauthor')")
+ dirs = AppDirs(appname)
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
+
+ print("\n-- app dirs (with disabled 'appauthor')")
+ dirs = AppDirs(appname, appauthor=False)
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
diff --git a/pip/_vendor/pkg_resources/__init__.py b/pip/_vendor/pkg_resources/__init__.py
index 91e1a9d24..8ac7f2fa8 100644
--- a/pip/_vendor/pkg_resources/__init__.py
+++ b/pip/_vendor/pkg_resources/__init__.py
@@ -1,3 +1,4 @@
+# coding: utf-8
"""
Package resource API
--------------------
@@ -65,6 +66,7 @@ try:
except ImportError:
importlib_machinery = None
+from pip._vendor import appdirs
from pip._vendor import packaging
__import__('pip._vendor.packaging.version')
__import__('pip._vendor.packaging.specifiers')
@@ -93,7 +95,6 @@ class PEP440Warning(RuntimeWarning):
class _SetuptoolsVersionMixin(object):
-
def __hash__(self):
return super(_SetuptoolsVersionMixin, self).__hash__()
@@ -155,7 +156,7 @@ class _SetuptoolsVersionMixin(object):
# pad for numeric comparison
yield part.zfill(8)
else:
- yield '*'+part
+ yield '*' + part
# ensure that alpha/beta/candidate are before final
yield '*final'
@@ -209,36 +210,44 @@ def parse_version(v):
_state_vars = {}
+
def _declare_state(vartype, **kw):
globals().update(kw)
_state_vars.update(dict.fromkeys(kw, vartype))
+
def __getstate__():
state = {}
g = globals()
for k, v in _state_vars.items():
- state[k] = g['_sget_'+v](g[k])
+ state[k] = g['_sget_' + v](g[k])
return state
+
def __setstate__(state):
g = globals()
for k, v in state.items():
- g['_sset_'+_state_vars[k]](k, g[k], v)
+ g['_sset_' + _state_vars[k]](k, g[k], v)
return state
+
def _sget_dict(val):
return val.copy()
+
def _sset_dict(key, ob, state):
ob.clear()
ob.update(state)
+
def _sget_object(val):
return val.__getstate__()
+
def _sset_object(key, ob, state):
ob.__setstate__(state)
+
_sget_none = _sset_none = lambda *args: None
@@ -265,9 +274,10 @@ def get_supported_platform():
pass
return plat
+
__all__ = [
# Basic resource access and distribution/entry point discovery
- 'require', 'run_script', 'get_provider', 'get_distribution',
+ 'require', 'run_script', 'get_provider', 'get_distribution',
'load_entry_point', 'get_entry_map', 'get_entry_info',
'iter_entry_points',
'resource_string', 'resource_stream', 'resource_filename',
@@ -311,10 +321,12 @@ __all__ = [
'run_main', 'AvailableDistributions',
]
+
class ResolutionError(Exception):
"""Abstract base for dependency resolution errors"""
+
def __repr__(self):
- return self.__class__.__name__+repr(self.args)
+ return self.__class__.__name__ + repr(self.args)
class VersionConflict(ResolutionError):
@@ -391,6 +403,8 @@ class DistributionNotFound(ResolutionError):
class UnknownExtra(ResolutionError):
"""Distribution doesn't have an "extra feature" of the given name"""
+
+
_provider_factories = {}
PY_MAJOR = sys.version[:3]
@@ -400,6 +414,7 @@ SOURCE_DIST = 1
CHECKOUT_DIST = 0
DEVELOP_DIST = -1
+
def register_loader_type(loader_type, provider_factory):
"""Register `provider_factory` to make providers for `loader_type`
@@ -409,6 +424,7 @@ def register_loader_type(loader_type, provider_factory):
"""
_provider_factories[loader_type] = provider_factory
+
def get_provider(moduleOrReq):
"""Return an IResourceProvider for the named module or requirement"""
if isinstance(moduleOrReq, Requirement):
@@ -421,6 +437,7 @@ def get_provider(moduleOrReq):
loader = getattr(module, '__loader__', None)
return _find_adapter(_provider_factories, loader)(module)
+
def _macosx_vers(_cache=[]):
if not _cache:
version = platform.mac_ver()[0]
@@ -436,9 +453,11 @@ def _macosx_vers(_cache=[]):
_cache.append(version.split('.'))
return _cache[0]
+
def _macosx_arch(machine):
return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)
+
def get_build_platform():
"""Return this platform's string for platform-specific distributions
@@ -464,6 +483,7 @@ def get_build_platform():
pass
return plat
+
macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")
darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
# XXX backward compat
@@ -477,7 +497,7 @@ def compatible_platforms(provided, required):
XXX Needs compatibility checks for Linux and other unixy OSes.
"""
- if provided is None or required is None or provided==required:
+ if provided is None or required is None or provided == required:
# easy case
return True
@@ -524,9 +544,11 @@ def run_script(dist_spec, script_name):
ns['__name__'] = name
require(dist_spec)[0].run_script(script_name, ns)
+
# backward compatibility
run_main = run_script
+
def get_distribution(dist):
"""Return a current distribution object for a Requirement or string"""
if isinstance(dist, six.string_types):
@@ -537,21 +559,23 @@ def get_distribution(dist):
raise TypeError("Expected string, Requirement, or Distribution", dist)
return dist
+
def load_entry_point(dist, group, name):
"""Return `name` entry point of `group` for `dist` or raise ImportError"""
return get_distribution(dist).load_entry_point(group, name)
+
def get_entry_map(dist, group=None):
"""Return the entry point map for `group`, or the full entry map"""
return get_distribution(dist).get_entry_map(group)
+
def get_entry_info(dist, group, name):
"""Return the EntryPoint object for `group`+`name`, or ``None``"""
return get_distribution(dist).get_entry_info(group, name)
class IMetadataProvider:
-
def has_metadata(name):
"""Does the package's distribution contain the named metadata?"""
@@ -732,7 +756,7 @@ class WorkingSet(object):
for key in self.entry_keys[item]:
if key not in seen:
- seen[key]=1
+ seen[key] = 1
yield self.by_key[key]
def add(self, dist, entry=None, insert=True, replace=False):
@@ -752,8 +776,8 @@ class WorkingSet(object):
if entry is None:
entry = dist.location
- keys = self.entry_keys.setdefault(entry,[])
- keys2 = self.entry_keys.setdefault(dist.location,[])
+ keys = self.entry_keys.setdefault(entry, [])
+ keys2 = self.entry_keys.setdefault(dist.location, [])
if not replace and dist.key in self.by_key:
# ignore hidden distros
return
@@ -947,11 +971,17 @@ class WorkingSet(object):
return needed
- def subscribe(self, callback):
- """Invoke `callback` for all distributions (including existing ones)"""
+ def subscribe(self, callback, existing=True):
+ """Invoke `callback` for all distributions
+
+ If `existing=True` (default),
+ call on all existing ones, as well.
+ """
if callback in self.callbacks:
return
self.callbacks.append(callback)
+ if not existing:
+ return
for dist in self:
callback(dist)
@@ -1027,7 +1057,7 @@ class Environment(object):
is returned.
"""
return (self.python is None or dist.py_version is None
- or dist.py_version==self.python) \
+ or dist.py_version == self.python) \
and compatible_platforms(dist.platform, self.platform)
def remove(self, dist):
@@ -1232,7 +1262,7 @@ class ResourceManager:
extract, as it tracks the generated names for possible cleanup later.
"""
extract_path = self.extraction_path or get_default_cache()
- target_path = os.path.join(extract_path, archive_name+'-tmp', *names)
+ target_path = os.path.join(extract_path, archive_name + '-tmp', *names)
try:
_bypass_ensure_directory(target_path)
except:
@@ -1326,49 +1356,18 @@ class ResourceManager:
"""
# XXX
-def get_default_cache():
- """Determine the default cache location
- This returns the ``PYTHON_EGG_CACHE`` environment variable, if set.
- Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of the
- "Application Data" directory. On all other systems, it's "~/.python-eggs".
+def get_default_cache():
"""
- try:
- return os.environ['PYTHON_EGG_CACHE']
- except KeyError:
- pass
+ Return the ``PYTHON_EGG_CACHE`` environment variable
+ or a platform-relevant user cache dir for an app
+ named "Python-Eggs".
+ """
+ return (
+ os.environ.get('PYTHON_EGG_CACHE')
+ or appdirs.user_cache_dir(appname='Python-Eggs')
+ )
- if os.name!='nt':
- return os.path.expanduser('~/.python-eggs')
-
- # XXX this may be locale-specific!
- app_data = 'Application Data'
- app_homes = [
- # best option, should be locale-safe
- (('APPDATA',), None),
- (('USERPROFILE',), app_data),
- (('HOMEDRIVE','HOMEPATH'), app_data),
- (('HOMEPATH',), app_data),
- (('HOME',), None),
- # 95/98/ME
- (('WINDIR',), app_data),
- ]
-
- for keys, subdir in app_homes:
- dirname = ''
- for key in keys:
- if key in os.environ:
- dirname = os.path.join(dirname, os.environ[key])
- else:
- break
- else:
- if subdir:
- dirname = os.path.join(dirname, subdir)
- return os.path.join(dirname, 'Python-Eggs')
- else:
- raise RuntimeError(
- "Please set the PYTHON_EGG_CACHE enviroment variable"
- )
def safe_name(name):
"""Convert an arbitrary string to a standard distribution name
@@ -1386,7 +1385,7 @@ def safe_version(version):
# normalize the version
return str(packaging.version.Version(version))
except packaging.version.InvalidVersion:
- version = version.replace(' ','.')
+ version = version.replace(' ', '.')
return re.sub('[^A-Za-z0-9.]+', '-', version)
@@ -1396,7 +1395,7 @@ def safe_extra(extra):
Any runs of non-alphanumeric characters are replaced with a single '_',
and the result is always lowercased.
"""
- return re.sub('[^A-Za-z0-9.]+', '_', extra).lower()
+ return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower()
def to_filename(name):
@@ -1404,7 +1403,7 @@ def to_filename(name):
Any '-' characters are currently replaced with '_'.
"""
- return name.replace('-','_')
+ return name.replace('-', '_')
def invalid_marker(text):
@@ -1462,16 +1461,11 @@ class NullProvider:
def has_metadata(self, name):
return self.egg_info and self._has(self._fn(self.egg_info, name))
- if sys.version_info <= (3,):
- def get_metadata(self, name):
- if not self.egg_info:
- return ""
- return self._get(self._fn(self.egg_info, name))
- else:
- def get_metadata(self, name):
- if not self.egg_info:
- return ""
- return self._get(self._fn(self.egg_info, name)).decode("utf-8")
+ def get_metadata(self, name):
+ if not self.egg_info:
+ return ""
+ value = self._get(self._fn(self.egg_info, name))
+ return value.decode('utf-8') if six.PY3 else value
def get_metadata_lines(self, name):
return yield_lines(self.get_metadata(name))
@@ -1491,7 +1485,7 @@ class NullProvider:
return []
def run_script(self, script_name, namespace):
- script = 'scripts/'+script_name
+ script = 'scripts/' + script_name
if not self.has_metadata(script):
raise ResolutionError("No script named %r" % script_name)
script_text = self.get_metadata(script).replace('\r\n', '\n')
@@ -1507,7 +1501,7 @@ class NullProvider:
cache[script_filename] = (
len(script_text), 0, script_text.split('\n'), script_filename
)
- script_code = compile(script_text, script_filename,'exec')
+ script_code = compile(script_text, script_filename, 'exec')
exec(script_code, namespace, namespace)
def _has(self, path):
@@ -1537,6 +1531,7 @@ class NullProvider:
"Can't perform this operation for loaders without 'get_data()'"
)
+
register_loader_type(object, NullProvider)
@@ -1552,7 +1547,7 @@ class EggProvider(NullProvider):
# of multiple eggs; that's why we use module_path instead of .archive
path = self.module_path
old = None
- while path!=old:
+ while path != old:
if _is_unpacked_egg(path):
self.egg_name = os.path.basename(path)
self.egg_info = os.path.join(path, 'EGG-INFO')
@@ -1561,6 +1556,7 @@ class EggProvider(NullProvider):
old = path
path, base = os.path.split(path)
+
class DefaultProvider(EggProvider):
"""Provides access to package resources in the filesystem"""
@@ -1586,6 +1582,7 @@ class DefaultProvider(EggProvider):
type(None))
register_loader_type(loader_cls, cls)
+
DefaultProvider._register()
@@ -1600,6 +1597,7 @@ class EmptyProvider(NullProvider):
def __init__(self):
pass
+
empty_provider = EmptyProvider()
@@ -1678,7 +1676,7 @@ class ZipProvider(EggProvider):
def __init__(self, module):
EggProvider.__init__(self, module)
- self.zip_pre = self.loader.archive+os.sep
+ self.zip_pre = self.loader.archive + os.sep
def _zipinfo_name(self, fspath):
# Convert a virtual filename (full path to file) into a zipfile subpath
@@ -1692,9 +1690,9 @@ class ZipProvider(EggProvider):
def _parts(self, zip_path):
# Convert a zipfile subpath into an egg-relative path part list.
# pseudo-fs path
- fspath = self.zip_pre+zip_path
- if fspath.startswith(self.egg_root+os.sep):
- return fspath[len(self.egg_root)+1:].split(os.sep)
+ fspath = self.zip_pre + zip_path
+ if fspath.startswith(self.egg_root + os.sep):
+ return fspath[len(self.egg_root) + 1:].split(os.sep)
raise AssertionError(
"%s is not a subpath of %s" % (fspath, self.egg_root)
)
@@ -1765,7 +1763,7 @@ class ZipProvider(EggProvider):
# so proceed.
return real_path
# Windows, del old file and retry
- elif os.name=='nt':
+ elif os.name == 'nt':
unlink(real_path)
rename(tmpnam, real_path)
return real_path
@@ -1785,7 +1783,7 @@ class ZipProvider(EggProvider):
if not os.path.isfile(file_path):
return False
stat = os.stat(file_path)
- if stat.st_size!=size or stat.st_mtime!=timestamp:
+ if stat.st_size != size or stat.st_mtime != timestamp:
return False
# check that the contents match
zip_contents = self.loader.get_data(zip_path)
@@ -1835,6 +1833,7 @@ class ZipProvider(EggProvider):
def _resource_to_zip(self, resource_name):
return self._zipinfo_name(self._fn(self.module_path, resource_name))
+
register_loader_type(zipimport.zipimporter, ZipProvider)
@@ -1854,20 +1853,24 @@ class FileMetadata(EmptyProvider):
self.path = path
def has_metadata(self, name):
- return name=='PKG-INFO' and os.path.isfile(self.path)
+ return name == 'PKG-INFO' and os.path.isfile(self.path)
def get_metadata(self, name):
- if name=='PKG-INFO':
- with io.open(self.path, encoding='utf-8') as f:
- try:
- metadata = f.read()
- except UnicodeDecodeError as exc:
- # add path context to error message
- tmpl = " in {self.path}"
- exc.reason += tmpl.format(self=self)
- raise
- return metadata
- raise KeyError("No metadata except PKG-INFO is available")
+ if name != 'PKG-INFO':
+ raise KeyError("No metadata except PKG-INFO is available")
+
+ with io.open(self.path, encoding='utf-8', errors="replace") as f:
+ metadata = f.read()
+ self._warn_on_replacement(metadata)
+ return metadata
+
+ def _warn_on_replacement(self, metadata):
+ # Python 2.6 and 3.2 compat for: replacement_char = '�'
+ replacement_char = b'\xef\xbf\xbd'.decode('utf-8')
+ if replacement_char in metadata:
+ tmpl = "{self.path} could not be properly decoded in UTF-8"
+ msg = tmpl.format(**locals())
+ warnings.warn(msg)
def get_metadata_lines(self, name):
return yield_lines(self.get_metadata(name))
@@ -1904,7 +1907,7 @@ class EggMetadata(ZipProvider):
def __init__(self, importer):
"""Create a metadata provider from a zipimporter"""
- self.zip_pre = importer.archive+os.sep
+ self.zip_pre = importer.archive + os.sep
self.loader = importer
if importer.prefix:
self.module_path = os.path.join(importer.archive, importer.prefix)
@@ -1912,7 +1915,9 @@ class EggMetadata(ZipProvider):
self.module_path = importer.archive
self._setup_prefix()
-_declare_state('dict', _distribution_finders = {})
+
+_declare_state('dict', _distribution_finders={})
+
def register_finder(importer_type, distribution_finder):
"""Register `distribution_finder` to find distributions in sys.path items
@@ -1930,6 +1935,7 @@ def find_distributions(path_item, only=False):
finder = _find_adapter(_distribution_finders, importer)
return finder(importer, path_item, only)
+
def find_eggs_in_zip(importer, path_item, only=False):
"""
Find eggs in zip files; possibly multiple nested eggs.
@@ -1950,12 +1956,17 @@ def find_eggs_in_zip(importer, path_item, only=False):
for dist in find_eggs_in_zip(zipimport.zipimporter(subpath), subpath):
yield dist
+
register_finder(zipimport.zipimporter, find_eggs_in_zip)
+
def find_nothing(importer, path_item, only=False):
return ()
+
+
register_finder(object, find_nothing)
+
def find_on_path(importer, path_item, only=False):
"""Yield distributions accessible on a sys.path directory"""
path_item = _normalize_cached(path_item)
@@ -1964,17 +1975,25 @@ def find_on_path(importer, path_item, only=False):
if _is_unpacked_egg(path_item):
yield Distribution.from_filename(
path_item, metadata=PathMetadata(
- path_item, os.path.join(path_item,'EGG-INFO')
+ path_item, os.path.join(path_item, 'EGG-INFO')
)
)
else:
# scan for .egg and .egg-info in directory
- for entry in os.listdir(path_item):
+
+ path_item_entries = os.listdir(path_item)
+ # Reverse so we find the newest version of a distribution,
+ path_item_entries.sort()
+ path_item_entries.reverse()
+ for entry in path_item_entries:
lower = entry.lower()
if lower.endswith('.egg-info') or lower.endswith('.dist-info'):
fullpath = os.path.join(path_item, entry)
if os.path.isdir(fullpath):
# egg-info directory, allow getting metadata
+ if len(os.listdir(fullpath)) == 0:
+ # Empty egg directory, skip.
+ continue
metadata = PathMetadata(path_item, fullpath)
else:
metadata = FileMetadata(fullpath)
@@ -1996,6 +2015,8 @@ def find_on_path(importer, path_item, only=False):
for item in dists:
yield item
break
+
+
register_finder(pkgutil.ImpImporter, find_on_path)
if hasattr(importlib_machinery, 'FileFinder'):
@@ -2022,6 +2043,7 @@ def register_namespace_handler(importer_type, namespace_handler):
"""
_namespace_handlers[importer_type] = namespace_handler
+
def _handle_ns(packageName, path_item):
"""Ensure that named package includes a subpath of path_item (if needed)"""
@@ -2036,7 +2058,7 @@ def _handle_ns(packageName, path_item):
module = sys.modules[packageName] = types.ModuleType(packageName)
module.__path__ = []
_set_parent_ns(packageName)
- elif not hasattr(module,'__path__'):
+ elif not hasattr(module, '__path__'):
raise TypeError("Not a package:", packageName)
handler = _find_adapter(_namespace_handlers, importer)
subpath = handler(importer, path_item, packageName, module)
@@ -2054,6 +2076,16 @@ def _rebuild_mod_path(orig_path, package_name, module):
corresponding to their sys.path order
"""
sys_path = [_normalize_cached(p) for p in sys.path]
+
+ def safe_sys_path_index(entry):
+ """
+ Workaround for #520 and #513.
+ """
+ try:
+ return sys_path.index(entry)
+ except ValueError:
+ return float('inf')
+
def position_in_sys_path(path):
"""
Return the ordinal of the path based on its position in sys.path
@@ -2061,7 +2093,7 @@ def _rebuild_mod_path(orig_path, package_name, module):
path_parts = path.split(os.sep)
module_parts = package_name.count('.') + 1
parts = path_parts[:-module_parts]
- return sys_path.index(_normalize_cached(os.sep.join(parts)))
+ return safe_sys_path_index(_normalize_cached(os.sep.join(parts)))
orig_path.sort(key=position_in_sys_path)
module.__path__[:] = [_normalize_cached(p) for p in orig_path]
@@ -2088,8 +2120,8 @@ def declare_namespace(packageName):
# Track what packages are namespaces, so when new path items are added,
# they can be updated
- _namespace_packages.setdefault(parent,[]).append(packageName)
- _namespace_packages.setdefault(packageName,[])
+ _namespace_packages.setdefault(parent, []).append(packageName)
+ _namespace_packages.setdefault(packageName, [])
for path_item in path:
# Ensure all the parent's path items are reflected in the child,
@@ -2099,29 +2131,32 @@ def declare_namespace(packageName):
finally:
_imp.release_lock()
+
def fixup_namespace_packages(path_item, parent=None):
"""Ensure that previously-declared namespace packages include path_item"""
_imp.acquire_lock()
try:
- for package in _namespace_packages.get(parent,()):
+ for package in _namespace_packages.get(parent, ()):
subpath = _handle_ns(package, path_item)
if subpath:
fixup_namespace_packages(subpath, package)
finally:
_imp.release_lock()
+
def file_ns_handler(importer, path_item, packageName, module):
"""Compute an ns-package subpath for a filesystem or zipfile importer"""
subpath = os.path.join(path_item, packageName.split('.')[-1])
normalized = _normalize_cached(subpath)
for item in module.__path__:
- if _normalize_cached(item)==normalized:
+ if _normalize_cached(item) == normalized:
break
else:
# Only return the path if it's not already there
return subpath
+
register_namespace_handler(pkgutil.ImpImporter, file_ns_handler)
register_namespace_handler(zipimport.zipimporter, file_ns_handler)
@@ -2132,6 +2167,7 @@ if hasattr(importlib_machinery, 'FileFinder'):
def null_ns_handler(importer, path_item, packageName, module):
return None
+
register_namespace_handler(object, null_ns_handler)
@@ -2139,6 +2175,7 @@ def normalize_path(filename):
"""Normalize a file/dir name for comparison purposes"""
return os.path.normcase(os.path.realpath(filename))
+
def _normalize_cached(filename, _cache={}):
try:
return _cache[filename]
@@ -2146,6 +2183,7 @@ def _normalize_cached(filename, _cache={}):
_cache[filename] = result = normalize_path(filename)
return result
+
def _is_unpacked_egg(path):
"""
Determine if given path appears to be an unpacked egg.
@@ -2154,6 +2192,7 @@ def _is_unpacked_egg(path):
path.lower().endswith('.egg')
)
+
def _set_parent_ns(packageName):
parts = packageName.split('.')
name = parts.pop()
@@ -2175,6 +2214,7 @@ def yield_lines(strs):
for s in yield_lines(ss):
yield s
+
MODULE = re.compile(r"\w+(\.\w+)*$").match
EGG_NAME = re.compile(
r"""
@@ -2293,7 +2333,7 @@ class EntryPoint(object):
ep = cls.parse(line, dist)
if ep.name in this:
raise ValueError("Duplicate entry point", group, ep.name)
- this[ep.name]=ep
+ this[ep.name] = ep
return this
@classmethod
@@ -2355,7 +2395,7 @@ class Distribution(object):
@classmethod
def from_location(cls, location, basename, metadata=None, **kw):
- project_name, version, py_version, platform = [None]*4
+ project_name, version, py_version, platform = [None] * 4
basename, ext = os.path.splitext(basename)
if ext.lower() in _distributionImpl:
cls = _distributionImpl[ext.lower()]
@@ -2477,11 +2517,11 @@ class Distribution(object):
extra, marker = extra.split(':', 1)
if invalid_marker(marker):
# XXX warn
- reqs=[]
+ reqs = []
elif not evaluate_marker(marker):
- reqs=[]
+ reqs = []
extra = safe_extra(extra) or None
- dm.setdefault(extra,[]).extend(parse_requirements(reqs))
+ dm.setdefault(extra, []).extend(parse_requirements(reqs))
return dm
def requires(self, extras=()):
@@ -2503,11 +2543,11 @@ class Distribution(object):
for line in self.get_metadata_lines(name):
yield line
- def activate(self, path=None):
+ def activate(self, path=None, replace=False):
"""Ensure distribution is importable on `path` (default=sys.path)"""
if path is None:
path = sys.path
- self.insert_on(path, replace=True)
+ self.insert_on(path, replace=replace)
if path is sys.path:
fixup_namespace_packages(self.location)
for pkg in self._get_metadata('namespace_packages.txt'):
@@ -2577,7 +2617,7 @@ class Distribution(object):
self._get_metadata('entry_points.txt'), self
)
if group is not None:
- return ep_map.get(group,{})
+ return ep_map.get(group, {})
return ep_map
def get_entry_info(self, group, name):
@@ -2585,7 +2625,24 @@ class Distribution(object):
return self.get_entry_map(group).get(name)
def insert_on(self, path, loc=None, replace=False):
- """Insert self.location in path before its nearest parent directory"""
+ """Ensure self.location is on path
+
+ If replace=False (default):
+ - If location is already in path anywhere, do nothing.
+ - Else:
+ - If it's an egg and its parent directory is on path,
+ insert just ahead of the parent.
+ - Else: add to the end of path.
+ If replace=True:
+ - If location is already on path anywhere (not eggs)
+ or higher priority than its parent (eggs)
+ do nothing.
+ - Else:
+ - If it's an egg and its parent directory is on path,
+ insert just ahead of the parent,
+ removing any lower-priority entries.
+ - Else: add it to the front of path.
+ """
loc = loc or self.location
if not loc:
@@ -2593,13 +2650,20 @@ class Distribution(object):
nloc = _normalize_cached(loc)
bdir = os.path.dirname(nloc)
- npath= [(p and _normalize_cached(p) or p) for p in path]
+ npath = [(p and _normalize_cached(p) or p) for p in path]
for p, item in enumerate(npath):
if item == nloc:
- break
+ if replace:
+ break
+ else:
+ # don't modify path (even removing duplicates) if found and not replace
+ return
elif item == bdir and self.precedence == EGG_DIST:
# if it's an .egg, give it precedence over its directory
+ # UNLESS it's already been added to sys.path and replace=False
+ if (not replace) and nloc in npath[p:]:
+ return
if path is sys.path:
self.check_version_conflict()
path.insert(p, loc)
@@ -2617,7 +2681,7 @@ class Distribution(object):
# p is the spot where we found or inserted loc; now remove duplicates
while True:
try:
- np = npath.index(nloc, p+1)
+ np = npath.index(nloc, p + 1)
except ValueError:
break
else:
@@ -2657,7 +2721,7 @@ class Distribution(object):
return False
return True
- def clone(self,**kw):
+ def clone(self, **kw):
"""Copy this distribution, substituting in any changed keyword args"""
names = 'project_name version py_version platform location precedence'
for attr in names.split():
@@ -2671,7 +2735,6 @@ class Distribution(object):
class EggInfoDistribution(Distribution):
-
def _reload_version(self):
"""
Packages installed by distutils (e.g. numpy or scipy),
@@ -2731,8 +2794,8 @@ class DistInfoDistribution(Distribution):
dm[None].extend(common)
for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
- extra = safe_extra(extra.strip())
- dm[extra] = list(frozenset(reqs_for_extra(extra)) - common)
+ s_extra = safe_extra(extra.strip())
+ dm[s_extra] = list(frozenset(reqs_for_extra(extra)) - common)
return dm
@@ -2744,7 +2807,7 @@ _distributionImpl = {
}
-def issue_warning(*args,**kw):
+def issue_warning(*args, **kw):
level = 1
g = globals()
try:
@@ -2837,10 +2900,14 @@ class Requirement(packaging.requirements.Requirement):
def _get_mro(cls):
"""Get an mro for a type or classic class"""
if not isinstance(cls, type):
- class cls(cls, object): pass
+
+ class cls(cls, object):
+ pass
+
return cls.__mro__[1:]
return cls.__mro__
+
def _find_adapter(registry, ob):
"""Return an adapter factory for `ob` from `registry`"""
for t in _get_mro(getattr(ob, '__class__', type(ob))):
@@ -2890,12 +2957,13 @@ def split_sections(s):
# wrap up last segment
yield section, content
-def _mkstemp(*args,**kw):
+
+def _mkstemp(*args, **kw):
old_open = os.open
try:
# temporarily bypass sandboxing
os.open = os_open
- return tempfile.mkstemp(*args,**kw)
+ return tempfile.mkstemp(*args, **kw)
finally:
# and then put it back
os.open = old_open
@@ -2946,11 +3014,16 @@ def _initialize_master_working_set():
run_script = working_set.run_script
# backward compatibility
run_main = run_script
- # Activate all distributions already on sys.path, and ensure that
- # all distributions added to the working set in the future (e.g. by
- # calling ``require()``) will get activated as well.
- add_activation_listener(lambda dist: dist.activate())
- working_set.entries=[]
+ # Activate all distributions already on sys.path with replace=False and
+ # ensure that all distributions added to the working set in the future
+ # (e.g. by calling ``require()``) will get activated as well,
+ # with higher priority (replace=True).
+ dist = None # ensure dist is defined for del dist below
+ for dist in working_set:
+ dist.activate(replace=False)
+ del dist
+ add_activation_listener(lambda dist: dist.activate(replace=True), existing=False)
+ working_set.entries = []
# match order
list(map(working_set.add_entry, sys.path))
globals().update(locals())
diff --git a/pip/_vendor/vendor.txt b/pip/_vendor/vendor.txt
index b744fc7bf..d1d359e52 100644
--- a/pip/_vendor/vendor.txt
+++ b/pip/_vendor/vendor.txt
@@ -1,3 +1,4 @@
+appdirs==1.4.0
distlib==0.2.4
distro==1.0.0
html5lib==1.0b10