Imported Upstream version 49.0.0 upstream/49.0.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 29 Dec 2020 22:06:45 +0000 (07:06 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 29 Dec 2020 22:06:45 +0000 (07:06 +0900)
27 files changed:
.bumpversion.cfg
CHANGES.rst
pkg_resources/__init__.py
pkg_resources/_vendor/packaging/__about__.py
pkg_resources/_vendor/packaging/__init__.py
pkg_resources/_vendor/packaging/_compat.py
pkg_resources/_vendor/packaging/_structures.py
pkg_resources/_vendor/packaging/markers.py
pkg_resources/_vendor/packaging/requirements.py
pkg_resources/_vendor/packaging/specifiers.py
pkg_resources/_vendor/packaging/tags.py [new file with mode: 0644]
pkg_resources/_vendor/packaging/utils.py
pkg_resources/_vendor/packaging/version.py
pkg_resources/_vendor/vendored.txt
setup.cfg
setuptools/archive_util.py
setuptools/command/develop.py
setuptools/command/easy_install.py
setuptools/command/egg_info.py
setuptools/command/rotate.py
setuptools/config.py
setuptools/dist.py
setuptools/installer.py
setuptools/msvc.py
setuptools/site-patch.py [deleted file]
setuptools/tests/test_easy_install.py
tox.ini

index bee22c9e0e3032c822690047d96a123fbcbe71b2..05ff5f1881e9847dab0d119f61640c0417289f5e 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 48.0.0
+current_version = 49.0.0
 commit = True
 tag = True
 
index d653d88920ce9a66ad75eb7410865023d3b00861..bd67931d715c4e16cd64e2cb56c2be922096777a 100644 (file)
@@ -1,3 +1,12 @@
+v49.0.0
+-------
+
+* #2165: Setuptools no longer installs a site.py file during easy_install or develop installs. As a result, .eggs on PYTHONPATH will no longer take precedence over other packages on sys.path. If this issue affects your production environment, please reach out to the maintainers at #2165.
+* #2137: Removed (private) pkg_resources.RequirementParseError, now replaced by packaging.requirements.InvalidRequirement. Kept the name for compatibility, but users should catch InvalidRequirement instead.
+* #2180: Update vendored packaging in pkg_resources to 19.2.
+* #2199: Fix exception causes all over the codebase by using ``raise new_exception from old_exception``
+
+
 v48.0.0
 -------
 
index 4ba49ec1e9044b92043107bacb9b32386b3bcd26..b9534903be567fb9e31a420363d3794aabeb78c0 100644 (file)
@@ -1378,7 +1378,7 @@ def evaluate_marker(text, extra=None):
         marker = packaging.markers.Marker(text)
         return marker.evaluate()
     except packaging.markers.InvalidMarker as e:
-        raise SyntaxError(e)
+        raise SyntaxError(e) from e
 
 
 class NullProvider:
@@ -2288,8 +2288,8 @@ def declare_namespace(packageName):
                 __import__(parent)
             try:
                 path = sys.modules[parent].__path__
-            except AttributeError:
-                raise TypeError("Not a package:", parent)
+            except AttributeError as e:
+                raise TypeError("Not a package:", parent) from e
 
         # Track what packages are namespaces, so when new path items are added,
         # they can be updated
@@ -2469,7 +2469,7 @@ class EntryPoint:
         try:
             return functools.reduce(getattr, self.attrs, module)
         except AttributeError as exc:
-            raise ImportError(str(exc))
+            raise ImportError(str(exc)) from exc
 
     def require(self, env=None, installer=None):
         if self.extras and not self.dist:
@@ -2689,14 +2689,14 @@ class Distribution:
     def version(self):
         try:
             return self._version
-        except AttributeError:
+        except AttributeError as e:
             version = self._get_version()
             if version is None:
                 path = self._get_metadata_path_for_display(self.PKG_INFO)
                 msg = (
                     "Missing 'Version:' header and/or {} file at path: {}"
                 ).format(self.PKG_INFO, path)
-                raise ValueError(msg, self)
+                raise ValueError(msg, self) from e
 
             return version
 
@@ -2749,10 +2749,10 @@ class Distribution:
         for ext in extras:
             try:
                 deps.extend(dm[safe_extra(ext)])
-            except KeyError:
+            except KeyError as e:
                 raise UnknownExtra(
                     "%s has no such extra feature %r" % (self, ext)
-                )
+                ) from e
         return deps
 
     def _get_metadata_path_for_display(self, name):
@@ -3077,11 +3077,6 @@ def issue_warning(*args, **kw):
     warnings.warn(stacklevel=level + 1, *args, **kw)
 
 
-class RequirementParseError(ValueError):
-    def __str__(self):
-        return ' '.join(self.args)
-
-
 def parse_requirements(strs):
     """Yield ``Requirement`` objects for each specification in `strs`
 
@@ -3104,13 +3099,14 @@ def parse_requirements(strs):
         yield Requirement(line)
 
 
+class RequirementParseError(packaging.requirements.InvalidRequirement):
+    "Compatibility wrapper for InvalidRequirement"
+
+
 class Requirement(packaging.requirements.Requirement):
     def __init__(self, requirement_string):
         """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
-        try:
-            super(Requirement, self).__init__(requirement_string)
-        except packaging.requirements.InvalidRequirement as e:
-            raise RequirementParseError(str(e))
+        super(Requirement, self).__init__(requirement_string)
         self.unsafe_name = self.name
         project_name = safe_name(self.name)
         self.project_name, self.key = project_name, project_name.lower()
index 95d330ef823aa2e12f7846bc63c0955b25df6029..dc95138d049ba3194964d528b552a6d1514fa382 100644 (file)
@@ -4,18 +4,24 @@
 from __future__ import absolute_import, division, print_function
 
 __all__ = [
-    "__title__", "__summary__", "__uri__", "__version__", "__author__",
-    "__email__", "__license__", "__copyright__",
+    "__title__",
+    "__summary__",
+    "__uri__",
+    "__version__",
+    "__author__",
+    "__email__",
+    "__license__",
+    "__copyright__",
 ]
 
 __title__ = "packaging"
 __summary__ = "Core utilities for Python packages"
 __uri__ = "https://github.com/pypa/packaging"
 
-__version__ = "16.8"
+__version__ = "19.2"
 
 __author__ = "Donald Stufft and individual contributors"
 __email__ = "donald@stufft.io"
 
 __license__ = "BSD or Apache License, Version 2.0"
-__copyright__ = "Copyright 2014-2016 %s" % __author__
+__copyright__ = "Copyright 2014-2019 %s" % __author__
index 5ee6220203e5425f900fb5a43676c24ea377c2fa..a0cf67df5245be16a020ca048832e180f7ce8661 100644 (file)
@@ -4,11 +4,23 @@
 from __future__ import absolute_import, division, print_function
 
 from .__about__ import (
-    __author__, __copyright__, __email__, __license__, __summary__, __title__,
-    __uri__, __version__
+    __author__,
+    __copyright__,
+    __email__,
+    __license__,
+    __summary__,
+    __title__,
+    __uri__,
+    __version__,
 )
 
 __all__ = [
-    "__title__", "__summary__", "__uri__", "__version__", "__author__",
-    "__email__", "__license__", "__copyright__",
+    "__title__",
+    "__summary__",
+    "__uri__",
+    "__version__",
+    "__author__",
+    "__email__",
+    "__license__",
+    "__copyright__",
 ]
index 210bb80b7e7b64cb79f7e7cdf3e42819fe3471fe..25da473c196855ad59a6d2d785ef1ddef49795be 100644 (file)
@@ -12,9 +12,9 @@ PY3 = sys.version_info[0] == 3
 # flake8: noqa
 
 if PY3:
-    string_types = str,
+    string_types = (str,)
 else:
-    string_types = basestring,
+    string_types = (basestring,)
 
 
 def with_metaclass(meta, *bases):
@@ -27,4 +27,5 @@ def with_metaclass(meta, *bases):
     class metaclass(meta):
         def __new__(cls, name, this_bases, d):
             return meta(name, bases, d)
-    return type.__new__(metaclass, 'temporary_class', (), {})
+
+    return type.__new__(metaclass, "temporary_class", (), {})
index ccc27861c3a4d9efaa3db753c77c4515a627bd98..68dcca634d8e3f0081bad2f9ae5e653a2942db68 100644 (file)
@@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function
 
 
 class Infinity(object):
-
     def __repr__(self):
         return "Infinity"
 
@@ -33,11 +32,11 @@ class Infinity(object):
     def __neg__(self):
         return NegativeInfinity
 
+
 Infinity = Infinity()
 
 
 class NegativeInfinity(object):
-
     def __repr__(self):
         return "-Infinity"
 
@@ -65,4 +64,5 @@ class NegativeInfinity(object):
     def __neg__(self):
         return Infinity
 
+
 NegativeInfinity = NegativeInfinity()
index 892e578edd4b992cc2996c31d9deb13af73d62c0..733123fb3220fc5d732848ffe4336f4b61dc2c70 100644 (file)
@@ -17,8 +17,11 @@ from .specifiers import Specifier, InvalidSpecifier
 
 
 __all__ = [
-    "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName",
-    "Marker", "default_environment",
+    "InvalidMarker",
+    "UndefinedComparison",
+    "UndefinedEnvironmentName",
+    "Marker",
+    "default_environment",
 ]
 
 
@@ -42,7 +45,6 @@ class UndefinedEnvironmentName(ValueError):
 
 
 class Node(object):
-
     def __init__(self, value):
         self.value = value
 
@@ -57,62 +59,52 @@ class Node(object):
 
 
 class Variable(Node):
-
     def serialize(self):
         return str(self)
 
 
 class Value(Node):
-
     def serialize(self):
         return '"{0}"'.format(self)
 
 
 class Op(Node):
-
     def serialize(self):
         return str(self)
 
 
 VARIABLE = (
-    L("implementation_version") |
-    L("platform_python_implementation") |
-    L("implementation_name") |
-    L("python_full_version") |
-    L("platform_release") |
-    L("platform_version") |
-    L("platform_machine") |
-    L("platform_system") |
-    L("python_version") |
-    L("sys_platform") |
-    L("os_name") |
-    L("os.name") |  # PEP-345
-    L("sys.platform") |  # PEP-345
-    L("platform.version") |  # PEP-345
-    L("platform.machine") |  # PEP-345
-    L("platform.python_implementation") |  # PEP-345
-    L("python_implementation") |  # undocumented setuptools legacy
-    L("extra")
+    L("implementation_version")
+    | L("platform_python_implementation")
+    | L("implementation_name")
+    | L("python_full_version")
+    | L("platform_release")
+    | L("platform_version")
+    | L("platform_machine")
+    | L("platform_system")
+    | L("python_version")
+    | L("sys_platform")
+    | L("os_name")
+    | L("os.name")
+    | L("sys.platform")  # PEP-345
+    | L("platform.version")  # PEP-345
+    | L("platform.machine")  # PEP-345
+    | L("platform.python_implementation")  # PEP-345
+    | L("python_implementation")  # PEP-345
+    | L("extra")  # undocumented setuptools legacy
 )
 ALIASES = {
-    'os.name': 'os_name',
-    'sys.platform': 'sys_platform',
-    'platform.version': 'platform_version',
-    'platform.machine': 'platform_machine',
-    'platform.python_implementation': 'platform_python_implementation',
-    'python_implementation': 'platform_python_implementation'
+    "os.name": "os_name",
+    "sys.platform": "sys_platform",
+    "platform.version": "platform_version",
+    "platform.machine": "platform_machine",
+    "platform.python_implementation": "platform_python_implementation",
+    "python_implementation": "platform_python_implementation",
 }
 VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
 
 VERSION_CMP = (
-    L("===") |
-    L("==") |
-    L(">=") |
-    L("<=") |
-    L("!=") |
-    L("~=") |
-    L(">") |
-    L("<")
+    L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
 )
 
 MARKER_OP = VERSION_CMP | L("not in") | L("in")
@@ -152,8 +144,11 @@ def _format_marker(marker, first=True):
     # where the single item is itself it's own list. In that case we want skip
     # the rest of this function so that we don't get extraneous () on the
     # outside.
-    if (isinstance(marker, list) and len(marker) == 1 and
-            isinstance(marker[0], (list, tuple))):
+    if (
+        isinstance(marker, list)
+        and len(marker) == 1
+        and isinstance(marker[0], (list, tuple))
+    ):
         return _format_marker(marker[0])
 
     if isinstance(marker, list):
@@ -239,20 +234,20 @@ def _evaluate_markers(markers, environment):
 
 
 def format_full_version(info):
-    version = '{0.major}.{0.minor}.{0.micro}'.format(info)
+    version = "{0.major}.{0.minor}.{0.micro}".format(info)
     kind = info.releaselevel
-    if kind != 'final':
+    if kind != "final":
         version += kind[0] + str(info.serial)
     return version
 
 
 def default_environment():
-    if hasattr(sys, 'implementation'):
+    if hasattr(sys, "implementation"):
         iver = format_full_version(sys.implementation.version)
         implementation_name = sys.implementation.name
     else:
-        iver = '0'
-        implementation_name = ''
+        iver = "0"
+        implementation_name = ""
 
     return {
         "implementation_name": implementation_name,
@@ -264,19 +259,19 @@ def default_environment():
         "platform_version": platform.version(),
         "python_full_version": platform.python_version(),
         "platform_python_implementation": platform.python_implementation(),
-        "python_version": platform.python_version()[:3],
+        "python_version": ".".join(platform.python_version_tuple()[:2]),
         "sys_platform": sys.platform,
     }
 
 
 class Marker(object):
-
     def __init__(self, marker):
         try:
             self._markers = _coerce_parse_result(MARKER.parseString(marker))
         except ParseException as e:
             err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
-                marker, marker[e.loc:e.loc + 8])
+                marker, marker[e.loc : e.loc + 8]
+            )
             raise InvalidMarker(err_str)
 
     def __str__(self):
index 0c8c4a3852fd37053fd552846aa7787805c30a48..c3424dcb64a2e092bfa8a815c30e1b1579fc568e 100644 (file)
@@ -38,8 +38,8 @@ IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
 NAME = IDENTIFIER("name")
 EXTRA = IDENTIFIER
 
-URI = Regex(r'[^ ]+')("url")
-URL = (AT + URI)
+URI = Regex(r"[^ ]+")("url")
+URL = AT + URI
 
 EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
 EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
@@ -48,28 +48,31 @@ VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
 VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
 
 VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
-VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE),
-                       joinString=",", adjacent=False)("_raw_spec")
+VERSION_MANY = Combine(
+    VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
+)("_raw_spec")
 _VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
-_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
+_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
 
 VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
 VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
 
 MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
 MARKER_EXPR.setParseAction(
-    lambda s, l, t: Marker(s[t._original_start:t._original_end])
+    lambda s, l, t: Marker(s[t._original_start : t._original_end])
 )
-MARKER_SEPERATOR = SEMICOLON
-MARKER = MARKER_SEPERATOR + MARKER_EXPR
+MARKER_SEPARATOR = SEMICOLON
+MARKER = MARKER_SEPARATOR + MARKER_EXPR
 
 VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
 URL_AND_MARKER = URL + Optional(MARKER)
 
-NAMED_REQUIREMENT = \
-    NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
+NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
 
 REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
+# pkg_resources.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
+# issue #104
+REQUIREMENT.parseString("x[]")
 
 
 class Requirement(object):
@@ -90,15 +93,21 @@ class Requirement(object):
             req = REQUIREMENT.parseString(requirement_string)
         except ParseException as e:
             raise InvalidRequirement(
-                "Invalid requirement, parse error at \"{0!r}\"".format(
-                    requirement_string[e.loc:e.loc + 8]))
+                'Parse error at "{0!r}": {1}'.format(
+                    requirement_string[e.loc : e.loc + 8], e.msg
+                )
+            )
 
         self.name = req.name
         if req.url:
             parsed_url = urlparse.urlparse(req.url)
-            if not (parsed_url.scheme and parsed_url.netloc) or (
-                    not parsed_url.scheme and not parsed_url.netloc):
-                raise InvalidRequirement("Invalid URL given")
+            if parsed_url.scheme == "file":
+                if urlparse.urlunparse(parsed_url) != req.url:
+                    raise InvalidRequirement("Invalid URL given")
+            elif not (parsed_url.scheme and parsed_url.netloc) or (
+                not parsed_url.scheme and not parsed_url.netloc
+            ):
+                raise InvalidRequirement("Invalid URL: {0}".format(req.url))
             self.url = req.url
         else:
             self.url = None
@@ -117,6 +126,8 @@ class Requirement(object):
 
         if self.url:
             parts.append("@ {0}".format(self.url))
+            if self.marker:
+                parts.append(" ")
 
         if self.marker:
             parts.append("; {0}".format(self.marker))
index 7f5a76cfd63f47dcce29b3ea82f59d10f4e8d771..743576a080a0af8d0995f307ea6afc645b13ca61 100644 (file)
@@ -19,7 +19,6 @@ class InvalidSpecifier(ValueError):
 
 
 class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
-
     @abc.abstractmethod
     def __str__(self):
         """
@@ -84,10 +83,7 @@ class _IndividualSpecifier(BaseSpecifier):
         if not match:
             raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
 
-        self._spec = (
-            match.group("operator").strip(),
-            match.group("version").strip(),
-        )
+        self._spec = (match.group("operator").strip(), match.group("version").strip())
 
         # Store whether or not this Specifier should accept prereleases
         self._prereleases = prereleases
@@ -99,11 +95,7 @@ class _IndividualSpecifier(BaseSpecifier):
             else ""
         )
 
-        return "<{0}({1!r}{2})>".format(
-            self.__class__.__name__,
-            str(self),
-            pre,
-        )
+        return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
 
     def __str__(self):
         return "{0}{1}".format(*self._spec)
@@ -194,11 +186,12 @@ class _IndividualSpecifier(BaseSpecifier):
                 # If our version is a prerelease, and we were not set to allow
                 # prereleases, then we'll store it for later incase nothing
                 # else matches this specifier.
-                if (parsed_version.is_prerelease and not
-                        (prereleases or self.prereleases)):
+                if parsed_version.is_prerelease and not (
+                    prereleases or self.prereleases
+                ):
                     found_prereleases.append(version)
                 # Either this is not a prerelease, or we should have been
-                # accepting prereleases from the begining.
+                # accepting prereleases from the beginning.
                 else:
                     yielded = True
                     yield version
@@ -213,8 +206,7 @@ class _IndividualSpecifier(BaseSpecifier):
 
 class LegacySpecifier(_IndividualSpecifier):
 
-    _regex_str = (
-        r"""
+    _regex_str = r"""
         (?P<operator>(==|!=|<=|>=|<|>))
         \s*
         (?P<version>
@@ -225,10 +217,8 @@ class LegacySpecifier(_IndividualSpecifier):
                       # them, and a comma since it's a version separator.
         )
         """
-    )
 
-    _regex = re.compile(
-        r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+    _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
 
     _operators = {
         "==": "equal",
@@ -269,13 +259,13 @@ def _require_version_compare(fn):
         if not isinstance(prospective, Version):
             return False
         return fn(self, prospective, spec)
+
     return wrapped
 
 
 class Specifier(_IndividualSpecifier):
 
-    _regex_str = (
-        r"""
+    _regex_str = r"""
         (?P<operator>(~=|==|!=|<=|>=|<|>|===))
         (?P<version>
             (?:
@@ -367,10 +357,8 @@ class Specifier(_IndividualSpecifier):
             )
         )
         """
-    )
 
-    _regex = re.compile(
-        r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+    _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
 
     _operators = {
         "~=": "compatible",
@@ -397,8 +385,7 @@ class Specifier(_IndividualSpecifier):
         prefix = ".".join(
             list(
                 itertools.takewhile(
-                    lambda x: (not x.startswith("post") and not
-                               x.startswith("dev")),
+                    lambda x: (not x.startswith("post") and not x.startswith("dev")),
                     _version_split(spec),
                 )
             )[:-1]
@@ -407,8 +394,9 @@ class Specifier(_IndividualSpecifier):
         # Add the prefix notation to the end of our string
         prefix += ".*"
 
-        return (self._get_operator(">=")(prospective, spec) and
-                self._get_operator("==")(prospective, prefix))
+        return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
+            prospective, prefix
+        )
 
     @_require_version_compare
     def _compare_equal(self, prospective, spec):
@@ -428,7 +416,7 @@ class Specifier(_IndividualSpecifier):
             # Shorten the prospective version to be the same length as the spec
             # so that we can determine if the specifier is a prefix of the
             # prospective version or not.
-            prospective = prospective[:len(spec)]
+            prospective = prospective[: len(spec)]
 
             # Pad out our two sides with zeros so that they both equal the same
             # length.
@@ -503,7 +491,7 @@ class Specifier(_IndividualSpecifier):
                 return False
 
         # Ensure that we do not allow a local version of the version mentioned
-        # in the specifier, which is techincally greater than, to match.
+        # in the specifier, which is technically greater than, to match.
         if prospective.local is not None:
             if Version(prospective.base_version) == Version(spec.base_version):
                 return False
@@ -567,27 +555,17 @@ def _pad_version(left, right):
     right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
 
     # Get the rest of our versions
-    left_split.append(left[len(left_split[0]):])
-    right_split.append(right[len(right_split[0]):])
+    left_split.append(left[len(left_split[0]) :])
+    right_split.append(right[len(right_split[0]) :])
 
     # Insert our padding
-    left_split.insert(
-        1,
-        ["0"] * max(0, len(right_split[0]) - len(left_split[0])),
-    )
-    right_split.insert(
-        1,
-        ["0"] * max(0, len(left_split[0]) - len(right_split[0])),
-    )
+    left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
+    right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
 
-    return (
-        list(itertools.chain(*left_split)),
-        list(itertools.chain(*right_split)),
-    )
+    return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
 
 
 class SpecifierSet(BaseSpecifier):
-
     def __init__(self, specifiers="", prereleases=None):
         # Split on , to break each indidivual specifier into it's own item, and
         # strip each item to remove leading/trailing whitespace.
@@ -721,10 +699,7 @@ class SpecifierSet(BaseSpecifier):
         # given version is contained within all of them.
         # Note: This use of all() here means that an empty set of specifiers
         #       will always return True, this is an explicit design decision.
-        return all(
-            s.contains(item, prereleases=prereleases)
-            for s in self._specs
-        )
+        return all(s.contains(item, prereleases=prereleases) for s in self._specs)
 
     def filter(self, iterable, prereleases=None):
         # Determine if we're forcing a prerelease or not, if we're not forcing
diff --git a/pkg_resources/_vendor/packaging/tags.py b/pkg_resources/_vendor/packaging/tags.py
new file mode 100644 (file)
index 0000000..ec9942f
--- /dev/null
@@ -0,0 +1,404 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import
+
+import distutils.util
+
+try:
+    from importlib.machinery import EXTENSION_SUFFIXES
+except ImportError:  # pragma: no cover
+    import imp
+
+    EXTENSION_SUFFIXES = [x[0] for x in imp.get_suffixes()]
+    del imp
+import platform
+import re
+import sys
+import sysconfig
+import warnings
+
+
+INTERPRETER_SHORT_NAMES = {
+    "python": "py",  # Generic.
+    "cpython": "cp",
+    "pypy": "pp",
+    "ironpython": "ip",
+    "jython": "jy",
+}
+
+
+_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32
+
+
+class Tag(object):
+
+    __slots__ = ["_interpreter", "_abi", "_platform"]
+
+    def __init__(self, interpreter, abi, platform):
+        self._interpreter = interpreter.lower()
+        self._abi = abi.lower()
+        self._platform = platform.lower()
+
+    @property
+    def interpreter(self):
+        return self._interpreter
+
+    @property
+    def abi(self):
+        return self._abi
+
+    @property
+    def platform(self):
+        return self._platform
+
+    def __eq__(self, other):
+        return (
+            (self.platform == other.platform)
+            and (self.abi == other.abi)
+            and (self.interpreter == other.interpreter)
+        )
+
+    def __hash__(self):
+        return hash((self._interpreter, self._abi, self._platform))
+
+    def __str__(self):
+        return "{}-{}-{}".format(self._interpreter, self._abi, self._platform)
+
+    def __repr__(self):
+        return "<{self} @ {self_id}>".format(self=self, self_id=id(self))
+
+
+def parse_tag(tag):
+    tags = set()
+    interpreters, abis, platforms = tag.split("-")
+    for interpreter in interpreters.split("."):
+        for abi in abis.split("."):
+            for platform_ in platforms.split("."):
+                tags.add(Tag(interpreter, abi, platform_))
+    return frozenset(tags)
+
+
+def _normalize_string(string):
+    return string.replace(".", "_").replace("-", "_")
+
+
+def _cpython_interpreter(py_version):
+    # TODO: Is using py_version_nodot for interpreter version critical?
+    return "cp{major}{minor}".format(major=py_version[0], minor=py_version[1])
+
+
+def _cpython_abis(py_version):
+    abis = []
+    version = "{}{}".format(*py_version[:2])
+    debug = pymalloc = ucs4 = ""
+    with_debug = sysconfig.get_config_var("Py_DEBUG")
+    has_refcount = hasattr(sys, "gettotalrefcount")
+    # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
+    # extension modules is the best option.
+    # https://github.com/pypa/pip/issues/3383#issuecomment-173267692
+    has_ext = "_d.pyd" in EXTENSION_SUFFIXES
+    if with_debug or (with_debug is None and (has_refcount or has_ext)):
+        debug = "d"
+    if py_version < (3, 8):
+        with_pymalloc = sysconfig.get_config_var("WITH_PYMALLOC")
+        if with_pymalloc or with_pymalloc is None:
+            pymalloc = "m"
+        if py_version < (3, 3):
+            unicode_size = sysconfig.get_config_var("Py_UNICODE_SIZE")
+            if unicode_size == 4 or (
+                unicode_size is None and sys.maxunicode == 0x10FFFF
+            ):
+                ucs4 = "u"
+    elif debug:
+        # Debug builds can also load "normal" extension modules.
+        # We can also assume no UCS-4 or pymalloc requirement.
+        abis.append("cp{version}".format(version=version))
+    abis.insert(
+        0,
+        "cp{version}{debug}{pymalloc}{ucs4}".format(
+            version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4
+        ),
+    )
+    return abis
+
+
+def _cpython_tags(py_version, interpreter, abis, platforms):
+    for abi in abis:
+        for platform_ in platforms:
+            yield Tag(interpreter, abi, platform_)
+    for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms):
+        yield tag
+    for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms):
+        yield tag
+    # PEP 384 was first implemented in Python 3.2.
+    for minor_version in range(py_version[1] - 1, 1, -1):
+        for platform_ in platforms:
+            interpreter = "cp{major}{minor}".format(
+                major=py_version[0], minor=minor_version
+            )
+            yield Tag(interpreter, "abi3", platform_)
+
+
+def _pypy_interpreter():
+    return "pp{py_major}{pypy_major}{pypy_minor}".format(
+        py_major=sys.version_info[0],
+        pypy_major=sys.pypy_version_info.major,
+        pypy_minor=sys.pypy_version_info.minor,
+    )
+
+
+def _generic_abi():
+    abi = sysconfig.get_config_var("SOABI")
+    if abi:
+        return _normalize_string(abi)
+    else:
+        return "none"
+
+
+def _pypy_tags(py_version, interpreter, abi, platforms):
+    for tag in (Tag(interpreter, abi, platform) for platform in platforms):
+        yield tag
+    for tag in (Tag(interpreter, "none", platform) for platform in platforms):
+        yield tag
+
+
+def _generic_tags(interpreter, py_version, abi, platforms):
+    for tag in (Tag(interpreter, abi, platform) for platform in platforms):
+        yield tag
+    if abi != "none":
+        tags = (Tag(interpreter, "none", platform_) for platform_ in platforms)
+        for tag in tags:
+            yield tag
+
+
+def _py_interpreter_range(py_version):
+    """
+    Yield Python versions in descending order.
+
+    After the latest version, the major-only version will be yielded, and then
+    all following versions up to 'end'.
+    """
+    yield "py{major}{minor}".format(major=py_version[0], minor=py_version[1])
+    yield "py{major}".format(major=py_version[0])
+    for minor in range(py_version[1] - 1, -1, -1):
+        yield "py{major}{minor}".format(major=py_version[0], minor=minor)
+
+
+def _independent_tags(interpreter, py_version, platforms):
+    """
+    Return the sequence of tags that are consistent across implementations.
+
+    The tags consist of:
+    - py*-none-<platform>
+    - <interpreter>-none-any
+    - py*-none-any
+    """
+    for version in _py_interpreter_range(py_version):
+        for platform_ in platforms:
+            yield Tag(version, "none", platform_)
+    yield Tag(interpreter, "none", "any")
+    for version in _py_interpreter_range(py_version):
+        yield Tag(version, "none", "any")
+
+
+def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
+    if not is_32bit:
+        return arch
+
+    if arch.startswith("ppc"):
+        return "ppc"
+
+    return "i386"
+
+
+def _mac_binary_formats(version, cpu_arch):
+    formats = [cpu_arch]
+    if cpu_arch == "x86_64":
+        if version < (10, 4):
+            return []
+        formats.extend(["intel", "fat64", "fat32"])
+
+    elif cpu_arch == "i386":
+        if version < (10, 4):
+            return []
+        formats.extend(["intel", "fat32", "fat"])
+
+    elif cpu_arch == "ppc64":
+        # TODO: Need to care about 32-bit PPC for ppc64 through 10.2?
+        if version > (10, 5) or version < (10, 4):
+            return []
+        formats.append("fat64")
+
+    elif cpu_arch == "ppc":
+        if version > (10, 6):
+            return []
+        formats.extend(["fat32", "fat"])
+
+    formats.append("universal")
+    return formats
+
+
+def _mac_platforms(version=None, arch=None):
+    version_str, _, cpu_arch = platform.mac_ver()
+    if version is None:
+        version = tuple(map(int, version_str.split(".")[:2]))
+    if arch is None:
+        arch = _mac_arch(cpu_arch)
+    platforms = []
+    for minor_version in range(version[1], -1, -1):
+        compat_version = version[0], minor_version
+        binary_formats = _mac_binary_formats(compat_version, arch)
+        for binary_format in binary_formats:
+            platforms.append(
+                "macosx_{major}_{minor}_{binary_format}".format(
+                    major=compat_version[0],
+                    minor=compat_version[1],
+                    binary_format=binary_format,
+                )
+            )
+    return platforms
+
+
+# From PEP 513.
+def _is_manylinux_compatible(name, glibc_version):
+    # Check for presence of _manylinux module.
+    try:
+        import _manylinux
+
+        return bool(getattr(_manylinux, name + "_compatible"))
+    except (ImportError, AttributeError):
+        # Fall through to heuristic check below.
+        pass
+
+    return _have_compatible_glibc(*glibc_version)
+
+
+def _glibc_version_string():
+    # Returns glibc version string, or None if not using glibc.
+    import ctypes
+
+    # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
+    # manpage says, "If filename is NULL, then the returned handle is for the
+    # main program". This way we can let the linker do the work to figure out
+    # which libc our process is actually using.
+    process_namespace = ctypes.CDLL(None)
+    try:
+        gnu_get_libc_version = process_namespace.gnu_get_libc_version
+    except AttributeError:
+        # Symbol doesn't exist -> therefore, we are not linked to
+        # glibc.
+        return None
+
+    # Call gnu_get_libc_version, which returns a string like "2.5"
+    gnu_get_libc_version.restype = ctypes.c_char_p
+    version_str = gnu_get_libc_version()
+    # py2 / py3 compatibility:
+    if not isinstance(version_str, str):
+        version_str = version_str.decode("ascii")
+
+    return version_str
+
+
+# Separated out from have_compatible_glibc for easier unit testing.
+def _check_glibc_version(version_str, required_major, minimum_minor):
+    # Parse string and check against requested version.
+    #
+    # We use a regexp instead of str.split because we want to discard any
+    # random junk that might come after the minor version -- this might happen
+    # in patched/forked versions of glibc (e.g. Linaro's version of glibc
+    # uses version strings like "2.20-2014.11"). See gh-3588.
+    m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
+    if not m:
+        warnings.warn(
+            "Expected glibc version with 2 components major.minor,"
+            " got: %s" % version_str,
+            RuntimeWarning,
+        )
+        return False
+    return (
+        int(m.group("major")) == required_major
+        and int(m.group("minor")) >= minimum_minor
+    )
+
+
+def _have_compatible_glibc(required_major, minimum_minor):
+    version_str = _glibc_version_string()
+    if version_str is None:
+        return False
+    return _check_glibc_version(version_str, required_major, minimum_minor)
+
+
+def _linux_platforms(is_32bit=_32_BIT_INTERPRETER):
+    linux = _normalize_string(distutils.util.get_platform())
+    if linux == "linux_x86_64" and is_32bit:
+        linux = "linux_i686"
+    manylinux_support = (
+        ("manylinux2014", (2, 17)),  # CentOS 7 w/ glibc 2.17 (PEP 599)
+        ("manylinux2010", (2, 12)),  # CentOS 6 w/ glibc 2.12 (PEP 571)
+        ("manylinux1", (2, 5)),  # CentOS 5 w/ glibc 2.5 (PEP 513)
+    )
+    manylinux_support_iter = iter(manylinux_support)
+    for name, glibc_version in manylinux_support_iter:
+        if _is_manylinux_compatible(name, glibc_version):
+            platforms = [linux.replace("linux", name)]
+            break
+    else:
+        platforms = []
+    # Support for a later manylinux implies support for an earlier version.
+    platforms += [linux.replace("linux", name) for name, _ in manylinux_support_iter]
+    platforms.append(linux)
+    return platforms
+
+
+def _generic_platforms():
+    platform = _normalize_string(distutils.util.get_platform())
+    return [platform]
+
+
+def _interpreter_name():
+    name = platform.python_implementation().lower()
+    return INTERPRETER_SHORT_NAMES.get(name) or name
+
+
+def _generic_interpreter(name, py_version):
+    version = sysconfig.get_config_var("py_version_nodot")
+    if not version:
+        version = "".join(map(str, py_version[:2]))
+    return "{name}{version}".format(name=name, version=version)
+
+
+def sys_tags():
+    """
+    Returns the sequence of tag triples for the running interpreter.
+
+    The order of the sequence corresponds to priority order for the
+    interpreter, from most to least important.
+    """
+    py_version = sys.version_info[:2]
+    interpreter_name = _interpreter_name()
+    if platform.system() == "Darwin":
+        platforms = _mac_platforms()
+    elif platform.system() == "Linux":
+        platforms = _linux_platforms()
+    else:
+        platforms = _generic_platforms()
+
+    if interpreter_name == "cp":
+        interpreter = _cpython_interpreter(py_version)
+        abis = _cpython_abis(py_version)
+        for tag in _cpython_tags(py_version, interpreter, abis, platforms):
+            yield tag
+    elif interpreter_name == "pp":
+        interpreter = _pypy_interpreter()
+        abi = _generic_abi()
+        for tag in _pypy_tags(py_version, interpreter, abi, platforms):
+            yield tag
+    else:
+        interpreter = _generic_interpreter(interpreter_name, py_version)
+        abi = _generic_abi()
+        for tag in _generic_tags(interpreter, py_version, abi, platforms):
+            yield tag
+    for tag in _independent_tags(interpreter, py_version, platforms):
+        yield tag
index 942387cef5d75f299a769b1eb43b6c7679e7a3a0..88418786933b8bc5f6179b8e191f60f79efd7074 100644 (file)
@@ -5,6 +5,8 @@ from __future__ import absolute_import, division, print_function
 
 import re
 
+from .version import InvalidVersion, Version
+
 
 _canonicalize_regex = re.compile(r"[-_.]+")
 
@@ -12,3 +14,44 @@ _canonicalize_regex = re.compile(r"[-_.]+")
 def canonicalize_name(name):
     # This is taken from PEP 503.
     return _canonicalize_regex.sub("-", name).lower()
+
+
+def canonicalize_version(version):
+    """
+    This is very similar to Version.__str__, but has one subtle differences
+    with the way it handles the release segment.
+    """
+
+    try:
+        version = Version(version)
+    except InvalidVersion:
+        # Legacy versions cannot be normalized
+        return version
+
+    parts = []
+
+    # Epoch
+    if version.epoch != 0:
+        parts.append("{0}!".format(version.epoch))
+
+    # Release segment
+    # NB: This strips trailing '.0's to normalize
+    parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
+
+    # Pre-release
+    if version.pre is not None:
+        parts.append("".join(str(x) for x in version.pre))
+
+    # Post-release
+    if version.post is not None:
+        parts.append(".post{0}".format(version.post))
+
+    # Development release
+    if version.dev is not None:
+        parts.append(".dev{0}".format(version.dev))
+
+    # Local version segment
+    if version.local is not None:
+        parts.append("+{0}".format(version.local))
+
+    return "".join(parts)
index 83b5ee8c5efadf22ce2f16ff08c8a8d75f1eb5df..95157a1f78c26829ffbe1bd2463f7735b636d16f 100644 (file)
@@ -10,14 +10,11 @@ import re
 from ._structures import Infinity
 
 
-__all__ = [
-    "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
-]
+__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
 
 
 _Version = collections.namedtuple(
-    "_Version",
-    ["epoch", "release", "dev", "pre", "post", "local"],
+    "_Version", ["epoch", "release", "dev", "pre", "post", "local"]
 )
 
 
@@ -40,7 +37,6 @@ class InvalidVersion(ValueError):
 
 
 class _BaseVersion(object):
-
     def __hash__(self):
         return hash(self._key)
 
@@ -70,7 +66,6 @@ class _BaseVersion(object):
 
 
 class LegacyVersion(_BaseVersion):
-
     def __init__(self, version):
         self._version = str(version)
         self._key = _legacy_cmpkey(self._version)
@@ -89,6 +84,26 @@ class LegacyVersion(_BaseVersion):
     def base_version(self):
         return self._version
 
+    @property
+    def epoch(self):
+        return -1
+
+    @property
+    def release(self):
+        return None
+
+    @property
+    def pre(self):
+        return None
+
+    @property
+    def post(self):
+        return None
+
+    @property
+    def dev(self):
+        return None
+
     @property
     def local(self):
         return None
@@ -101,13 +116,19 @@ class LegacyVersion(_BaseVersion):
     def is_postrelease(self):
         return False
 
+    @property
+    def is_devrelease(self):
+        return False
 
-_legacy_version_component_re = re.compile(
-    r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
-)
+
+_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE)
 
 _legacy_version_replacement_map = {
-    "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
+    "pre": "c",
+    "preview": "c",
+    "-": "final-",
+    "rc": "c",
+    "dev": "@",
 }
 
 
@@ -154,6 +175,7 @@ def _legacy_cmpkey(version):
 
     return epoch, parts
 
+
 # Deliberately not anchored to the start and end of the string, to make it
 # easier for 3rd party code to reuse
 VERSION_PATTERN = r"""
@@ -190,10 +212,7 @@ VERSION_PATTERN = r"""
 
 class Version(_BaseVersion):
 
-    _regex = re.compile(
-        r"^\s*" + VERSION_PATTERN + r"\s*$",
-        re.VERBOSE | re.IGNORECASE,
-    )
+    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
 
     def __init__(self, version):
         # Validate the version and parse it into pieces
@@ -205,18 +224,11 @@ class Version(_BaseVersion):
         self._version = _Version(
             epoch=int(match.group("epoch")) if match.group("epoch") else 0,
             release=tuple(int(i) for i in match.group("release").split(".")),
-            pre=_parse_letter_version(
-                match.group("pre_l"),
-                match.group("pre_n"),
-            ),
+            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
             post=_parse_letter_version(
-                match.group("post_l"),
-                match.group("post_n1") or match.group("post_n2"),
-            ),
-            dev=_parse_letter_version(
-                match.group("dev_l"),
-                match.group("dev_n"),
+                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
             ),
+            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
             local=_parse_local_version(match.group("local")),
         )
 
@@ -237,32 +249,57 @@ class Version(_BaseVersion):
         parts = []
 
         # Epoch
-        if self._version.epoch != 0:
-            parts.append("{0}!".format(self._version.epoch))
+        if self.epoch != 0:
+            parts.append("{0}!".format(self.epoch))
 
         # Release segment
-        parts.append(".".join(str(x) for x in self._version.release))
+        parts.append(".".join(str(x) for x in self.release))
 
         # Pre-release
-        if self._version.pre is not None:
-            parts.append("".join(str(x) for x in self._version.pre))
+        if self.pre is not None:
+            parts.append("".join(str(x) for x in self.pre))
 
         # Post-release
-        if self._version.post is not None:
-            parts.append(".post{0}".format(self._version.post[1]))
+        if self.post is not None:
+            parts.append(".post{0}".format(self.post))
 
         # Development release
-        if self._version.dev is not None:
-            parts.append(".dev{0}".format(self._version.dev[1]))
+        if self.dev is not None:
+            parts.append(".dev{0}".format(self.dev))
 
         # Local version segment
-        if self._version.local is not None:
-            parts.append(
-                "+{0}".format(".".join(str(x) for x in self._version.local))
-            )
+        if self.local is not None:
+            parts.append("+{0}".format(self.local))
 
         return "".join(parts)
 
+    @property
+    def epoch(self):
+        return self._version.epoch
+
+    @property
+    def release(self):
+        return self._version.release
+
+    @property
+    def pre(self):
+        return self._version.pre
+
+    @property
+    def post(self):
+        return self._version.post[1] if self._version.post else None
+
+    @property
+    def dev(self):
+        return self._version.dev[1] if self._version.dev else None
+
+    @property
+    def local(self):
+        if self._version.local:
+            return ".".join(str(x) for x in self._version.local)
+        else:
+            return None
+
     @property
     def public(self):
         return str(self).split("+", 1)[0]
@@ -272,27 +309,25 @@ class Version(_BaseVersion):
         parts = []
 
         # Epoch
-        if self._version.epoch != 0:
-            parts.append("{0}!".format(self._version.epoch))
+        if self.epoch != 0:
+            parts.append("{0}!".format(self.epoch))
 
         # Release segment
-        parts.append(".".join(str(x) for x in self._version.release))
+        parts.append(".".join(str(x) for x in self.release))
 
         return "".join(parts)
 
-    @property
-    def local(self):
-        version_string = str(self)
-        if "+" in version_string:
-            return version_string.split("+", 1)[1]
-
     @property
     def is_prerelease(self):
-        return bool(self._version.dev or self._version.pre)
+        return self.dev is not None or self.pre is not None
 
     @property
     def is_postrelease(self):
-        return bool(self._version.post)
+        return self.post is not None
+
+    @property
+    def is_devrelease(self):
+        return self.dev is not None
 
 
 def _parse_letter_version(letter, number):
@@ -326,7 +361,7 @@ def _parse_letter_version(letter, number):
         return letter, int(number)
 
 
-_local_version_seperators = re.compile(r"[\._-]")
+_local_version_separators = re.compile(r"[\._-]")
 
 
 def _parse_local_version(local):
@@ -336,7 +371,7 @@ def _parse_local_version(local):
     if local is not None:
         return tuple(
             part.lower() if not part.isdigit() else int(part)
-            for part in _local_version_seperators.split(local)
+            for part in _local_version_separators.split(local)
         )
 
 
@@ -347,12 +382,7 @@ def _cmpkey(epoch, release, pre, post, dev, local):
     # re-reverse it back into the correct order and make it a tuple and use
     # that for our sorting key.
     release = tuple(
-        reversed(list(
-            itertools.dropwhile(
-                lambda x: x == 0,
-                reversed(release),
-            )
-        ))
+        reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
     )
 
     # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
@@ -385,9 +415,6 @@ def _cmpkey(epoch, release, pre, post, dev, local):
         # - Numeric segments sort numerically
         # - Shorter versions sort before longer versions when the prefixes
         #   match exactly
-        local = tuple(
-            (i, "") if isinstance(i, int) else (-Infinity, i)
-            for i in local
-        )
+        local = tuple((i, "") if isinstance(i, int) else (-Infinity, i) for i in local)
 
     return epoch, release, pre, post, dev, local
index 7f4f40879b25e49e9ef688fcccbcb8700040b6d4..f581a6234914a3d8b81dc18bba2c9057c82e4760 100644 (file)
@@ -1,4 +1,4 @@
-packaging==16.8
+packaging==19.2
 pyparsing==2.2.1
 six==1.10.0
 appdirs==1.4.3
index 05638dbc1712e134a890e98f873d877e82578703..d73241861ece68793179f50f634d239b8a468d39 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -16,7 +16,7 @@ formats = zip
 
 [metadata]
 name = setuptools
-version = 48.0.0
+version = 49.0.0
 description = Easily download, build, install, upgrade, and uninstall Python packages
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
index 64528ca7a52a44cfd2dd74361f1821925392f316..0ce190b8cf7258ef7ac1d9d71d9293038f36d69d 100644 (file)
@@ -134,10 +134,10 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
     """
     try:
         tarobj = tarfile.open(filename)
-    except tarfile.TarError:
+    except tarfile.TarError as e:
         raise UnrecognizedFormat(
             "%s is not a compressed or uncompressed tar file" % (filename,)
-        )
+        ) from e
     with contextlib.closing(tarobj):
         # don't do any chowning!
         tarobj.chown = lambda *args: None
index b561924609a63a38e9f5fe98091ecf93e100a7ae..e7e03cd449d4407a69479b840c18619c2e6fbb6b 100644 (file)
@@ -139,7 +139,6 @@ class develop(namespaces.DevelopInstaller, easy_install):
             self.reinitialize_command('build_ext', inplace=1)
             self.run_command('build_ext')
 
-        self.install_site_py()  # ensure that target dir is site-safe
         if setuptools.bootstrap_install_from:
             self.easy_install(setuptools.bootstrap_install_from)
             setuptools.bootstrap_install_from = None
index 89be91ac2e8fc5d2108a46b5c6b7e4fe55e94531..bcbd4f58f5d42f3270742196046dafc542f221d7 100644 (file)
@@ -205,7 +205,6 @@ class easy_install(Command):
         self.pth_file = self.always_copy_from = None
         self.site_dirs = None
         self.installed_projects = {}
-        self.sitepy_installed = False
         # Always read easy_install options, even if we are subclassed, or have
         # an independent instance created.  This ensures that defaults will
         # always come from the standard configuration file(s)' "easy_install"
@@ -356,8 +355,10 @@ class easy_install(Command):
                 self.optimize = int(self.optimize)
                 if not (0 <= self.optimize <= 2):
                     raise ValueError
-            except ValueError:
-                raise DistutilsOptionError("--optimize must be 0, 1, or 2")
+            except ValueError as e:
+                raise DistutilsOptionError(
+                    "--optimize must be 0, 1, or 2"
+                ) from e
 
         if self.editable and not self.build_directory:
             raise DistutilsArgError(
@@ -494,12 +495,8 @@ class easy_install(Command):
         else:
             self.pth_file = None
 
-        if instdir not in map(normalize_path, _pythonpath()):
-            # only PYTHONPATH dirs need a site.py, so pretend it's there
-            self.sitepy_installed = True
-        elif self.multi_version and not os.path.exists(pth_file):
-            self.sitepy_installed = True  # don't need site.py in this case
-            self.pth_file = None  # and don't create a .pth file
+        if self.multi_version and not os.path.exists(pth_file):
+            self.pth_file = None  # don't create a .pth file
         self.install_dir = instdir
 
     __cant_write_msg = textwrap.dedent("""
@@ -656,9 +653,6 @@ class easy_install(Command):
             os.path.exists(tmpdir) and rmtree(rmtree_safe(tmpdir))
 
     def easy_install(self, spec, deps=False):
-        if not self.editable:
-            self.install_site_py()
-
         with self._tmpdir() as tmpdir:
             if not isinstance(spec, Requirement):
                 if URL_SCHEME(spec):
@@ -765,9 +759,9 @@ class easy_install(Command):
                 [requirement], self.local_index, self.easy_install
             )
         except DistributionNotFound as e:
-            raise DistutilsError(str(e))
+            raise DistutilsError(str(e)) from e
         except VersionConflict as e:
-            raise DistutilsError(e.report())
+            raise DistutilsError(e.report()) from e
         if self.always_copy or self.always_copy_from:
             # Force all the relevant distros to be copied or activated
             for dist in distros:
@@ -1156,7 +1150,9 @@ class easy_install(Command):
         try:
             run_setup(setup_script, args)
         except SystemExit as v:
-            raise DistutilsError("Setup script exited with %s" % (v.args[0],))
+            raise DistutilsError(
+                "Setup script exited with %s" % (v.args[0],)
+            ) from v
 
     def build_and_install(self, setup_script, setup_base):
         args = ['bdist_egg', '--dist-dir']
@@ -1317,38 +1313,6 @@ class easy_install(Command):
         Please make the appropriate changes for your system and try again.
         """).strip()
 
-    def install_site_py(self):
-        """Make sure there's a site.py in the target dir, if needed"""
-
-        if self.sitepy_installed:
-            return  # already did it, or don't need to
-
-        sitepy = os.path.join(self.install_dir, "site.py")
-        source = resource_string("setuptools", "site-patch.py")
-        source = source.decode('utf-8')
-        current = ""
-
-        if os.path.exists(sitepy):
-            log.debug("Checking existing site.py in %s", self.install_dir)
-            with io.open(sitepy) as strm:
-                current = strm.read()
-
-            if not current.startswith('def __boot():'):
-                raise DistutilsError(
-                    "%s is not a setuptools-generated site.py; please"
-                    " remove it." % sitepy
-                )
-
-        if current != source:
-            log.info("Creating %s", sitepy)
-            if not self.dry_run:
-                ensure_directory(sitepy)
-                with io.open(sitepy, 'w', encoding='utf-8') as strm:
-                    strm.write(source)
-            self.byte_compile([sitepy])
-
-        self.sitepy_installed = True
-
     def create_home_path(self):
         """Create directories under ~."""
         if not self.user:
index 7fa89541cdbc98b868f2edf01e0dfcb62306d952..0855207ceb9dc5988e198005e2bd08bbab363555 100644 (file)
@@ -208,11 +208,11 @@ class egg_info(InfoCommon, Command):
             list(
                 parse_requirements(spec % (self.egg_name, self.egg_version))
             )
-        except ValueError:
+        except ValueError as e:
             raise distutils.errors.DistutilsOptionError(
                 "Invalid distribution name or version syntax: %s-%s" %
                 (self.egg_name, self.egg_version)
-            )
+            ) from e
 
         if self.egg_base is None:
             dirs = self.distribution.package_dir
index b89353f529b3d08e768dea69a9dc8b5e7403003d..e398834fa71486e86cca09159df2a41ec8660edd 100644 (file)
@@ -36,8 +36,8 @@ class rotate(Command):
             raise DistutilsOptionError("Must specify number of files to keep")
         try:
             self.keep = int(self.keep)
-        except ValueError:
-            raise DistutilsOptionError("--keep must be an integer")
+        except ValueError as e:
+            raise DistutilsOptionError("--keep must be an integer") from e
         if isinstance(self.match, six.string_types):
             self.match = [
                 convert_path(p.strip()) for p in self.match.split(',')
index 45df2e3f2e83f5552f8f1f8da31476ab40aff26d..a8f8b6b0068f453d858140b9589ef7a8df5d74bf 100644 (file)
@@ -42,9 +42,10 @@ class StaticModule:
                 for target in statement.targets
                 if isinstance(target, ast.Name) and target.id == attr
             )
-        except Exception:
+        except Exception as e:
             raise AttributeError(
-                "{self.name} has no attribute {attr}".format(**locals()))
+                "{self.name} has no attribute {attr}".format(**locals())
+            ) from e
 
 
 @contextlib.contextmanager
index fe64afa919ecee1f6c7f7541073ed7fafc6b73c7..e813b11ca762376d4094d381d53b063e785a53cc 100644 (file)
@@ -204,11 +204,11 @@ def check_importable(dist, attr, value):
     try:
         ep = pkg_resources.EntryPoint.parse('x=' + value)
         assert not ep.extras
-    except (TypeError, ValueError, AttributeError, AssertionError):
+    except (TypeError, ValueError, AttributeError, AssertionError) as e:
         raise DistutilsSetupError(
             "%r must be importable 'module:attrs' string (got %r)"
             % (attr, value)
-        )
+        ) from e
 
 
 def assert_string_list(dist, attr, value):
@@ -219,10 +219,10 @@ def assert_string_list(dist, attr, value):
         assert isinstance(value, (list, tuple))
         # verify that elements of value are strings
         assert ''.join(value) != value
-    except (TypeError, ValueError, AttributeError, AssertionError):
+    except (TypeError, ValueError, AttributeError, AssertionError) as e:
         raise DistutilsSetupError(
             "%r must be a list of strings (got %r)" % (attr, value)
-        )
+        ) from e
 
 
 def check_nsp(dist, attr, value):
@@ -247,12 +247,12 @@ def check_extras(dist, attr, value):
     """Verify that extras_require mapping is valid"""
     try:
         list(itertools.starmap(_check_extra, value.items()))
-    except (TypeError, ValueError, AttributeError):
+    except (TypeError, ValueError, AttributeError) as e:
         raise DistutilsSetupError(
             "'extras_require' must be a dictionary whose values are "
             "strings or lists of strings containing valid project/version "
             "requirement specifiers."
-        )
+        ) from e
 
 
 def _check_extra(extra, reqs):
@@ -280,7 +280,9 @@ def check_requirements(dist, attr, value):
             "{attr!r} must be a string or list of strings "
             "containing valid project/version requirement specifiers; {error}"
         )
-        raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
+        raise DistutilsSetupError(
+            tmpl.format(attr=attr, error=error)
+        ) from error
 
 
 def check_specifier(dist, attr, value):
@@ -292,7 +294,9 @@ def check_specifier(dist, attr, value):
             "{attr!r} must be a string "
             "containing valid version specifiers; {error}"
         )
-        raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
+        raise DistutilsSetupError(
+            tmpl.format(attr=attr, error=error)
+        ) from error
 
 
 def check_entry_points(dist, attr, value):
@@ -300,7 +304,7 @@ def check_entry_points(dist, attr, value):
     try:
         pkg_resources.EntryPoint.parse_map(value)
     except ValueError as e:
-        raise DistutilsSetupError(e)
+        raise DistutilsSetupError(e) from e
 
 
 def check_test_suite(dist, attr, value):
@@ -609,8 +613,8 @@ class Distribution(_Distribution):
                         setattr(self, opt, strtobool(val))
                     else:
                         setattr(self, opt, val)
-                except ValueError as msg:
-                    raise DistutilsOptionError(msg)
+                except ValueError as e:
+                    raise DistutilsOptionError(e) from e
 
     @staticmethod
     def _try_str(val):
@@ -676,8 +680,8 @@ class Distribution(_Distribution):
                     raise DistutilsOptionError(
                         "error in %s: command '%s' has no such option '%s'"
                         % (source, command_name, option))
-            except ValueError as msg:
-                raise DistutilsOptionError(msg)
+            except ValueError as e:
+                raise DistutilsOptionError(e) from e
 
     def parse_config_files(self, filenames=None, ignore_option_errors=False):
         """Parses configuration files from various levels
@@ -843,10 +847,10 @@ class Distribution(_Distribution):
             )
         try:
             old = getattr(self, name)
-        except AttributeError:
+        except AttributeError as e:
             raise DistutilsSetupError(
                 "%s: No such distribution setting" % name
-            )
+            ) from e
         if old is not None and not isinstance(old, sequence):
             raise DistutilsSetupError(
                 name + ": this setting cannot be changed via include/exclude"
@@ -863,10 +867,10 @@ class Distribution(_Distribution):
             )
         try:
             old = getattr(self, name)
-        except AttributeError:
+        except AttributeError as e:
             raise DistutilsSetupError(
                 "%s: No such distribution setting" % name
-            )
+            ) from e
         if old is None:
             setattr(self, name, value)
         elif not isinstance(old, sequence):
index 1f183bd9af390418ef179ac0b2da88d0f6544c42..e5acec2726e15d7d7de652055d3bee7a9544e96a 100644 (file)
@@ -127,7 +127,7 @@ def fetch_build_egg(dist, req):
         try:
             subprocess.check_call(cmd)
         except subprocess.CalledProcessError as e:
-            raise DistutilsError(str(e))
+            raise DistutilsError(str(e)) from e
         wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0])
         dist_location = os.path.join(eggs_dir, wheel.egg_name())
         wheel.install_as_egg(dist_location)
index 09f8565ef6c2bf76efc77c4b50fdd617256c208c..72383eb849142cf05018e450f537a183ba61151a 100644 (file)
@@ -277,7 +277,7 @@ def _msvc14_get_vc_env(plat_spec):
     except subprocess.CalledProcessError as exc:
         raise distutils.errors.DistutilsPlatformError(
             "Error executing {}".format(exc.cmd)
-        )
+        ) from exc
 
     env = {
         key.lower(): value
diff --git a/setuptools/site-patch.py b/setuptools/site-patch.py
deleted file mode 100644 (file)
index be0d43d..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-def __boot():
-    import sys
-    import os
-    PYTHONPATH = os.environ.get('PYTHONPATH')
-    if PYTHONPATH is None or (sys.platform == 'win32' and not PYTHONPATH):
-        PYTHONPATH = []
-    else:
-        PYTHONPATH = PYTHONPATH.split(os.pathsep)
-
-    pic = getattr(sys, 'path_importer_cache', {})
-    stdpath = sys.path[len(PYTHONPATH):]
-    mydir = os.path.dirname(__file__)
-
-    for item in stdpath:
-        if item == mydir or not item:
-            continue  # skip if current dir. on Windows, or my own directory
-        importer = pic.get(item)
-        if importer is not None:
-            loader = importer.find_module('site')
-            if loader is not None:
-                # This should actually reload the current module
-                loader.load_module('site')
-                break
-        else:
-            try:
-                import imp  # Avoid import loop in Python 3
-                stream, path, descr = imp.find_module('site', [item])
-            except ImportError:
-                continue
-            if stream is None:
-                continue
-            try:
-                # This should actually reload the current module
-                imp.load_module('site', stream, path, descr)
-            finally:
-                stream.close()
-            break
-    else:
-        raise ImportError("Couldn't find the real 'site' module")
-
-    # 2.2 comp
-    known_paths = dict([(
-        makepath(item)[1], 1) for item in sys.path])  # noqa
-
-    oldpos = getattr(sys, '__egginsert', 0)  # save old insertion position
-    sys.__egginsert = 0  # and reset the current one
-
-    for item in PYTHONPATH:
-        addsitedir(item)  # noqa
-
-    sys.__egginsert += oldpos  # restore effective old position
-
-    d, nd = makepath(stdpath[0])  # noqa
-    insert_at = None
-    new_path = []
-
-    for item in sys.path:
-        p, np = makepath(item)  # noqa
-
-        if np == nd and insert_at is None:
-            # We've hit the first 'system' path entry, so added entries go here
-            insert_at = len(new_path)
-
-        if np in known_paths or insert_at is None:
-            new_path.append(item)
-        else:
-            # new path after the insert point, back-insert it
-            new_path.insert(insert_at, item)
-            insert_at += 1
-
-    sys.path[:] = new_path
-
-
-if __name__ == 'site':
-    __boot()
-    del __boot
index 8611dc166e8f205f4bd118b500f6258bef0ff3d0..c07b5bea817509fbd618a85a8f5472d7cf33eddd 100644 (file)
@@ -62,14 +62,6 @@ SETUP_PY = DALS("""
 
 
 class TestEasyInstallTest:
-    def test_install_site_py(self, tmpdir):
-        dist = Distribution()
-        cmd = ei.easy_install(dist)
-        cmd.sitepy_installed = False
-        cmd.install_dir = str(tmpdir)
-        cmd.install_site_py()
-        assert (tmpdir / 'site.py').exists()
-
     def test_get_script_args(self):
         header = ei.CommandSpec.best().from_environment().as_header()
         dist = FakeDist()
diff --git a/tox.ini b/tox.ini
index 59213e88f9b6aba547eb9d2e1a2898a1a481e36d..5ae7b660aa210ba328f005aa22f8bc103e719ff1 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -7,8 +7,6 @@ envlist=python
 minversion = 3.2
 requires =
        tox-pip-version >= 0.0.6
-       # workaround for #1998
-       virtualenv < 20; python_version=="2.7"
 
 [helpers]
 # Custom pip behavior