Commit 5f151cbb authored by Jason R. Coombs's avatar Jason R. Coombs Committed by GitHub

Merge branch 'master' into 2020-06-11-raise-from

parents a9eb9e73 a877dab0
[bumpversion] [bumpversion]
current_version = 47.3.0 current_version = 48.0.0
commit = True commit = True
tag = True tag = True
......
[run]
source=
pkg_resources
setuptools
omit=
*/_vendor/*
[report]
...@@ -98,5 +98,3 @@ jobs: ...@@ -98,5 +98,3 @@ jobs:
python -m python -m
tox tox
--parallel auto --parallel auto
--
--cov
...@@ -5,7 +5,6 @@ jobs: ...@@ -5,7 +5,6 @@ jobs:
fast_finish: true fast_finish: true
include: include:
- python: pypy3 - python: pypy3
env: DISABLE_COVERAGE=1 # Don't run coverage on pypy (too slow).
- python: 3.5 - python: 3.5
- python: 3.6 - python: 3.6
- python: 3.7 - python: 3.7
...@@ -15,12 +14,12 @@ jobs: ...@@ -15,12 +14,12 @@ jobs:
env: LANG=C env: LANG=C
- python: 3.8-dev - python: 3.8-dev
- <<: *latest_py3 - <<: *latest_py3
env: TOXENV=docs DISABLE_COVERAGE=1 env: TOXENV=docs
allow_failures: allow_failures:
# suppress failures due to pypa/setuptools#2000 # suppress failures due to pypa/setuptools#2000
- python: pypy3 - python: pypy3
- <<: *latest_py3 - <<: *latest_py3
env: TOXENV=docs DISABLE_COVERAGE=1 env: TOXENV=docs
cache: pip cache: pip
...@@ -39,22 +38,8 @@ install: ...@@ -39,22 +38,8 @@ install:
script: script:
- export NETWORK_REQUIRED=1 - export NETWORK_REQUIRED=1
- | - tox
( # Run testsuite.
if [ -z "$DISABLE_COVERAGE" ]
then
tox -- --cov
else
tox
fi
)
after_success: after_success:
- | - export TRAVIS_JOB_NAME="${TRAVIS_PYTHON_VERSION} (LANG=$LANG)" CODECOV_ENV=TRAVIS_JOB_NAME
( # Upload coverage data. - tox -e coverage,codecov
if [ -z "$DISABLE_COVERAGE" ]
then
export TRAVIS_JOB_NAME="${TRAVIS_PYTHON_VERSION} (LANG=$LANG)" CODECOV_ENV=TRAVIS_JOB_NAME
tox -e coverage,codecov
fi
)
v48.0.0
-------
* #2143: Setuptools adopts distutils from the Python 3.9 standard library and no longer depends on distutils in the standard library. When importing ``setuptools`` or ``setuptools.distutils_patch``, Setuptools will expose its bundled version as a top-level ``distutils`` package (and unload any previously-imported top-level distutils package), retaining the expectation that ``distutils``' objects are actually Setuptools objects. Although this change is not expected to break any use cases, it will likely affect tool chains that are monkey-patching distutils or relying on Setuptools' own monkey-patching of distutils.
v47.3.2
-------
* #2071: Replaced references to the deprecated imp package with references to importlib
v47.3.1
-------
* #1973: Removed ``pkg_resources.py31compat.makedirs`` in favor of the stdlib. Use ``os.makedirs()`` instead.
* #2198: Restore ``__requires__`` directive in easy-install wrapper scripts.
v47.3.0 v47.3.0
------- -------
......
Removed ``pkg_resources.py31compat.makedirs`` in favor of the stdlib. Use ``os.makedirs()`` instead.
Removed (private) pkg_resources.RequirementParseError, now replaced by packaging.requirements.InvalidRequirement. Kept the name for compatibility, but users should catch InvalidRequirement instead.
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.
Update vendored packaging in pkg_resources to 19.2.
...@@ -14,6 +14,7 @@ def pytest_addoption(parser): ...@@ -14,6 +14,7 @@ def pytest_addoption(parser):
collect_ignore = [ collect_ignore = [
'tests/manual_test.py', 'tests/manual_test.py',
'setuptools/tests/mod_with_constant.py', 'setuptools/tests/mod_with_constant.py',
'setuptools/_distutils',
] ]
......
...@@ -145,5 +145,5 @@ setuptools from source. Eventually, this limitation may be lifted as ...@@ -145,5 +145,5 @@ setuptools from source. Eventually, this limitation may be lifted as
PEP 517/518 reach ubiquitous adoption, but for now, Setuptools PEP 517/518 reach ubiquitous adoption, but for now, Setuptools
cannot declare dependencies other than through cannot declare dependencies other than through
``setuptools/_vendor/vendored.txt`` and ``setuptools/_vendor/vendored.txt`` and
``pkg_reosurces/_vendor/vendored.txt`` and refreshed by way of ``pkg_resources/_vendor/vendored.txt`` and refreshed by way of
``paver update_vendored`` (pavement.py). ``paver update_vendored`` (pavement.py).
...@@ -1458,7 +1458,8 @@ class NullProvider: ...@@ -1458,7 +1458,8 @@ class NullProvider:
script_filename = self._fn(self.egg_info, script) script_filename = self._fn(self.egg_info, script)
namespace['__file__'] = script_filename namespace['__file__'] = script_filename
if os.path.exists(script_filename): if os.path.exists(script_filename):
source = open(script_filename).read() with open(script_filename) as fid:
source = fid.read()
code = compile(source, script_filename, 'exec') code = compile(source, script_filename, 'exec')
exec(code, namespace, namespace) exec(code, namespace, namespace)
else: else:
...@@ -3076,11 +3077,6 @@ def issue_warning(*args, **kw): ...@@ -3076,11 +3077,6 @@ def issue_warning(*args, **kw):
warnings.warn(stacklevel=level + 1, *args, **kw) warnings.warn(stacklevel=level + 1, *args, **kw)
class RequirementParseError(ValueError):
def __str__(self):
return ' '.join(self.args)
def parse_requirements(strs): def parse_requirements(strs):
"""Yield ``Requirement`` objects for each specification in `strs` """Yield ``Requirement`` objects for each specification in `strs`
...@@ -3103,13 +3099,14 @@ def parse_requirements(strs): ...@@ -3103,13 +3099,14 @@ def parse_requirements(strs):
yield Requirement(line) yield Requirement(line)
class RequirementParseError(packaging.requirements.InvalidRequirement):
"Compatibility wrapper for InvalidRequirement"
class Requirement(packaging.requirements.Requirement): class Requirement(packaging.requirements.Requirement):
def __init__(self, requirement_string): def __init__(self, requirement_string):
"""DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
try: super(Requirement, self).__init__(requirement_string)
super(Requirement, self).__init__(requirement_string)
except packaging.requirements.InvalidRequirement as e:
raise RequirementParseError(str(e)) from e
self.unsafe_name = self.name self.unsafe_name = self.name
project_name = safe_name(self.name) project_name = safe_name(self.name)
self.project_name, self.key = project_name, project_name.lower() self.project_name, self.key = project_name, project_name.lower()
......
...@@ -4,18 +4,24 @@ ...@@ -4,18 +4,24 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
__all__ = [ __all__ = [
"__title__", "__summary__", "__uri__", "__version__", "__author__", "__title__",
"__email__", "__license__", "__copyright__", "__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
] ]
__title__ = "packaging" __title__ = "packaging"
__summary__ = "Core utilities for Python packages" __summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging" __uri__ = "https://github.com/pypa/packaging"
__version__ = "16.8" __version__ = "19.2"
__author__ = "Donald Stufft and individual contributors" __author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io" __email__ = "donald@stufft.io"
__license__ = "BSD or Apache License, Version 2.0" __license__ = "BSD or Apache License, Version 2.0"
__copyright__ = "Copyright 2014-2016 %s" % __author__ __copyright__ = "Copyright 2014-2019 %s" % __author__
...@@ -4,11 +4,23 @@ ...@@ -4,11 +4,23 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
from .__about__ import ( from .__about__ import (
__author__, __copyright__, __email__, __license__, __summary__, __title__, __author__,
__uri__, __version__ __copyright__,
__email__,
__license__,
__summary__,
__title__,
__uri__,
__version__,
) )
__all__ = [ __all__ = [
"__title__", "__summary__", "__uri__", "__version__", "__author__", "__title__",
"__email__", "__license__", "__copyright__", "__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
] ]
...@@ -12,9 +12,9 @@ PY3 = sys.version_info[0] == 3 ...@@ -12,9 +12,9 @@ PY3 = sys.version_info[0] == 3
# flake8: noqa # flake8: noqa
if PY3: if PY3:
string_types = str, string_types = (str,)
else: else:
string_types = basestring, string_types = (basestring,)
def with_metaclass(meta, *bases): def with_metaclass(meta, *bases):
...@@ -27,4 +27,5 @@ def with_metaclass(meta, *bases): ...@@ -27,4 +27,5 @@ def with_metaclass(meta, *bases):
class metaclass(meta): class metaclass(meta):
def __new__(cls, name, this_bases, d): def __new__(cls, name, this_bases, d):
return meta(name, bases, d) return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})
return type.__new__(metaclass, "temporary_class", (), {})
...@@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function ...@@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function
class Infinity(object): class Infinity(object):
def __repr__(self): def __repr__(self):
return "Infinity" return "Infinity"
...@@ -33,11 +32,11 @@ class Infinity(object): ...@@ -33,11 +32,11 @@ class Infinity(object):
def __neg__(self): def __neg__(self):
return NegativeInfinity return NegativeInfinity
Infinity = Infinity() Infinity = Infinity()
class NegativeInfinity(object): class NegativeInfinity(object):
def __repr__(self): def __repr__(self):
return "-Infinity" return "-Infinity"
...@@ -65,4 +64,5 @@ class NegativeInfinity(object): ...@@ -65,4 +64,5 @@ class NegativeInfinity(object):
def __neg__(self): def __neg__(self):
return Infinity return Infinity
NegativeInfinity = NegativeInfinity() NegativeInfinity = NegativeInfinity()
...@@ -17,8 +17,11 @@ from .specifiers import Specifier, InvalidSpecifier ...@@ -17,8 +17,11 @@ from .specifiers import Specifier, InvalidSpecifier
__all__ = [ __all__ = [
"InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName", "InvalidMarker",
"Marker", "default_environment", "UndefinedComparison",
"UndefinedEnvironmentName",
"Marker",
"default_environment",
] ]
...@@ -42,7 +45,6 @@ class UndefinedEnvironmentName(ValueError): ...@@ -42,7 +45,6 @@ class UndefinedEnvironmentName(ValueError):
class Node(object): class Node(object):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
...@@ -57,62 +59,52 @@ class Node(object): ...@@ -57,62 +59,52 @@ class Node(object):
class Variable(Node): class Variable(Node):
def serialize(self): def serialize(self):
return str(self) return str(self)
class Value(Node): class Value(Node):
def serialize(self): def serialize(self):
return '"{0}"'.format(self) return '"{0}"'.format(self)
class Op(Node): class Op(Node):
def serialize(self): def serialize(self):
return str(self) return str(self)
VARIABLE = ( VARIABLE = (
L("implementation_version") | L("implementation_version")
L("platform_python_implementation") | | L("platform_python_implementation")
L("implementation_name") | | L("implementation_name")
L("python_full_version") | | L("python_full_version")
L("platform_release") | | L("platform_release")
L("platform_version") | | L("platform_version")
L("platform_machine") | | L("platform_machine")
L("platform_system") | | L("platform_system")
L("python_version") | | L("python_version")
L("sys_platform") | | L("sys_platform")
L("os_name") | | L("os_name")
L("os.name") | # PEP-345 | L("os.name")
L("sys.platform") | # PEP-345 | L("sys.platform") # PEP-345
L("platform.version") | # PEP-345 | L("platform.version") # PEP-345
L("platform.machine") | # PEP-345 | L("platform.machine") # PEP-345
L("platform.python_implementation") | # PEP-345 | L("platform.python_implementation") # PEP-345
L("python_implementation") | # undocumented setuptools legacy | L("python_implementation") # PEP-345
L("extra") | L("extra") # undocumented setuptools legacy
) )
ALIASES = { ALIASES = {
'os.name': 'os_name', "os.name": "os_name",
'sys.platform': 'sys_platform', "sys.platform": "sys_platform",
'platform.version': 'platform_version', "platform.version": "platform_version",
'platform.machine': 'platform_machine', "platform.machine": "platform_machine",
'platform.python_implementation': 'platform_python_implementation', "platform.python_implementation": "platform_python_implementation",
'python_implementation': 'platform_python_implementation' "python_implementation": "platform_python_implementation",
} }
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
VERSION_CMP = ( 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") MARKER_OP = VERSION_CMP | L("not in") | L("in")
...@@ -152,8 +144,11 @@ def _format_marker(marker, first=True): ...@@ -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 # 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 # the rest of this function so that we don't get extraneous () on the
# outside. # outside.
if (isinstance(marker, list) and len(marker) == 1 and if (
isinstance(marker[0], (list, tuple))): isinstance(marker, list)
and len(marker) == 1
and isinstance(marker[0], (list, tuple))
):
return _format_marker(marker[0]) return _format_marker(marker[0])
if isinstance(marker, list): if isinstance(marker, list):
...@@ -239,20 +234,20 @@ def _evaluate_markers(markers, environment): ...@@ -239,20 +234,20 @@ def _evaluate_markers(markers, environment):
def format_full_version(info): 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 kind = info.releaselevel
if kind != 'final': if kind != "final":
version += kind[0] + str(info.serial) version += kind[0] + str(info.serial)
return version return version
def default_environment(): def default_environment():
if hasattr(sys, 'implementation'): if hasattr(sys, "implementation"):
iver = format_full_version(sys.implementation.version) iver = format_full_version(sys.implementation.version)
implementation_name = sys.implementation.name implementation_name = sys.implementation.name
else: else:
iver = '0' iver = "0"
implementation_name = '' implementation_name = ""
return { return {
"implementation_name": implementation_name, "implementation_name": implementation_name,
...@@ -264,19 +259,19 @@ def default_environment(): ...@@ -264,19 +259,19 @@ def default_environment():
"platform_version": platform.version(), "platform_version": platform.version(),
"python_full_version": platform.python_version(), "python_full_version": platform.python_version(),
"platform_python_implementation": platform.python_implementation(), "platform_python_implementation": platform.python_implementation(),
"python_version": platform.python_version()[:3], "python_version": ".".join(platform.python_version_tuple()[:2]),
"sys_platform": sys.platform, "sys_platform": sys.platform,
} }
class Marker(object): class Marker(object):
def __init__(self, marker): def __init__(self, marker):
try: try:
self._markers = _coerce_parse_result(MARKER.parseString(marker)) self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e: except ParseException as e:
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( 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) raise InvalidMarker(err_str)
def __str__(self): def __str__(self):
......
...@@ -38,8 +38,8 @@ IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) ...@@ -38,8 +38,8 @@ IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
NAME = IDENTIFIER("name") NAME = IDENTIFIER("name")
EXTRA = IDENTIFIER EXTRA = IDENTIFIER
URI = Regex(r'[^ ]+')("url") URI = Regex(r"[^ ]+")("url")
URL = (AT + URI) URL = AT + URI
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
...@@ -48,28 +48,31 @@ VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) ...@@ -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_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), VERSION_MANY = Combine(
joinString=",", adjacent=False)("_raw_spec") VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
)("_raw_spec")
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) _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 = originalTextFor(_VERSION_SPEC)("specifier")
VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
MARKER_EXPR.setParseAction( 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_SEPARATOR = SEMICOLON
MARKER = MARKER_SEPERATOR + MARKER_EXPR MARKER = MARKER_SEPARATOR + MARKER_EXPR
VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
URL_AND_MARKER = URL + Optional(MARKER) URL_AND_MARKER = URL + Optional(MARKER)
NAMED_REQUIREMENT = \ NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd 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): class Requirement(object):
...@@ -90,15 +93,21 @@ class Requirement(object): ...@@ -90,15 +93,21 @@ class Requirement(object):
req = REQUIREMENT.parseString(requirement_string) req = REQUIREMENT.parseString(requirement_string)
except ParseException as e: except ParseException as e:
raise InvalidRequirement( raise InvalidRequirement(
"Invalid requirement, parse error at \"{0!r}\"".format( 'Parse error at "{0!r}": {1}'.format(
requirement_string[e.loc:e.loc + 8])) requirement_string[e.loc : e.loc + 8], e.msg
)
)
self.name = req.name self.name = req.name
if req.url: if req.url:
parsed_url = urlparse.urlparse(req.url) parsed_url = urlparse.urlparse(req.url)
if not (parsed_url.scheme and parsed_url.netloc) or ( if parsed_url.scheme == "file":
not parsed_url.scheme and not parsed_url.netloc): if urlparse.urlunparse(parsed_url) != req.url:
raise InvalidRequirement("Invalid URL given") 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 self.url = req.url
else: else:
self.url = None self.url = None
...@@ -117,6 +126,8 @@ class Requirement(object): ...@@ -117,6 +126,8 @@ class Requirement(object):
if self.url: if self.url:
parts.append("@ {0}".format(self.url)) parts.append("@ {0}".format(self.url))
if self.marker:
parts.append(" ")
if self.marker: if self.marker:
parts.append("; {0}".format(self.marker)) parts.append("; {0}".format(self.marker))
......
...@@ -19,7 +19,6 @@ class InvalidSpecifier(ValueError): ...@@ -19,7 +19,6 @@ class InvalidSpecifier(ValueError):
class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@abc.abstractmethod @abc.abstractmethod
def __str__(self): def __str__(self):
""" """
...@@ -84,10 +83,7 @@ class _IndividualSpecifier(BaseSpecifier): ...@@ -84,10 +83,7 @@ class _IndividualSpecifier(BaseSpecifier):
if not match: if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
self._spec = ( self._spec = (match.group("operator").strip(), match.group("version").strip())
match.group("operator").strip(),
match.group("version").strip(),
)
# Store whether or not this Specifier should accept prereleases # Store whether or not this Specifier should accept prereleases
self._prereleases = prereleases self._prereleases = prereleases
...@@ -99,11 +95,7 @@ class _IndividualSpecifier(BaseSpecifier): ...@@ -99,11 +95,7 @@ class _IndividualSpecifier(BaseSpecifier):
else "" else ""
) )
return "<{0}({1!r}{2})>".format( return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
self.__class__.__name__,
str(self),
pre,
)
def __str__(self): def __str__(self):
return "{0}{1}".format(*self._spec) return "{0}{1}".format(*self._spec)
...@@ -194,11 +186,12 @@ class _IndividualSpecifier(BaseSpecifier): ...@@ -194,11 +186,12 @@ class _IndividualSpecifier(BaseSpecifier):
# If our version is a prerelease, and we were not set to allow # If our version is a prerelease, and we were not set to allow
# prereleases, then we'll store it for later incase nothing # prereleases, then we'll store it for later incase nothing
# else matches this specifier. # else matches this specifier.
if (parsed_version.is_prerelease and not if parsed_version.is_prerelease and not (
(prereleases or self.prereleases)): prereleases or self.prereleases
):
found_prereleases.append(version) found_prereleases.append(version)
# Either this is not a prerelease, or we should have been # Either this is not a prerelease, or we should have been
# accepting prereleases from the begining. # accepting prereleases from the beginning.
else: else:
yielded = True yielded = True
yield version yield version
...@@ -213,8 +206,7 @@ class _IndividualSpecifier(BaseSpecifier): ...@@ -213,8 +206,7 @@ class _IndividualSpecifier(BaseSpecifier):
class LegacySpecifier(_IndividualSpecifier): class LegacySpecifier(_IndividualSpecifier):
_regex_str = ( _regex_str = r"""
r"""
(?P<operator>(==|!=|<=|>=|<|>)) (?P<operator>(==|!=|<=|>=|<|>))
\s* \s*
(?P<version> (?P<version>
...@@ -225,10 +217,8 @@ class LegacySpecifier(_IndividualSpecifier): ...@@ -225,10 +217,8 @@ class LegacySpecifier(_IndividualSpecifier):
# them, and a comma since it's a version separator. # them, and a comma since it's a version separator.
) )
""" """
)
_regex = re.compile( _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = { _operators = {
"==": "equal", "==": "equal",
...@@ -269,13 +259,13 @@ def _require_version_compare(fn): ...@@ -269,13 +259,13 @@ def _require_version_compare(fn):
if not isinstance(prospective, Version): if not isinstance(prospective, Version):
return False return False
return fn(self, prospective, spec) return fn(self, prospective, spec)
return wrapped return wrapped
class Specifier(_IndividualSpecifier): class Specifier(_IndividualSpecifier):
_regex_str = ( _regex_str = r"""
r"""
(?P<operator>(~=|==|!=|<=|>=|<|>|===)) (?P<operator>(~=|==|!=|<=|>=|<|>|===))
(?P<version> (?P<version>
(?: (?:
...@@ -367,10 +357,8 @@ class Specifier(_IndividualSpecifier): ...@@ -367,10 +357,8 @@ class Specifier(_IndividualSpecifier):
) )
) )
""" """
)
_regex = re.compile( _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = { _operators = {
"~=": "compatible", "~=": "compatible",
...@@ -397,8 +385,7 @@ class Specifier(_IndividualSpecifier): ...@@ -397,8 +385,7 @@ class Specifier(_IndividualSpecifier):
prefix = ".".join( prefix = ".".join(
list( list(
itertools.takewhile( itertools.takewhile(
lambda x: (not x.startswith("post") and not lambda x: (not x.startswith("post") and not x.startswith("dev")),
x.startswith("dev")),
_version_split(spec), _version_split(spec),
) )
)[:-1] )[:-1]
...@@ -407,8 +394,9 @@ class Specifier(_IndividualSpecifier): ...@@ -407,8 +394,9 @@ class Specifier(_IndividualSpecifier):
# Add the prefix notation to the end of our string # Add the prefix notation to the end of our string
prefix += ".*" prefix += ".*"
return (self._get_operator(">=")(prospective, spec) and return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
self._get_operator("==")(prospective, prefix)) prospective, prefix
)
@_require_version_compare @_require_version_compare
def _compare_equal(self, prospective, spec): def _compare_equal(self, prospective, spec):
...@@ -428,7 +416,7 @@ class Specifier(_IndividualSpecifier): ...@@ -428,7 +416,7 @@ class Specifier(_IndividualSpecifier):
# Shorten the prospective version to be the same length as the spec # 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 # so that we can determine if the specifier is a prefix of the
# prospective version or not. # 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 # Pad out our two sides with zeros so that they both equal the same
# length. # length.
...@@ -503,7 +491,7 @@ class Specifier(_IndividualSpecifier): ...@@ -503,7 +491,7 @@ class Specifier(_IndividualSpecifier):
return False return False
# Ensure that we do not allow a local version of the version mentioned # 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 prospective.local is not None:
if Version(prospective.base_version) == Version(spec.base_version): if Version(prospective.base_version) == Version(spec.base_version):
return False return False
...@@ -567,27 +555,17 @@ def _pad_version(left, right): ...@@ -567,27 +555,17 @@ def _pad_version(left, right):
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
# Get the rest of our versions # Get the rest of our versions
left_split.append(left[len(left_split[0]):]) left_split.append(left[len(left_split[0]) :])
right_split.append(right[len(right_split[0]):]) right_split.append(right[len(right_split[0]) :])
# Insert our padding # Insert our padding
left_split.insert( left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
1, right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
["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 ( return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
list(itertools.chain(*left_split)),
list(itertools.chain(*right_split)),
)
class SpecifierSet(BaseSpecifier): class SpecifierSet(BaseSpecifier):
def __init__(self, specifiers="", prereleases=None): def __init__(self, specifiers="", prereleases=None):
# Split on , to break each indidivual specifier into it's own item, and # Split on , to break each indidivual specifier into it's own item, and
# strip each item to remove leading/trailing whitespace. # strip each item to remove leading/trailing whitespace.
...@@ -721,10 +699,7 @@ class SpecifierSet(BaseSpecifier): ...@@ -721,10 +699,7 @@ class SpecifierSet(BaseSpecifier):
# given version is contained within all of them. # given version is contained within all of them.
# Note: This use of all() here means that an empty set of specifiers # Note: This use of all() here means that an empty set of specifiers
# will always return True, this is an explicit design decision. # will always return True, this is an explicit design decision.
return all( return all(s.contains(item, prereleases=prereleases) for s in self._specs)
s.contains(item, prereleases=prereleases)
for s in self._specs
)
def filter(self, iterable, prereleases=None): def filter(self, iterable, prereleases=None):
# Determine if we're forcing a prerelease or not, if we're not forcing # Determine if we're forcing a prerelease or not, if we're not forcing
......
This diff is collapsed.
...@@ -5,6 +5,8 @@ from __future__ import absolute_import, division, print_function ...@@ -5,6 +5,8 @@ from __future__ import absolute_import, division, print_function
import re import re
from .version import InvalidVersion, Version
_canonicalize_regex = re.compile(r"[-_.]+") _canonicalize_regex = re.compile(r"[-_.]+")
...@@ -12,3 +14,44 @@ _canonicalize_regex = re.compile(r"[-_.]+") ...@@ -12,3 +14,44 @@ _canonicalize_regex = re.compile(r"[-_.]+")
def canonicalize_name(name): def canonicalize_name(name):
# This is taken from PEP 503. # This is taken from PEP 503.
return _canonicalize_regex.sub("-", name).lower() 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)
...@@ -10,14 +10,11 @@ import re ...@@ -10,14 +10,11 @@ import re
from ._structures import Infinity from ._structures import Infinity
__all__ = [ __all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
"parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
]
_Version = collections.namedtuple( _Version = collections.namedtuple(
"_Version", "_Version", ["epoch", "release", "dev", "pre", "post", "local"]
["epoch", "release", "dev", "pre", "post", "local"],
) )
...@@ -40,7 +37,6 @@ class InvalidVersion(ValueError): ...@@ -40,7 +37,6 @@ class InvalidVersion(ValueError):
class _BaseVersion(object): class _BaseVersion(object):
def __hash__(self): def __hash__(self):
return hash(self._key) return hash(self._key)
...@@ -70,7 +66,6 @@ class _BaseVersion(object): ...@@ -70,7 +66,6 @@ class _BaseVersion(object):
class LegacyVersion(_BaseVersion): class LegacyVersion(_BaseVersion):
def __init__(self, version): def __init__(self, version):
self._version = str(version) self._version = str(version)
self._key = _legacy_cmpkey(self._version) self._key = _legacy_cmpkey(self._version)
...@@ -89,6 +84,26 @@ class LegacyVersion(_BaseVersion): ...@@ -89,6 +84,26 @@ class LegacyVersion(_BaseVersion):
def base_version(self): def base_version(self):
return self._version 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 @property
def local(self): def local(self):
return None return None
...@@ -101,13 +116,19 @@ class LegacyVersion(_BaseVersion): ...@@ -101,13 +116,19 @@ class LegacyVersion(_BaseVersion):
def is_postrelease(self): def is_postrelease(self):
return False 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 = { _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): ...@@ -154,6 +175,7 @@ def _legacy_cmpkey(version):
return epoch, parts return epoch, parts
# Deliberately not anchored to the start and end of the string, to make it # Deliberately not anchored to the start and end of the string, to make it
# easier for 3rd party code to reuse # easier for 3rd party code to reuse
VERSION_PATTERN = r""" VERSION_PATTERN = r"""
...@@ -190,10 +212,7 @@ VERSION_PATTERN = r""" ...@@ -190,10 +212,7 @@ VERSION_PATTERN = r"""
class Version(_BaseVersion): class Version(_BaseVersion):
_regex = re.compile( _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
r"^\s*" + VERSION_PATTERN + r"\s*$",
re.VERBOSE | re.IGNORECASE,
)
def __init__(self, version): def __init__(self, version):
# Validate the version and parse it into pieces # Validate the version and parse it into pieces
...@@ -205,18 +224,11 @@ class Version(_BaseVersion): ...@@ -205,18 +224,11 @@ class Version(_BaseVersion):
self._version = _Version( self._version = _Version(
epoch=int(match.group("epoch")) if match.group("epoch") else 0, epoch=int(match.group("epoch")) if match.group("epoch") else 0,
release=tuple(int(i) for i in match.group("release").split(".")), release=tuple(int(i) for i in match.group("release").split(".")),
pre=_parse_letter_version( pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
match.group("pre_l"),
match.group("pre_n"),
),
post=_parse_letter_version( post=_parse_letter_version(
match.group("post_l"), match.group("post_l"), match.group("post_n1") or match.group("post_n2")
match.group("post_n1") or match.group("post_n2"),
),
dev=_parse_letter_version(
match.group("dev_l"),
match.group("dev_n"),
), ),
dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
local=_parse_local_version(match.group("local")), local=_parse_local_version(match.group("local")),
) )
...@@ -237,32 +249,57 @@ class Version(_BaseVersion): ...@@ -237,32 +249,57 @@ class Version(_BaseVersion):
parts = [] parts = []
# Epoch # Epoch
if self._version.epoch != 0: if self.epoch != 0:
parts.append("{0}!".format(self._version.epoch)) parts.append("{0}!".format(self.epoch))
# Release segment # 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 # Pre-release
if self._version.pre is not None: if self.pre is not None:
parts.append("".join(str(x) for x in self._version.pre)) parts.append("".join(str(x) for x in self.pre))
# Post-release # Post-release
if self._version.post is not None: if self.post is not None:
parts.append(".post{0}".format(self._version.post[1])) parts.append(".post{0}".format(self.post))
# Development release # Development release
if self._version.dev is not None: if self.dev is not None:
parts.append(".dev{0}".format(self._version.dev[1])) parts.append(".dev{0}".format(self.dev))
# Local version segment # Local version segment
if self._version.local is not None: if self.local is not None:
parts.append( parts.append("+{0}".format(self.local))
"+{0}".format(".".join(str(x) for x in self._version.local))
)
return "".join(parts) 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 @property
def public(self): def public(self):
return str(self).split("+", 1)[0] return str(self).split("+", 1)[0]
...@@ -272,27 +309,25 @@ class Version(_BaseVersion): ...@@ -272,27 +309,25 @@ class Version(_BaseVersion):
parts = [] parts = []
# Epoch # Epoch
if self._version.epoch != 0: if self.epoch != 0:
parts.append("{0}!".format(self._version.epoch)) parts.append("{0}!".format(self.epoch))
# Release segment # 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) return "".join(parts)
@property
def local(self):
version_string = str(self)
if "+" in version_string:
return version_string.split("+", 1)[1]
@property @property
def is_prerelease(self): 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 @property
def is_postrelease(self): 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): def _parse_letter_version(letter, number):
...@@ -326,7 +361,7 @@ def _parse_letter_version(letter, number): ...@@ -326,7 +361,7 @@ def _parse_letter_version(letter, number):
return letter, int(number) return letter, int(number)
_local_version_seperators = re.compile(r"[\._-]") _local_version_separators = re.compile(r"[\._-]")
def _parse_local_version(local): def _parse_local_version(local):
...@@ -336,7 +371,7 @@ def _parse_local_version(local): ...@@ -336,7 +371,7 @@ def _parse_local_version(local):
if local is not None: if local is not None:
return tuple( return tuple(
part.lower() if not part.isdigit() else int(part) 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): ...@@ -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 # re-reverse it back into the correct order and make it a tuple and use
# that for our sorting key. # that for our sorting key.
release = tuple( release = tuple(
reversed(list( reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
itertools.dropwhile(
lambda x: x == 0,
reversed(release),
)
))
) )
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. # 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): ...@@ -385,9 +415,6 @@ def _cmpkey(epoch, release, pre, post, dev, local):
# - Numeric segments sort numerically # - Numeric segments sort numerically
# - Shorter versions sort before longer versions when the prefixes # - Shorter versions sort before longer versions when the prefixes
# match exactly # match exactly
local = tuple( local = tuple((i, "") if isinstance(i, int) else (-Infinity, i) for i in local)
(i, "") if isinstance(i, int) else (-Infinity, i)
for i in local
)
return epoch, release, pre, post, dev, local return epoch, release, pre, post, dev, local
packaging==16.8 packaging==19.2
pyparsing==2.2.1 pyparsing==2.2.1
six==1.10.0 six==1.10.0
appdirs==1.4.3 appdirs==1.4.3
[pytest] [pytest]
addopts=--doctest-modules --flake8 --doctest-glob=pkg_resources/api_tests.txt -r sxX addopts=--doctest-modules --flake8 --doctest-glob=pkg_resources/api_tests.txt --cov -r sxX
norecursedirs=dist build *.egg setuptools/extern pkg_resources/extern pkg_resources/tests/data tools .* setuptools/_vendor pkg_resources/_vendor norecursedirs=dist build *.egg setuptools/extern pkg_resources/extern pkg_resources/tests/data tools .* setuptools/_vendor pkg_resources/_vendor
doctest_optionflags=ELLIPSIS ALLOW_UNICODE doctest_optionflags=ELLIPSIS ALLOW_UNICODE
filterwarnings = filterwarnings =
......
...@@ -16,7 +16,7 @@ formats = zip ...@@ -16,7 +16,7 @@ formats = zip
[metadata] [metadata]
name = setuptools name = setuptools
version = 47.3.0 version = 48.0.0
description = Easily download, build, install, upgrade, and uninstall Python packages description = Easily download, build, install, upgrade, and uninstall Python packages
author = Python Packaging Authority author = Python Packaging Authority
author_email = distutils-sig@python.org author_email = distutils-sig@python.org
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
import os import os
import functools import functools
import setuptools.distutils_patch # noqa: F401
import distutils.core import distutils.core
import distutils.filelist import distutils.filelist
import re import re
......
This directory contains the Distutils package.
There's a full documentation available at:
http://docs.python.org/distutils/
The Distutils-SIG web page is also a good starting point:
http://www.python.org/sigs/distutils-sig/
$Id$
"""distutils
The main package for the Python Module Distribution Utilities. Normally
used from a setup script as
from distutils.core import setup
setup (...)
"""
import sys
__version__ = sys.version[:sys.version.index(' ')]
local = True
This diff is collapsed.
"""distutils.archive_util
Utility functions for creating archive files (tarballs, zip files,
that sort of thing)."""
import os
from warnings import warn
import sys
try:
import zipfile
except ImportError:
zipfile = None
from distutils.errors import DistutilsExecError
from distutils.spawn import spawn
from distutils.dir_util import mkpath
from distutils import log
try:
from pwd import getpwnam
except ImportError:
getpwnam = None
try:
from grp import getgrnam
except ImportError:
getgrnam = None
def _get_gid(name):
"""Returns a gid, given a group name."""
if getgrnam is None or name is None:
return None
try:
result = getgrnam(name)
except KeyError:
result = None
if result is not None:
return result[2]
return None
def _get_uid(name):
"""Returns an uid, given a user name."""
if getpwnam is None or name is None:
return None
try:
result = getpwnam(name)
except KeyError:
result = None
if result is not None:
return result[2]
return None
def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
owner=None, group=None):
"""Create a (possibly compressed) tar file from all the files under
'base_dir'.
'compress' must be "gzip" (the default), "bzip2", "xz", "compress", or
None. ("compress" will be deprecated in Python 3.2)
'owner' and 'group' can be used to define an owner and a group for the
archive that is being built. If not provided, the current owner and group
will be used.
The output tar file will be named 'base_dir' + ".tar", possibly plus
the appropriate compression extension (".gz", ".bz2", ".xz" or ".Z").
Returns the output filename.
"""
tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '',
'compress': ''}
compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz',
'compress': '.Z'}
# flags for compression program, each element of list will be an argument
if compress is not None and compress not in compress_ext.keys():
raise ValueError(
"bad value for 'compress': must be None, 'gzip', 'bzip2', "
"'xz' or 'compress'")
archive_name = base_name + '.tar'
if compress != 'compress':
archive_name += compress_ext.get(compress, '')
mkpath(os.path.dirname(archive_name), dry_run=dry_run)
# creating the tarball
import tarfile # late import so Python build itself doesn't break
log.info('Creating tar archive')
uid = _get_uid(owner)
gid = _get_gid(group)
def _set_uid_gid(tarinfo):
if gid is not None:
tarinfo.gid = gid
tarinfo.gname = group
if uid is not None:
tarinfo.uid = uid
tarinfo.uname = owner
return tarinfo
if not dry_run:
tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
try:
tar.add(base_dir, filter=_set_uid_gid)
finally:
tar.close()
# compression using `compress`
if compress == 'compress':
warn("'compress' will be deprecated.", PendingDeprecationWarning)
# the option varies depending on the platform
compressed_name = archive_name + compress_ext[compress]
if sys.platform == 'win32':
cmd = [compress, archive_name, compressed_name]
else:
cmd = [compress, '-f', archive_name]
spawn(cmd, dry_run=dry_run)
return compressed_name
return archive_name
def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
"""Create a zip file from all the files under 'base_dir'.
The output zip file will be named 'base_name' + ".zip". Uses either the
"zipfile" Python module (if available) or the InfoZIP "zip" utility
(if installed and found on the default search path). If neither tool is
available, raises DistutilsExecError. Returns the name of the output zip
file.
"""
zip_filename = base_name + ".zip"
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
# If zipfile module is not available, try spawning an external
# 'zip' command.
if zipfile is None:
if verbose:
zipoptions = "-r"
else:
zipoptions = "-rq"
try:
spawn(["zip", zipoptions, zip_filename, base_dir],
dry_run=dry_run)
except DistutilsExecError:
# XXX really should distinguish between "couldn't find
# external 'zip' command" and "zip failed".
raise DistutilsExecError(("unable to create zip file '%s': "
"could neither import the 'zipfile' module nor "
"find a standalone zip utility") % zip_filename)
else:
log.info("creating '%s' and adding '%s' to it",
zip_filename, base_dir)
if not dry_run:
try:
zip = zipfile.ZipFile(zip_filename, "w",
compression=zipfile.ZIP_DEFLATED)
except RuntimeError:
zip = zipfile.ZipFile(zip_filename, "w",
compression=zipfile.ZIP_STORED)
with zip:
if base_dir != os.curdir:
path = os.path.normpath(os.path.join(base_dir, ''))
zip.write(path, path)
log.info("adding '%s'", path)
for dirpath, dirnames, filenames in os.walk(base_dir):
for name in dirnames:
path = os.path.normpath(os.path.join(dirpath, name, ''))
zip.write(path, path)
log.info("adding '%s'", path)
for name in filenames:
path = os.path.normpath(os.path.join(dirpath, name))
if os.path.isfile(path):
zip.write(path, path)
log.info("adding '%s'", path)
return zip_filename
ARCHIVE_FORMATS = {
'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"),
'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"),
'tar': (make_tarball, [('compress', None)], "uncompressed tar file"),
'zip': (make_zipfile, [],"ZIP file")
}
def check_archive_formats(formats):
"""Returns the first format from the 'format' list that is unknown.
If all formats are known, returns None
"""
for format in formats:
if format not in ARCHIVE_FORMATS:
return format
return None
def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
dry_run=0, owner=None, group=None):
"""Create an archive file (eg. zip or tar).
'base_name' is the name of the file to create, minus any format-specific
extension; 'format' is the archive format: one of "zip", "tar", "gztar",
"bztar", "xztar", or "ztar".
'root_dir' is a directory that will be the root directory of the
archive; ie. we typically chdir into 'root_dir' before creating the
archive. 'base_dir' is the directory where we start archiving from;
ie. 'base_dir' will be the common prefix of all files and
directories in the archive. 'root_dir' and 'base_dir' both default
to the current directory. Returns the name of the archive file.
'owner' and 'group' are used when creating a tar archive. By default,
uses the current owner and group.
"""
save_cwd = os.getcwd()
if root_dir is not None:
log.debug("changing into '%s'", root_dir)
base_name = os.path.abspath(base_name)
if not dry_run:
os.chdir(root_dir)
if base_dir is None:
base_dir = os.curdir
kwargs = {'dry_run': dry_run}
try:
format_info = ARCHIVE_FORMATS[format]
except KeyError:
raise ValueError("unknown archive format '%s'" % format)
func = format_info[0]
for arg, val in format_info[1]:
kwargs[arg] = val
if format != 'zip':
kwargs['owner'] = owner
kwargs['group'] = group
try:
filename = func(base_name, base_dir, **kwargs)
finally:
if root_dir is not None:
log.debug("changing back to '%s'", save_cwd)
os.chdir(save_cwd)
return filename
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
"""distutils.command
Package containing implementation of all the standard Distutils
commands."""
__all__ = ['build',
'build_py',
'build_ext',
'build_clib',
'build_scripts',
'clean',
'install',
'install_lib',
'install_headers',
'install_scripts',
'install_data',
'sdist',
'register',
'bdist',
'bdist_dumb',
'bdist_rpm',
'bdist_wininst',
'check',
'upload',
# These two are reserved for future use:
#'bdist_sdux',
#'bdist_pkgtool',
# Note:
# bdist_packager is not included because it only provides
# an abstract base class
]
"""distutils.command.bdist
Implements the Distutils 'bdist' command (create a built [binary]
distribution)."""
import os
from distutils.core import Command
from distutils.errors import *
from distutils.util import get_platform
def show_formats():
"""Print list of available formats (arguments to "--format" option).
"""
from distutils.fancy_getopt import FancyGetopt
formats = []
for format in bdist.format_commands:
formats.append(("formats=" + format, None,
bdist.format_command[format][1]))
pretty_printer = FancyGetopt(formats)
pretty_printer.print_help("List of available distribution formats:")
class bdist(Command):
description = "create a built (binary) distribution"
user_options = [('bdist-base=', 'b',
"temporary directory for creating built distributions"),
('plat-name=', 'p',
"platform name to embed in generated filenames "
"(default: %s)" % get_platform()),
('formats=', None,
"formats for distribution (comma-separated list)"),
('dist-dir=', 'd',
"directory to put final built distributions in "
"[default: dist]"),
('skip-build', None,
"skip rebuilding everything (for testing/debugging)"),
('owner=', 'u',
"Owner name used when creating a tar file"
" [default: current user]"),
('group=', 'g',
"Group name used when creating a tar file"
" [default: current group]"),
]
boolean_options = ['skip-build']
help_options = [
('help-formats', None,
"lists available distribution formats", show_formats),
]
# The following commands do not take a format option from bdist
no_format_option = ('bdist_rpm',)
# This won't do in reality: will need to distinguish RPM-ish Linux,
# Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS.
default_format = {'posix': 'gztar',
'nt': 'zip'}
# Establish the preferred order (for the --help-formats option).
format_commands = ['rpm', 'gztar', 'bztar', 'xztar', 'ztar', 'tar',
'wininst', 'zip', 'msi']
# And the real information.
format_command = {'rpm': ('bdist_rpm', "RPM distribution"),
'gztar': ('bdist_dumb', "gzip'ed tar file"),
'bztar': ('bdist_dumb', "bzip2'ed tar file"),
'xztar': ('bdist_dumb', "xz'ed tar file"),
'ztar': ('bdist_dumb', "compressed tar file"),
'tar': ('bdist_dumb', "tar file"),
'wininst': ('bdist_wininst',
"Windows executable installer"),
'zip': ('bdist_dumb', "ZIP file"),
'msi': ('bdist_msi', "Microsoft Installer")
}
def initialize_options(self):
self.bdist_base = None
self.plat_name = None
self.formats = None
self.dist_dir = None
self.skip_build = 0
self.group = None
self.owner = None
def finalize_options(self):
# have to finalize 'plat_name' before 'bdist_base'
if self.plat_name is None:
if self.skip_build:
self.plat_name = get_platform()
else:
self.plat_name = self.get_finalized_command('build').plat_name
# 'bdist_base' -- parent of per-built-distribution-format
# temporary directories (eg. we'll probably have
# "build/bdist.<plat>/dumb", "build/bdist.<plat>/rpm", etc.)
if self.bdist_base is None:
build_base = self.get_finalized_command('build').build_base
self.bdist_base = os.path.join(build_base,
'bdist.' + self.plat_name)
self.ensure_string_list('formats')
if self.formats is None:
try:
self.formats = [self.default_format[os.name]]
except KeyError:
raise DistutilsPlatformError(
"don't know how to create built distributions "
"on platform %s" % os.name)
if self.dist_dir is None:
self.dist_dir = "dist"
def run(self):
# Figure out which sub-commands we need to run.
commands = []
for format in self.formats:
try:
commands.append(self.format_command[format][0])
except KeyError:
raise DistutilsOptionError("invalid format '%s'" % format)
# Reinitialize and run each command.
for i in range(len(self.formats)):
cmd_name = commands[i]
sub_cmd = self.reinitialize_command(cmd_name)
if cmd_name not in self.no_format_option:
sub_cmd.format = self.formats[i]
# passing the owner and group names for tar archiving
if cmd_name == 'bdist_dumb':
sub_cmd.owner = self.owner
sub_cmd.group = self.group
# If we're going to need to run this command again, tell it to
# keep its temporary files around so subsequent runs go faster.
if cmd_name in commands[i+1:]:
sub_cmd.keep_temp = 1
self.run_command(cmd_name)
"""distutils.command.bdist_dumb
Implements the Distutils 'bdist_dumb' command (create a "dumb" built
distribution -- i.e., just an archive to be unpacked under $prefix or
$exec_prefix)."""
import os
from distutils.core import Command
from distutils.util import get_platform
from distutils.dir_util import remove_tree, ensure_relative
from distutils.errors import *
from distutils.sysconfig import get_python_version
from distutils import log
class bdist_dumb(Command):
description = "create a \"dumb\" built distribution"
user_options = [('bdist-dir=', 'd',
"temporary directory for creating the distribution"),
('plat-name=', 'p',
"platform name to embed in generated filenames "
"(default: %s)" % get_platform()),
('format=', 'f',
"archive format to create (tar, gztar, bztar, xztar, "
"ztar, zip)"),
('keep-temp', 'k',
"keep the pseudo-installation tree around after " +
"creating the distribution archive"),
('dist-dir=', 'd',
"directory to put final built distributions in"),
('skip-build', None,
"skip rebuilding everything (for testing/debugging)"),
('relative', None,
"build the archive using relative paths "
"(default: false)"),
('owner=', 'u',
"Owner name used when creating a tar file"
" [default: current user]"),
('group=', 'g',
"Group name used when creating a tar file"
" [default: current group]"),
]
boolean_options = ['keep-temp', 'skip-build', 'relative']
default_format = { 'posix': 'gztar',
'nt': 'zip' }
def initialize_options(self):
self.bdist_dir = None
self.plat_name = None
self.format = None
self.keep_temp = 0
self.dist_dir = None
self.skip_build = None
self.relative = 0
self.owner = None
self.group = None
def finalize_options(self):
if self.bdist_dir is None:
bdist_base = self.get_finalized_command('bdist').bdist_base
self.bdist_dir = os.path.join(bdist_base, 'dumb')
if self.format is None:
try:
self.format = self.default_format[os.name]
except KeyError:
raise DistutilsPlatformError(
"don't know how to create dumb built distributions "
"on platform %s" % os.name)
self.set_undefined_options('bdist',
('dist_dir', 'dist_dir'),
('plat_name', 'plat_name'),
('skip_build', 'skip_build'))
def run(self):
if not self.skip_build:
self.run_command('build')
install = self.reinitialize_command('install', reinit_subcommands=1)
install.root = self.bdist_dir
install.skip_build = self.skip_build
install.warn_dir = 0
log.info("installing to %s", self.bdist_dir)
self.run_command('install')
# And make an archive relative to the root of the
# pseudo-installation tree.
archive_basename = "%s.%s" % (self.distribution.get_fullname(),
self.plat_name)
pseudoinstall_root = os.path.join(self.dist_dir, archive_basename)
if not self.relative:
archive_root = self.bdist_dir
else:
if (self.distribution.has_ext_modules() and
(install.install_base != install.install_platbase)):
raise DistutilsPlatformError(
"can't make a dumb built distribution where "
"base and platbase are different (%s, %s)"
% (repr(install.install_base),
repr(install.install_platbase)))
else:
archive_root = os.path.join(self.bdist_dir,
ensure_relative(install.install_base))
# Make the archive
filename = self.make_archive(pseudoinstall_root,
self.format, root_dir=archive_root,
owner=self.owner, group=self.group)
if self.distribution.has_ext_modules():
pyversion = get_python_version()
else:
pyversion = 'any'
self.distribution.dist_files.append(('bdist_dumb', pyversion,
filename))
if not self.keep_temp:
remove_tree(self.bdist_dir, dry_run=self.dry_run)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
"""distutils.command.build
Implements the Distutils 'build' command."""
import sys, os
from distutils.core import Command
from distutils.errors import DistutilsOptionError
from distutils.util import get_platform
def show_compilers():
from distutils.ccompiler import show_compilers
show_compilers()
class build(Command):
description = "build everything needed to install"
user_options = [
('build-base=', 'b',
"base directory for build library"),
('build-purelib=', None,
"build directory for platform-neutral distributions"),
('build-platlib=', None,
"build directory for platform-specific distributions"),
('build-lib=', None,
"build directory for all distribution (defaults to either " +
"build-purelib or build-platlib"),
('build-scripts=', None,
"build directory for scripts"),
('build-temp=', 't',
"temporary build directory"),
('plat-name=', 'p',
"platform name to build for, if supported "
"(default: %s)" % get_platform()),
('compiler=', 'c',
"specify the compiler type"),
('parallel=', 'j',
"number of parallel build jobs"),
('debug', 'g',
"compile extensions and libraries with debugging information"),
('force', 'f',
"forcibly build everything (ignore file timestamps)"),
('executable=', 'e',
"specify final destination interpreter path (build.py)"),
]
boolean_options = ['debug', 'force']
help_options = [
('help-compiler', None,
"list available compilers", show_compilers),
]
def initialize_options(self):
self.build_base = 'build'
# these are decided only after 'build_base' has its final value
# (unless overridden by the user or client)
self.build_purelib = None
self.build_platlib = None
self.build_lib = None
self.build_temp = None
self.build_scripts = None
self.compiler = None
self.plat_name = None
self.debug = None
self.force = 0
self.executable = None
self.parallel = None
def finalize_options(self):
if self.plat_name is None:
self.plat_name = get_platform()
else:
# plat-name only supported for windows (other platforms are
# supported via ./configure flags, if at all). Avoid misleading
# other platforms.
if os.name != 'nt':
raise DistutilsOptionError(
"--plat-name only supported on Windows (try "
"using './configure --help' on your platform)")
plat_specifier = ".%s-%d.%d" % (self.plat_name, *sys.version_info[:2])
# Make it so Python 2.x and Python 2.x with --with-pydebug don't
# share the same build directories. Doing so confuses the build
# process for C modules
if hasattr(sys, 'gettotalrefcount'):
plat_specifier += '-pydebug'
# 'build_purelib' and 'build_platlib' just default to 'lib' and
# 'lib.<plat>' under the base build directory. We only use one of
# them for a given distribution, though --
if self.build_purelib is None:
self.build_purelib = os.path.join(self.build_base, 'lib')
if self.build_platlib is None:
self.build_platlib = os.path.join(self.build_base,
'lib' + plat_specifier)
# 'build_lib' is the actual directory that we will use for this
# particular module distribution -- if user didn't supply it, pick
# one of 'build_purelib' or 'build_platlib'.
if self.build_lib is None:
if self.distribution.ext_modules:
self.build_lib = self.build_platlib
else:
self.build_lib = self.build_purelib
# 'build_temp' -- temporary directory for compiler turds,
# "build/temp.<plat>"
if self.build_temp is None:
self.build_temp = os.path.join(self.build_base,
'temp' + plat_specifier)
if self.build_scripts is None:
self.build_scripts = os.path.join(self.build_base,
'scripts-%d.%d' % sys.version_info[:2])
if self.executable is None and sys.executable:
self.executable = os.path.normpath(sys.executable)
if isinstance(self.parallel, str):
try:
self.parallel = int(self.parallel)
except ValueError:
raise DistutilsOptionError("parallel should be an integer")
def run(self):
# Run all relevant sub-commands. This will be some subset of:
# - build_py - pure Python modules
# - build_clib - standalone C libraries
# - build_ext - Python extensions
# - build_scripts - (Python) scripts
for cmd_name in self.get_sub_commands():
self.run_command(cmd_name)
# -- Predicates for the sub-command list ---------------------------
def has_pure_modules(self):
return self.distribution.has_pure_modules()
def has_c_libraries(self):
return self.distribution.has_c_libraries()
def has_ext_modules(self):
return self.distribution.has_ext_modules()
def has_scripts(self):
return self.distribution.has_scripts()
sub_commands = [('build_py', has_pure_modules),
('build_clib', has_c_libraries),
('build_ext', has_ext_modules),
('build_scripts', has_scripts),
]
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import os
# If DISTUTILS_DEBUG is anything other than the empty string, we run in
# debug mode.
DEBUG = os.environ.get('DISTUTILS_DEBUG')
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment