mirror of
https://github.com/ansible/awx.git
synced 2026-05-16 05:47:38 -02:30
Upgrading setuptools (and related modules) to 12.0.5
This commit is contained in:
@@ -54,7 +54,7 @@ rackspace-novaclient==1.4 (no files)
|
|||||||
rax-default-network-flags-python-novaclient-ext==0.2.3 (rax_default_network_flags_python_novaclient_ext/*)
|
rax-default-network-flags-python-novaclient-ext==0.2.3 (rax_default_network_flags_python_novaclient_ext/*)
|
||||||
rax-scheduled-images-python-novaclient-ext==0.2.1 (rax_scheduled_images_python_novaclient_ext/*)
|
rax-scheduled-images-python-novaclient-ext==0.2.1 (rax_scheduled_images_python_novaclient_ext/*)
|
||||||
requests==2.3.0 (requests/*)
|
requests==2.3.0 (requests/*)
|
||||||
setuptools==2.2 (setuptools/*, _markerlib/*, pkg_resources.py, easy_install.py, excluded bin/easy_install*)
|
setuptools==12.0.5 (setuptools/*, _markerlib/*, pkg_resources/*, easy_install.py)
|
||||||
simplejson==3.6.0 (simplejson/*, excluded simplejson/_speedups.so)
|
simplejson==3.6.0 (simplejson/*, excluded simplejson/_speedups.so)
|
||||||
six==1.7.3 (six.py)
|
six==1.7.3 (six.py)
|
||||||
South==0.8.4 (south/*)
|
South==0.8.4 (south/*)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
|||||||
|
# Copyright 2014 Donald Stufft
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"__title__", "__summary__", "__uri__", "__version__", "__author__",
|
||||||
|
"__email__", "__license__", "__copyright__",
|
||||||
|
]
|
||||||
|
|
||||||
|
__title__ = "packaging"
|
||||||
|
__summary__ = "Core utilities for Python packages"
|
||||||
|
__uri__ = "https://github.com/pypa/packaging"
|
||||||
|
|
||||||
|
__version__ = "15.0"
|
||||||
|
|
||||||
|
__author__ = "Donald Stufft"
|
||||||
|
__email__ = "donald@stufft.io"
|
||||||
|
|
||||||
|
__license__ = "Apache License, Version 2.0"
|
||||||
|
__copyright__ = "Copyright 2014 %s" % __author__
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2014 Donald Stufft
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from .__about__ import (
|
||||||
|
__author__, __copyright__, __email__, __license__, __summary__, __title__,
|
||||||
|
__uri__, __version__
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"__title__", "__summary__", "__uri__", "__version__", "__author__",
|
||||||
|
"__email__", "__license__", "__copyright__",
|
||||||
|
]
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Copyright 2014 Donald Stufft
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
PY2 = sys.version_info[0] == 2
|
||||||
|
PY3 = sys.version_info[0] == 3
|
||||||
|
|
||||||
|
# flake8: noqa
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
string_types = str,
|
||||||
|
else:
|
||||||
|
string_types = basestring,
|
||||||
|
|
||||||
|
|
||||||
|
def with_metaclass(meta, *bases):
|
||||||
|
"""
|
||||||
|
Create a base class with a metaclass.
|
||||||
|
"""
|
||||||
|
# This requires a bit of explanation: the basic idea is to make a dummy
|
||||||
|
# metaclass for one level of class instantiation that replaces itself with
|
||||||
|
# the actual metaclass.
|
||||||
|
class metaclass(meta):
|
||||||
|
def __new__(cls, name, this_bases, d):
|
||||||
|
return meta(name, bases, d)
|
||||||
|
return type.__new__(metaclass, 'temporary_class', (), {})
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# Copyright 2014 Donald Stufft
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
|
||||||
|
class Infinity(object):
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "Infinity"
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(repr(self))
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return isinstance(other, self.__class__)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not isinstance(other, self.__class__)
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __ge__(self, other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
return NegativeInfinity
|
||||||
|
|
||||||
|
Infinity = Infinity()
|
||||||
|
|
||||||
|
|
||||||
|
class NegativeInfinity(object):
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "-Infinity"
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(repr(self))
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return isinstance(other, self.__class__)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not isinstance(other, self.__class__)
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __ge__(self, other):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
return Infinity
|
||||||
|
|
||||||
|
NegativeInfinity = NegativeInfinity()
|
||||||
@@ -0,0 +1,772 @@
|
|||||||
|
# Copyright 2014 Donald Stufft
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import abc
|
||||||
|
import functools
|
||||||
|
import itertools
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ._compat import string_types, with_metaclass
|
||||||
|
from .version import Version, LegacyVersion, parse
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidSpecifier(ValueError):
|
||||||
|
"""
|
||||||
|
An invalid specifier was found, users should refer to PEP 440.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def __str__(self):
|
||||||
|
"""
|
||||||
|
Returns the str representation of this Specifier like object. This
|
||||||
|
should be representative of the Specifier itself.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def __hash__(self):
|
||||||
|
"""
|
||||||
|
Returns a hash value for this Specifier like object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def __eq__(self, other):
|
||||||
|
"""
|
||||||
|
Returns a boolean representing whether or not the two Specifier like
|
||||||
|
objects are equal.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def __ne__(self, other):
|
||||||
|
"""
|
||||||
|
Returns a boolean representing whether or not the two Specifier like
|
||||||
|
objects are not equal.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractproperty
|
||||||
|
def prereleases(self):
|
||||||
|
"""
|
||||||
|
Returns whether or not pre-releases as a whole are allowed by this
|
||||||
|
specifier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@prereleases.setter
|
||||||
|
def prereleases(self, value):
|
||||||
|
"""
|
||||||
|
Sets whether or not pre-releases as a whole are allowed by this
|
||||||
|
specifier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def contains(self, item, prereleases=None):
|
||||||
|
"""
|
||||||
|
Determines if the given item is contained within this specifier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def filter(self, iterable, prereleases=None):
|
||||||
|
"""
|
||||||
|
Takes an iterable of items and filters them so that only items which
|
||||||
|
are contained within this specifier are allowed in it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class _IndividualSpecifier(BaseSpecifier):
|
||||||
|
|
||||||
|
_operators = {}
|
||||||
|
|
||||||
|
def __init__(self, spec="", prereleases=None):
|
||||||
|
match = self._regex.search(spec)
|
||||||
|
if not match:
|
||||||
|
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
|
||||||
|
|
||||||
|
self._spec = (
|
||||||
|
match.group("operator").strip(),
|
||||||
|
match.group("version").strip(),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Store whether or not this Specifier should accept prereleases
|
||||||
|
self._prereleases = prereleases
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
pre = (
|
||||||
|
", prereleases={0!r}".format(self.prereleases)
|
||||||
|
if self._prereleases is not None
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
return "<{0}({1!r}{2})>".format(
|
||||||
|
self.__class__.__name__,
|
||||||
|
str(self),
|
||||||
|
pre,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{0}{1}".format(*self._spec)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self._spec)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, string_types):
|
||||||
|
try:
|
||||||
|
other = self.__class__(other)
|
||||||
|
except InvalidSpecifier:
|
||||||
|
return NotImplemented
|
||||||
|
elif not isinstance(other, self.__class__):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return self._spec == other._spec
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
if isinstance(other, string_types):
|
||||||
|
try:
|
||||||
|
other = self.__class__(other)
|
||||||
|
except InvalidSpecifier:
|
||||||
|
return NotImplemented
|
||||||
|
elif not isinstance(other, self.__class__):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return self._spec != other._spec
|
||||||
|
|
||||||
|
def _get_operator(self, op):
|
||||||
|
return getattr(self, "_compare_{0}".format(self._operators[op]))
|
||||||
|
|
||||||
|
def _coerce_version(self, version):
|
||||||
|
if not isinstance(version, (LegacyVersion, Version)):
|
||||||
|
version = parse(version)
|
||||||
|
return version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def prereleases(self):
|
||||||
|
return self._prereleases
|
||||||
|
|
||||||
|
@prereleases.setter
|
||||||
|
def prereleases(self, value):
|
||||||
|
self._prereleases = value
|
||||||
|
|
||||||
|
def contains(self, item, prereleases=None):
|
||||||
|
# Determine if prereleases are to be allowed or not.
|
||||||
|
if prereleases is None:
|
||||||
|
prereleases = self.prereleases
|
||||||
|
|
||||||
|
# Normalize item to a Version or LegacyVersion, this allows us to have
|
||||||
|
# a shortcut for ``"2.0" in Specifier(">=2")
|
||||||
|
item = self._coerce_version(item)
|
||||||
|
|
||||||
|
# Determine if we should be supporting prereleases in this specifier
|
||||||
|
# or not, if we do not support prereleases than we can short circuit
|
||||||
|
# logic if this version is a prereleases.
|
||||||
|
if item.is_prerelease and not prereleases:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Actually do the comparison to determine if this item is contained
|
||||||
|
# within this Specifier or not.
|
||||||
|
return self._get_operator(self._spec[0])(item, self._spec[1])
|
||||||
|
|
||||||
|
def filter(self, iterable, prereleases=None):
|
||||||
|
yielded = False
|
||||||
|
found_prereleases = []
|
||||||
|
|
||||||
|
kw = {"prereleases": prereleases if prereleases is not None else True}
|
||||||
|
|
||||||
|
# Attempt to iterate over all the values in the iterable and if any of
|
||||||
|
# them match, yield them.
|
||||||
|
for version in iterable:
|
||||||
|
parsed_version = self._coerce_version(version)
|
||||||
|
|
||||||
|
if self.contains(parsed_version, **kw):
|
||||||
|
# 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)):
|
||||||
|
found_prereleases.append(version)
|
||||||
|
# Either this is not a prerelease, or we should have been
|
||||||
|
# accepting prereleases from the begining.
|
||||||
|
else:
|
||||||
|
yielded = True
|
||||||
|
yield version
|
||||||
|
|
||||||
|
# Now that we've iterated over everything, determine if we've yielded
|
||||||
|
# any values, and if we have not and we have any prereleases stored up
|
||||||
|
# then we will go ahead and yield the prereleases.
|
||||||
|
if not yielded and found_prereleases:
|
||||||
|
for version in found_prereleases:
|
||||||
|
yield version
|
||||||
|
|
||||||
|
|
||||||
|
class LegacySpecifier(_IndividualSpecifier):
|
||||||
|
|
||||||
|
_regex = re.compile(
|
||||||
|
r"""
|
||||||
|
^
|
||||||
|
\s*
|
||||||
|
(?P<operator>(==|!=|<=|>=|<|>))
|
||||||
|
\s*
|
||||||
|
(?P<version>
|
||||||
|
[^\s]* # We just match everything, except for whitespace since this
|
||||||
|
# is a "legacy" specifier and the version string can be just
|
||||||
|
# about anything.
|
||||||
|
)
|
||||||
|
\s*
|
||||||
|
$
|
||||||
|
""",
|
||||||
|
re.VERBOSE | re.IGNORECASE,
|
||||||
|
)
|
||||||
|
|
||||||
|
_operators = {
|
||||||
|
"==": "equal",
|
||||||
|
"!=": "not_equal",
|
||||||
|
"<=": "less_than_equal",
|
||||||
|
">=": "greater_than_equal",
|
||||||
|
"<": "less_than",
|
||||||
|
">": "greater_than",
|
||||||
|
}
|
||||||
|
|
||||||
|
def _coerce_version(self, version):
|
||||||
|
if not isinstance(version, LegacyVersion):
|
||||||
|
version = LegacyVersion(str(version))
|
||||||
|
return version
|
||||||
|
|
||||||
|
def _compare_equal(self, prospective, spec):
|
||||||
|
return prospective == self._coerce_version(spec)
|
||||||
|
|
||||||
|
def _compare_not_equal(self, prospective, spec):
|
||||||
|
return prospective != self._coerce_version(spec)
|
||||||
|
|
||||||
|
def _compare_less_than_equal(self, prospective, spec):
|
||||||
|
return prospective <= self._coerce_version(spec)
|
||||||
|
|
||||||
|
def _compare_greater_than_equal(self, prospective, spec):
|
||||||
|
return prospective >= self._coerce_version(spec)
|
||||||
|
|
||||||
|
def _compare_less_than(self, prospective, spec):
|
||||||
|
return prospective < self._coerce_version(spec)
|
||||||
|
|
||||||
|
def _compare_greater_than(self, prospective, spec):
|
||||||
|
return prospective > self._coerce_version(spec)
|
||||||
|
|
||||||
|
|
||||||
|
def _require_version_compare(fn):
|
||||||
|
@functools.wraps(fn)
|
||||||
|
def wrapped(self, prospective, spec):
|
||||||
|
if not isinstance(prospective, Version):
|
||||||
|
return False
|
||||||
|
return fn(self, prospective, spec)
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
|
class Specifier(_IndividualSpecifier):
|
||||||
|
|
||||||
|
_regex = re.compile(
|
||||||
|
r"""
|
||||||
|
^
|
||||||
|
\s*
|
||||||
|
(?P<operator>(~=|==|!=|<=|>=|<|>|===))
|
||||||
|
(?P<version>
|
||||||
|
(?:
|
||||||
|
# The identity operators allow for an escape hatch that will
|
||||||
|
# do an exact string match of the version you wish to install.
|
||||||
|
# This will not be parsed by PEP 440 and we cannot determine
|
||||||
|
# any semantic meaning from it. This operator is discouraged
|
||||||
|
# but included entirely as an escape hatch.
|
||||||
|
(?<====) # Only match for the identity operator
|
||||||
|
\s*
|
||||||
|
[^\s]* # We just match everything, except for whitespace
|
||||||
|
# since we are only testing for strict identity.
|
||||||
|
)
|
||||||
|
|
|
||||||
|
(?:
|
||||||
|
# The (non)equality operators allow for wild card and local
|
||||||
|
# versions to be specified so we have to define these two
|
||||||
|
# operators separately to enable that.
|
||||||
|
(?<===|!=) # Only match for equals and not equals
|
||||||
|
|
||||||
|
\s*
|
||||||
|
v?
|
||||||
|
(?:[0-9]+!)? # epoch
|
||||||
|
[0-9]+(?:\.[0-9]+)* # release
|
||||||
|
(?: # pre release
|
||||||
|
[-_\.]?
|
||||||
|
(a|b|c|rc|alpha|beta|pre|preview)
|
||||||
|
[-_\.]?
|
||||||
|
[0-9]*
|
||||||
|
)?
|
||||||
|
(?: # post release
|
||||||
|
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
||||||
|
)?
|
||||||
|
|
||||||
|
# You cannot use a wild card and a dev or local version
|
||||||
|
# together so group them with a | and make them optional.
|
||||||
|
(?:
|
||||||
|
(?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
||||||
|
(?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
|
||||||
|
|
|
||||||
|
\.\* # Wild card syntax of .*
|
||||||
|
)?
|
||||||
|
)
|
||||||
|
|
|
||||||
|
(?:
|
||||||
|
# The compatible operator requires at least two digits in the
|
||||||
|
# release segment.
|
||||||
|
(?<=~=) # Only match for the compatible operator
|
||||||
|
|
||||||
|
\s*
|
||||||
|
v?
|
||||||
|
(?:[0-9]+!)? # epoch
|
||||||
|
[0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
|
||||||
|
(?: # pre release
|
||||||
|
[-_\.]?
|
||||||
|
(a|b|c|rc|alpha|beta|pre|preview)
|
||||||
|
[-_\.]?
|
||||||
|
[0-9]*
|
||||||
|
)?
|
||||||
|
(?: # post release
|
||||||
|
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
||||||
|
)?
|
||||||
|
(?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
||||||
|
)
|
||||||
|
|
|
||||||
|
(?:
|
||||||
|
# All other operators only allow a sub set of what the
|
||||||
|
# (non)equality operators do. Specifically they do not allow
|
||||||
|
# local versions to be specified nor do they allow the prefix
|
||||||
|
# matching wild cards.
|
||||||
|
(?<!==|!=|~=) # We have special cases for these
|
||||||
|
# operators so we want to make sure they
|
||||||
|
# don't match here.
|
||||||
|
|
||||||
|
\s*
|
||||||
|
v?
|
||||||
|
(?:[0-9]+!)? # epoch
|
||||||
|
[0-9]+(?:\.[0-9]+)* # release
|
||||||
|
(?: # pre release
|
||||||
|
[-_\.]?
|
||||||
|
(a|b|c|rc|alpha|beta|pre|preview)
|
||||||
|
[-_\.]?
|
||||||
|
[0-9]*
|
||||||
|
)?
|
||||||
|
(?: # post release
|
||||||
|
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
||||||
|
)?
|
||||||
|
(?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
||||||
|
)
|
||||||
|
)
|
||||||
|
\s*
|
||||||
|
$
|
||||||
|
""",
|
||||||
|
re.VERBOSE | re.IGNORECASE,
|
||||||
|
)
|
||||||
|
|
||||||
|
_operators = {
|
||||||
|
"~=": "compatible",
|
||||||
|
"==": "equal",
|
||||||
|
"!=": "not_equal",
|
||||||
|
"<=": "less_than_equal",
|
||||||
|
">=": "greater_than_equal",
|
||||||
|
"<": "less_than",
|
||||||
|
">": "greater_than",
|
||||||
|
"===": "arbitrary",
|
||||||
|
}
|
||||||
|
|
||||||
|
@_require_version_compare
|
||||||
|
def _compare_compatible(self, prospective, spec):
|
||||||
|
# Compatible releases have an equivalent combination of >= and ==. That
|
||||||
|
# is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
|
||||||
|
# implement this in terms of the other specifiers instead of
|
||||||
|
# implementing it ourselves. The only thing we need to do is construct
|
||||||
|
# the other specifiers.
|
||||||
|
|
||||||
|
# We want everything but the last item in the version, but we want to
|
||||||
|
# ignore post and dev releases and we want to treat the pre-release as
|
||||||
|
# it's own separate segment.
|
||||||
|
prefix = ".".join(
|
||||||
|
list(
|
||||||
|
itertools.takewhile(
|
||||||
|
lambda x: (not x.startswith("post")
|
||||||
|
and not x.startswith("dev")),
|
||||||
|
_version_split(spec),
|
||||||
|
)
|
||||||
|
)[:-1]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the prefix notation to the end of our string
|
||||||
|
prefix += ".*"
|
||||||
|
|
||||||
|
return (self._get_operator(">=")(prospective, spec)
|
||||||
|
and self._get_operator("==")(prospective, prefix))
|
||||||
|
|
||||||
|
@_require_version_compare
|
||||||
|
def _compare_equal(self, prospective, spec):
|
||||||
|
# We need special logic to handle prefix matching
|
||||||
|
if spec.endswith(".*"):
|
||||||
|
# Split the spec out by dots, and pretend that there is an implicit
|
||||||
|
# dot in between a release segment and a pre-release segment.
|
||||||
|
spec = _version_split(spec[:-2]) # Remove the trailing .*
|
||||||
|
|
||||||
|
# Split the prospective version out by dots, and pretend that there
|
||||||
|
# is an implicit dot in between a release segment and a pre-release
|
||||||
|
# segment.
|
||||||
|
prospective = _version_split(str(prospective))
|
||||||
|
|
||||||
|
# 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)]
|
||||||
|
|
||||||
|
# Pad out our two sides with zeros so that they both equal the same
|
||||||
|
# length.
|
||||||
|
spec, prospective = _pad_version(spec, prospective)
|
||||||
|
else:
|
||||||
|
# Convert our spec string into a Version
|
||||||
|
spec = Version(spec)
|
||||||
|
|
||||||
|
# If the specifier does not have a local segment, then we want to
|
||||||
|
# act as if the prospective version also does not have a local
|
||||||
|
# segment.
|
||||||
|
if not spec.local:
|
||||||
|
prospective = Version(prospective.public)
|
||||||
|
|
||||||
|
return prospective == spec
|
||||||
|
|
||||||
|
@_require_version_compare
|
||||||
|
def _compare_not_equal(self, prospective, spec):
|
||||||
|
return not self._compare_equal(prospective, spec)
|
||||||
|
|
||||||
|
@_require_version_compare
|
||||||
|
def _compare_less_than_equal(self, prospective, spec):
|
||||||
|
return prospective <= Version(spec)
|
||||||
|
|
||||||
|
@_require_version_compare
|
||||||
|
def _compare_greater_than_equal(self, prospective, spec):
|
||||||
|
return prospective >= Version(spec)
|
||||||
|
|
||||||
|
@_require_version_compare
|
||||||
|
def _compare_less_than(self, prospective, spec):
|
||||||
|
# Convert our spec to a Version instance, since we'll want to work with
|
||||||
|
# it as a version.
|
||||||
|
spec = Version(spec)
|
||||||
|
|
||||||
|
# Check to see if the prospective version is less than the spec
|
||||||
|
# version. If it's not we can short circuit and just return False now
|
||||||
|
# instead of doing extra unneeded work.
|
||||||
|
if not prospective < spec:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# This special case is here so that, unless the specifier itself
|
||||||
|
# includes is a pre-release version, that we do not accept pre-release
|
||||||
|
# versions for the version mentioned in the specifier (e.g. <3.1 should
|
||||||
|
# not match 3.1.dev0, but should match 3.0.dev0).
|
||||||
|
if not spec.is_prerelease and prospective.is_prerelease:
|
||||||
|
if Version(prospective.base_version) == Version(spec.base_version):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# If we've gotten to here, it means that prospective version is both
|
||||||
|
# less than the spec version *and* it's not a pre-release of the same
|
||||||
|
# version in the spec.
|
||||||
|
return True
|
||||||
|
|
||||||
|
@_require_version_compare
|
||||||
|
def _compare_greater_than(self, prospective, spec):
|
||||||
|
# Convert our spec to a Version instance, since we'll want to work with
|
||||||
|
# it as a version.
|
||||||
|
spec = Version(spec)
|
||||||
|
|
||||||
|
# Check to see if the prospective version is greater than the spec
|
||||||
|
# version. If it's not we can short circuit and just return False now
|
||||||
|
# instead of doing extra unneeded work.
|
||||||
|
if not prospective > spec:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# This special case is here so that, unless the specifier itself
|
||||||
|
# includes is a post-release version, that we do not accept
|
||||||
|
# post-release versions for the version mentioned in the specifier
|
||||||
|
# (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
|
||||||
|
if not spec.is_postrelease and prospective.is_postrelease:
|
||||||
|
if Version(prospective.base_version) == Version(spec.base_version):
|
||||||
|
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.
|
||||||
|
if prospective.local is not None:
|
||||||
|
if Version(prospective.base_version) == Version(spec.base_version):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# If we've gotten to here, it means that prospective version is both
|
||||||
|
# greater than the spec version *and* it's not a pre-release of the
|
||||||
|
# same version in the spec.
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _compare_arbitrary(self, prospective, spec):
|
||||||
|
return str(prospective).lower() == str(spec).lower()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def prereleases(self):
|
||||||
|
# If there is an explicit prereleases set for this, then we'll just
|
||||||
|
# blindly use that.
|
||||||
|
if self._prereleases is not None:
|
||||||
|
return self._prereleases
|
||||||
|
|
||||||
|
# Look at all of our specifiers and determine if they are inclusive
|
||||||
|
# operators, and if they are if they are including an explicit
|
||||||
|
# prerelease.
|
||||||
|
operator, version = self._spec
|
||||||
|
if operator in ["==", ">=", "<=", "~="]:
|
||||||
|
# The == specifier can include a trailing .*, if it does we
|
||||||
|
# want to remove before parsing.
|
||||||
|
if operator == "==" and version.endswith(".*"):
|
||||||
|
version = version[:-2]
|
||||||
|
|
||||||
|
# Parse the version, and if it is a pre-release than this
|
||||||
|
# specifier allows pre-releases.
|
||||||
|
if parse(version).is_prerelease:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
@prereleases.setter
|
||||||
|
def prereleases(self, value):
|
||||||
|
self._prereleases = value
|
||||||
|
|
||||||
|
|
||||||
|
_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
|
||||||
|
|
||||||
|
|
||||||
|
def _version_split(version):
|
||||||
|
result = []
|
||||||
|
for item in version.split("."):
|
||||||
|
match = _prefix_regex.search(item)
|
||||||
|
if match:
|
||||||
|
result.extend(match.groups())
|
||||||
|
else:
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _pad_version(left, right):
|
||||||
|
left_split, right_split = [], []
|
||||||
|
|
||||||
|
# Get the release segment of our versions
|
||||||
|
left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
|
||||||
|
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
|
||||||
|
|
||||||
|
# Get the rest of our versions
|
||||||
|
left_split.append(left[len(left_split):])
|
||||||
|
right_split.append(left[len(right_split):])
|
||||||
|
|
||||||
|
# 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])),
|
||||||
|
)
|
||||||
|
|
||||||
|
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.
|
||||||
|
specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
|
||||||
|
|
||||||
|
# Parsed each individual specifier, attempting first to make it a
|
||||||
|
# Specifier and falling back to a LegacySpecifier.
|
||||||
|
parsed = set()
|
||||||
|
for specifier in specifiers:
|
||||||
|
try:
|
||||||
|
parsed.add(Specifier(specifier))
|
||||||
|
except InvalidSpecifier:
|
||||||
|
parsed.add(LegacySpecifier(specifier))
|
||||||
|
|
||||||
|
# Turn our parsed specifiers into a frozen set and save them for later.
|
||||||
|
self._specs = frozenset(parsed)
|
||||||
|
|
||||||
|
# Store our prereleases value so we can use it later to determine if
|
||||||
|
# we accept prereleases or not.
|
||||||
|
self._prereleases = prereleases
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
pre = (
|
||||||
|
", prereleases={0!r}".format(self.prereleases)
|
||||||
|
if self._prereleases is not None
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ",".join(sorted(str(s) for s in self._specs))
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self._specs)
|
||||||
|
|
||||||
|
def __and__(self, other):
|
||||||
|
if isinstance(other, string_types):
|
||||||
|
other = SpecifierSet(other)
|
||||||
|
elif not isinstance(other, SpecifierSet):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
specifier = SpecifierSet()
|
||||||
|
specifier._specs = frozenset(self._specs | other._specs)
|
||||||
|
|
||||||
|
if self._prereleases is None and other._prereleases is not None:
|
||||||
|
specifier._prereleases = other._prereleases
|
||||||
|
elif self._prereleases is not None and other._prereleases is None:
|
||||||
|
specifier._prereleases = self._prereleases
|
||||||
|
elif self._prereleases == other._prereleases:
|
||||||
|
specifier._prereleases = self._prereleases
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
"Cannot combine SpecifierSets with True and False prerelease "
|
||||||
|
"overrides."
|
||||||
|
)
|
||||||
|
|
||||||
|
return specifier
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, string_types):
|
||||||
|
other = SpecifierSet(other)
|
||||||
|
elif isinstance(other, _IndividualSpecifier):
|
||||||
|
other = SpecifierSet(str(other))
|
||||||
|
elif not isinstance(other, SpecifierSet):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return self._specs == other._specs
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
if isinstance(other, string_types):
|
||||||
|
other = SpecifierSet(other)
|
||||||
|
elif isinstance(other, _IndividualSpecifier):
|
||||||
|
other = SpecifierSet(str(other))
|
||||||
|
elif not isinstance(other, SpecifierSet):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return self._specs != other._specs
|
||||||
|
|
||||||
|
@property
|
||||||
|
def prereleases(self):
|
||||||
|
# If we have been given an explicit prerelease modifier, then we'll
|
||||||
|
# pass that through here.
|
||||||
|
if self._prereleases is not None:
|
||||||
|
return self._prereleases
|
||||||
|
|
||||||
|
# Otherwise we'll see if any of the given specifiers accept
|
||||||
|
# prereleases, if any of them do we'll return True, otherwise False.
|
||||||
|
# Note: The use of any() here means that an empty set of specifiers
|
||||||
|
# will always return False, this is an explicit design decision.
|
||||||
|
return any(s.prereleases for s in self._specs)
|
||||||
|
|
||||||
|
@prereleases.setter
|
||||||
|
def prereleases(self, value):
|
||||||
|
self._prereleases = value
|
||||||
|
|
||||||
|
def contains(self, item, prereleases=None):
|
||||||
|
# Ensure that our item is a Version or LegacyVersion instance.
|
||||||
|
if not isinstance(item, (LegacyVersion, Version)):
|
||||||
|
item = parse(item)
|
||||||
|
|
||||||
|
# We can determine if we're going to allow pre-releases by looking to
|
||||||
|
# see if any of the underlying items supports them. If none of them do
|
||||||
|
# and this item is a pre-release then we do not allow it and we can
|
||||||
|
# short circuit that here.
|
||||||
|
# Note: This means that 1.0.dev1 would not be contained in something
|
||||||
|
# like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
|
||||||
|
if (not (self.prereleases or prereleases)) and item.is_prerelease:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Determine if we're forcing a prerelease or not, we bypass
|
||||||
|
# self.prereleases here and use self._prereleases because we want to
|
||||||
|
# only take into consideration actual *forced* values. The underlying
|
||||||
|
# specifiers will handle the other logic.
|
||||||
|
# The logic here is: If prereleases is anything but None, we'll just
|
||||||
|
# go aheand and continue to use that. However if
|
||||||
|
# prereleases is None, then we'll use whatever the
|
||||||
|
# value of self._prereleases is as long as it is not
|
||||||
|
# None itself.
|
||||||
|
if prereleases is None and self._prereleases is not None:
|
||||||
|
prereleases = self._prereleases
|
||||||
|
|
||||||
|
# We simply dispatch to the underlying specs here to make sure that the
|
||||||
|
# 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
|
||||||
|
)
|
||||||
|
|
||||||
|
def filter(self, iterable, prereleases=None):
|
||||||
|
# Determine if we're forcing a prerelease or not, we bypass
|
||||||
|
# self.prereleases here and use self._prereleases because we want to
|
||||||
|
# only take into consideration actual *forced* values. The underlying
|
||||||
|
# specifiers will handle the other logic.
|
||||||
|
# The logic here is: If prereleases is anything but None, we'll just
|
||||||
|
# go aheand and continue to use that. However if
|
||||||
|
# prereleases is None, then we'll use whatever the
|
||||||
|
# value of self._prereleases is as long as it is not
|
||||||
|
# None itself.
|
||||||
|
if prereleases is None and self._prereleases is not None:
|
||||||
|
prereleases = self._prereleases
|
||||||
|
|
||||||
|
# If we have any specifiers, then we want to wrap our iterable in the
|
||||||
|
# filter method for each one, this will act as a logical AND amongst
|
||||||
|
# each specifier.
|
||||||
|
if self._specs:
|
||||||
|
for spec in self._specs:
|
||||||
|
iterable = spec.filter(iterable, prereleases=prereleases)
|
||||||
|
return iterable
|
||||||
|
# If we do not have any specifiers, then we need to have a rough filter
|
||||||
|
# which will filter out any pre-releases, unless there are no final
|
||||||
|
# releases, and which will filter out LegacyVersion in general.
|
||||||
|
else:
|
||||||
|
filtered = []
|
||||||
|
found_prereleases = []
|
||||||
|
|
||||||
|
for item in iterable:
|
||||||
|
# Ensure that we some kind of Version class for this item.
|
||||||
|
if not isinstance(item, (LegacyVersion, Version)):
|
||||||
|
parsed_version = parse(item)
|
||||||
|
else:
|
||||||
|
parsed_version = item
|
||||||
|
|
||||||
|
# Filter out any item which is parsed as a LegacyVersion
|
||||||
|
if isinstance(parsed_version, LegacyVersion):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Store any item which is a pre-release for later unless we've
|
||||||
|
# already found a final version or we are accepting prereleases
|
||||||
|
if parsed_version.is_prerelease and not prereleases:
|
||||||
|
if not filtered:
|
||||||
|
found_prereleases.append(item)
|
||||||
|
else:
|
||||||
|
filtered.append(item)
|
||||||
|
|
||||||
|
# If we've found no items except for pre-releases, then we'll go
|
||||||
|
# ahead and use the pre-releases
|
||||||
|
if not filtered and found_prereleases and prereleases is None:
|
||||||
|
return found_prereleases
|
||||||
|
|
||||||
|
return filtered
|
||||||
401
awx/lib/site-packages/pkg_resources/_vendor/packaging/version.py
Normal file
401
awx/lib/site-packages/pkg_resources/_vendor/packaging/version.py
Normal file
@@ -0,0 +1,401 @@
|
|||||||
|
# Copyright 2014 Donald Stufft
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import itertools
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ._structures import Infinity
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
_Version = collections.namedtuple(
|
||||||
|
"_Version",
|
||||||
|
["epoch", "release", "dev", "pre", "post", "local"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse(version):
|
||||||
|
"""
|
||||||
|
Parse the given version string and return either a :class:`Version` object
|
||||||
|
or a :class:`LegacyVersion` object depending on if the given version is
|
||||||
|
a valid PEP 440 version or a legacy version.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return Version(version)
|
||||||
|
except InvalidVersion:
|
||||||
|
return LegacyVersion(version)
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidVersion(ValueError):
|
||||||
|
"""
|
||||||
|
An invalid version was found, users should refer to PEP 440.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class _BaseVersion(object):
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self._key)
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self._compare(other, lambda s, o: s < o)
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
return self._compare(other, lambda s, o: s <= o)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self._compare(other, lambda s, o: s == o)
|
||||||
|
|
||||||
|
def __ge__(self, other):
|
||||||
|
return self._compare(other, lambda s, o: s >= o)
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self._compare(other, lambda s, o: s > o)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return self._compare(other, lambda s, o: s != o)
|
||||||
|
|
||||||
|
def _compare(self, other, method):
|
||||||
|
if not isinstance(other, _BaseVersion):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return method(self._key, other._key)
|
||||||
|
|
||||||
|
|
||||||
|
class LegacyVersion(_BaseVersion):
|
||||||
|
|
||||||
|
def __init__(self, version):
|
||||||
|
self._version = str(version)
|
||||||
|
self._key = _legacy_cmpkey(self._version)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self._version
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<LegacyVersion({0})>".format(repr(str(self)))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def public(self):
|
||||||
|
return self._version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def base_version(self):
|
||||||
|
return self._version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def local(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_prerelease(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_postrelease(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
_legacy_version_component_re = re.compile(
|
||||||
|
r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
|
||||||
|
)
|
||||||
|
|
||||||
|
_legacy_version_replacement_map = {
|
||||||
|
"pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_version_parts(s):
|
||||||
|
for part in _legacy_version_component_re.split(s):
|
||||||
|
part = _legacy_version_replacement_map.get(part, part)
|
||||||
|
|
||||||
|
if not part or part == ".":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if part[:1] in "0123456789":
|
||||||
|
# pad for numeric comparison
|
||||||
|
yield part.zfill(8)
|
||||||
|
else:
|
||||||
|
yield "*" + part
|
||||||
|
|
||||||
|
# ensure that alpha/beta/candidate are before final
|
||||||
|
yield "*final"
|
||||||
|
|
||||||
|
|
||||||
|
def _legacy_cmpkey(version):
|
||||||
|
# We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
|
||||||
|
# greater than or equal to 0. This will effectively put the LegacyVersion,
|
||||||
|
# which uses the defacto standard originally implemented by setuptools,
|
||||||
|
# as before all PEP 440 versions.
|
||||||
|
epoch = -1
|
||||||
|
|
||||||
|
# This scheme is taken from pkg_resources.parse_version setuptools prior to
|
||||||
|
# it's adoption of the packaging library.
|
||||||
|
parts = []
|
||||||
|
for part in _parse_version_parts(version.lower()):
|
||||||
|
if part.startswith("*"):
|
||||||
|
# remove "-" before a prerelease tag
|
||||||
|
if part < "*final":
|
||||||
|
while parts and parts[-1] == "*final-":
|
||||||
|
parts.pop()
|
||||||
|
|
||||||
|
# remove trailing zeros from each series of numeric parts
|
||||||
|
while parts and parts[-1] == "00000000":
|
||||||
|
parts.pop()
|
||||||
|
|
||||||
|
parts.append(part)
|
||||||
|
parts = tuple(parts)
|
||||||
|
|
||||||
|
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"""
|
||||||
|
v?
|
||||||
|
(?:
|
||||||
|
(?:(?P<epoch>[0-9]+)!)? # epoch
|
||||||
|
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
|
||||||
|
(?P<pre> # pre-release
|
||||||
|
[-_\.]?
|
||||||
|
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
|
||||||
|
[-_\.]?
|
||||||
|
(?P<pre_n>[0-9]+)?
|
||||||
|
)?
|
||||||
|
(?P<post> # post release
|
||||||
|
(?:-(?P<post_n1>[0-9]+))
|
||||||
|
|
|
||||||
|
(?:
|
||||||
|
[-_\.]?
|
||||||
|
(?P<post_l>post|rev|r)
|
||||||
|
[-_\.]?
|
||||||
|
(?P<post_n2>[0-9]+)?
|
||||||
|
)
|
||||||
|
)?
|
||||||
|
(?P<dev> # dev release
|
||||||
|
[-_\.]?
|
||||||
|
(?P<dev_l>dev)
|
||||||
|
[-_\.]?
|
||||||
|
(?P<dev_n>[0-9]+)?
|
||||||
|
)?
|
||||||
|
)
|
||||||
|
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class Version(_BaseVersion):
|
||||||
|
|
||||||
|
_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
|
||||||
|
match = self._regex.search(version)
|
||||||
|
if not match:
|
||||||
|
raise InvalidVersion("Invalid version: '{0}'".format(version))
|
||||||
|
|
||||||
|
# Store the parsed out pieces of the version
|
||||||
|
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"),
|
||||||
|
),
|
||||||
|
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"),
|
||||||
|
),
|
||||||
|
local=_parse_local_version(match.group("local")),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate a key which will be used for sorting
|
||||||
|
self._key = _cmpkey(
|
||||||
|
self._version.epoch,
|
||||||
|
self._version.release,
|
||||||
|
self._version.pre,
|
||||||
|
self._version.post,
|
||||||
|
self._version.dev,
|
||||||
|
self._version.local,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Version({0})>".format(repr(str(self)))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
parts = []
|
||||||
|
|
||||||
|
# Epoch
|
||||||
|
if self._version.epoch != 0:
|
||||||
|
parts.append("{0}!".format(self._version.epoch))
|
||||||
|
|
||||||
|
# Release segment
|
||||||
|
parts.append(".".join(str(x) for x in self._version.release))
|
||||||
|
|
||||||
|
# Pre-release
|
||||||
|
if self._version.pre is not None:
|
||||||
|
parts.append("".join(str(x) for x in self._version.pre))
|
||||||
|
|
||||||
|
# Post-release
|
||||||
|
if self._version.post is not None:
|
||||||
|
parts.append(".post{0}".format(self._version.post[1]))
|
||||||
|
|
||||||
|
# Development release
|
||||||
|
if self._version.dev is not None:
|
||||||
|
parts.append(".dev{0}".format(self._version.dev[1]))
|
||||||
|
|
||||||
|
# Local version segment
|
||||||
|
if self._version.local is not None:
|
||||||
|
parts.append(
|
||||||
|
"+{0}".format(".".join(str(x) for x in self._version.local))
|
||||||
|
)
|
||||||
|
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def public(self):
|
||||||
|
return str(self).split("+", 1)[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def base_version(self):
|
||||||
|
parts = []
|
||||||
|
|
||||||
|
# Epoch
|
||||||
|
if self._version.epoch != 0:
|
||||||
|
parts.append("{0}!".format(self._version.epoch))
|
||||||
|
|
||||||
|
# Release segment
|
||||||
|
parts.append(".".join(str(x) for x in self._version.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)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_postrelease(self):
|
||||||
|
return bool(self._version.post)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_letter_version(letter, number):
|
||||||
|
if letter:
|
||||||
|
# We consider there to be an implicit 0 in a pre-release if there is
|
||||||
|
# not a numeral associated with it.
|
||||||
|
if number is None:
|
||||||
|
number = 0
|
||||||
|
|
||||||
|
# We normalize any letters to their lower case form
|
||||||
|
letter = letter.lower()
|
||||||
|
|
||||||
|
# We consider some words to be alternate spellings of other words and
|
||||||
|
# in those cases we want to normalize the spellings to our preferred
|
||||||
|
# spelling.
|
||||||
|
if letter == "alpha":
|
||||||
|
letter = "a"
|
||||||
|
elif letter == "beta":
|
||||||
|
letter = "b"
|
||||||
|
elif letter in ["c", "pre", "preview"]:
|
||||||
|
letter = "rc"
|
||||||
|
|
||||||
|
return letter, int(number)
|
||||||
|
if not letter and number:
|
||||||
|
# We assume if we are given a number, but we are not given a letter
|
||||||
|
# then this is using the implicit post release syntax (e.g. 1.0-1)
|
||||||
|
letter = "post"
|
||||||
|
|
||||||
|
return letter, int(number)
|
||||||
|
|
||||||
|
|
||||||
|
_local_version_seperators = re.compile(r"[\._-]")
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_local_version(local):
|
||||||
|
"""
|
||||||
|
Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
|
||||||
|
"""
|
||||||
|
if local is not None:
|
||||||
|
return tuple(
|
||||||
|
part.lower() if not part.isdigit() else int(part)
|
||||||
|
for part in _local_version_seperators.split(local)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _cmpkey(epoch, release, pre, post, dev, local):
|
||||||
|
# When we compare a release version, we want to compare it with all of the
|
||||||
|
# trailing zeros removed. So we'll use a reverse the list, drop all the now
|
||||||
|
# leading zeros until we come to something non zero, then take the rest
|
||||||
|
# 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),
|
||||||
|
)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
|
||||||
|
# We'll do this by abusing the pre segment, but we _only_ want to do this
|
||||||
|
# if there is not a pre or a post segment. If we have one of those then
|
||||||
|
# the normal sorting rules will handle this case correctly.
|
||||||
|
if pre is None and post is None and dev is not None:
|
||||||
|
pre = -Infinity
|
||||||
|
# Versions without a pre-release (except as noted above) should sort after
|
||||||
|
# those with one.
|
||||||
|
elif pre is None:
|
||||||
|
pre = Infinity
|
||||||
|
|
||||||
|
# Versions without a post segment should sort before those with one.
|
||||||
|
if post is None:
|
||||||
|
post = -Infinity
|
||||||
|
|
||||||
|
# Versions without a development segment should sort after those with one.
|
||||||
|
if dev is None:
|
||||||
|
dev = Infinity
|
||||||
|
|
||||||
|
if local is None:
|
||||||
|
# Versions without a local segment should sort before those with one.
|
||||||
|
local = -Infinity
|
||||||
|
else:
|
||||||
|
# Versions with a local segment need that segment parsed to implement
|
||||||
|
# the sorting rules in PEP440.
|
||||||
|
# - Alpha numeric segments sort before numeric segments
|
||||||
|
# - Alpha numeric segments sort lexicographically
|
||||||
|
# - 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
|
||||||
|
)
|
||||||
|
|
||||||
|
return epoch, release, pre, post, dev, local
|
||||||
1
awx/lib/site-packages/pkg_resources/_vendor/vendored.txt
Normal file
1
awx/lib/site-packages/pkg_resources/_vendor/vendored.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
packaging==15.0
|
||||||
419
awx/lib/site-packages/pkg_resources/api_tests.txt
Normal file
419
awx/lib/site-packages/pkg_resources/api_tests.txt
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
Pluggable Distributions of Python Software
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Distributions
|
||||||
|
-------------
|
||||||
|
|
||||||
|
A "Distribution" is a collection of files that represent a "Release" of a
|
||||||
|
"Project" as of a particular point in time, denoted by a
|
||||||
|
"Version"::
|
||||||
|
|
||||||
|
>>> import sys, pkg_resources
|
||||||
|
>>> from pkg_resources import Distribution
|
||||||
|
>>> Distribution(project_name="Foo", version="1.2")
|
||||||
|
Foo 1.2
|
||||||
|
|
||||||
|
Distributions have a location, which can be a filename, URL, or really anything
|
||||||
|
else you care to use::
|
||||||
|
|
||||||
|
>>> dist = Distribution(
|
||||||
|
... location="http://example.com/something",
|
||||||
|
... project_name="Bar", version="0.9"
|
||||||
|
... )
|
||||||
|
|
||||||
|
>>> dist
|
||||||
|
Bar 0.9 (http://example.com/something)
|
||||||
|
|
||||||
|
|
||||||
|
Distributions have various introspectable attributes::
|
||||||
|
|
||||||
|
>>> dist.location
|
||||||
|
'http://example.com/something'
|
||||||
|
|
||||||
|
>>> dist.project_name
|
||||||
|
'Bar'
|
||||||
|
|
||||||
|
>>> dist.version
|
||||||
|
'0.9'
|
||||||
|
|
||||||
|
>>> dist.py_version == sys.version[:3]
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> print(dist.platform)
|
||||||
|
None
|
||||||
|
|
||||||
|
Including various computed attributes::
|
||||||
|
|
||||||
|
>>> from pkg_resources import parse_version
|
||||||
|
>>> dist.parsed_version == parse_version(dist.version)
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> dist.key # case-insensitive form of the project name
|
||||||
|
'bar'
|
||||||
|
|
||||||
|
Distributions are compared (and hashed) by version first::
|
||||||
|
|
||||||
|
>>> Distribution(version='1.0') == Distribution(version='1.0')
|
||||||
|
True
|
||||||
|
>>> Distribution(version='1.0') == Distribution(version='1.1')
|
||||||
|
False
|
||||||
|
>>> Distribution(version='1.0') < Distribution(version='1.1')
|
||||||
|
True
|
||||||
|
|
||||||
|
but also by project name (case-insensitive), platform, Python version,
|
||||||
|
location, etc.::
|
||||||
|
|
||||||
|
>>> Distribution(project_name="Foo",version="1.0") == \
|
||||||
|
... Distribution(project_name="Foo",version="1.0")
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> Distribution(project_name="Foo",version="1.0") == \
|
||||||
|
... Distribution(project_name="foo",version="1.0")
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> Distribution(project_name="Foo",version="1.0") == \
|
||||||
|
... Distribution(project_name="Foo",version="1.1")
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> Distribution(project_name="Foo",py_version="2.3",version="1.0") == \
|
||||||
|
... Distribution(project_name="Foo",py_version="2.4",version="1.0")
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> Distribution(location="spam",version="1.0") == \
|
||||||
|
... Distribution(location="spam",version="1.0")
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> Distribution(location="spam",version="1.0") == \
|
||||||
|
... Distribution(location="baz",version="1.0")
|
||||||
|
False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Hash and compare distribution by prio/plat
|
||||||
|
|
||||||
|
Get version from metadata
|
||||||
|
provider capabilities
|
||||||
|
egg_name()
|
||||||
|
as_requirement()
|
||||||
|
from_location, from_filename (w/path normalization)
|
||||||
|
|
||||||
|
Releases may have zero or more "Requirements", which indicate
|
||||||
|
what releases of another project the release requires in order to
|
||||||
|
function. A Requirement names the other project, expresses some criteria
|
||||||
|
as to what releases of that project are acceptable, and lists any "Extras"
|
||||||
|
that the requiring release may need from that project. (An Extra is an
|
||||||
|
optional feature of a Release, that can only be used if its additional
|
||||||
|
Requirements are satisfied.)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The Working Set
|
||||||
|
---------------
|
||||||
|
|
||||||
|
A collection of active distributions is called a Working Set. Note that a
|
||||||
|
Working Set can contain any importable distribution, not just pluggable ones.
|
||||||
|
For example, the Python standard library is an importable distribution that
|
||||||
|
will usually be part of the Working Set, even though it is not pluggable.
|
||||||
|
Similarly, when you are doing development work on a project, the files you are
|
||||||
|
editing are also a Distribution. (And, with a little attention to the
|
||||||
|
directory names used, and including some additional metadata, such a
|
||||||
|
"development distribution" can be made pluggable as well.)
|
||||||
|
|
||||||
|
>>> from pkg_resources import WorkingSet
|
||||||
|
|
||||||
|
A working set's entries are the sys.path entries that correspond to the active
|
||||||
|
distributions. By default, the working set's entries are the items on
|
||||||
|
``sys.path``::
|
||||||
|
|
||||||
|
>>> ws = WorkingSet()
|
||||||
|
>>> ws.entries == sys.path
|
||||||
|
True
|
||||||
|
|
||||||
|
But you can also create an empty working set explicitly, and add distributions
|
||||||
|
to it::
|
||||||
|
|
||||||
|
>>> ws = WorkingSet([])
|
||||||
|
>>> ws.add(dist)
|
||||||
|
>>> ws.entries
|
||||||
|
['http://example.com/something']
|
||||||
|
>>> dist in ws
|
||||||
|
True
|
||||||
|
>>> Distribution('foo',version="") in ws
|
||||||
|
False
|
||||||
|
|
||||||
|
And you can iterate over its distributions::
|
||||||
|
|
||||||
|
>>> list(ws)
|
||||||
|
[Bar 0.9 (http://example.com/something)]
|
||||||
|
|
||||||
|
Adding the same distribution more than once is a no-op::
|
||||||
|
|
||||||
|
>>> ws.add(dist)
|
||||||
|
>>> list(ws)
|
||||||
|
[Bar 0.9 (http://example.com/something)]
|
||||||
|
|
||||||
|
For that matter, adding multiple distributions for the same project also does
|
||||||
|
nothing, because a working set can only hold one active distribution per
|
||||||
|
project -- the first one added to it::
|
||||||
|
|
||||||
|
>>> ws.add(
|
||||||
|
... Distribution(
|
||||||
|
... 'http://example.com/something', project_name="Bar",
|
||||||
|
... version="7.2"
|
||||||
|
... )
|
||||||
|
... )
|
||||||
|
>>> list(ws)
|
||||||
|
[Bar 0.9 (http://example.com/something)]
|
||||||
|
|
||||||
|
You can append a path entry to a working set using ``add_entry()``::
|
||||||
|
|
||||||
|
>>> ws.entries
|
||||||
|
['http://example.com/something']
|
||||||
|
>>> ws.add_entry(pkg_resources.__file__)
|
||||||
|
>>> ws.entries
|
||||||
|
['http://example.com/something', '...pkg_resources...']
|
||||||
|
|
||||||
|
Multiple additions result in multiple entries, even if the entry is already in
|
||||||
|
the working set (because ``sys.path`` can contain the same entry more than
|
||||||
|
once)::
|
||||||
|
|
||||||
|
>>> ws.add_entry(pkg_resources.__file__)
|
||||||
|
>>> ws.entries
|
||||||
|
['...example.com...', '...pkg_resources...', '...pkg_resources...']
|
||||||
|
|
||||||
|
And you can specify the path entry a distribution was found under, using the
|
||||||
|
optional second parameter to ``add()``::
|
||||||
|
|
||||||
|
>>> ws = WorkingSet([])
|
||||||
|
>>> ws.add(dist,"foo")
|
||||||
|
>>> ws.entries
|
||||||
|
['foo']
|
||||||
|
|
||||||
|
But even if a distribution is found under multiple path entries, it still only
|
||||||
|
shows up once when iterating the working set:
|
||||||
|
|
||||||
|
>>> ws.add_entry(ws.entries[0])
|
||||||
|
>>> list(ws)
|
||||||
|
[Bar 0.9 (http://example.com/something)]
|
||||||
|
|
||||||
|
You can ask a WorkingSet to ``find()`` a distribution matching a requirement::
|
||||||
|
|
||||||
|
>>> from pkg_resources import Requirement
|
||||||
|
>>> print(ws.find(Requirement.parse("Foo==1.0"))) # no match, return None
|
||||||
|
None
|
||||||
|
|
||||||
|
>>> ws.find(Requirement.parse("Bar==0.9")) # match, return distribution
|
||||||
|
Bar 0.9 (http://example.com/something)
|
||||||
|
|
||||||
|
Note that asking for a conflicting version of a distribution already in a
|
||||||
|
working set triggers a ``pkg_resources.VersionConflict`` error:
|
||||||
|
|
||||||
|
>>> try:
|
||||||
|
... ws.find(Requirement.parse("Bar==1.0"))
|
||||||
|
... except pkg_resources.VersionConflict as exc:
|
||||||
|
... print(str(exc))
|
||||||
|
... else:
|
||||||
|
... raise AssertionError("VersionConflict was not raised")
|
||||||
|
(Bar 0.9 (http://example.com/something), Requirement.parse('Bar==1.0'))
|
||||||
|
|
||||||
|
You can subscribe a callback function to receive notifications whenever a new
|
||||||
|
distribution is added to a working set. The callback is immediately invoked
|
||||||
|
once for each existing distribution in the working set, and then is called
|
||||||
|
again for new distributions added thereafter::
|
||||||
|
|
||||||
|
>>> def added(dist): print("Added %s" % dist)
|
||||||
|
>>> ws.subscribe(added)
|
||||||
|
Added Bar 0.9
|
||||||
|
>>> foo12 = Distribution(project_name="Foo", version="1.2", location="f12")
|
||||||
|
>>> ws.add(foo12)
|
||||||
|
Added Foo 1.2
|
||||||
|
|
||||||
|
Note, however, that only the first distribution added for a given project name
|
||||||
|
will trigger a callback, even during the initial ``subscribe()`` callback::
|
||||||
|
|
||||||
|
>>> foo14 = Distribution(project_name="Foo", version="1.4", location="f14")
|
||||||
|
>>> ws.add(foo14) # no callback, because Foo 1.2 is already active
|
||||||
|
|
||||||
|
>>> ws = WorkingSet([])
|
||||||
|
>>> ws.add(foo12)
|
||||||
|
>>> ws.add(foo14)
|
||||||
|
>>> ws.subscribe(added)
|
||||||
|
Added Foo 1.2
|
||||||
|
|
||||||
|
And adding a callback more than once has no effect, either::
|
||||||
|
|
||||||
|
>>> ws.subscribe(added) # no callbacks
|
||||||
|
|
||||||
|
# and no double-callbacks on subsequent additions, either
|
||||||
|
>>> just_a_test = Distribution(project_name="JustATest", version="0.99")
|
||||||
|
>>> ws.add(just_a_test)
|
||||||
|
Added JustATest 0.99
|
||||||
|
|
||||||
|
|
||||||
|
Finding Plugins
|
||||||
|
---------------
|
||||||
|
|
||||||
|
``WorkingSet`` objects can be used to figure out what plugins in an
|
||||||
|
``Environment`` can be loaded without any resolution errors::
|
||||||
|
|
||||||
|
>>> from pkg_resources import Environment
|
||||||
|
|
||||||
|
>>> plugins = Environment([]) # normally, a list of plugin directories
|
||||||
|
>>> plugins.add(foo12)
|
||||||
|
>>> plugins.add(foo14)
|
||||||
|
>>> plugins.add(just_a_test)
|
||||||
|
|
||||||
|
In the simplest case, we just get the newest version of each distribution in
|
||||||
|
the plugin environment::
|
||||||
|
|
||||||
|
>>> ws = WorkingSet([])
|
||||||
|
>>> ws.find_plugins(plugins)
|
||||||
|
([JustATest 0.99, Foo 1.4 (f14)], {})
|
||||||
|
|
||||||
|
But if there's a problem with a version conflict or missing requirements, the
|
||||||
|
method falls back to older versions, and the error info dict will contain an
|
||||||
|
exception instance for each unloadable plugin::
|
||||||
|
|
||||||
|
>>> ws.add(foo12) # this will conflict with Foo 1.4
|
||||||
|
>>> ws.find_plugins(plugins)
|
||||||
|
([JustATest 0.99, Foo 1.2 (f12)], {Foo 1.4 (f14): VersionConflict(...)})
|
||||||
|
|
||||||
|
But if you disallow fallbacks, the failed plugin will be skipped instead of
|
||||||
|
trying older versions::
|
||||||
|
|
||||||
|
>>> ws.find_plugins(plugins, fallback=False)
|
||||||
|
([JustATest 0.99], {Foo 1.4 (f14): VersionConflict(...)})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Platform Compatibility Rules
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
On the Mac, there are potential compatibility issues for modules compiled
|
||||||
|
on newer versions of Mac OS X than what the user is running. Additionally,
|
||||||
|
Mac OS X will soon have two platforms to contend with: Intel and PowerPC.
|
||||||
|
|
||||||
|
Basic equality works as on other platforms::
|
||||||
|
|
||||||
|
>>> from pkg_resources import compatible_platforms as cp
|
||||||
|
>>> reqd = 'macosx-10.4-ppc'
|
||||||
|
>>> cp(reqd, reqd)
|
||||||
|
True
|
||||||
|
>>> cp("win32", reqd)
|
||||||
|
False
|
||||||
|
|
||||||
|
Distributions made on other machine types are not compatible::
|
||||||
|
|
||||||
|
>>> cp("macosx-10.4-i386", reqd)
|
||||||
|
False
|
||||||
|
|
||||||
|
Distributions made on earlier versions of the OS are compatible, as
|
||||||
|
long as they are from the same top-level version. The patchlevel version
|
||||||
|
number does not matter::
|
||||||
|
|
||||||
|
>>> cp("macosx-10.4-ppc", reqd)
|
||||||
|
True
|
||||||
|
>>> cp("macosx-10.3-ppc", reqd)
|
||||||
|
True
|
||||||
|
>>> cp("macosx-10.5-ppc", reqd)
|
||||||
|
False
|
||||||
|
>>> cp("macosx-9.5-ppc", reqd)
|
||||||
|
False
|
||||||
|
|
||||||
|
Backwards compatibility for packages made via earlier versions of
|
||||||
|
setuptools is provided as well::
|
||||||
|
|
||||||
|
>>> cp("darwin-8.2.0-Power_Macintosh", reqd)
|
||||||
|
True
|
||||||
|
>>> cp("darwin-7.2.0-Power_Macintosh", reqd)
|
||||||
|
True
|
||||||
|
>>> cp("darwin-8.2.0-Power_Macintosh", "macosx-10.3-ppc")
|
||||||
|
False
|
||||||
|
|
||||||
|
|
||||||
|
Environment Markers
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
>>> from pkg_resources import invalid_marker as im, evaluate_marker as em
|
||||||
|
>>> import os
|
||||||
|
|
||||||
|
>>> print(im("sys_platform"))
|
||||||
|
Comparison or logical expression expected
|
||||||
|
|
||||||
|
>>> print(im("sys_platform=="))
|
||||||
|
invalid syntax
|
||||||
|
|
||||||
|
>>> print(im("sys_platform=='win32'"))
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> print(im("sys=='x'"))
|
||||||
|
Unknown name 'sys'
|
||||||
|
|
||||||
|
>>> print(im("(extra)"))
|
||||||
|
Comparison or logical expression expected
|
||||||
|
|
||||||
|
>>> print(im("(extra"))
|
||||||
|
invalid syntax
|
||||||
|
|
||||||
|
>>> print(im("os.open('foo')=='y'"))
|
||||||
|
Language feature not supported in environment markers
|
||||||
|
|
||||||
|
>>> print(im("'x'=='y' and os.open('foo')=='y'")) # no short-circuit!
|
||||||
|
Language feature not supported in environment markers
|
||||||
|
|
||||||
|
>>> print(im("'x'=='x' or os.open('foo')=='y'")) # no short-circuit!
|
||||||
|
Language feature not supported in environment markers
|
||||||
|
|
||||||
|
>>> print(im("'x' < 'y'"))
|
||||||
|
'<' operator not allowed in environment markers
|
||||||
|
|
||||||
|
>>> print(im("'x' < 'y' < 'z'"))
|
||||||
|
Chained comparison not allowed in environment markers
|
||||||
|
|
||||||
|
>>> print(im("r'x'=='x'"))
|
||||||
|
Only plain strings allowed in environment markers
|
||||||
|
|
||||||
|
>>> print(im("'''x'''=='x'"))
|
||||||
|
Only plain strings allowed in environment markers
|
||||||
|
|
||||||
|
>>> print(im('"""x"""=="x"'))
|
||||||
|
Only plain strings allowed in environment markers
|
||||||
|
|
||||||
|
>>> print(im(r"'x\n'=='x'"))
|
||||||
|
Only plain strings allowed in environment markers
|
||||||
|
|
||||||
|
>>> print(im("os.open=='y'"))
|
||||||
|
Language feature not supported in environment markers
|
||||||
|
|
||||||
|
>>> em('"x"=="x"')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> em('"x"=="y"')
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> em('"x"=="y" and "x"=="x"')
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> em('"x"=="y" or "x"=="x"')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> em('"x"=="y" and "x"=="q" or "z"=="z"')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> em('"x"=="y" and ("x"=="q" or "z"=="z")')
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> em('"x"=="y" and "z"=="z" or "x"=="q"')
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> em('"x"=="x" and "z"=="z" or "x"=="q"')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> em("sys_platform=='win32'") == (sys.platform=='win32')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> em("'x' in 'yx'")
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> em("'yx' in 'x'")
|
||||||
|
False
|
||||||
111
awx/lib/site-packages/pkg_resources/tests/test_pkg_resources.py
Normal file
111
awx/lib/site-packages/pkg_resources/tests/test_pkg_resources.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
import zipfile
|
||||||
|
import datetime
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
|
try:
|
||||||
|
unicode
|
||||||
|
except NameError:
|
||||||
|
unicode = str
|
||||||
|
|
||||||
|
def timestamp(dt):
|
||||||
|
"""
|
||||||
|
Return a timestamp for a local, naive datetime instance.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return dt.timestamp()
|
||||||
|
except AttributeError:
|
||||||
|
# Python 3.2 and earlier
|
||||||
|
return time.mktime(dt.timetuple())
|
||||||
|
|
||||||
|
class EggRemover(unicode):
|
||||||
|
def __call__(self):
|
||||||
|
if self in sys.path:
|
||||||
|
sys.path.remove(self)
|
||||||
|
if os.path.exists(self):
|
||||||
|
os.remove(self)
|
||||||
|
|
||||||
|
class TestZipProvider(object):
|
||||||
|
finalizers = []
|
||||||
|
|
||||||
|
ref_time = datetime.datetime(2013, 5, 12, 13, 25, 0)
|
||||||
|
"A reference time for a file modification"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"create a zip egg and add it to sys.path"
|
||||||
|
egg = tempfile.NamedTemporaryFile(suffix='.egg', delete=False)
|
||||||
|
zip_egg = zipfile.ZipFile(egg, 'w')
|
||||||
|
zip_info = zipfile.ZipInfo()
|
||||||
|
zip_info.filename = 'mod.py'
|
||||||
|
zip_info.date_time = cls.ref_time.timetuple()
|
||||||
|
zip_egg.writestr(zip_info, 'x = 3\n')
|
||||||
|
zip_info = zipfile.ZipInfo()
|
||||||
|
zip_info.filename = 'data.dat'
|
||||||
|
zip_info.date_time = cls.ref_time.timetuple()
|
||||||
|
zip_egg.writestr(zip_info, 'hello, world!')
|
||||||
|
zip_egg.close()
|
||||||
|
egg.close()
|
||||||
|
|
||||||
|
sys.path.append(egg.name)
|
||||||
|
cls.finalizers.append(EggRemover(egg.name))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def teardown_class(cls):
|
||||||
|
for finalizer in cls.finalizers:
|
||||||
|
finalizer()
|
||||||
|
|
||||||
|
def test_resource_filename_rewrites_on_change(self):
|
||||||
|
"""
|
||||||
|
If a previous call to get_resource_filename has saved the file, but
|
||||||
|
the file has been subsequently mutated with different file of the
|
||||||
|
same size and modification time, it should not be overwritten on a
|
||||||
|
subsequent call to get_resource_filename.
|
||||||
|
"""
|
||||||
|
import mod
|
||||||
|
manager = pkg_resources.ResourceManager()
|
||||||
|
zp = pkg_resources.ZipProvider(mod)
|
||||||
|
filename = zp.get_resource_filename(manager, 'data.dat')
|
||||||
|
actual = datetime.datetime.fromtimestamp(os.stat(filename).st_mtime)
|
||||||
|
assert actual == self.ref_time
|
||||||
|
f = open(filename, 'w')
|
||||||
|
f.write('hello, world?')
|
||||||
|
f.close()
|
||||||
|
ts = timestamp(self.ref_time)
|
||||||
|
os.utime(filename, (ts, ts))
|
||||||
|
filename = zp.get_resource_filename(manager, 'data.dat')
|
||||||
|
f = open(filename)
|
||||||
|
assert f.read() == 'hello, world!'
|
||||||
|
manager.cleanup_resources()
|
||||||
|
|
||||||
|
class TestResourceManager(object):
|
||||||
|
def test_get_cache_path(self):
|
||||||
|
mgr = pkg_resources.ResourceManager()
|
||||||
|
path = mgr.get_cache_path('foo')
|
||||||
|
type_ = str(type(path))
|
||||||
|
message = "Unexpected type from get_cache_path: " + type_
|
||||||
|
assert isinstance(path, (unicode, str)), message
|
||||||
|
|
||||||
|
|
||||||
|
class TestIndependence:
|
||||||
|
"""
|
||||||
|
Tests to ensure that pkg_resources runs independently from setuptools.
|
||||||
|
"""
|
||||||
|
def test_setuptools_not_imported(self):
|
||||||
|
"""
|
||||||
|
In a separate Python environment, import pkg_resources and assert
|
||||||
|
that action doesn't cause setuptools to be imported.
|
||||||
|
"""
|
||||||
|
lines = (
|
||||||
|
'import pkg_resources',
|
||||||
|
'import sys',
|
||||||
|
'assert "setuptools" not in sys.modules, '
|
||||||
|
'"setuptools was imported"',
|
||||||
|
)
|
||||||
|
cmd = [sys.executable, '-c', '; '.join(lines)]
|
||||||
|
subprocess.check_call(cmd)
|
||||||
661
awx/lib/site-packages/pkg_resources/tests/test_resources.py
Normal file
661
awx/lib/site-packages/pkg_resources/tests/test_resources.py
Normal file
@@ -0,0 +1,661 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import string
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import pkg_resources
|
||||||
|
from pkg_resources import (parse_requirements, VersionConflict, parse_version,
|
||||||
|
Distribution, EntryPoint, Requirement, safe_version, safe_name,
|
||||||
|
WorkingSet)
|
||||||
|
|
||||||
|
packaging = pkg_resources.packaging
|
||||||
|
|
||||||
|
|
||||||
|
def safe_repr(obj, short=False):
|
||||||
|
""" copied from Python2.7"""
|
||||||
|
try:
|
||||||
|
result = repr(obj)
|
||||||
|
except Exception:
|
||||||
|
result = object.__repr__(obj)
|
||||||
|
if not short or len(result) < pkg_resources._MAX_LENGTH:
|
||||||
|
return result
|
||||||
|
return result[:pkg_resources._MAX_LENGTH] + ' [truncated]...'
|
||||||
|
|
||||||
|
|
||||||
|
class Metadata(pkg_resources.EmptyProvider):
|
||||||
|
"""Mock object to return metadata as if from an on-disk distribution"""
|
||||||
|
|
||||||
|
def __init__(self, *pairs):
|
||||||
|
self.metadata = dict(pairs)
|
||||||
|
|
||||||
|
def has_metadata(self, name):
|
||||||
|
return name in self.metadata
|
||||||
|
|
||||||
|
def get_metadata(self, name):
|
||||||
|
return self.metadata[name]
|
||||||
|
|
||||||
|
def get_metadata_lines(self, name):
|
||||||
|
return pkg_resources.yield_lines(self.get_metadata(name))
|
||||||
|
|
||||||
|
|
||||||
|
dist_from_fn = pkg_resources.Distribution.from_filename
|
||||||
|
|
||||||
|
class TestDistro:
|
||||||
|
|
||||||
|
def testCollection(self):
|
||||||
|
# empty path should produce no distributions
|
||||||
|
ad = pkg_resources.Environment([], platform=None, python=None)
|
||||||
|
assert list(ad) == []
|
||||||
|
assert ad['FooPkg'] == []
|
||||||
|
ad.add(dist_from_fn("FooPkg-1.3_1.egg"))
|
||||||
|
ad.add(dist_from_fn("FooPkg-1.4-py2.4-win32.egg"))
|
||||||
|
ad.add(dist_from_fn("FooPkg-1.2-py2.4.egg"))
|
||||||
|
|
||||||
|
# Name is in there now
|
||||||
|
assert ad['FooPkg']
|
||||||
|
# But only 1 package
|
||||||
|
assert list(ad) == ['foopkg']
|
||||||
|
|
||||||
|
# Distributions sort by version
|
||||||
|
assert [dist.version for dist in ad['FooPkg']] == ['1.4','1.3-1','1.2']
|
||||||
|
|
||||||
|
# Removing a distribution leaves sequence alone
|
||||||
|
ad.remove(ad['FooPkg'][1])
|
||||||
|
assert [dist.version for dist in ad['FooPkg']] == ['1.4','1.2']
|
||||||
|
|
||||||
|
# And inserting adds them in order
|
||||||
|
ad.add(dist_from_fn("FooPkg-1.9.egg"))
|
||||||
|
assert [dist.version for dist in ad['FooPkg']] == ['1.9','1.4','1.2']
|
||||||
|
|
||||||
|
ws = WorkingSet([])
|
||||||
|
foo12 = dist_from_fn("FooPkg-1.2-py2.4.egg")
|
||||||
|
foo14 = dist_from_fn("FooPkg-1.4-py2.4-win32.egg")
|
||||||
|
req, = parse_requirements("FooPkg>=1.3")
|
||||||
|
|
||||||
|
# Nominal case: no distros on path, should yield all applicable
|
||||||
|
assert ad.best_match(req, ws).version == '1.9'
|
||||||
|
# If a matching distro is already installed, should return only that
|
||||||
|
ws.add(foo14)
|
||||||
|
assert ad.best_match(req, ws).version == '1.4'
|
||||||
|
|
||||||
|
# If the first matching distro is unsuitable, it's a version conflict
|
||||||
|
ws = WorkingSet([])
|
||||||
|
ws.add(foo12)
|
||||||
|
ws.add(foo14)
|
||||||
|
with pytest.raises(VersionConflict):
|
||||||
|
ad.best_match(req, ws)
|
||||||
|
|
||||||
|
# If more than one match on the path, the first one takes precedence
|
||||||
|
ws = WorkingSet([])
|
||||||
|
ws.add(foo14)
|
||||||
|
ws.add(foo12)
|
||||||
|
ws.add(foo14)
|
||||||
|
assert ad.best_match(req, ws).version == '1.4'
|
||||||
|
|
||||||
|
def checkFooPkg(self,d):
|
||||||
|
assert d.project_name == "FooPkg"
|
||||||
|
assert d.key == "foopkg"
|
||||||
|
assert d.version == "1.3.post1"
|
||||||
|
assert d.py_version == "2.4"
|
||||||
|
assert d.platform == "win32"
|
||||||
|
assert d.parsed_version == parse_version("1.3-1")
|
||||||
|
|
||||||
|
def testDistroBasics(self):
|
||||||
|
d = Distribution(
|
||||||
|
"/some/path",
|
||||||
|
project_name="FooPkg",version="1.3-1",py_version="2.4",platform="win32"
|
||||||
|
)
|
||||||
|
self.checkFooPkg(d)
|
||||||
|
|
||||||
|
d = Distribution("/some/path")
|
||||||
|
assert d.py_version == sys.version[:3]
|
||||||
|
assert d.platform == None
|
||||||
|
|
||||||
|
def testDistroParse(self):
|
||||||
|
d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg")
|
||||||
|
self.checkFooPkg(d)
|
||||||
|
d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg-info")
|
||||||
|
self.checkFooPkg(d)
|
||||||
|
|
||||||
|
def testDistroMetadata(self):
|
||||||
|
d = Distribution(
|
||||||
|
"/some/path", project_name="FooPkg", py_version="2.4", platform="win32",
|
||||||
|
metadata = Metadata(
|
||||||
|
('PKG-INFO',"Metadata-Version: 1.0\nVersion: 1.3-1\n")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.checkFooPkg(d)
|
||||||
|
|
||||||
|
def distRequires(self, txt):
|
||||||
|
return Distribution("/foo", metadata=Metadata(('depends.txt', txt)))
|
||||||
|
|
||||||
|
def checkRequires(self, dist, txt, extras=()):
|
||||||
|
assert list(dist.requires(extras)) == list(parse_requirements(txt))
|
||||||
|
|
||||||
|
def testDistroDependsSimple(self):
|
||||||
|
for v in "Twisted>=1.5", "Twisted>=1.5\nZConfig>=2.0":
|
||||||
|
self.checkRequires(self.distRequires(v), v)
|
||||||
|
|
||||||
|
def testResolve(self):
|
||||||
|
ad = pkg_resources.Environment([])
|
||||||
|
ws = WorkingSet([])
|
||||||
|
# Resolving no requirements -> nothing to install
|
||||||
|
assert list(ws.resolve([], ad)) == []
|
||||||
|
# Request something not in the collection -> DistributionNotFound
|
||||||
|
with pytest.raises(pkg_resources.DistributionNotFound):
|
||||||
|
ws.resolve(parse_requirements("Foo"), ad)
|
||||||
|
|
||||||
|
Foo = Distribution.from_filename(
|
||||||
|
"/foo_dir/Foo-1.2.egg",
|
||||||
|
metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0"))
|
||||||
|
)
|
||||||
|
ad.add(Foo)
|
||||||
|
ad.add(Distribution.from_filename("Foo-0.9.egg"))
|
||||||
|
|
||||||
|
# Request thing(s) that are available -> list to activate
|
||||||
|
for i in range(3):
|
||||||
|
targets = list(ws.resolve(parse_requirements("Foo"), ad))
|
||||||
|
assert targets == [Foo]
|
||||||
|
list(map(ws.add,targets))
|
||||||
|
with pytest.raises(VersionConflict):
|
||||||
|
ws.resolve(parse_requirements("Foo==0.9"), ad)
|
||||||
|
ws = WorkingSet([]) # reset
|
||||||
|
|
||||||
|
# Request an extra that causes an unresolved dependency for "Baz"
|
||||||
|
with pytest.raises(pkg_resources.DistributionNotFound):
|
||||||
|
ws.resolve(parse_requirements("Foo[bar]"), ad)
|
||||||
|
Baz = Distribution.from_filename(
|
||||||
|
"/foo_dir/Baz-2.1.egg", metadata=Metadata(('depends.txt', "Foo"))
|
||||||
|
)
|
||||||
|
ad.add(Baz)
|
||||||
|
|
||||||
|
# Activation list now includes resolved dependency
|
||||||
|
assert list(ws.resolve(parse_requirements("Foo[bar]"), ad)) ==[Foo,Baz]
|
||||||
|
# Requests for conflicting versions produce VersionConflict
|
||||||
|
with pytest.raises(VersionConflict) as vc:
|
||||||
|
ws.resolve(parse_requirements("Foo==1.2\nFoo!=1.2"), ad)
|
||||||
|
|
||||||
|
msg = 'Foo 0.9 is installed but Foo==1.2 is required'
|
||||||
|
assert vc.value.report() == msg
|
||||||
|
|
||||||
|
def testDistroDependsOptions(self):
|
||||||
|
d = self.distRequires("""
|
||||||
|
Twisted>=1.5
|
||||||
|
[docgen]
|
||||||
|
ZConfig>=2.0
|
||||||
|
docutils>=0.3
|
||||||
|
[fastcgi]
|
||||||
|
fcgiapp>=0.1""")
|
||||||
|
self.checkRequires(d,"Twisted>=1.5")
|
||||||
|
self.checkRequires(
|
||||||
|
d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3".split(), ["docgen"]
|
||||||
|
)
|
||||||
|
self.checkRequires(
|
||||||
|
d,"Twisted>=1.5 fcgiapp>=0.1".split(), ["fastcgi"]
|
||||||
|
)
|
||||||
|
self.checkRequires(
|
||||||
|
d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3 fcgiapp>=0.1".split(),
|
||||||
|
["docgen","fastcgi"]
|
||||||
|
)
|
||||||
|
self.checkRequires(
|
||||||
|
d,"Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(),
|
||||||
|
["fastcgi", "docgen"]
|
||||||
|
)
|
||||||
|
with pytest.raises(pkg_resources.UnknownExtra):
|
||||||
|
d.requires(["foo"])
|
||||||
|
|
||||||
|
|
||||||
|
class TestWorkingSet:
|
||||||
|
def test_find_conflicting(self):
|
||||||
|
ws = WorkingSet([])
|
||||||
|
Foo = Distribution.from_filename("/foo_dir/Foo-1.2.egg")
|
||||||
|
ws.add(Foo)
|
||||||
|
|
||||||
|
# create a requirement that conflicts with Foo 1.2
|
||||||
|
req = next(parse_requirements("Foo<1.2"))
|
||||||
|
|
||||||
|
with pytest.raises(VersionConflict) as vc:
|
||||||
|
ws.find(req)
|
||||||
|
|
||||||
|
msg = 'Foo 1.2 is installed but Foo<1.2 is required'
|
||||||
|
assert vc.value.report() == msg
|
||||||
|
|
||||||
|
def test_resolve_conflicts_with_prior(self):
|
||||||
|
"""
|
||||||
|
A ContextualVersionConflict should be raised when a requirement
|
||||||
|
conflicts with a prior requirement for a different package.
|
||||||
|
"""
|
||||||
|
# Create installation where Foo depends on Baz 1.0 and Bar depends on
|
||||||
|
# Baz 2.0.
|
||||||
|
ws = WorkingSet([])
|
||||||
|
md = Metadata(('depends.txt', "Baz==1.0"))
|
||||||
|
Foo = Distribution.from_filename("/foo_dir/Foo-1.0.egg", metadata=md)
|
||||||
|
ws.add(Foo)
|
||||||
|
md = Metadata(('depends.txt', "Baz==2.0"))
|
||||||
|
Bar = Distribution.from_filename("/foo_dir/Bar-1.0.egg", metadata=md)
|
||||||
|
ws.add(Bar)
|
||||||
|
Baz = Distribution.from_filename("/foo_dir/Baz-1.0.egg")
|
||||||
|
ws.add(Baz)
|
||||||
|
Baz = Distribution.from_filename("/foo_dir/Baz-2.0.egg")
|
||||||
|
ws.add(Baz)
|
||||||
|
|
||||||
|
with pytest.raises(VersionConflict) as vc:
|
||||||
|
ws.resolve(parse_requirements("Foo\nBar\n"))
|
||||||
|
|
||||||
|
msg = "Baz 1.0 is installed but Baz==2.0 is required by {'Bar'}"
|
||||||
|
if pkg_resources.PY2:
|
||||||
|
msg = msg.replace("{'Bar'}", "set(['Bar'])")
|
||||||
|
assert vc.value.report() == msg
|
||||||
|
|
||||||
|
|
||||||
|
class TestEntryPoints:
|
||||||
|
|
||||||
|
def assertfields(self, ep):
|
||||||
|
assert ep.name == "foo"
|
||||||
|
assert ep.module_name == "pkg_resources.tests.test_resources"
|
||||||
|
assert ep.attrs == ("TestEntryPoints",)
|
||||||
|
assert ep.extras == ("x",)
|
||||||
|
assert ep.load() is TestEntryPoints
|
||||||
|
expect = "foo = pkg_resources.tests.test_resources:TestEntryPoints [x]"
|
||||||
|
assert str(ep) == expect
|
||||||
|
|
||||||
|
def setup_method(self, method):
|
||||||
|
self.dist = Distribution.from_filename(
|
||||||
|
"FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt','[x]')))
|
||||||
|
|
||||||
|
def testBasics(self):
|
||||||
|
ep = EntryPoint(
|
||||||
|
"foo", "pkg_resources.tests.test_resources", ["TestEntryPoints"],
|
||||||
|
["x"], self.dist
|
||||||
|
)
|
||||||
|
self.assertfields(ep)
|
||||||
|
|
||||||
|
def testParse(self):
|
||||||
|
s = "foo = pkg_resources.tests.test_resources:TestEntryPoints [x]"
|
||||||
|
ep = EntryPoint.parse(s, self.dist)
|
||||||
|
self.assertfields(ep)
|
||||||
|
|
||||||
|
ep = EntryPoint.parse("bar baz= spammity[PING]")
|
||||||
|
assert ep.name == "bar baz"
|
||||||
|
assert ep.module_name == "spammity"
|
||||||
|
assert ep.attrs == ()
|
||||||
|
assert ep.extras == ("ping",)
|
||||||
|
|
||||||
|
ep = EntryPoint.parse(" fizzly = wocka:foo")
|
||||||
|
assert ep.name == "fizzly"
|
||||||
|
assert ep.module_name == "wocka"
|
||||||
|
assert ep.attrs == ("foo",)
|
||||||
|
assert ep.extras == ()
|
||||||
|
|
||||||
|
# plus in the name
|
||||||
|
spec = "html+mako = mako.ext.pygmentplugin:MakoHtmlLexer"
|
||||||
|
ep = EntryPoint.parse(spec)
|
||||||
|
assert ep.name == 'html+mako'
|
||||||
|
|
||||||
|
reject_specs = "foo", "x=a:b:c", "q=x/na", "fez=pish:tush-z", "x=f[a]>2"
|
||||||
|
@pytest.mark.parametrize("reject_spec", reject_specs)
|
||||||
|
def test_reject_spec(self, reject_spec):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
EntryPoint.parse(reject_spec)
|
||||||
|
|
||||||
|
def test_printable_name(self):
|
||||||
|
"""
|
||||||
|
Allow any printable character in the name.
|
||||||
|
"""
|
||||||
|
# Create a name with all printable characters; strip the whitespace.
|
||||||
|
name = string.printable.strip()
|
||||||
|
spec = "{name} = module:attr".format(**locals())
|
||||||
|
ep = EntryPoint.parse(spec)
|
||||||
|
assert ep.name == name
|
||||||
|
|
||||||
|
def checkSubMap(self, m):
|
||||||
|
assert len(m) == len(self.submap_expect)
|
||||||
|
for key, ep in pkg_resources.iteritems(self.submap_expect):
|
||||||
|
assert repr(m.get(key)) == repr(ep)
|
||||||
|
|
||||||
|
submap_expect = dict(
|
||||||
|
feature1=EntryPoint('feature1', 'somemodule', ['somefunction']),
|
||||||
|
feature2=EntryPoint('feature2', 'another.module', ['SomeClass'], ['extra1','extra2']),
|
||||||
|
feature3=EntryPoint('feature3', 'this.module', extras=['something'])
|
||||||
|
)
|
||||||
|
submap_str = """
|
||||||
|
# define features for blah blah
|
||||||
|
feature1 = somemodule:somefunction
|
||||||
|
feature2 = another.module:SomeClass [extra1,extra2]
|
||||||
|
feature3 = this.module [something]
|
||||||
|
"""
|
||||||
|
|
||||||
|
def testParseList(self):
|
||||||
|
self.checkSubMap(EntryPoint.parse_group("xyz", self.submap_str))
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
EntryPoint.parse_group("x a", "foo=bar")
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
EntryPoint.parse_group("x", ["foo=baz", "foo=bar"])
|
||||||
|
|
||||||
|
def testParseMap(self):
|
||||||
|
m = EntryPoint.parse_map({'xyz':self.submap_str})
|
||||||
|
self.checkSubMap(m['xyz'])
|
||||||
|
assert list(m.keys()) == ['xyz']
|
||||||
|
m = EntryPoint.parse_map("[xyz]\n"+self.submap_str)
|
||||||
|
self.checkSubMap(m['xyz'])
|
||||||
|
assert list(m.keys()) == ['xyz']
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
EntryPoint.parse_map(["[xyz]", "[xyz]"])
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
EntryPoint.parse_map(self.submap_str)
|
||||||
|
|
||||||
|
class TestRequirements:
|
||||||
|
|
||||||
|
def testBasics(self):
|
||||||
|
r = Requirement.parse("Twisted>=1.2")
|
||||||
|
assert str(r) == "Twisted>=1.2"
|
||||||
|
assert repr(r) == "Requirement.parse('Twisted>=1.2')"
|
||||||
|
assert r == Requirement("Twisted", [('>=','1.2')], ())
|
||||||
|
assert r == Requirement("twisTed", [('>=','1.2')], ())
|
||||||
|
assert r != Requirement("Twisted", [('>=','2.0')], ())
|
||||||
|
assert r != Requirement("Zope", [('>=','1.2')], ())
|
||||||
|
assert r != Requirement("Zope", [('>=','3.0')], ())
|
||||||
|
assert r != Requirement.parse("Twisted[extras]>=1.2")
|
||||||
|
|
||||||
|
def testOrdering(self):
|
||||||
|
r1 = Requirement("Twisted", [('==','1.2c1'),('>=','1.2')], ())
|
||||||
|
r2 = Requirement("Twisted", [('>=','1.2'),('==','1.2c1')], ())
|
||||||
|
assert r1 == r2
|
||||||
|
assert str(r1) == str(r2)
|
||||||
|
assert str(r2) == "Twisted==1.2c1,>=1.2"
|
||||||
|
|
||||||
|
def testBasicContains(self):
|
||||||
|
r = Requirement("Twisted", [('>=','1.2')], ())
|
||||||
|
foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg")
|
||||||
|
twist11 = Distribution.from_filename("Twisted-1.1.egg")
|
||||||
|
twist12 = Distribution.from_filename("Twisted-1.2.egg")
|
||||||
|
assert parse_version('1.2') in r
|
||||||
|
assert parse_version('1.1') not in r
|
||||||
|
assert '1.2' in r
|
||||||
|
assert '1.1' not in r
|
||||||
|
assert foo_dist not in r
|
||||||
|
assert twist11 not in r
|
||||||
|
assert twist12 in r
|
||||||
|
|
||||||
|
def testOptionsAndHashing(self):
|
||||||
|
r1 = Requirement.parse("Twisted[foo,bar]>=1.2")
|
||||||
|
r2 = Requirement.parse("Twisted[bar,FOO]>=1.2")
|
||||||
|
assert r1 == r2
|
||||||
|
assert r1.extras == ("foo","bar")
|
||||||
|
assert r2.extras == ("bar","foo") # extras are normalized
|
||||||
|
assert hash(r1) == hash(r2)
|
||||||
|
assert (
|
||||||
|
hash(r1)
|
||||||
|
==
|
||||||
|
hash((
|
||||||
|
"twisted",
|
||||||
|
packaging.specifiers.SpecifierSet(">=1.2"),
|
||||||
|
frozenset(["foo","bar"]),
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
def testVersionEquality(self):
|
||||||
|
r1 = Requirement.parse("foo==0.3a2")
|
||||||
|
r2 = Requirement.parse("foo!=0.3a4")
|
||||||
|
d = Distribution.from_filename
|
||||||
|
|
||||||
|
assert d("foo-0.3a4.egg") not in r1
|
||||||
|
assert d("foo-0.3a1.egg") not in r1
|
||||||
|
assert d("foo-0.3a4.egg") not in r2
|
||||||
|
|
||||||
|
assert d("foo-0.3a2.egg") in r1
|
||||||
|
assert d("foo-0.3a2.egg") in r2
|
||||||
|
assert d("foo-0.3a3.egg") in r2
|
||||||
|
assert d("foo-0.3a5.egg") in r2
|
||||||
|
|
||||||
|
def testSetuptoolsProjectName(self):
|
||||||
|
"""
|
||||||
|
The setuptools project should implement the setuptools package.
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert (
|
||||||
|
Requirement.parse('setuptools').project_name == 'setuptools')
|
||||||
|
# setuptools 0.7 and higher means setuptools.
|
||||||
|
assert (
|
||||||
|
Requirement.parse('setuptools == 0.7').project_name == 'setuptools')
|
||||||
|
assert (
|
||||||
|
Requirement.parse('setuptools == 0.7a1').project_name == 'setuptools')
|
||||||
|
assert (
|
||||||
|
Requirement.parse('setuptools >= 0.7').project_name == 'setuptools')
|
||||||
|
|
||||||
|
|
||||||
|
class TestParsing:
|
||||||
|
|
||||||
|
def testEmptyParse(self):
|
||||||
|
assert list(parse_requirements('')) == []
|
||||||
|
|
||||||
|
def testYielding(self):
|
||||||
|
for inp,out in [
|
||||||
|
([], []), ('x',['x']), ([[]],[]), (' x\n y', ['x','y']),
|
||||||
|
(['x\n\n','y'], ['x','y']),
|
||||||
|
]:
|
||||||
|
assert list(pkg_resources.yield_lines(inp)) == out
|
||||||
|
|
||||||
|
def testSplitting(self):
|
||||||
|
sample = """
|
||||||
|
x
|
||||||
|
[Y]
|
||||||
|
z
|
||||||
|
|
||||||
|
a
|
||||||
|
[b ]
|
||||||
|
# foo
|
||||||
|
c
|
||||||
|
[ d]
|
||||||
|
[q]
|
||||||
|
v
|
||||||
|
"""
|
||||||
|
assert (
|
||||||
|
list(pkg_resources.split_sections(sample))
|
||||||
|
==
|
||||||
|
[
|
||||||
|
(None, ["x"]),
|
||||||
|
("Y", ["z", "a"]),
|
||||||
|
("b", ["c"]),
|
||||||
|
("d", []),
|
||||||
|
("q", ["v"]),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
list(pkg_resources.split_sections("[foo"))
|
||||||
|
|
||||||
|
def testSafeName(self):
|
||||||
|
assert safe_name("adns-python") == "adns-python"
|
||||||
|
assert safe_name("WSGI Utils") == "WSGI-Utils"
|
||||||
|
assert safe_name("WSGI Utils") == "WSGI-Utils"
|
||||||
|
assert safe_name("Money$$$Maker") == "Money-Maker"
|
||||||
|
assert safe_name("peak.web") != "peak-web"
|
||||||
|
|
||||||
|
def testSafeVersion(self):
|
||||||
|
assert safe_version("1.2-1") == "1.2.post1"
|
||||||
|
assert safe_version("1.2 alpha") == "1.2.alpha"
|
||||||
|
assert safe_version("2.3.4 20050521") == "2.3.4.20050521"
|
||||||
|
assert safe_version("Money$$$Maker") == "Money-Maker"
|
||||||
|
assert safe_version("peak.web") == "peak.web"
|
||||||
|
|
||||||
|
def testSimpleRequirements(self):
|
||||||
|
assert (
|
||||||
|
list(parse_requirements('Twis-Ted>=1.2-1'))
|
||||||
|
==
|
||||||
|
[Requirement('Twis-Ted',[('>=','1.2-1')], ())]
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
list(parse_requirements('Twisted >=1.2, \ # more\n<2.0'))
|
||||||
|
==
|
||||||
|
[Requirement('Twisted',[('>=','1.2'),('<','2.0')], ())]
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
Requirement.parse("FooBar==1.99a3")
|
||||||
|
==
|
||||||
|
Requirement("FooBar", [('==','1.99a3')], ())
|
||||||
|
)
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Requirement.parse(">=2.3")
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Requirement.parse("x\\")
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Requirement.parse("x==2 q")
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Requirement.parse("X==1\nY==2")
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Requirement.parse("#")
|
||||||
|
|
||||||
|
def testVersionEquality(self):
|
||||||
|
def c(s1,s2):
|
||||||
|
p1, p2 = parse_version(s1),parse_version(s2)
|
||||||
|
assert p1 == p2, (s1,s2,p1,p2)
|
||||||
|
|
||||||
|
c('1.2-rc1', '1.2rc1')
|
||||||
|
c('0.4', '0.4.0')
|
||||||
|
c('0.4.0.0', '0.4.0')
|
||||||
|
c('0.4.0-0', '0.4-0')
|
||||||
|
c('0post1', '0.0post1')
|
||||||
|
c('0pre1', '0.0c1')
|
||||||
|
c('0.0.0preview1', '0c1')
|
||||||
|
c('0.0c1', '0-rc1')
|
||||||
|
c('1.2a1', '1.2.a.1')
|
||||||
|
c('1.2.a', '1.2a')
|
||||||
|
|
||||||
|
def testVersionOrdering(self):
|
||||||
|
def c(s1,s2):
|
||||||
|
p1, p2 = parse_version(s1),parse_version(s2)
|
||||||
|
assert p1<p2, (s1,s2,p1,p2)
|
||||||
|
|
||||||
|
c('2.1','2.1.1')
|
||||||
|
c('2a1','2b0')
|
||||||
|
c('2a1','2.1')
|
||||||
|
c('2.3a1', '2.3')
|
||||||
|
c('2.1-1', '2.1-2')
|
||||||
|
c('2.1-1', '2.1.1')
|
||||||
|
c('2.1', '2.1post4')
|
||||||
|
c('2.1a0-20040501', '2.1')
|
||||||
|
c('1.1', '02.1')
|
||||||
|
c('3.2', '3.2.post0')
|
||||||
|
c('3.2post1', '3.2post2')
|
||||||
|
c('0.4', '4.0')
|
||||||
|
c('0.0.4', '0.4.0')
|
||||||
|
c('0post1', '0.4post1')
|
||||||
|
c('2.1.0-rc1','2.1.0')
|
||||||
|
c('2.1dev','2.1a0')
|
||||||
|
|
||||||
|
torture ="""
|
||||||
|
0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1
|
||||||
|
0.79.9999+0.80.0pre2-3 0.79.9999+0.80.0pre2-2
|
||||||
|
0.77.2-1 0.77.1-1 0.77.0-1
|
||||||
|
""".split()
|
||||||
|
|
||||||
|
for p,v1 in enumerate(torture):
|
||||||
|
for v2 in torture[p+1:]:
|
||||||
|
c(v2,v1)
|
||||||
|
|
||||||
|
def testVersionBuildout(self):
|
||||||
|
"""
|
||||||
|
Buildout has a function in it's bootstrap.py that inspected the return
|
||||||
|
value of parse_version. The new parse_version returns a Version class
|
||||||
|
which needs to support this behavior, at least for now.
|
||||||
|
"""
|
||||||
|
def buildout(parsed_version):
|
||||||
|
_final_parts = '*final-', '*final'
|
||||||
|
|
||||||
|
def _final_version(parsed_version):
|
||||||
|
for part in parsed_version:
|
||||||
|
if (part[:1] == '*') and (part not in _final_parts):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
return _final_version(parsed_version)
|
||||||
|
|
||||||
|
assert buildout(parse_version("1.0"))
|
||||||
|
assert not buildout(parse_version("1.0a1"))
|
||||||
|
|
||||||
|
def testVersionIndexable(self):
|
||||||
|
"""
|
||||||
|
Some projects were doing things like parse_version("v")[0], so we'll
|
||||||
|
support indexing the same as we support iterating.
|
||||||
|
"""
|
||||||
|
assert parse_version("1.0")[0] == "00000001"
|
||||||
|
|
||||||
|
def testVersionTupleSort(self):
|
||||||
|
"""
|
||||||
|
Some projects expected to be able to sort tuples against the return
|
||||||
|
value of parse_version. So again we'll add a warning enabled shim to
|
||||||
|
make this possible.
|
||||||
|
"""
|
||||||
|
assert parse_version("1.0") < tuple(parse_version("2.0"))
|
||||||
|
assert parse_version("1.0") <= tuple(parse_version("2.0"))
|
||||||
|
assert parse_version("1.0") == tuple(parse_version("1.0"))
|
||||||
|
assert parse_version("3.0") > tuple(parse_version("2.0"))
|
||||||
|
assert parse_version("3.0") >= tuple(parse_version("2.0"))
|
||||||
|
assert parse_version("3.0") != tuple(parse_version("2.0"))
|
||||||
|
assert not (parse_version("3.0") != tuple(parse_version("3.0")))
|
||||||
|
|
||||||
|
def testVersionHashable(self):
|
||||||
|
"""
|
||||||
|
Ensure that our versions stay hashable even though we've subclassed
|
||||||
|
them and added some shim code to them.
|
||||||
|
"""
|
||||||
|
assert (
|
||||||
|
hash(parse_version("1.0"))
|
||||||
|
==
|
||||||
|
hash(parse_version("1.0"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestNamespaces:
|
||||||
|
|
||||||
|
def setup_method(self, method):
|
||||||
|
self._ns_pkgs = pkg_resources._namespace_packages.copy()
|
||||||
|
self._tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-")
|
||||||
|
os.makedirs(os.path.join(self._tmpdir, "site-pkgs"))
|
||||||
|
self._prev_sys_path = sys.path[:]
|
||||||
|
sys.path.append(os.path.join(self._tmpdir, "site-pkgs"))
|
||||||
|
|
||||||
|
def teardown_method(self, method):
|
||||||
|
shutil.rmtree(self._tmpdir)
|
||||||
|
pkg_resources._namespace_packages = self._ns_pkgs.copy()
|
||||||
|
sys.path = self._prev_sys_path[:]
|
||||||
|
|
||||||
|
@pytest.mark.skipif(os.path.islink(tempfile.gettempdir()),
|
||||||
|
reason="Test fails when /tmp is a symlink. See #231")
|
||||||
|
def test_two_levels_deep(self):
|
||||||
|
"""
|
||||||
|
Test nested namespace packages
|
||||||
|
Create namespace packages in the following tree :
|
||||||
|
site-packages-1/pkg1/pkg2
|
||||||
|
site-packages-2/pkg1/pkg2
|
||||||
|
Check both are in the _namespace_packages dict and that their __path__
|
||||||
|
is correct
|
||||||
|
"""
|
||||||
|
sys.path.append(os.path.join(self._tmpdir, "site-pkgs2"))
|
||||||
|
os.makedirs(os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2"))
|
||||||
|
os.makedirs(os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2"))
|
||||||
|
ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n"
|
||||||
|
for site in ["site-pkgs", "site-pkgs2"]:
|
||||||
|
pkg1_init = open(os.path.join(self._tmpdir, site,
|
||||||
|
"pkg1", "__init__.py"), "w")
|
||||||
|
pkg1_init.write(ns_str)
|
||||||
|
pkg1_init.close()
|
||||||
|
pkg2_init = open(os.path.join(self._tmpdir, site,
|
||||||
|
"pkg1", "pkg2", "__init__.py"), "w")
|
||||||
|
pkg2_init.write(ns_str)
|
||||||
|
pkg2_init.close()
|
||||||
|
import pkg1
|
||||||
|
assert "pkg1" in pkg_resources._namespace_packages
|
||||||
|
# attempt to import pkg2 from site-pkgs2
|
||||||
|
import pkg1.pkg2
|
||||||
|
# check the _namespace_packages dict
|
||||||
|
assert "pkg1.pkg2" in pkg_resources._namespace_packages
|
||||||
|
assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"]
|
||||||
|
# check the __path__ attribute contains both paths
|
||||||
|
expected = [
|
||||||
|
os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2"),
|
||||||
|
os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2"),
|
||||||
|
]
|
||||||
|
assert pkg1.pkg2.__path__ == expected
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
"""Extensions to the 'distutils' for large or complex distributions"""
|
"""Extensions to the 'distutils' for large or complex distributions"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import distutils.core
|
import distutils.core
|
||||||
import distutils.filelist
|
import distutils.filelist
|
||||||
from distutils.core import Command as _Command
|
from distutils.core import Command as _Command
|
||||||
from distutils.util import convert_path
|
from distutils.util import convert_path
|
||||||
|
from fnmatch import fnmatchcase
|
||||||
|
|
||||||
import setuptools.version
|
import setuptools.version
|
||||||
from setuptools.extension import Extension
|
from setuptools.extension import Extension
|
||||||
from setuptools.dist import Distribution, Feature, _get_unpatched
|
from setuptools.dist import Distribution, Feature, _get_unpatched
|
||||||
from setuptools.depends import Require
|
from setuptools.depends import Require
|
||||||
|
from setuptools.compat import filterfalse
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
|
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
|
||||||
@@ -27,33 +28,87 @@ run_2to3_on_doctests = True
|
|||||||
# Standard package names for fixer packages
|
# Standard package names for fixer packages
|
||||||
lib2to3_fixer_packages = ['lib2to3.fixes']
|
lib2to3_fixer_packages = ['lib2to3.fixes']
|
||||||
|
|
||||||
def find_packages(where='.', exclude=()):
|
|
||||||
"""Return a list all Python packages found within directory 'where'
|
|
||||||
|
|
||||||
'where' should be supplied as a "cross-platform" (i.e. URL-style) path; it
|
class PackageFinder(object):
|
||||||
will be converted to the appropriate local path syntax. 'exclude' is a
|
@classmethod
|
||||||
sequence of package names to exclude; '*' can be used as a wildcard in the
|
def find(cls, where='.', exclude=(), include=('*',)):
|
||||||
names, such that 'foo.*' will exclude all subpackages of 'foo' (but not
|
"""Return a list all Python packages found within directory 'where'
|
||||||
'foo' itself).
|
|
||||||
"""
|
'where' should be supplied as a "cross-platform" (i.e. URL-style)
|
||||||
out = []
|
path; it will be converted to the appropriate local path syntax.
|
||||||
stack=[(convert_path(where), '')]
|
'exclude' is a sequence of package names to exclude; '*' can be used
|
||||||
while stack:
|
as a wildcard in the names, such that 'foo.*' will exclude all
|
||||||
where,prefix = stack.pop(0)
|
subpackages of 'foo' (but not 'foo' itself).
|
||||||
for name in os.listdir(where):
|
|
||||||
fn = os.path.join(where,name)
|
'include' is a sequence of package names to include. If it's
|
||||||
looks_like_package = (
|
specified, only the named packages will be included. If it's not
|
||||||
'.' not in name
|
specified, all found packages will be included. 'include' can contain
|
||||||
and os.path.isdir(fn)
|
shell style wildcard patterns just like 'exclude'.
|
||||||
and os.path.isfile(os.path.join(fn, '__init__.py'))
|
|
||||||
)
|
The list of included packages is built up first and then any
|
||||||
if looks_like_package:
|
explicitly excluded packages are removed from it.
|
||||||
out.append(prefix+name)
|
"""
|
||||||
stack.append((fn, prefix+name+'.'))
|
out = cls._find_packages_iter(convert_path(where))
|
||||||
for pat in list(exclude)+['ez_setup']:
|
out = cls.require_parents(out)
|
||||||
from fnmatch import fnmatchcase
|
includes = cls._build_filter(*include)
|
||||||
out = [item for item in out if not fnmatchcase(item,pat)]
|
excludes = cls._build_filter('ez_setup', '*__pycache__', *exclude)
|
||||||
return out
|
out = filter(includes, out)
|
||||||
|
out = filterfalse(excludes, out)
|
||||||
|
return list(out)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def require_parents(packages):
|
||||||
|
"""
|
||||||
|
Exclude any apparent package that apparently doesn't include its
|
||||||
|
parent.
|
||||||
|
|
||||||
|
For example, exclude 'foo.bar' if 'foo' is not present.
|
||||||
|
"""
|
||||||
|
found = []
|
||||||
|
for pkg in packages:
|
||||||
|
base, sep, child = pkg.rpartition('.')
|
||||||
|
if base and base not in found:
|
||||||
|
continue
|
||||||
|
found.append(pkg)
|
||||||
|
yield pkg
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _all_dirs(base_path):
|
||||||
|
"""
|
||||||
|
Return all dirs in base_path, relative to base_path
|
||||||
|
"""
|
||||||
|
for root, dirs, files in os.walk(base_path, followlinks=True):
|
||||||
|
for dir in dirs:
|
||||||
|
yield os.path.relpath(os.path.join(root, dir), base_path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _find_packages_iter(cls, base_path):
|
||||||
|
dirs = cls._all_dirs(base_path)
|
||||||
|
suitable = filterfalse(lambda n: '.' in n, dirs)
|
||||||
|
return (
|
||||||
|
path.replace(os.path.sep, '.')
|
||||||
|
for path in suitable
|
||||||
|
if cls._looks_like_package(os.path.join(base_path, path))
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _looks_like_package(path):
|
||||||
|
return os.path.isfile(os.path.join(path, '__init__.py'))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _build_filter(*patterns):
|
||||||
|
"""
|
||||||
|
Given a list of patterns, return a callable that will be true only if
|
||||||
|
the input matches one of the patterns.
|
||||||
|
"""
|
||||||
|
return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
|
||||||
|
|
||||||
|
class PEP420PackageFinder(PackageFinder):
|
||||||
|
@staticmethod
|
||||||
|
def _looks_like_package(path):
|
||||||
|
return True
|
||||||
|
|
||||||
|
find_packages = PackageFinder.find
|
||||||
|
|
||||||
setup = distutils.core.setup
|
setup = distutils.core.setup
|
||||||
|
|
||||||
@@ -83,7 +138,7 @@ def findall(dir = os.curdir):
|
|||||||
(relative to 'dir').
|
(relative to 'dir').
|
||||||
"""
|
"""
|
||||||
all_files = []
|
all_files = []
|
||||||
for base, dirs, files in os.walk(dir):
|
for base, dirs, files in os.walk(dir, followlinks=True):
|
||||||
if base==os.curdir or base.startswith(os.curdir+os.sep):
|
if base==os.curdir or base.startswith(os.curdir+os.sep):
|
||||||
base = base[2:]
|
base = base[2:]
|
||||||
if base:
|
if base:
|
||||||
@@ -92,7 +147,3 @@ def findall(dir = os.curdir):
|
|||||||
return all_files
|
return all_files
|
||||||
|
|
||||||
distutils.filelist.findall = findall # fix findall bug in distutils.
|
distutils.filelist.findall = findall # fix findall bug in distutils.
|
||||||
|
|
||||||
# sys.dont_write_bytecode was introduced in Python 2.6.
|
|
||||||
_dont_write_bytecode = getattr(sys, 'dont_write_bytecode',
|
|
||||||
bool(os.environ.get("PYTHONDONTWRITEBYTECODE")))
|
|
||||||
|
|||||||
@@ -6,42 +6,25 @@ __all__ = [
|
|||||||
"UnrecognizedFormat", "extraction_drivers", "unpack_directory",
|
"UnrecognizedFormat", "extraction_drivers", "unpack_directory",
|
||||||
]
|
]
|
||||||
|
|
||||||
import zipfile, tarfile, os, shutil, posixpath
|
import zipfile
|
||||||
from pkg_resources import ensure_directory
|
import tarfile
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import posixpath
|
||||||
|
import contextlib
|
||||||
|
from pkg_resources import ensure_directory, ContextualZipFile
|
||||||
from distutils.errors import DistutilsError
|
from distutils.errors import DistutilsError
|
||||||
|
|
||||||
class UnrecognizedFormat(DistutilsError):
|
class UnrecognizedFormat(DistutilsError):
|
||||||
"""Couldn't recognize the archive type"""
|
"""Couldn't recognize the archive type"""
|
||||||
|
|
||||||
def default_filter(src,dst):
|
def default_filter(src,dst):
|
||||||
"""The default progress/filter callback; returns True for all files"""
|
"""The default progress/filter callback; returns True for all files"""
|
||||||
return dst
|
return dst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def unpack_archive(filename, extract_dir, progress_filter=default_filter,
|
def unpack_archive(filename, extract_dir, progress_filter=default_filter,
|
||||||
drivers=None
|
drivers=None):
|
||||||
):
|
|
||||||
"""Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
|
"""Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
|
||||||
|
|
||||||
`progress_filter` is a function taking two arguments: a source path
|
`progress_filter` is a function taking two arguments: a source path
|
||||||
@@ -75,52 +58,33 @@ def unpack_archive(filename, extract_dir, progress_filter=default_filter,
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def unpack_directory(filename, extract_dir, progress_filter=default_filter):
|
def unpack_directory(filename, extract_dir, progress_filter=default_filter):
|
||||||
""""Unpack" a directory, using the same interface as for archives
|
""""Unpack" a directory, using the same interface as for archives
|
||||||
|
|
||||||
Raises ``UnrecognizedFormat`` if `filename` is not a directory
|
Raises ``UnrecognizedFormat`` if `filename` is not a directory
|
||||||
"""
|
"""
|
||||||
if not os.path.isdir(filename):
|
if not os.path.isdir(filename):
|
||||||
raise UnrecognizedFormat("%s is not a directory" % (filename,))
|
raise UnrecognizedFormat("%s is not a directory" % filename)
|
||||||
|
|
||||||
paths = {filename:('',extract_dir)}
|
paths = {
|
||||||
|
filename: ('', extract_dir),
|
||||||
|
}
|
||||||
for base, dirs, files in os.walk(filename):
|
for base, dirs, files in os.walk(filename):
|
||||||
src,dst = paths[base]
|
src, dst = paths[base]
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
paths[os.path.join(base,d)] = src+d+'/', os.path.join(dst,d)
|
paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d)
|
||||||
for f in files:
|
for f in files:
|
||||||
name = src+f
|
target = os.path.join(dst, f)
|
||||||
target = os.path.join(dst,f)
|
target = progress_filter(src + f, target)
|
||||||
target = progress_filter(src+f, target)
|
|
||||||
if not target:
|
if not target:
|
||||||
continue # skip non-files
|
# skip non-files
|
||||||
|
continue
|
||||||
ensure_directory(target)
|
ensure_directory(target)
|
||||||
f = os.path.join(base,f)
|
f = os.path.join(base, f)
|
||||||
shutil.copyfile(f, target)
|
shutil.copyfile(f, target)
|
||||||
shutil.copystat(f, target)
|
shutil.copystat(f, target)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
|
def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
|
||||||
"""Unpack zip `filename` to `extract_dir`
|
"""Unpack zip `filename` to `extract_dir`
|
||||||
|
|
||||||
@@ -132,8 +96,7 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
|
|||||||
if not zipfile.is_zipfile(filename):
|
if not zipfile.is_zipfile(filename):
|
||||||
raise UnrecognizedFormat("%s is not a zip file" % (filename,))
|
raise UnrecognizedFormat("%s is not a zip file" % (filename,))
|
||||||
|
|
||||||
z = zipfile.ZipFile(filename)
|
with ContextualZipFile(filename) as z:
|
||||||
try:
|
|
||||||
for info in z.infolist():
|
for info in z.infolist():
|
||||||
name = info.filename
|
name = info.filename
|
||||||
|
|
||||||
@@ -152,17 +115,11 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
|
|||||||
# file
|
# file
|
||||||
ensure_directory(target)
|
ensure_directory(target)
|
||||||
data = z.read(info.filename)
|
data = z.read(info.filename)
|
||||||
f = open(target,'wb')
|
with open(target, 'wb') as f:
|
||||||
try:
|
|
||||||
f.write(data)
|
f.write(data)
|
||||||
finally:
|
|
||||||
f.close()
|
|
||||||
del data
|
|
||||||
unix_attributes = info.external_attr >> 16
|
unix_attributes = info.external_attr >> 16
|
||||||
if unix_attributes:
|
if unix_attributes:
|
||||||
os.chmod(target, unix_attributes)
|
os.chmod(target, unix_attributes)
|
||||||
finally:
|
|
||||||
z.close()
|
|
||||||
|
|
||||||
|
|
||||||
def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
|
def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
|
||||||
@@ -178,19 +135,22 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
|
|||||||
raise UnrecognizedFormat(
|
raise UnrecognizedFormat(
|
||||||
"%s is not a compressed or uncompressed tar file" % (filename,)
|
"%s is not a compressed or uncompressed tar file" % (filename,)
|
||||||
)
|
)
|
||||||
try:
|
with contextlib.closing(tarobj):
|
||||||
tarobj.chown = lambda *args: None # don't do any chowning!
|
# don't do any chowning!
|
||||||
|
tarobj.chown = lambda *args: None
|
||||||
for member in tarobj:
|
for member in tarobj:
|
||||||
name = member.name
|
name = member.name
|
||||||
# don't extract absolute paths or ones with .. in them
|
# don't extract absolute paths or ones with .. in them
|
||||||
if not name.startswith('/') and '..' not in name.split('/'):
|
if not name.startswith('/') and '..' not in name.split('/'):
|
||||||
prelim_dst = os.path.join(extract_dir, *name.split('/'))
|
prelim_dst = os.path.join(extract_dir, *name.split('/'))
|
||||||
|
|
||||||
# resolve any links and to extract the link targets as normal files
|
# resolve any links and to extract the link targets as normal
|
||||||
|
# files
|
||||||
while member is not None and (member.islnk() or member.issym()):
|
while member is not None and (member.islnk() or member.issym()):
|
||||||
linkpath = member.linkname
|
linkpath = member.linkname
|
||||||
if member.issym():
|
if member.issym():
|
||||||
linkpath = posixpath.join(posixpath.dirname(member.name), linkpath)
|
base = posixpath.dirname(member.name)
|
||||||
|
linkpath = posixpath.join(base, linkpath)
|
||||||
linkpath = posixpath.normpath(linkpath)
|
linkpath = posixpath.normpath(linkpath)
|
||||||
member = tarobj._getmember(linkpath)
|
member = tarobj._getmember(linkpath)
|
||||||
|
|
||||||
@@ -200,11 +160,11 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
|
|||||||
if final_dst.endswith(os.sep):
|
if final_dst.endswith(os.sep):
|
||||||
final_dst = final_dst[:-1]
|
final_dst = final_dst[:-1]
|
||||||
try:
|
try:
|
||||||
tarobj._extract_member(member, final_dst) # XXX Ugh
|
# XXX Ugh
|
||||||
|
tarobj._extract_member(member, final_dst)
|
||||||
except tarfile.ExtractError:
|
except tarfile.ExtractError:
|
||||||
pass # chown/chmod/mkfifo/mknode/makedev failed
|
# chown/chmod/mkfifo/mknode/makedev failed
|
||||||
|
pass
|
||||||
return True
|
return True
|
||||||
finally:
|
|
||||||
tarobj.close()
|
|
||||||
|
|
||||||
extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile
|
extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ __all__ = [
|
|||||||
'register', 'bdist_wininst', 'upload_docs',
|
'register', 'bdist_wininst', 'upload_docs',
|
||||||
]
|
]
|
||||||
|
|
||||||
from setuptools.command import install_scripts
|
from distutils.command.bdist import bdist
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from distutils.command.bdist import bdist
|
from setuptools.command import install_scripts
|
||||||
|
|
||||||
|
|
||||||
if 'egg' not in bdist.format_commands:
|
if 'egg' not in bdist.format_commands:
|
||||||
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
|
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
import distutils, os
|
from distutils.errors import DistutilsOptionError
|
||||||
from setuptools import Command
|
|
||||||
from distutils.util import convert_path
|
|
||||||
from distutils import log
|
|
||||||
from distutils.errors import *
|
|
||||||
from setuptools.command.setopt import edit_config, option_base, config_file
|
from setuptools.command.setopt import edit_config, option_base, config_file
|
||||||
|
|
||||||
|
|
||||||
def shquote(arg):
|
def shquote(arg):
|
||||||
"""Quote an argument for later parsing by shlex.split()"""
|
"""Quote an argument for later parsing by shlex.split()"""
|
||||||
for c in '"', "'", "\\", "#":
|
for c in '"', "'", "\\", "#":
|
||||||
if c in arg: return repr(arg)
|
if c in arg:
|
||||||
|
return repr(arg)
|
||||||
if arg.split() != [arg]:
|
if arg.split() != [arg]:
|
||||||
return repr(arg)
|
return repr(arg)
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
|
|
||||||
class alias(option_base):
|
class alias(option_base):
|
||||||
"""Define a shortcut that invokes one or more commands"""
|
"""Define a shortcut that invokes one or more commands"""
|
||||||
|
|
||||||
description = "define a shortcut to invoke one or more commands"
|
description = "define a shortcut to invoke one or more commands"
|
||||||
command_consumes_arguments = True
|
command_consumes_arguments = True
|
||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
('remove', 'r', 'remove (unset) the alias'),
|
('remove', 'r', 'remove (unset) the alias'),
|
||||||
] + option_base.user_options
|
] + option_base.user_options
|
||||||
|
|
||||||
boolean_options = option_base.boolean_options + ['remove']
|
boolean_options = option_base.boolean_options + ['remove']
|
||||||
@@ -49,7 +48,7 @@ class alias(option_base):
|
|||||||
print("setup.py alias", format_alias(alias, aliases))
|
print("setup.py alias", format_alias(alias, aliases))
|
||||||
return
|
return
|
||||||
|
|
||||||
elif len(self.args)==1:
|
elif len(self.args) == 1:
|
||||||
alias, = self.args
|
alias, = self.args
|
||||||
if self.remove:
|
if self.remove:
|
||||||
command = None
|
command = None
|
||||||
@@ -61,9 +60,9 @@ class alias(option_base):
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
alias = self.args[0]
|
alias = self.args[0]
|
||||||
command = ' '.join(map(shquote,self.args[1:]))
|
command = ' '.join(map(shquote, self.args[1:]))
|
||||||
|
|
||||||
edit_config(self.filename, {'aliases': {alias:command}}, self.dry_run)
|
edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run)
|
||||||
|
|
||||||
|
|
||||||
def format_alias(name, aliases):
|
def format_alias(name, aliases):
|
||||||
@@ -76,7 +75,4 @@ def format_alias(name, aliases):
|
|||||||
source = ''
|
source = ''
|
||||||
else:
|
else:
|
||||||
source = '--filename=%r' % source
|
source = '--filename=%r' % source
|
||||||
return source+name+' '+command
|
return source + name + ' ' + command
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,26 +3,33 @@
|
|||||||
Build .egg distributions"""
|
Build .egg distributions"""
|
||||||
|
|
||||||
# This module should be kept compatible with Python 2.3
|
# This module should be kept compatible with Python 2.3
|
||||||
import sys, os, marshal
|
from distutils.errors import DistutilsSetupError
|
||||||
from setuptools import Command
|
|
||||||
from distutils.dir_util import remove_tree, mkpath
|
from distutils.dir_util import remove_tree, mkpath
|
||||||
|
from distutils import log
|
||||||
|
from types import CodeType
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import marshal
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from pkg_resources import get_build_platform, Distribution, ensure_directory
|
||||||
|
from pkg_resources import EntryPoint
|
||||||
|
from setuptools.compat import basestring
|
||||||
|
from setuptools.extension import Library
|
||||||
|
from setuptools import Command
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Python 2.7 or >=3.2
|
# Python 2.7 or >=3.2
|
||||||
from sysconfig import get_path, get_python_version
|
from sysconfig import get_path, get_python_version
|
||||||
|
|
||||||
def _get_purelib():
|
def _get_purelib():
|
||||||
return get_path("purelib")
|
return get_path("purelib")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from distutils.sysconfig import get_python_lib, get_python_version
|
from distutils.sysconfig import get_python_lib, get_python_version
|
||||||
|
|
||||||
def _get_purelib():
|
def _get_purelib():
|
||||||
return get_python_lib(False)
|
return get_python_lib(False)
|
||||||
|
|
||||||
from distutils import log
|
|
||||||
from distutils.errors import DistutilsSetupError
|
|
||||||
from pkg_resources import get_build_platform, Distribution, ensure_directory
|
|
||||||
from pkg_resources import EntryPoint
|
|
||||||
from types import CodeType
|
|
||||||
from setuptools.compat import basestring, next
|
|
||||||
from setuptools.extension import Library
|
|
||||||
|
|
||||||
def strip_module(filename):
|
def strip_module(filename):
|
||||||
if '.' in filename:
|
if '.' in filename:
|
||||||
@@ -31,66 +38,45 @@ def strip_module(filename):
|
|||||||
filename = filename[:-6]
|
filename = filename[:-6]
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
def write_stub(resource, pyfile):
|
|
||||||
f = open(pyfile,'w')
|
|
||||||
f.write('\n'.join([
|
|
||||||
"def __bootstrap__():",
|
|
||||||
" global __bootstrap__, __loader__, __file__",
|
|
||||||
" import sys, pkg_resources, imp",
|
|
||||||
" __file__ = pkg_resources.resource_filename(__name__,%r)"
|
|
||||||
% resource,
|
|
||||||
" __loader__ = None; del __bootstrap__, __loader__",
|
|
||||||
" imp.load_dynamic(__name__,__file__)",
|
|
||||||
"__bootstrap__()",
|
|
||||||
"" # terminal \n
|
|
||||||
]))
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
# stub __init__.py for packages distributed without one
|
def write_stub(resource, pyfile):
|
||||||
NS_PKG_STUB = '__import__("pkg_resources").declare_namespace(__name__)'
|
_stub_template = textwrap.dedent("""
|
||||||
|
def __bootstrap__():
|
||||||
|
global __bootstrap__, __loader__, __file__
|
||||||
|
import sys, pkg_resources, imp
|
||||||
|
__file__ = pkg_resources.resource_filename(__name__, %r)
|
||||||
|
__loader__ = None; del __bootstrap__, __loader__
|
||||||
|
imp.load_dynamic(__name__,__file__)
|
||||||
|
__bootstrap__()
|
||||||
|
""").lstrip()
|
||||||
|
with open(pyfile, 'w') as f:
|
||||||
|
f.write(_stub_template % resource)
|
||||||
|
|
||||||
|
|
||||||
class bdist_egg(Command):
|
class bdist_egg(Command):
|
||||||
|
|
||||||
description = "create an \"egg\" distribution"
|
description = "create an \"egg\" distribution"
|
||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
('bdist-dir=', 'b',
|
('bdist-dir=', 'b',
|
||||||
"temporary directory for creating the distribution"),
|
"temporary directory for creating the distribution"),
|
||||||
('plat-name=', 'p',
|
('plat-name=', 'p', "platform name to embed in generated filenames "
|
||||||
"platform name to embed in generated filenames "
|
"(default: %s)" % get_build_platform()),
|
||||||
"(default: %s)" % get_build_platform()),
|
|
||||||
('exclude-source-files', None,
|
('exclude-source-files', None,
|
||||||
"remove all .py files from the generated egg"),
|
"remove all .py files from the generated egg"),
|
||||||
('keep-temp', 'k',
|
('keep-temp', 'k',
|
||||||
"keep the pseudo-installation tree around after " +
|
"keep the pseudo-installation tree around after " +
|
||||||
"creating the distribution archive"),
|
"creating the distribution archive"),
|
||||||
('dist-dir=', 'd',
|
('dist-dir=', 'd',
|
||||||
"directory to put final built distributions in"),
|
"directory to put final built distributions in"),
|
||||||
('skip-build', None,
|
('skip-build', None,
|
||||||
"skip rebuilding everything (for testing/debugging)"),
|
"skip rebuilding everything (for testing/debugging)"),
|
||||||
]
|
]
|
||||||
|
|
||||||
boolean_options = [
|
boolean_options = [
|
||||||
'keep-temp', 'skip-build', 'exclude-source-files'
|
'keep-temp', 'skip-build', 'exclude-source-files'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def initialize_options (self):
|
|
||||||
self.bdist_dir = None
|
self.bdist_dir = None
|
||||||
self.plat_name = None
|
self.plat_name = None
|
||||||
self.keep_temp = 0
|
self.keep_temp = 0
|
||||||
@@ -99,7 +85,6 @@ class bdist_egg(Command):
|
|||||||
self.egg_output = None
|
self.egg_output = None
|
||||||
self.exclude_source_files = None
|
self.exclude_source_files = None
|
||||||
|
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
|
ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
|
||||||
self.egg_info = ei_cmd.egg_info
|
self.egg_info = ei_cmd.egg_info
|
||||||
@@ -111,7 +96,7 @@ class bdist_egg(Command):
|
|||||||
if self.plat_name is None:
|
if self.plat_name is None:
|
||||||
self.plat_name = get_build_platform()
|
self.plat_name = get_build_platform()
|
||||||
|
|
||||||
self.set_undefined_options('bdist',('dist_dir', 'dist_dir'))
|
self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
|
||||||
|
|
||||||
if self.egg_output is None:
|
if self.egg_output is None:
|
||||||
|
|
||||||
@@ -122,32 +107,25 @@ class bdist_egg(Command):
|
|||||||
self.distribution.has_ext_modules() and self.plat_name
|
self.distribution.has_ext_modules() and self.plat_name
|
||||||
).egg_name()
|
).egg_name()
|
||||||
|
|
||||||
self.egg_output = os.path.join(self.dist_dir, basename+'.egg')
|
self.egg_output = os.path.join(self.dist_dir, basename + '.egg')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def do_install_data(self):
|
def do_install_data(self):
|
||||||
# Hack for packages that install data to install's --install-lib
|
# Hack for packages that install data to install's --install-lib
|
||||||
self.get_finalized_command('install').install_lib = self.bdist_dir
|
self.get_finalized_command('install').install_lib = self.bdist_dir
|
||||||
|
|
||||||
site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
|
site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
|
||||||
old, self.distribution.data_files = self.distribution.data_files,[]
|
old, self.distribution.data_files = self.distribution.data_files, []
|
||||||
|
|
||||||
for item in old:
|
for item in old:
|
||||||
if isinstance(item,tuple) and len(item)==2:
|
if isinstance(item, tuple) and len(item) == 2:
|
||||||
if os.path.isabs(item[0]):
|
if os.path.isabs(item[0]):
|
||||||
realpath = os.path.realpath(item[0])
|
realpath = os.path.realpath(item[0])
|
||||||
normalized = os.path.normcase(realpath)
|
normalized = os.path.normcase(realpath)
|
||||||
if normalized==site_packages or normalized.startswith(
|
if normalized == site_packages or normalized.startswith(
|
||||||
site_packages+os.sep
|
site_packages + os.sep
|
||||||
):
|
):
|
||||||
item = realpath[len(site_packages)+1:], item[1]
|
item = realpath[len(site_packages) + 1:], item[1]
|
||||||
# XXX else: raise ???
|
# XXX else: raise ???
|
||||||
self.distribution.data_files.append(item)
|
self.distribution.data_files.append(item)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -156,22 +134,19 @@ class bdist_egg(Command):
|
|||||||
finally:
|
finally:
|
||||||
self.distribution.data_files = old
|
self.distribution.data_files = old
|
||||||
|
|
||||||
|
|
||||||
def get_outputs(self):
|
def get_outputs(self):
|
||||||
return [self.egg_output]
|
return [self.egg_output]
|
||||||
|
|
||||||
|
def call_command(self, cmdname, **kw):
|
||||||
def call_command(self,cmdname,**kw):
|
|
||||||
"""Invoke reinitialized command `cmdname` with keyword args"""
|
"""Invoke reinitialized command `cmdname` with keyword args"""
|
||||||
for dirname in INSTALL_DIRECTORY_ATTRS:
|
for dirname in INSTALL_DIRECTORY_ATTRS:
|
||||||
kw.setdefault(dirname,self.bdist_dir)
|
kw.setdefault(dirname, self.bdist_dir)
|
||||||
kw.setdefault('skip_build',self.skip_build)
|
kw.setdefault('skip_build', self.skip_build)
|
||||||
kw.setdefault('dry_run', self.dry_run)
|
kw.setdefault('dry_run', self.dry_run)
|
||||||
cmd = self.reinitialize_command(cmdname, **kw)
|
cmd = self.reinitialize_command(cmdname, **kw)
|
||||||
self.run_command(cmdname)
|
self.run_command(cmdname)
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# Generate metadata first
|
# Generate metadata first
|
||||||
self.run_command("egg_info")
|
self.run_command("egg_info")
|
||||||
@@ -179,7 +154,8 @@ class bdist_egg(Command):
|
|||||||
# pull their data path from the install_lib command.
|
# pull their data path from the install_lib command.
|
||||||
log.info("installing library code to %s" % self.bdist_dir)
|
log.info("installing library code to %s" % self.bdist_dir)
|
||||||
instcmd = self.get_finalized_command('install')
|
instcmd = self.get_finalized_command('install')
|
||||||
old_root = instcmd.root; instcmd.root = None
|
old_root = instcmd.root
|
||||||
|
instcmd.root = None
|
||||||
if self.distribution.has_c_libraries() and not self.skip_build:
|
if self.distribution.has_c_libraries() and not self.skip_build:
|
||||||
self.run_command('build_clib')
|
self.run_command('build_clib')
|
||||||
cmd = self.call_command('install_lib', warn_dir=0)
|
cmd = self.call_command('install_lib', warn_dir=0)
|
||||||
@@ -188,17 +164,17 @@ class bdist_egg(Command):
|
|||||||
all_outputs, ext_outputs = self.get_ext_outputs()
|
all_outputs, ext_outputs = self.get_ext_outputs()
|
||||||
self.stubs = []
|
self.stubs = []
|
||||||
to_compile = []
|
to_compile = []
|
||||||
for (p,ext_name) in enumerate(ext_outputs):
|
for (p, ext_name) in enumerate(ext_outputs):
|
||||||
filename,ext = os.path.splitext(ext_name)
|
filename, ext = os.path.splitext(ext_name)
|
||||||
pyfile = os.path.join(self.bdist_dir, strip_module(filename)+'.py')
|
pyfile = os.path.join(self.bdist_dir, strip_module(filename) +
|
||||||
|
'.py')
|
||||||
self.stubs.append(pyfile)
|
self.stubs.append(pyfile)
|
||||||
log.info("creating stub loader for %s" % ext_name)
|
log.info("creating stub loader for %s" % ext_name)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
write_stub(os.path.basename(ext_name), pyfile)
|
write_stub(os.path.basename(ext_name), pyfile)
|
||||||
to_compile.append(pyfile)
|
to_compile.append(pyfile)
|
||||||
ext_outputs[p] = ext_name.replace(os.sep,'/')
|
ext_outputs[p] = ext_name.replace(os.sep, '/')
|
||||||
|
|
||||||
to_compile.extend(self.make_init_files())
|
|
||||||
if to_compile:
|
if to_compile:
|
||||||
cmd.byte_compile(to_compile)
|
cmd.byte_compile(to_compile)
|
||||||
if self.distribution.data_files:
|
if self.distribution.data_files:
|
||||||
@@ -206,12 +182,13 @@ class bdist_egg(Command):
|
|||||||
|
|
||||||
# Make the EGG-INFO directory
|
# Make the EGG-INFO directory
|
||||||
archive_root = self.bdist_dir
|
archive_root = self.bdist_dir
|
||||||
egg_info = os.path.join(archive_root,'EGG-INFO')
|
egg_info = os.path.join(archive_root, 'EGG-INFO')
|
||||||
self.mkpath(egg_info)
|
self.mkpath(egg_info)
|
||||||
if self.distribution.scripts:
|
if self.distribution.scripts:
|
||||||
script_dir = os.path.join(egg_info, 'scripts')
|
script_dir = os.path.join(egg_info, 'scripts')
|
||||||
log.info("installing scripts to %s" % script_dir)
|
log.info("installing scripts to %s" % script_dir)
|
||||||
self.call_command('install_scripts',install_dir=script_dir,no_ep=1)
|
self.call_command('install_scripts', install_dir=script_dir,
|
||||||
|
no_ep=1)
|
||||||
|
|
||||||
self.copy_metadata_to(egg_info)
|
self.copy_metadata_to(egg_info)
|
||||||
native_libs = os.path.join(egg_info, "native_libs.txt")
|
native_libs = os.path.join(egg_info, "native_libs.txt")
|
||||||
@@ -229,10 +206,10 @@ class bdist_egg(Command):
|
|||||||
os.unlink(native_libs)
|
os.unlink(native_libs)
|
||||||
|
|
||||||
write_safety_flag(
|
write_safety_flag(
|
||||||
os.path.join(archive_root,'EGG-INFO'), self.zip_safe()
|
os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()
|
||||||
)
|
)
|
||||||
|
|
||||||
if os.path.exists(os.path.join(self.egg_info,'depends.txt')):
|
if os.path.exists(os.path.join(self.egg_info, 'depends.txt')):
|
||||||
log.warn(
|
log.warn(
|
||||||
"WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
|
"WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
|
||||||
"Use the install_requires/extras_require setup() args instead."
|
"Use the install_requires/extras_require setup() args instead."
|
||||||
@@ -243,61 +220,33 @@ class bdist_egg(Command):
|
|||||||
|
|
||||||
# Make the archive
|
# Make the archive
|
||||||
make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
|
make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
|
||||||
dry_run=self.dry_run, mode=self.gen_header())
|
dry_run=self.dry_run, mode=self.gen_header())
|
||||||
if not self.keep_temp:
|
if not self.keep_temp:
|
||||||
remove_tree(self.bdist_dir, dry_run=self.dry_run)
|
remove_tree(self.bdist_dir, dry_run=self.dry_run)
|
||||||
|
|
||||||
# Add to 'Distribution.dist_files' so that the "upload" command works
|
# Add to 'Distribution.dist_files' so that the "upload" command works
|
||||||
getattr(self.distribution,'dist_files',[]).append(
|
getattr(self.distribution, 'dist_files', []).append(
|
||||||
('bdist_egg',get_python_version(),self.egg_output))
|
('bdist_egg', get_python_version(), self.egg_output))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def zap_pyfiles(self):
|
def zap_pyfiles(self):
|
||||||
log.info("Removing .py files from temporary directory")
|
log.info("Removing .py files from temporary directory")
|
||||||
for base,dirs,files in walk_egg(self.bdist_dir):
|
for base, dirs, files in walk_egg(self.bdist_dir):
|
||||||
for name in files:
|
for name in files:
|
||||||
if name.endswith('.py'):
|
if name.endswith('.py'):
|
||||||
path = os.path.join(base,name)
|
path = os.path.join(base, name)
|
||||||
log.debug("Deleting %s", path)
|
log.debug("Deleting %s", path)
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
|
|
||||||
def zip_safe(self):
|
def zip_safe(self):
|
||||||
safe = getattr(self.distribution,'zip_safe',None)
|
safe = getattr(self.distribution, 'zip_safe', None)
|
||||||
if safe is not None:
|
if safe is not None:
|
||||||
return safe
|
return safe
|
||||||
log.warn("zip_safe flag not set; analyzing archive contents...")
|
log.warn("zip_safe flag not set; analyzing archive contents...")
|
||||||
return analyze_egg(self.bdist_dir, self.stubs)
|
return analyze_egg(self.bdist_dir, self.stubs)
|
||||||
|
|
||||||
def make_init_files(self):
|
|
||||||
"""Create missing package __init__ files"""
|
|
||||||
init_files = []
|
|
||||||
for base,dirs,files in walk_egg(self.bdist_dir):
|
|
||||||
if base==self.bdist_dir:
|
|
||||||
# don't put an __init__ in the root
|
|
||||||
continue
|
|
||||||
for name in files:
|
|
||||||
if name.endswith('.py'):
|
|
||||||
if '__init__.py' not in files:
|
|
||||||
pkg = base[len(self.bdist_dir)+1:].replace(os.sep,'.')
|
|
||||||
if self.distribution.has_contents_for(pkg):
|
|
||||||
log.warn("Creating missing __init__.py for %s",pkg)
|
|
||||||
filename = os.path.join(base,'__init__.py')
|
|
||||||
if not self.dry_run:
|
|
||||||
f = open(filename,'w'); f.write(NS_PKG_STUB)
|
|
||||||
f.close()
|
|
||||||
init_files.append(filename)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# not a package, don't traverse to subdirectories
|
|
||||||
dirs[:] = []
|
|
||||||
|
|
||||||
return init_files
|
|
||||||
|
|
||||||
def gen_header(self):
|
def gen_header(self):
|
||||||
epm = EntryPoint.parse_map(self.distribution.entry_points or '')
|
epm = EntryPoint.parse_map(self.distribution.entry_points or '')
|
||||||
ep = epm.get('setuptools.installation',{}).get('eggsecutable')
|
ep = epm.get('setuptools.installation', {}).get('eggsecutable')
|
||||||
if ep is None:
|
if ep is None:
|
||||||
return 'w' # not an eggsecutable, do it the usual way.
|
return 'w' # not an eggsecutable, do it the usual way.
|
||||||
|
|
||||||
@@ -325,7 +274,6 @@ class bdist_egg(Command):
|
|||||||
' echo Please rename it back to %(basename)s and try again.\n'
|
' echo Please rename it back to %(basename)s and try again.\n'
|
||||||
' exec false\n'
|
' exec false\n'
|
||||||
'fi\n'
|
'fi\n'
|
||||||
|
|
||||||
) % locals()
|
) % locals()
|
||||||
|
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
@@ -335,13 +283,12 @@ class bdist_egg(Command):
|
|||||||
f.close()
|
f.close()
|
||||||
return 'a'
|
return 'a'
|
||||||
|
|
||||||
|
|
||||||
def copy_metadata_to(self, target_dir):
|
def copy_metadata_to(self, target_dir):
|
||||||
"Copy metadata (egg info) to the target_dir"
|
"Copy metadata (egg info) to the target_dir"
|
||||||
# normalize the path (so that a forward-slash in egg_info will
|
# normalize the path (so that a forward-slash in egg_info will
|
||||||
# match using startswith below)
|
# match using startswith below)
|
||||||
norm_egg_info = os.path.normpath(self.egg_info)
|
norm_egg_info = os.path.normpath(self.egg_info)
|
||||||
prefix = os.path.join(norm_egg_info,'')
|
prefix = os.path.join(norm_egg_info, '')
|
||||||
for path in self.ei_cmd.filelist.files:
|
for path in self.ei_cmd.filelist.files:
|
||||||
if path.startswith(prefix):
|
if path.startswith(prefix):
|
||||||
target = os.path.join(target_dir, path[len(prefix):])
|
target = os.path.join(target_dir, path[len(prefix):])
|
||||||
@@ -354,23 +301,24 @@ class bdist_egg(Command):
|
|||||||
all_outputs = []
|
all_outputs = []
|
||||||
ext_outputs = []
|
ext_outputs = []
|
||||||
|
|
||||||
paths = {self.bdist_dir:''}
|
paths = {self.bdist_dir: ''}
|
||||||
for base, dirs, files in os.walk(self.bdist_dir):
|
for base, dirs, files in os.walk(self.bdist_dir):
|
||||||
for filename in files:
|
for filename in files:
|
||||||
if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
|
if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
|
||||||
all_outputs.append(paths[base]+filename)
|
all_outputs.append(paths[base] + filename)
|
||||||
for filename in dirs:
|
for filename in dirs:
|
||||||
paths[os.path.join(base,filename)] = paths[base]+filename+'/'
|
paths[os.path.join(base, filename)] = (paths[base] +
|
||||||
|
filename + '/')
|
||||||
|
|
||||||
if self.distribution.has_ext_modules():
|
if self.distribution.has_ext_modules():
|
||||||
build_cmd = self.get_finalized_command('build_ext')
|
build_cmd = self.get_finalized_command('build_ext')
|
||||||
for ext in build_cmd.extensions:
|
for ext in build_cmd.extensions:
|
||||||
if isinstance(ext,Library):
|
if isinstance(ext, Library):
|
||||||
continue
|
continue
|
||||||
fullname = build_cmd.get_ext_fullname(ext.name)
|
fullname = build_cmd.get_ext_fullname(ext.name)
|
||||||
filename = build_cmd.get_ext_filename(fullname)
|
filename = build_cmd.get_ext_filename(fullname)
|
||||||
if not os.path.basename(filename).startswith('dl-'):
|
if not os.path.basename(filename).startswith('dl-'):
|
||||||
if os.path.exists(os.path.join(self.bdist_dir,filename)):
|
if os.path.exists(os.path.join(self.bdist_dir, filename)):
|
||||||
ext_outputs.append(filename)
|
ext_outputs.append(filename)
|
||||||
|
|
||||||
return all_outputs, ext_outputs
|
return all_outputs, ext_outputs
|
||||||
@@ -379,24 +327,24 @@ class bdist_egg(Command):
|
|||||||
NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
|
NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def walk_egg(egg_dir):
|
def walk_egg(egg_dir):
|
||||||
"""Walk an unpacked egg's contents, skipping the metadata directory"""
|
"""Walk an unpacked egg's contents, skipping the metadata directory"""
|
||||||
walker = os.walk(egg_dir)
|
walker = os.walk(egg_dir)
|
||||||
base,dirs,files = next(walker)
|
base, dirs, files = next(walker)
|
||||||
if 'EGG-INFO' in dirs:
|
if 'EGG-INFO' in dirs:
|
||||||
dirs.remove('EGG-INFO')
|
dirs.remove('EGG-INFO')
|
||||||
yield base,dirs,files
|
yield base, dirs, files
|
||||||
for bdf in walker:
|
for bdf in walker:
|
||||||
yield bdf
|
yield bdf
|
||||||
|
|
||||||
|
|
||||||
def analyze_egg(egg_dir, stubs):
|
def analyze_egg(egg_dir, stubs):
|
||||||
# check for existing flag in EGG-INFO
|
# check for existing flag in EGG-INFO
|
||||||
for flag,fn in safety_flags.items():
|
for flag, fn in safety_flags.items():
|
||||||
if os.path.exists(os.path.join(egg_dir,'EGG-INFO',fn)):
|
if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)):
|
||||||
return flag
|
return flag
|
||||||
if not can_scan(): return False
|
if not can_scan():
|
||||||
|
return False
|
||||||
safe = True
|
safe = True
|
||||||
for base, dirs, files in walk_egg(egg_dir):
|
for base, dirs, files in walk_egg(egg_dir):
|
||||||
for name in files:
|
for name in files:
|
||||||
@@ -407,35 +355,42 @@ def analyze_egg(egg_dir, stubs):
|
|||||||
safe = scan_module(egg_dir, base, name, stubs) and safe
|
safe = scan_module(egg_dir, base, name, stubs) and safe
|
||||||
return safe
|
return safe
|
||||||
|
|
||||||
|
|
||||||
def write_safety_flag(egg_dir, safe):
|
def write_safety_flag(egg_dir, safe):
|
||||||
# Write or remove zip safety flag file(s)
|
# Write or remove zip safety flag file(s)
|
||||||
for flag,fn in safety_flags.items():
|
for flag, fn in safety_flags.items():
|
||||||
fn = os.path.join(egg_dir, fn)
|
fn = os.path.join(egg_dir, fn)
|
||||||
if os.path.exists(fn):
|
if os.path.exists(fn):
|
||||||
if safe is None or bool(safe) != flag:
|
if safe is None or bool(safe) != flag:
|
||||||
os.unlink(fn)
|
os.unlink(fn)
|
||||||
elif safe is not None and bool(safe)==flag:
|
elif safe is not None and bool(safe) == flag:
|
||||||
f=open(fn,'wt'); f.write('\n'); f.close()
|
f = open(fn, 'wt')
|
||||||
|
f.write('\n')
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
safety_flags = {
|
safety_flags = {
|
||||||
True: 'zip-safe',
|
True: 'zip-safe',
|
||||||
False: 'not-zip-safe',
|
False: 'not-zip-safe',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def scan_module(egg_dir, base, name, stubs):
|
def scan_module(egg_dir, base, name, stubs):
|
||||||
"""Check whether module possibly uses unsafe-for-zipfile stuff"""
|
"""Check whether module possibly uses unsafe-for-zipfile stuff"""
|
||||||
|
|
||||||
filename = os.path.join(base,name)
|
filename = os.path.join(base, name)
|
||||||
if filename[:-1] in stubs:
|
if filename[:-1] in stubs:
|
||||||
return True # Extension module
|
return True # Extension module
|
||||||
pkg = base[len(egg_dir)+1:].replace(os.sep,'.')
|
pkg = base[len(egg_dir) + 1:].replace(os.sep, '.')
|
||||||
module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0]
|
module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
|
||||||
if sys.version_info < (3, 3):
|
if sys.version_info < (3, 3):
|
||||||
skip = 8 # skip magic & date
|
skip = 8 # skip magic & date
|
||||||
else:
|
else:
|
||||||
skip = 12 # skip magic & date & file size
|
skip = 12 # skip magic & date & file size
|
||||||
f = open(filename,'rb'); f.read(skip)
|
f = open(filename, 'rb')
|
||||||
code = marshal.load(f); f.close()
|
f.read(skip)
|
||||||
|
code = marshal.load(f)
|
||||||
|
f.close()
|
||||||
safe = True
|
safe = True
|
||||||
symbols = dict.fromkeys(iter_symbols(code))
|
symbols = dict.fromkeys(iter_symbols(code))
|
||||||
for bad in ['__file__', '__path__']:
|
for bad in ['__file__', '__path__']:
|
||||||
@@ -452,21 +407,24 @@ def scan_module(egg_dir, base, name, stubs):
|
|||||||
log.warn("%s: module MAY be using inspect.%s", module, bad)
|
log.warn("%s: module MAY be using inspect.%s", module, bad)
|
||||||
safe = False
|
safe = False
|
||||||
if '__name__' in symbols and '__main__' in symbols and '.' not in module:
|
if '__name__' in symbols and '__main__' in symbols and '.' not in module:
|
||||||
if sys.version[:3]=="2.4": # -m works w/zipfiles in 2.5
|
if sys.version[:3] == "2.4": # -m works w/zipfiles in 2.5
|
||||||
log.warn("%s: top-level module may be 'python -m' script", module)
|
log.warn("%s: top-level module may be 'python -m' script", module)
|
||||||
safe = False
|
safe = False
|
||||||
return safe
|
return safe
|
||||||
|
|
||||||
|
|
||||||
def iter_symbols(code):
|
def iter_symbols(code):
|
||||||
"""Yield names and strings used by `code` and its nested code objects"""
|
"""Yield names and strings used by `code` and its nested code objects"""
|
||||||
for name in code.co_names: yield name
|
for name in code.co_names:
|
||||||
|
yield name
|
||||||
for const in code.co_consts:
|
for const in code.co_consts:
|
||||||
if isinstance(const,basestring):
|
if isinstance(const, basestring):
|
||||||
yield const
|
yield const
|
||||||
elif isinstance(const,CodeType):
|
elif isinstance(const, CodeType):
|
||||||
for name in iter_symbols(const):
|
for name in iter_symbols(const):
|
||||||
yield name
|
yield name
|
||||||
|
|
||||||
|
|
||||||
def can_scan():
|
def can_scan():
|
||||||
if not sys.platform.startswith('java') and sys.platform != 'cli':
|
if not sys.platform.startswith('java') and sys.platform != 'cli':
|
||||||
# CPython, PyPy, etc.
|
# CPython, PyPy, etc.
|
||||||
@@ -475,39 +433,6 @@ def can_scan():
|
|||||||
log.warn("Please ask the author to include a 'zip_safe'"
|
log.warn("Please ask the author to include a 'zip_safe'"
|
||||||
" setting (either True or False) in the package's setup.py")
|
" setting (either True or False) in the package's setup.py")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Attribute names of options for commands that might need to be convinced to
|
# Attribute names of options for commands that might need to be convinced to
|
||||||
# install to the egg build directory
|
# install to the egg build directory
|
||||||
|
|
||||||
@@ -515,9 +440,9 @@ INSTALL_DIRECTORY_ATTRS = [
|
|||||||
'install_lib', 'install_dir', 'install_data', 'install_base'
|
'install_lib', 'install_dir', 'install_data', 'install_base'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
|
def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
|
||||||
mode='w'
|
mode='w'):
|
||||||
):
|
|
||||||
"""Create a zip file from all the files under 'base_dir'. The output
|
"""Create a zip file from all the files under 'base_dir'. The output
|
||||||
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
|
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
|
||||||
Python module (if available) or the InfoZIP "zip" utility (if installed
|
Python module (if available) or the InfoZIP "zip" utility (if installed
|
||||||
@@ -525,6 +450,7 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
|
|||||||
raises DistutilsExecError. Returns the name of the output zip file.
|
raises DistutilsExecError. Returns the name of the output zip file.
|
||||||
"""
|
"""
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
|
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
|
||||||
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
|
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
|
||||||
|
|
||||||
@@ -532,13 +458,14 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
|
|||||||
for name in names:
|
for name in names:
|
||||||
path = os.path.normpath(os.path.join(dirname, name))
|
path = os.path.normpath(os.path.join(dirname, name))
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
p = path[len(base_dir)+1:]
|
p = path[len(base_dir) + 1:]
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
z.write(path, p)
|
z.write(path, p)
|
||||||
log.debug("adding '%s'" % p)
|
log.debug("adding '%s'" % p)
|
||||||
|
|
||||||
if compress is None:
|
if compress is None:
|
||||||
compress = (sys.version>="2.4") # avoid 2.3 zipimport bug when 64 bits
|
# avoid 2.3 zipimport bug when 64 bits
|
||||||
|
compress = (sys.version >= "2.4")
|
||||||
|
|
||||||
compression = [zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED][bool(compress)]
|
compression = [zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED][bool(compress)]
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
@@ -550,4 +477,3 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
|
|||||||
for dirname, dirs, files in os.walk(base_dir):
|
for dirname, dirs, files in os.walk(base_dir):
|
||||||
visit(None, dirname, files)
|
visit(None, dirname, files)
|
||||||
return zip_filename
|
return zip_filename
|
||||||
#
|
|
||||||
|
|||||||
@@ -1,51 +1,30 @@
|
|||||||
# This is just a kludge so that bdist_rpm doesn't guess wrong about the
|
import distutils.command.bdist_rpm as orig
|
||||||
# distribution name and version, if the egg_info command is going to alter
|
|
||||||
# them, another kludge to allow you to build old-style non-egg RPMs, and
|
|
||||||
# finally, a kludge to track .rpm files for uploading when run on Python <2.5.
|
|
||||||
|
|
||||||
from distutils.command.bdist_rpm import bdist_rpm as _bdist_rpm
|
|
||||||
import sys, os
|
|
||||||
|
|
||||||
class bdist_rpm(_bdist_rpm):
|
class bdist_rpm(orig.bdist_rpm):
|
||||||
|
"""
|
||||||
|
Override the default bdist_rpm behavior to do the following:
|
||||||
|
|
||||||
def initialize_options(self):
|
1. Run egg_info to ensure the name and version are properly calculated.
|
||||||
_bdist_rpm.initialize_options(self)
|
2. Always run 'install' using --single-version-externally-managed to
|
||||||
self.no_egg = None
|
disable eggs in RPM distributions.
|
||||||
|
3. Replace dash with underscore in the version numbers for better RPM
|
||||||
if sys.version<"2.5":
|
compatibility.
|
||||||
# Track for uploading any .rpm file(s) moved to self.dist_dir
|
"""
|
||||||
def move_file(self, src, dst, level=1):
|
|
||||||
_bdist_rpm.move_file(self, src, dst, level)
|
|
||||||
if dst==self.dist_dir and src.endswith('.rpm'):
|
|
||||||
getattr(self.distribution,'dist_files',[]).append(
|
|
||||||
('bdist_rpm',
|
|
||||||
src.endswith('.src.rpm') and 'any' or sys.version[:3],
|
|
||||||
os.path.join(dst, os.path.basename(src)))
|
|
||||||
)
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.run_command('egg_info') # ensure distro name is up-to-date
|
# ensure distro name is up-to-date
|
||||||
_bdist_rpm.run(self)
|
self.run_command('egg_info')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
orig.bdist_rpm.run(self)
|
||||||
|
|
||||||
def _make_spec_file(self):
|
def _make_spec_file(self):
|
||||||
version = self.distribution.get_version()
|
version = self.distribution.get_version()
|
||||||
rpmversion = version.replace('-','_')
|
rpmversion = version.replace('-', '_')
|
||||||
spec = _bdist_rpm._make_spec_file(self)
|
spec = orig.bdist_rpm._make_spec_file(self)
|
||||||
line23 = '%define version '+version
|
line23 = '%define version ' + version
|
||||||
line24 = '%define version '+rpmversion
|
line24 = '%define version ' + rpmversion
|
||||||
spec = [
|
spec = [
|
||||||
line.replace(
|
line.replace(
|
||||||
"Source0: %{name}-%{version}.tar",
|
"Source0: %{name}-%{version}.tar",
|
||||||
"Source0: %{name}-%{unmangled_version}.tar"
|
"Source0: %{name}-%{unmangled_version}.tar"
|
||||||
@@ -55,28 +34,10 @@ class bdist_rpm(_bdist_rpm):
|
|||||||
).replace(
|
).replace(
|
||||||
"%setup",
|
"%setup",
|
||||||
"%setup -n %{name}-%{unmangled_version}"
|
"%setup -n %{name}-%{unmangled_version}"
|
||||||
).replace(line23,line24)
|
).replace(line23, line24)
|
||||||
for line in spec
|
for line in spec
|
||||||
]
|
]
|
||||||
spec.insert(spec.index(line24)+1, "%define unmangled_version "+version)
|
insert_loc = spec.index(line24) + 1
|
||||||
|
unmangled_version = "%define unmangled_version " + version
|
||||||
|
spec.insert(insert_loc, unmangled_version)
|
||||||
return spec
|
return spec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,82 +1,21 @@
|
|||||||
from distutils.command.bdist_wininst import bdist_wininst as _bdist_wininst
|
import distutils.command.bdist_wininst as orig
|
||||||
import os, sys
|
|
||||||
|
|
||||||
class bdist_wininst(_bdist_wininst):
|
|
||||||
_good_upload = _bad_upload = None
|
|
||||||
|
|
||||||
def create_exe(self, arcname, fullname, bitmap=None):
|
class bdist_wininst(orig.bdist_wininst):
|
||||||
_bdist_wininst.create_exe(self, arcname, fullname, bitmap)
|
def reinitialize_command(self, command, reinit_subcommands=0):
|
||||||
installer_name = self.get_installer_filename(fullname)
|
"""
|
||||||
if self.target_version:
|
Supplement reinitialize_command to work around
|
||||||
pyversion = self.target_version
|
http://bugs.python.org/issue20819
|
||||||
# fix 2.5+ bdist_wininst ignoring --target-version spec
|
"""
|
||||||
self._bad_upload = ('bdist_wininst', 'any', installer_name)
|
|
||||||
else:
|
|
||||||
pyversion = 'any'
|
|
||||||
self._good_upload = ('bdist_wininst', pyversion, installer_name)
|
|
||||||
|
|
||||||
def _fix_upload_names(self):
|
|
||||||
good, bad = self._good_upload, self._bad_upload
|
|
||||||
dist_files = getattr(self.distribution, 'dist_files', [])
|
|
||||||
if bad in dist_files:
|
|
||||||
dist_files.remove(bad)
|
|
||||||
if good not in dist_files:
|
|
||||||
dist_files.append(good)
|
|
||||||
|
|
||||||
def reinitialize_command (self, command, reinit_subcommands=0):
|
|
||||||
cmd = self.distribution.reinitialize_command(
|
cmd = self.distribution.reinitialize_command(
|
||||||
command, reinit_subcommands)
|
command, reinit_subcommands)
|
||||||
if command in ('install', 'install_lib'):
|
if command in ('install', 'install_lib'):
|
||||||
cmd.install_lib = None # work around distutils bug
|
cmd.install_lib = None
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self._is_running = True
|
self._is_running = True
|
||||||
try:
|
try:
|
||||||
_bdist_wininst.run(self)
|
orig.bdist_wininst.run(self)
|
||||||
self._fix_upload_names()
|
|
||||||
finally:
|
finally:
|
||||||
self._is_running = False
|
self._is_running = False
|
||||||
|
|
||||||
|
|
||||||
if not hasattr(_bdist_wininst, 'get_installer_filename'):
|
|
||||||
def get_installer_filename(self, fullname):
|
|
||||||
# Factored out to allow overriding in subclasses
|
|
||||||
if self.target_version:
|
|
||||||
# if we create an installer for a specific python version,
|
|
||||||
# it's better to include this in the name
|
|
||||||
installer_name = os.path.join(self.dist_dir,
|
|
||||||
"%s.win32-py%s.exe" %
|
|
||||||
(fullname, self.target_version))
|
|
||||||
else:
|
|
||||||
installer_name = os.path.join(self.dist_dir,
|
|
||||||
"%s.win32.exe" % fullname)
|
|
||||||
return installer_name
|
|
||||||
# get_installer_filename()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,30 @@
|
|||||||
from distutils.command.build_ext import build_ext as _du_build_ext
|
from distutils.command.build_ext import build_ext as _du_build_ext
|
||||||
|
from distutils.file_util import copy_file
|
||||||
|
from distutils.ccompiler import new_compiler
|
||||||
|
from distutils.sysconfig import customize_compiler
|
||||||
|
from distutils.errors import DistutilsError
|
||||||
|
from distutils import log
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
from setuptools.extension import Library
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Attempt to use Pyrex for building extensions, if available
|
# Attempt to use Pyrex for building extensions, if available
|
||||||
from Pyrex.Distutils.build_ext import build_ext as _build_ext
|
from Pyrex.Distutils.build_ext import build_ext as _build_ext
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_build_ext = _du_build_ext
|
_build_ext = _du_build_ext
|
||||||
|
|
||||||
import os, sys
|
|
||||||
from distutils.file_util import copy_file
|
|
||||||
from setuptools.extension import Library
|
|
||||||
from distutils.ccompiler import new_compiler
|
|
||||||
from distutils.sysconfig import customize_compiler
|
|
||||||
try:
|
try:
|
||||||
# Python 2.7 or >=3.2
|
# Python 2.7 or >=3.2
|
||||||
from sysconfig import _CONFIG_VARS
|
from sysconfig import _CONFIG_VARS
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from distutils.sysconfig import get_config_var
|
from distutils.sysconfig import get_config_var
|
||||||
|
|
||||||
get_config_var("LDSHARED") # make sure _config_vars is initialized
|
get_config_var("LDSHARED") # make sure _config_vars is initialized
|
||||||
del get_config_var
|
del get_config_var
|
||||||
from distutils.sysconfig import _config_vars as _CONFIG_VARS
|
from distutils.sysconfig import _config_vars as _CONFIG_VARS
|
||||||
from distutils import log
|
|
||||||
from distutils.errors import *
|
|
||||||
|
|
||||||
have_rtld = False
|
have_rtld = False
|
||||||
use_stubs = False
|
use_stubs = False
|
||||||
@@ -29,20 +34,13 @@ if sys.platform == "darwin":
|
|||||||
use_stubs = True
|
use_stubs = True
|
||||||
elif os.name != 'nt':
|
elif os.name != 'nt':
|
||||||
try:
|
try:
|
||||||
from dl import RTLD_NOW
|
import dl
|
||||||
have_rtld = True
|
use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW')
|
||||||
use_stubs = True
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def if_dl(s):
|
|
||||||
if have_rtld:
|
|
||||||
return s
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if_dl = lambda s: s if have_rtld else ''
|
||||||
|
|
||||||
|
|
||||||
class build_ext(_build_ext):
|
class build_ext(_build_ext):
|
||||||
@@ -62,8 +60,9 @@ class build_ext(_build_ext):
|
|||||||
modpath = fullname.split('.')
|
modpath = fullname.split('.')
|
||||||
package = '.'.join(modpath[:-1])
|
package = '.'.join(modpath[:-1])
|
||||||
package_dir = build_py.get_package_dir(package)
|
package_dir = build_py.get_package_dir(package)
|
||||||
dest_filename = os.path.join(package_dir,os.path.basename(filename))
|
dest_filename = os.path.join(package_dir,
|
||||||
src_filename = os.path.join(self.build_lib,filename)
|
os.path.basename(filename))
|
||||||
|
src_filename = os.path.join(self.build_lib, filename)
|
||||||
|
|
||||||
# Always copy, even if source is older than destination, to ensure
|
# Always copy, even if source is older than destination, to ensure
|
||||||
# that the right extensions for the current Python/platform are
|
# that the right extensions for the current Python/platform are
|
||||||
@@ -75,8 +74,8 @@ class build_ext(_build_ext):
|
|||||||
if ext._needs_stub:
|
if ext._needs_stub:
|
||||||
self.write_stub(package_dir or os.curdir, ext, True)
|
self.write_stub(package_dir or os.curdir, ext, True)
|
||||||
|
|
||||||
|
if _build_ext is not _du_build_ext and not hasattr(_build_ext,
|
||||||
if _build_ext is not _du_build_ext and not hasattr(_build_ext,'pyrex_sources'):
|
'pyrex_sources'):
|
||||||
# Workaround for problems using some Pyrex versions w/SWIG and/or 2.4
|
# Workaround for problems using some Pyrex versions w/SWIG and/or 2.4
|
||||||
def swig_sources(self, sources, *otherargs):
|
def swig_sources(self, sources, *otherargs):
|
||||||
# first do any Pyrex processing
|
# first do any Pyrex processing
|
||||||
@@ -84,18 +83,16 @@ class build_ext(_build_ext):
|
|||||||
# Then do any actual SWIG stuff on the remainder
|
# Then do any actual SWIG stuff on the remainder
|
||||||
return _du_build_ext.swig_sources(self, sources, *otherargs)
|
return _du_build_ext.swig_sources(self, sources, *otherargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_ext_filename(self, fullname):
|
def get_ext_filename(self, fullname):
|
||||||
filename = _build_ext.get_ext_filename(self,fullname)
|
filename = _build_ext.get_ext_filename(self, fullname)
|
||||||
if fullname in self.ext_map:
|
if fullname in self.ext_map:
|
||||||
ext = self.ext_map[fullname]
|
ext = self.ext_map[fullname]
|
||||||
if isinstance(ext,Library):
|
if isinstance(ext, Library):
|
||||||
fn, ext = os.path.splitext(filename)
|
fn, ext = os.path.splitext(filename)
|
||||||
return self.shlib_compiler.library_filename(fn,libtype)
|
return self.shlib_compiler.library_filename(fn, libtype)
|
||||||
elif use_stubs and ext._links_to_dynamic:
|
elif use_stubs and ext._links_to_dynamic:
|
||||||
d,fn = os.path.split(filename)
|
d, fn = os.path.split(filename)
|
||||||
return os.path.join(d,'dl-'+fn)
|
return os.path.join(d, 'dl-' + fn)
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
@@ -109,7 +106,7 @@ class build_ext(_build_ext):
|
|||||||
self.extensions = self.extensions or []
|
self.extensions = self.extensions or []
|
||||||
self.check_extensions_list(self.extensions)
|
self.check_extensions_list(self.extensions)
|
||||||
self.shlibs = [ext for ext in self.extensions
|
self.shlibs = [ext for ext in self.extensions
|
||||||
if isinstance(ext,Library)]
|
if isinstance(ext, Library)]
|
||||||
if self.shlibs:
|
if self.shlibs:
|
||||||
self.setup_shlib_compiler()
|
self.setup_shlib_compiler()
|
||||||
for ext in self.extensions:
|
for ext in self.extensions:
|
||||||
@@ -122,11 +119,12 @@ class build_ext(_build_ext):
|
|||||||
# XXX what to do with conflicts?
|
# XXX what to do with conflicts?
|
||||||
self.ext_map[fullname.split('.')[-1]] = ext
|
self.ext_map[fullname.split('.')[-1]] = ext
|
||||||
|
|
||||||
ltd = ext._links_to_dynamic = \
|
ltd = self.shlibs and self.links_to_dynamic(ext) or False
|
||||||
self.shlibs and self.links_to_dynamic(ext) or False
|
ns = ltd and use_stubs and not isinstance(ext, Library)
|
||||||
ext._needs_stub = ltd and use_stubs and not isinstance(ext,Library)
|
ext._links_to_dynamic = ltd
|
||||||
|
ext._needs_stub = ns
|
||||||
filename = ext._file_name = self.get_ext_filename(fullname)
|
filename = ext._file_name = self.get_ext_filename(fullname)
|
||||||
libdir = os.path.dirname(os.path.join(self.build_lib,filename))
|
libdir = os.path.dirname(os.path.join(self.build_lib, filename))
|
||||||
if ltd and libdir not in ext.library_dirs:
|
if ltd and libdir not in ext.library_dirs:
|
||||||
ext.library_dirs.append(libdir)
|
ext.library_dirs.append(libdir)
|
||||||
if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
|
if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
|
||||||
@@ -140,7 +138,8 @@ class build_ext(_build_ext):
|
|||||||
tmp = _CONFIG_VARS.copy()
|
tmp = _CONFIG_VARS.copy()
|
||||||
try:
|
try:
|
||||||
# XXX Help! I don't have any idea whether these are right...
|
# XXX Help! I don't have any idea whether these are right...
|
||||||
_CONFIG_VARS['LDSHARED'] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup"
|
_CONFIG_VARS['LDSHARED'] = (
|
||||||
|
"gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")
|
||||||
_CONFIG_VARS['CCSHARED'] = " -dynamiclib"
|
_CONFIG_VARS['CCSHARED'] = " -dynamiclib"
|
||||||
_CONFIG_VARS['SO'] = ".dylib"
|
_CONFIG_VARS['SO'] = ".dylib"
|
||||||
customize_compiler(compiler)
|
customize_compiler(compiler)
|
||||||
@@ -154,7 +153,7 @@ class build_ext(_build_ext):
|
|||||||
compiler.set_include_dirs(self.include_dirs)
|
compiler.set_include_dirs(self.include_dirs)
|
||||||
if self.define is not None:
|
if self.define is not None:
|
||||||
# 'define' option is a list of (name,value) tuples
|
# 'define' option is a list of (name,value) tuples
|
||||||
for (name,value) in self.define:
|
for (name, value) in self.define:
|
||||||
compiler.define_macro(name, value)
|
compiler.define_macro(name, value)
|
||||||
if self.undef is not None:
|
if self.undef is not None:
|
||||||
for macro in self.undef:
|
for macro in self.undef:
|
||||||
@@ -171,23 +170,20 @@ class build_ext(_build_ext):
|
|||||||
# hack so distutils' build_extension() builds a library instead
|
# hack so distutils' build_extension() builds a library instead
|
||||||
compiler.link_shared_object = link_shared_object.__get__(compiler)
|
compiler.link_shared_object = link_shared_object.__get__(compiler)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_export_symbols(self, ext):
|
def get_export_symbols(self, ext):
|
||||||
if isinstance(ext,Library):
|
if isinstance(ext, Library):
|
||||||
return ext.export_symbols
|
return ext.export_symbols
|
||||||
return _build_ext.get_export_symbols(self,ext)
|
return _build_ext.get_export_symbols(self, ext)
|
||||||
|
|
||||||
def build_extension(self, ext):
|
def build_extension(self, ext):
|
||||||
_compiler = self.compiler
|
_compiler = self.compiler
|
||||||
try:
|
try:
|
||||||
if isinstance(ext,Library):
|
if isinstance(ext, Library):
|
||||||
self.compiler = self.shlib_compiler
|
self.compiler = self.shlib_compiler
|
||||||
_build_ext.build_extension(self,ext)
|
_build_ext.build_extension(self, ext)
|
||||||
if ext._needs_stub:
|
if ext._needs_stub:
|
||||||
self.write_stub(
|
cmd = self.get_finalized_command('build_py').build_lib
|
||||||
self.get_finalized_command('build_py').build_lib, ext
|
self.write_stub(cmd, ext)
|
||||||
)
|
|
||||||
finally:
|
finally:
|
||||||
self.compiler = _compiler
|
self.compiler = _compiler
|
||||||
|
|
||||||
@@ -197,54 +193,66 @@ class build_ext(_build_ext):
|
|||||||
# XXX as dynamic, and not just using a locally-found version or a
|
# XXX as dynamic, and not just using a locally-found version or a
|
||||||
# XXX static-compiled version
|
# XXX static-compiled version
|
||||||
libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
|
libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
|
||||||
pkg = '.'.join(ext._full_name.split('.')[:-1]+[''])
|
pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])
|
||||||
for libname in ext.libraries:
|
return any(pkg + libname in libnames for libname in ext.libraries)
|
||||||
if pkg+libname in libnames: return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_outputs(self):
|
def get_outputs(self):
|
||||||
outputs = _build_ext.get_outputs(self)
|
return _build_ext.get_outputs(self) + self.__get_stubs_outputs()
|
||||||
optimize = self.get_finalized_command('build_py').optimize
|
|
||||||
for ext in self.extensions:
|
def __get_stubs_outputs(self):
|
||||||
if ext._needs_stub:
|
# assemble the base name for each extension that needs a stub
|
||||||
base = os.path.join(self.build_lib, *ext._full_name.split('.'))
|
ns_ext_bases = (
|
||||||
outputs.append(base+'.py')
|
os.path.join(self.build_lib, *ext._full_name.split('.'))
|
||||||
outputs.append(base+'.pyc')
|
for ext in self.extensions
|
||||||
if optimize:
|
if ext._needs_stub
|
||||||
outputs.append(base+'.pyo')
|
)
|
||||||
return outputs
|
# pair each base with the extension
|
||||||
|
pairs = itertools.product(ns_ext_bases, self.__get_output_extensions())
|
||||||
|
return list(base + fnext for base, fnext in pairs)
|
||||||
|
|
||||||
|
def __get_output_extensions(self):
|
||||||
|
yield '.py'
|
||||||
|
yield '.pyc'
|
||||||
|
if self.get_finalized_command('build_py').optimize:
|
||||||
|
yield '.pyo'
|
||||||
|
|
||||||
def write_stub(self, output_dir, ext, compile=False):
|
def write_stub(self, output_dir, ext, compile=False):
|
||||||
log.info("writing stub loader for %s to %s",ext._full_name, output_dir)
|
log.info("writing stub loader for %s to %s", ext._full_name,
|
||||||
stub_file = os.path.join(output_dir, *ext._full_name.split('.'))+'.py'
|
output_dir)
|
||||||
|
stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) +
|
||||||
|
'.py')
|
||||||
if compile and os.path.exists(stub_file):
|
if compile and os.path.exists(stub_file):
|
||||||
raise DistutilsError(stub_file+" already exists! Please delete.")
|
raise DistutilsError(stub_file + " already exists! Please delete.")
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
f = open(stub_file,'w')
|
f = open(stub_file, 'w')
|
||||||
f.write('\n'.join([
|
f.write(
|
||||||
"def __bootstrap__():",
|
'\n'.join([
|
||||||
" global __bootstrap__, __file__, __loader__",
|
"def __bootstrap__():",
|
||||||
" import sys, os, pkg_resources, imp"+if_dl(", dl"),
|
" global __bootstrap__, __file__, __loader__",
|
||||||
" __file__ = pkg_resources.resource_filename(__name__,%r)"
|
" import sys, os, pkg_resources, imp" + if_dl(", dl"),
|
||||||
% os.path.basename(ext._file_name),
|
" __file__ = pkg_resources.resource_filename"
|
||||||
" del __bootstrap__",
|
"(__name__,%r)"
|
||||||
" if '__loader__' in globals():",
|
% os.path.basename(ext._file_name),
|
||||||
" del __loader__",
|
" del __bootstrap__",
|
||||||
if_dl(" old_flags = sys.getdlopenflags()"),
|
" if '__loader__' in globals():",
|
||||||
" old_dir = os.getcwd()",
|
" del __loader__",
|
||||||
" try:",
|
if_dl(" old_flags = sys.getdlopenflags()"),
|
||||||
" os.chdir(os.path.dirname(__file__))",
|
" old_dir = os.getcwd()",
|
||||||
if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),
|
" try:",
|
||||||
" imp.load_dynamic(__name__,__file__)",
|
" os.chdir(os.path.dirname(__file__))",
|
||||||
" finally:",
|
if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),
|
||||||
if_dl(" sys.setdlopenflags(old_flags)"),
|
" imp.load_dynamic(__name__,__file__)",
|
||||||
" os.chdir(old_dir)",
|
" finally:",
|
||||||
"__bootstrap__()",
|
if_dl(" sys.setdlopenflags(old_flags)"),
|
||||||
"" # terminal \n
|
" os.chdir(old_dir)",
|
||||||
]))
|
"__bootstrap__()",
|
||||||
|
"" # terminal \n
|
||||||
|
])
|
||||||
|
)
|
||||||
f.close()
|
f.close()
|
||||||
if compile:
|
if compile:
|
||||||
from distutils.util import byte_compile
|
from distutils.util import byte_compile
|
||||||
|
|
||||||
byte_compile([stub_file], optimize=0,
|
byte_compile([stub_file], optimize=0,
|
||||||
force=True, dry_run=self.dry_run)
|
force=True, dry_run=self.dry_run)
|
||||||
optimize = self.get_finalized_command('install_lib').optimize
|
optimize = self.get_finalized_command('install_lib').optimize
|
||||||
@@ -255,14 +263,15 @@ class build_ext(_build_ext):
|
|||||||
os.unlink(stub_file)
|
os.unlink(stub_file)
|
||||||
|
|
||||||
|
|
||||||
if use_stubs or os.name=='nt':
|
if use_stubs or os.name == 'nt':
|
||||||
# Build shared libraries
|
# Build shared libraries
|
||||||
#
|
#
|
||||||
def link_shared_object(self, objects, output_libname, output_dir=None,
|
def link_shared_object(
|
||||||
libraries=None, library_dirs=None, runtime_library_dirs=None,
|
self, objects, output_libname, output_dir=None, libraries=None,
|
||||||
export_symbols=None, debug=0, extra_preargs=None,
|
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
|
||||||
extra_postargs=None, build_temp=None, target_lang=None
|
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
|
||||||
): self.link(
|
target_lang=None):
|
||||||
|
self.link(
|
||||||
self.SHARED_LIBRARY, objects, output_libname,
|
self.SHARED_LIBRARY, objects, output_libname,
|
||||||
output_dir, libraries, library_dirs, runtime_library_dirs,
|
output_dir, libraries, library_dirs, runtime_library_dirs,
|
||||||
export_symbols, debug, extra_preargs, extra_postargs,
|
export_symbols, debug, extra_preargs, extra_postargs,
|
||||||
@@ -272,19 +281,19 @@ else:
|
|||||||
# Build static libraries everywhere else
|
# Build static libraries everywhere else
|
||||||
libtype = 'static'
|
libtype = 'static'
|
||||||
|
|
||||||
def link_shared_object(self, objects, output_libname, output_dir=None,
|
def link_shared_object(
|
||||||
libraries=None, library_dirs=None, runtime_library_dirs=None,
|
self, objects, output_libname, output_dir=None, libraries=None,
|
||||||
export_symbols=None, debug=0, extra_preargs=None,
|
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
|
||||||
extra_postargs=None, build_temp=None, target_lang=None
|
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
|
||||||
):
|
target_lang=None):
|
||||||
# XXX we need to either disallow these attrs on Library instances,
|
# XXX we need to either disallow these attrs on Library instances,
|
||||||
# or warn/abort here if set, or something...
|
# or warn/abort here if set, or something...
|
||||||
#libraries=None, library_dirs=None, runtime_library_dirs=None,
|
# libraries=None, library_dirs=None, runtime_library_dirs=None,
|
||||||
#export_symbols=None, extra_preargs=None, extra_postargs=None,
|
# export_symbols=None, extra_preargs=None, extra_postargs=None,
|
||||||
#build_temp=None
|
# build_temp=None
|
||||||
|
|
||||||
assert output_dir is None # distutils build_ext doesn't pass this
|
assert output_dir is None # distutils build_ext doesn't pass this
|
||||||
output_dir,filename = os.path.split(output_libname)
|
output_dir, filename = os.path.split(output_libname)
|
||||||
basename, ext = os.path.splitext(filename)
|
basename, ext = os.path.splitext(filename)
|
||||||
if self.library_filename("x").startswith('lib'):
|
if self.library_filename("x").startswith('lib'):
|
||||||
# strip 'lib' prefix; this is kludgy if some platform uses
|
# strip 'lib' prefix; this is kludgy if some platform uses
|
||||||
@@ -294,5 +303,3 @@ else:
|
|||||||
self.create_static_lib(
|
self.create_static_lib(
|
||||||
objects, basename, output_dir, debug, target_lang
|
objects, basename, output_dir, debug, target_lang
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
from glob import glob
|
||||||
|
from distutils.util import convert_path
|
||||||
|
import distutils.command.build_py as orig
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import textwrap
|
import textwrap
|
||||||
from distutils.command.build_py import build_py as _build_py
|
|
||||||
from distutils.util import convert_path
|
|
||||||
from glob import glob
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from setuptools.lib2to3_ex import Mixin2to3
|
from setuptools.lib2to3_ex import Mixin2to3
|
||||||
@@ -13,7 +13,8 @@ except ImportError:
|
|||||||
def run_2to3(self, files, doctests=True):
|
def run_2to3(self, files, doctests=True):
|
||||||
"do nothing"
|
"do nothing"
|
||||||
|
|
||||||
class build_py(_build_py, Mixin2to3):
|
|
||||||
|
class build_py(orig.build_py, Mixin2to3):
|
||||||
"""Enhanced 'build_py' command that includes data files with packages
|
"""Enhanced 'build_py' command that includes data files with packages
|
||||||
|
|
||||||
The data files are specified via a 'package_data' argument to 'setup()'.
|
The data files are specified via a 'package_data' argument to 'setup()'.
|
||||||
@@ -22,11 +23,14 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
Also, this version of the 'build_py' command allows you to specify both
|
Also, this version of the 'build_py' command allows you to specify both
|
||||||
'py_modules' and 'packages' in the same setup operation.
|
'py_modules' and 'packages' in the same setup operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
_build_py.finalize_options(self)
|
orig.build_py.finalize_options(self)
|
||||||
self.package_data = self.distribution.package_data
|
self.package_data = self.distribution.package_data
|
||||||
self.exclude_package_data = self.distribution.exclude_package_data or {}
|
self.exclude_package_data = (self.distribution.exclude_package_data or
|
||||||
if 'data_files' in self.__dict__: del self.__dict__['data_files']
|
{})
|
||||||
|
if 'data_files' in self.__dict__:
|
||||||
|
del self.__dict__['data_files']
|
||||||
self.__updated_files = []
|
self.__updated_files = []
|
||||||
self.__doctests_2to3 = []
|
self.__doctests_2to3 = []
|
||||||
|
|
||||||
@@ -48,16 +52,17 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
|
|
||||||
# Only compile actual .py files, using our base class' idea of what our
|
# Only compile actual .py files, using our base class' idea of what our
|
||||||
# output files are.
|
# output files are.
|
||||||
self.byte_compile(_build_py.get_outputs(self, include_bytecode=0))
|
self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if attr=='data_files': # lazily compute data files
|
if attr == 'data_files': # lazily compute data files
|
||||||
self.data_files = files = self._get_data_files()
|
self.data_files = files = self._get_data_files()
|
||||||
return files
|
return files
|
||||||
return _build_py.__getattr__(self,attr)
|
return orig.build_py.__getattr__(self, attr)
|
||||||
|
|
||||||
def build_module(self, module, module_file, package):
|
def build_module(self, module, module_file, package):
|
||||||
outfile, copied = _build_py.build_module(self, module, module_file, package)
|
outfile, copied = orig.build_py.build_module(self, module, module_file,
|
||||||
|
package)
|
||||||
if copied:
|
if copied:
|
||||||
self.__updated_files.append(outfile)
|
self.__updated_files.append(outfile)
|
||||||
return outfile, copied
|
return outfile, copied
|
||||||
@@ -74,12 +79,12 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
|
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
|
||||||
|
|
||||||
# Length of path to strip from found files
|
# Length of path to strip from found files
|
||||||
plen = len(src_dir)+1
|
plen = len(src_dir) + 1
|
||||||
|
|
||||||
# Strip directory from globbed filenames
|
# Strip directory from globbed filenames
|
||||||
filenames = [
|
filenames = [
|
||||||
file[plen:] for file in self.find_data_files(package, src_dir)
|
file[plen:] for file in self.find_data_files(package, src_dir)
|
||||||
]
|
]
|
||||||
data.append((package, src_dir, build_dir, filenames))
|
data.append((package, src_dir, build_dir, filenames))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@@ -102,7 +107,8 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
srcfile = os.path.join(src_dir, filename)
|
srcfile = os.path.join(src_dir, filename)
|
||||||
outf, copied = self.copy_file(srcfile, target)
|
outf, copied = self.copy_file(srcfile, target)
|
||||||
srcfile = os.path.abspath(srcfile)
|
srcfile = os.path.abspath(srcfile)
|
||||||
if copied and srcfile in self.distribution.convert_2to3_doctests:
|
if (copied and
|
||||||
|
srcfile in self.distribution.convert_2to3_doctests):
|
||||||
self.__doctests_2to3.append(outf)
|
self.__doctests_2to3.append(outf)
|
||||||
|
|
||||||
def analyze_manifest(self):
|
def analyze_manifest(self):
|
||||||
@@ -117,21 +123,22 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
self.run_command('egg_info')
|
self.run_command('egg_info')
|
||||||
ei_cmd = self.get_finalized_command('egg_info')
|
ei_cmd = self.get_finalized_command('egg_info')
|
||||||
for path in ei_cmd.filelist.files:
|
for path in ei_cmd.filelist.files:
|
||||||
d,f = os.path.split(assert_relative(path))
|
d, f = os.path.split(assert_relative(path))
|
||||||
prev = None
|
prev = None
|
||||||
oldf = f
|
oldf = f
|
||||||
while d and d!=prev and d not in src_dirs:
|
while d and d != prev and d not in src_dirs:
|
||||||
prev = d
|
prev = d
|
||||||
d, df = os.path.split(d)
|
d, df = os.path.split(d)
|
||||||
f = os.path.join(df, f)
|
f = os.path.join(df, f)
|
||||||
if d in src_dirs:
|
if d in src_dirs:
|
||||||
if path.endswith('.py') and f==oldf:
|
if path.endswith('.py') and f == oldf:
|
||||||
continue # it's a module, not data
|
continue # it's a module, not data
|
||||||
mf.setdefault(src_dirs[d],[]).append(path)
|
mf.setdefault(src_dirs[d], []).append(path)
|
||||||
|
|
||||||
def get_data_files(self): pass # kludge 2.4 for lazy computation
|
def get_data_files(self):
|
||||||
|
pass # kludge 2.4 for lazy computation
|
||||||
|
|
||||||
if sys.version<"2.4": # Python 2.4 already has this code
|
if sys.version < "2.4": # Python 2.4 already has this code
|
||||||
def get_outputs(self, include_bytecode=1):
|
def get_outputs(self, include_bytecode=1):
|
||||||
"""Return complete list of files copied to the build directory
|
"""Return complete list of files copied to the build directory
|
||||||
|
|
||||||
@@ -140,11 +147,11 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
needed for the 'install_lib' command to do its job properly, and to
|
needed for the 'install_lib' command to do its job properly, and to
|
||||||
generate a correct installation manifest.)
|
generate a correct installation manifest.)
|
||||||
"""
|
"""
|
||||||
return _build_py.get_outputs(self, include_bytecode) + [
|
return orig.build_py.get_outputs(self, include_bytecode) + [
|
||||||
os.path.join(build_dir, filename)
|
os.path.join(build_dir, filename)
|
||||||
for package, src_dir, build_dir,filenames in self.data_files
|
for package, src_dir, build_dir, filenames in self.data_files
|
||||||
for filename in filenames
|
for filename in filenames
|
||||||
]
|
]
|
||||||
|
|
||||||
def check_package(self, package, package_dir):
|
def check_package(self, package, package_dir):
|
||||||
"""Check namespace packages' __init__ for declare_namespace"""
|
"""Check namespace packages' __init__ for declare_namespace"""
|
||||||
@@ -153,36 +160,37 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
init_py = _build_py.check_package(self, package, package_dir)
|
init_py = orig.build_py.check_package(self, package, package_dir)
|
||||||
self.packages_checked[package] = init_py
|
self.packages_checked[package] = init_py
|
||||||
|
|
||||||
if not init_py or not self.distribution.namespace_packages:
|
if not init_py or not self.distribution.namespace_packages:
|
||||||
return init_py
|
return init_py
|
||||||
|
|
||||||
for pkg in self.distribution.namespace_packages:
|
for pkg in self.distribution.namespace_packages:
|
||||||
if pkg==package or pkg.startswith(package+'.'):
|
if pkg == package or pkg.startswith(package + '.'):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
return init_py
|
return init_py
|
||||||
|
|
||||||
f = open(init_py,'rbU')
|
f = open(init_py, 'rbU')
|
||||||
if 'declare_namespace'.encode() not in f.read():
|
if 'declare_namespace'.encode() not in f.read():
|
||||||
from distutils import log
|
from distutils.errors import DistutilsError
|
||||||
log.warn(
|
|
||||||
"WARNING: %s is a namespace package, but its __init__.py does\n"
|
raise DistutilsError(
|
||||||
"not declare_namespace(); setuptools 0.7 will REQUIRE this!\n"
|
"Namespace package problem: %s is a namespace package, but "
|
||||||
'(See the setuptools manual under "Namespace Packages" for '
|
"its\n__init__.py does not call declare_namespace()! Please "
|
||||||
"details.)\n", package
|
'fix it.\n(See the setuptools manual under '
|
||||||
|
'"Namespace Packages" for details.)\n"' % (package,)
|
||||||
)
|
)
|
||||||
f.close()
|
f.close()
|
||||||
return init_py
|
return init_py
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
self.packages_checked={}
|
self.packages_checked = {}
|
||||||
_build_py.initialize_options(self)
|
orig.build_py.initialize_options(self)
|
||||||
|
|
||||||
def get_package_dir(self, package):
|
def get_package_dir(self, package):
|
||||||
res = _build_py.get_package_dir(self, package)
|
res = orig.build_py.get_package_dir(self, package)
|
||||||
if self.distribution.src_root is not None:
|
if self.distribution.src_root is not None:
|
||||||
return os.path.join(self.distribution.src_root, res)
|
return os.path.join(self.distribution.src_root, res)
|
||||||
return res
|
return res
|
||||||
@@ -202,7 +210,7 @@ class build_py(_build_py, Mixin2to3):
|
|||||||
seen = {}
|
seen = {}
|
||||||
return [
|
return [
|
||||||
f for f in files if f not in bad
|
f for f in files if f not in bad
|
||||||
and f not in seen and seen.setdefault(f,1) # ditch dupes
|
and f not in seen and seen.setdefault(f, 1) # ditch dupes
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -210,6 +218,7 @@ def assert_relative(path):
|
|||||||
if not os.path.isabs(path):
|
if not os.path.isabs(path):
|
||||||
return path
|
return path
|
||||||
from distutils.errors import DistutilsSetupError
|
from distutils.errors import DistutilsSetupError
|
||||||
|
|
||||||
msg = textwrap.dedent("""
|
msg = textwrap.dedent("""
|
||||||
Error: setup script specifies an absolute path:
|
Error: setup script specifies an absolute path:
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
from setuptools.command.easy_install import easy_install
|
from distutils.util import convert_path
|
||||||
from distutils.util import convert_path, subst_vars
|
|
||||||
from pkg_resources import Distribution, PathMetadata, normalize_path
|
|
||||||
from distutils import log
|
from distutils import log
|
||||||
from distutils.errors import DistutilsError, DistutilsOptionError
|
from distutils.errors import DistutilsError, DistutilsOptionError
|
||||||
import os, sys, setuptools, glob
|
import os
|
||||||
|
import glob
|
||||||
|
|
||||||
|
from pkg_resources import Distribution, PathMetadata, normalize_path
|
||||||
|
from setuptools.command.easy_install import easy_install
|
||||||
|
from setuptools.compat import PY3
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
|
||||||
class develop(easy_install):
|
class develop(easy_install):
|
||||||
"""Set up package for development"""
|
"""Set up package for development"""
|
||||||
@@ -32,59 +37,56 @@ class develop(easy_install):
|
|||||||
self.egg_path = None
|
self.egg_path = None
|
||||||
easy_install.initialize_options(self)
|
easy_install.initialize_options(self)
|
||||||
self.setup_path = None
|
self.setup_path = None
|
||||||
self.always_copy_from = '.' # always copy eggs installed in curdir
|
self.always_copy_from = '.' # always copy eggs installed in curdir
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
ei = self.get_finalized_command("egg_info")
|
ei = self.get_finalized_command("egg_info")
|
||||||
if ei.broken_egg_info:
|
if ei.broken_egg_info:
|
||||||
raise DistutilsError(
|
template = "Please rename %r to %r before using 'develop'"
|
||||||
"Please rename %r to %r before using 'develop'"
|
args = ei.egg_info, ei.broken_egg_info
|
||||||
% (ei.egg_info, ei.broken_egg_info)
|
raise DistutilsError(template % args)
|
||||||
)
|
|
||||||
self.args = [ei.egg_name]
|
self.args = [ei.egg_name]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
easy_install.finalize_options(self)
|
easy_install.finalize_options(self)
|
||||||
self.expand_basedirs()
|
self.expand_basedirs()
|
||||||
self.expand_dirs()
|
self.expand_dirs()
|
||||||
# pick up setup-dir .egg files only: no .egg-info
|
# pick up setup-dir .egg files only: no .egg-info
|
||||||
self.package_index.scan(glob.glob('*.egg'))
|
self.package_index.scan(glob.glob('*.egg'))
|
||||||
|
|
||||||
self.egg_link = os.path.join(self.install_dir, ei.egg_name+'.egg-link')
|
self.egg_link = os.path.join(self.install_dir, ei.egg_name +
|
||||||
|
'.egg-link')
|
||||||
self.egg_base = ei.egg_base
|
self.egg_base = ei.egg_base
|
||||||
if self.egg_path is None:
|
if self.egg_path is None:
|
||||||
self.egg_path = os.path.abspath(ei.egg_base)
|
self.egg_path = os.path.abspath(ei.egg_base)
|
||||||
|
|
||||||
target = normalize_path(self.egg_base)
|
target = normalize_path(self.egg_base)
|
||||||
if normalize_path(os.path.join(self.install_dir, self.egg_path)) != target:
|
egg_path = normalize_path(os.path.join(self.install_dir,
|
||||||
|
self.egg_path))
|
||||||
|
if egg_path != target:
|
||||||
raise DistutilsOptionError(
|
raise DistutilsOptionError(
|
||||||
"--egg-path must be a relative path from the install"
|
"--egg-path must be a relative path from the install"
|
||||||
" directory to "+target
|
" directory to " + target
|
||||||
)
|
)
|
||||||
|
|
||||||
# Make a distribution for the package's source
|
# Make a distribution for the package's source
|
||||||
self.dist = Distribution(
|
self.dist = Distribution(
|
||||||
target,
|
target,
|
||||||
PathMetadata(target, os.path.abspath(ei.egg_info)),
|
PathMetadata(target, os.path.abspath(ei.egg_info)),
|
||||||
project_name = ei.egg_name
|
project_name=ei.egg_name
|
||||||
)
|
)
|
||||||
|
|
||||||
p = self.egg_base.replace(os.sep,'/')
|
p = self.egg_base.replace(os.sep, '/')
|
||||||
if p!= os.curdir:
|
if p != os.curdir:
|
||||||
p = '../' * (p.count('/')+1)
|
p = '../' * (p.count('/') + 1)
|
||||||
self.setup_path = p
|
self.setup_path = p
|
||||||
p = normalize_path(os.path.join(self.install_dir, self.egg_path, p))
|
p = normalize_path(os.path.join(self.install_dir, self.egg_path, p))
|
||||||
if p != normalize_path(os.curdir):
|
if p != normalize_path(os.curdir):
|
||||||
raise DistutilsOptionError(
|
raise DistutilsOptionError(
|
||||||
"Can't get a consistent path to setup script from"
|
"Can't get a consistent path to setup script from"
|
||||||
" installation directory", p, normalize_path(os.curdir))
|
" installation directory", p, normalize_path(os.curdir))
|
||||||
|
|
||||||
def install_for_development(self):
|
def install_for_development(self):
|
||||||
if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
|
if PY3 and getattr(self.distribution, 'use_2to3', False):
|
||||||
# If we run 2to3 we can not do this inplace:
|
# If we run 2to3 we can not do this inplace:
|
||||||
|
|
||||||
# Ensure metadata is up-to-date
|
# Ensure metadata is up-to-date
|
||||||
@@ -99,12 +101,13 @@ class develop(easy_install):
|
|||||||
|
|
||||||
self.reinitialize_command('build_ext', inplace=0)
|
self.reinitialize_command('build_ext', inplace=0)
|
||||||
self.run_command('build_ext')
|
self.run_command('build_ext')
|
||||||
|
|
||||||
# Fixup egg-link and easy-install.pth
|
# Fixup egg-link and easy-install.pth
|
||||||
ei_cmd = self.get_finalized_command("egg_info")
|
ei_cmd = self.get_finalized_command("egg_info")
|
||||||
self.egg_path = build_path
|
self.egg_path = build_path
|
||||||
self.dist.location = build_path
|
self.dist.location = build_path
|
||||||
self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info) # XXX
|
# XXX
|
||||||
|
self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info)
|
||||||
else:
|
else:
|
||||||
# Without 2to3 inplace works fine:
|
# Without 2to3 inplace works fine:
|
||||||
self.run_command('egg_info')
|
self.run_command('egg_info')
|
||||||
@@ -112,7 +115,7 @@ class develop(easy_install):
|
|||||||
# Build extensions in-place
|
# Build extensions in-place
|
||||||
self.reinitialize_command('build_ext', inplace=1)
|
self.reinitialize_command('build_ext', inplace=1)
|
||||||
self.run_command('build_ext')
|
self.run_command('build_ext')
|
||||||
|
|
||||||
self.install_site_py() # ensure that target dir is site-safe
|
self.install_site_py() # ensure that target dir is site-safe
|
||||||
if setuptools.bootstrap_install_from:
|
if setuptools.bootstrap_install_from:
|
||||||
self.easy_install(setuptools.bootstrap_install_from)
|
self.easy_install(setuptools.bootstrap_install_from)
|
||||||
@@ -121,21 +124,21 @@ class develop(easy_install):
|
|||||||
# create an .egg-link in the installation dir, pointing to our egg
|
# create an .egg-link in the installation dir, pointing to our egg
|
||||||
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
|
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
f = open(self.egg_link,"w")
|
f = open(self.egg_link, "w")
|
||||||
f.write(self.egg_path + "\n" + self.setup_path)
|
f.write(self.egg_path + "\n" + self.setup_path)
|
||||||
f.close()
|
f.close()
|
||||||
# postprocess the installed distro, fixing up .pth, installing scripts,
|
# postprocess the installed distro, fixing up .pth, installing scripts,
|
||||||
# and handling requirements
|
# and handling requirements
|
||||||
self.process_distribution(None, self.dist, not self.no_deps)
|
self.process_distribution(None, self.dist, not self.no_deps)
|
||||||
|
|
||||||
|
|
||||||
def uninstall_link(self):
|
def uninstall_link(self):
|
||||||
if os.path.exists(self.egg_link):
|
if os.path.exists(self.egg_link):
|
||||||
log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
|
log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
|
||||||
egg_link_file = open(self.egg_link)
|
egg_link_file = open(self.egg_link)
|
||||||
contents = [line.rstrip() for line in egg_link_file]
|
contents = [line.rstrip() for line in egg_link_file]
|
||||||
egg_link_file.close()
|
egg_link_file.close()
|
||||||
if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
|
if contents not in ([self.egg_path],
|
||||||
|
[self.egg_path, self.setup_path]):
|
||||||
log.warn("Link points to %s: uninstall aborted", contents)
|
log.warn("Link points to %s: uninstall aborted", contents)
|
||||||
return
|
return
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
@@ -149,7 +152,7 @@ class develop(easy_install):
|
|||||||
def install_egg_scripts(self, dist):
|
def install_egg_scripts(self, dist):
|
||||||
if dist is not self.dist:
|
if dist is not self.dist:
|
||||||
# Installing a dependency, so fall back to normal behavior
|
# Installing a dependency, so fall back to normal behavior
|
||||||
return easy_install.install_egg_scripts(self,dist)
|
return easy_install.install_egg_scripts(self, dist)
|
||||||
|
|
||||||
# create wrapper scripts in the script dir, pointing to dist.scripts
|
# create wrapper scripts in the script dir, pointing to dist.scripts
|
||||||
|
|
||||||
@@ -160,8 +163,7 @@ class develop(easy_install):
|
|||||||
for script_name in self.distribution.scripts or []:
|
for script_name in self.distribution.scripts or []:
|
||||||
script_path = os.path.abspath(convert_path(script_name))
|
script_path = os.path.abspath(convert_path(script_name))
|
||||||
script_name = os.path.basename(script_path)
|
script_name = os.path.basename(script_path)
|
||||||
f = open(script_path,'rU')
|
f = open(script_path, 'rU')
|
||||||
script_text = f.read()
|
script_text = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
self.install_script(dist, script_name, script_text, script_path)
|
self.install_script(dist, script_name, script_text, script_path)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,22 +2,30 @@
|
|||||||
|
|
||||||
Create a distribution's .egg-info directory and contents"""
|
Create a distribution's .egg-info directory and contents"""
|
||||||
|
|
||||||
|
from distutils.filelist import FileList as _FileList
|
||||||
|
from distutils.util import convert_path
|
||||||
|
from distutils import log
|
||||||
|
import distutils.errors
|
||||||
|
import distutils.filelist
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from setuptools import Command
|
try:
|
||||||
import distutils.errors
|
from setuptools_svn import svn_utils
|
||||||
from distutils import log
|
except ImportError:
|
||||||
from setuptools.command.sdist import sdist
|
pass
|
||||||
from setuptools.compat import basestring
|
|
||||||
from setuptools import svn_utils
|
|
||||||
from distutils.util import convert_path
|
|
||||||
from distutils.filelist import FileList as _FileList
|
|
||||||
from pkg_resources import (parse_requirements, safe_name, parse_version,
|
|
||||||
safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
|
|
||||||
from setuptools.command.sdist import walk_revctrl
|
|
||||||
|
|
||||||
|
from setuptools import Command
|
||||||
|
from setuptools.command.sdist import sdist
|
||||||
|
from setuptools.compat import basestring, PY3, StringIO
|
||||||
|
from setuptools.command.sdist import walk_revctrl
|
||||||
|
from pkg_resources import (
|
||||||
|
parse_requirements, safe_name, parse_version,
|
||||||
|
safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
|
||||||
|
import setuptools.unicode_utils as unicode_utils
|
||||||
|
|
||||||
|
from pkg_resources import packaging
|
||||||
|
|
||||||
class egg_info(Command):
|
class egg_info(Command):
|
||||||
description = "create a distribution's .egg-info directory"
|
description = "create a distribution's .egg-info directory"
|
||||||
@@ -26,11 +34,11 @@ class egg_info(Command):
|
|||||||
('egg-base=', 'e', "directory containing .egg-info directories"
|
('egg-base=', 'e', "directory containing .egg-info directories"
|
||||||
" (default: top of the source tree)"),
|
" (default: top of the source tree)"),
|
||||||
('tag-svn-revision', 'r',
|
('tag-svn-revision', 'r',
|
||||||
"Add subversion revision ID to version number"),
|
"Add subversion revision ID to version number"),
|
||||||
('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
|
('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
|
||||||
('tag-build=', 'b', "Specify explicit tag to add to version number"),
|
('tag-build=', 'b', "Specify explicit tag to add to version number"),
|
||||||
('no-svn-revision', 'R',
|
('no-svn-revision', 'R',
|
||||||
"Don't add subversion revision ID [default]"),
|
"Don't add subversion revision ID [default]"),
|
||||||
('no-date', 'D', "Don't include date stamp [default]"),
|
('no-date', 'D', "Don't include date stamp [default]"),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -51,6 +59,7 @@ class egg_info(Command):
|
|||||||
|
|
||||||
def save_version_info(self, filename):
|
def save_version_info(self, filename):
|
||||||
from setuptools.command.setopt import edit_config
|
from setuptools.command.setopt import edit_config
|
||||||
|
|
||||||
values = dict(
|
values = dict(
|
||||||
egg_info=dict(
|
egg_info=dict(
|
||||||
tag_svn_revision=0,
|
tag_svn_revision=0,
|
||||||
@@ -65,25 +74,32 @@ class egg_info(Command):
|
|||||||
self.vtags = self.tags()
|
self.vtags = self.tags()
|
||||||
self.egg_version = self.tagged_version()
|
self.egg_version = self.tagged_version()
|
||||||
|
|
||||||
|
parsed_version = parse_version(self.egg_version)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
is_version = isinstance(parsed_version, packaging.version.Version)
|
||||||
|
spec = (
|
||||||
|
"%s==%s" if is_version else "%s===%s"
|
||||||
|
)
|
||||||
list(
|
list(
|
||||||
parse_requirements('%s==%s' % (self.egg_name,self.egg_version))
|
parse_requirements(spec % (self.egg_name, self.egg_version))
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise distutils.errors.DistutilsOptionError(
|
raise distutils.errors.DistutilsOptionError(
|
||||||
"Invalid distribution name or version syntax: %s-%s" %
|
"Invalid distribution name or version syntax: %s-%s" %
|
||||||
(self.egg_name,self.egg_version)
|
(self.egg_name, self.egg_version)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.egg_base is None:
|
if self.egg_base is None:
|
||||||
dirs = self.distribution.package_dir
|
dirs = self.distribution.package_dir
|
||||||
self.egg_base = (dirs or {}).get('',os.curdir)
|
self.egg_base = (dirs or {}).get('', os.curdir)
|
||||||
|
|
||||||
self.ensure_dirname('egg_base')
|
self.ensure_dirname('egg_base')
|
||||||
self.egg_info = to_filename(self.egg_name)+'.egg-info'
|
self.egg_info = to_filename(self.egg_name) + '.egg-info'
|
||||||
if self.egg_base != os.curdir:
|
if self.egg_base != os.curdir:
|
||||||
self.egg_info = os.path.join(self.egg_base, self.egg_info)
|
self.egg_info = os.path.join(self.egg_base, self.egg_info)
|
||||||
if '-' in self.egg_name: self.check_broken_egg_info()
|
if '-' in self.egg_name:
|
||||||
|
self.check_broken_egg_info()
|
||||||
|
|
||||||
# Set package version for the benefit of dumber commands
|
# Set package version for the benefit of dumber commands
|
||||||
# (e.g. sdist, bdist_wininst, etc.)
|
# (e.g. sdist, bdist_wininst, etc.)
|
||||||
@@ -95,7 +111,7 @@ class egg_info(Command):
|
|||||||
# to the version info
|
# to the version info
|
||||||
#
|
#
|
||||||
pd = self.distribution._patched_dist
|
pd = self.distribution._patched_dist
|
||||||
if pd is not None and pd.key==self.egg_name.lower():
|
if pd is not None and pd.key == self.egg_name.lower():
|
||||||
pd._version = self.egg_version
|
pd._version = self.egg_version
|
||||||
pd._parsed_version = parse_version(self.egg_version)
|
pd._parsed_version = parse_version(self.egg_version)
|
||||||
self.distribution._patched_dist = None
|
self.distribution._patched_dist = None
|
||||||
@@ -127,7 +143,7 @@ class egg_info(Command):
|
|||||||
to the file.
|
to the file.
|
||||||
"""
|
"""
|
||||||
log.info("writing %s to %s", what, filename)
|
log.info("writing %s to %s", what, filename)
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
data = data.encode("utf-8")
|
data = data.encode("utf-8")
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
f = open(filename, 'wb')
|
f = open(filename, 'wb')
|
||||||
@@ -153,7 +169,7 @@ class egg_info(Command):
|
|||||||
installer = self.distribution.fetch_build_egg
|
installer = self.distribution.fetch_build_egg
|
||||||
for ep in iter_entry_points('egg_info.writers'):
|
for ep in iter_entry_points('egg_info.writers'):
|
||||||
writer = ep.load(installer=installer)
|
writer = ep.load(installer=installer)
|
||||||
writer(self, ep.name, os.path.join(self.egg_info,ep.name))
|
writer(self, ep.name, os.path.join(self.egg_info, ep.name))
|
||||||
|
|
||||||
# Get rid of native_libs.txt if it was put there by older bdist_egg
|
# Get rid of native_libs.txt if it was put there by older bdist_egg
|
||||||
nl = os.path.join(self.egg_info, "native_libs.txt")
|
nl = os.path.join(self.egg_info, "native_libs.txt")
|
||||||
@@ -165,68 +181,96 @@ class egg_info(Command):
|
|||||||
def tags(self):
|
def tags(self):
|
||||||
version = ''
|
version = ''
|
||||||
if self.tag_build:
|
if self.tag_build:
|
||||||
version+=self.tag_build
|
version += self.tag_build
|
||||||
if self.tag_svn_revision and (
|
if self.tag_svn_revision:
|
||||||
os.path.exists('.svn') or os.path.exists('PKG-INFO')
|
rev = self.get_svn_revision()
|
||||||
): version += '-r%s' % self.get_svn_revision()
|
if rev: # is 0 if it's not an svn working copy
|
||||||
|
version += '-r%s' % rev
|
||||||
if self.tag_date:
|
if self.tag_date:
|
||||||
import time
|
import time
|
||||||
|
|
||||||
version += time.strftime("-%Y%m%d")
|
version += time.strftime("-%Y%m%d")
|
||||||
return version
|
return version
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_svn_revision():
|
def get_svn_revision():
|
||||||
|
if 'svn_utils' not in globals():
|
||||||
|
return "0"
|
||||||
return str(svn_utils.SvnInfo.load(os.curdir).get_revision())
|
return str(svn_utils.SvnInfo.load(os.curdir).get_revision())
|
||||||
|
|
||||||
def find_sources(self):
|
def find_sources(self):
|
||||||
"""Generate SOURCES.txt manifest file"""
|
"""Generate SOURCES.txt manifest file"""
|
||||||
manifest_filename = os.path.join(self.egg_info,"SOURCES.txt")
|
manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
|
||||||
mm = manifest_maker(self.distribution)
|
mm = manifest_maker(self.distribution)
|
||||||
mm.manifest = manifest_filename
|
mm.manifest = manifest_filename
|
||||||
mm.run()
|
mm.run()
|
||||||
self.filelist = mm.filelist
|
self.filelist = mm.filelist
|
||||||
|
|
||||||
def check_broken_egg_info(self):
|
def check_broken_egg_info(self):
|
||||||
bei = self.egg_name+'.egg-info'
|
bei = self.egg_name + '.egg-info'
|
||||||
if self.egg_base != os.curdir:
|
if self.egg_base != os.curdir:
|
||||||
bei = os.path.join(self.egg_base, bei)
|
bei = os.path.join(self.egg_base, bei)
|
||||||
if os.path.exists(bei):
|
if os.path.exists(bei):
|
||||||
log.warn(
|
log.warn(
|
||||||
"-"*78+'\n'
|
"-" * 78 + '\n'
|
||||||
"Note: Your current .egg-info directory has a '-' in its name;"
|
"Note: Your current .egg-info directory has a '-' in its name;"
|
||||||
'\nthis will not work correctly with "setup.py develop".\n\n'
|
'\nthis will not work correctly with "setup.py develop".\n\n'
|
||||||
'Please rename %s to %s to correct this problem.\n'+'-'*78,
|
'Please rename %s to %s to correct this problem.\n' + '-' * 78,
|
||||||
bei, self.egg_info
|
bei, self.egg_info
|
||||||
)
|
)
|
||||||
self.broken_egg_info = self.egg_info
|
self.broken_egg_info = self.egg_info
|
||||||
self.egg_info = bei # make it work for now
|
self.egg_info = bei # make it work for now
|
||||||
|
|
||||||
|
|
||||||
class FileList(_FileList):
|
class FileList(_FileList):
|
||||||
"""File list that accepts only existing, platform-independent paths"""
|
"""File list that accepts only existing, platform-independent paths"""
|
||||||
|
|
||||||
def append(self, item):
|
def append(self, item):
|
||||||
if item.endswith('\r'): # Fix older sdists built on Windows
|
if item.endswith('\r'): # Fix older sdists built on Windows
|
||||||
item = item[:-1]
|
item = item[:-1]
|
||||||
path = convert_path(item)
|
path = convert_path(item)
|
||||||
|
|
||||||
if sys.version_info >= (3,):
|
if self._safe_path(path):
|
||||||
try:
|
self.files.append(path)
|
||||||
if os.path.exists(path) or os.path.exists(path.encode('utf-8')):
|
|
||||||
self.files.append(path)
|
def extend(self, paths):
|
||||||
except UnicodeEncodeError:
|
self.files.extend(filter(self._safe_path, paths))
|
||||||
# Accept UTF-8 filenames even if LANG=C
|
|
||||||
if os.path.exists(path.encode('utf-8')):
|
def _repair(self):
|
||||||
self.files.append(path)
|
"""
|
||||||
else:
|
Replace self.files with only safe paths
|
||||||
log.warn("'%s' not %s encodable -- skipping", path,
|
|
||||||
sys.getfilesystemencoding())
|
Because some owners of FileList manipulate the underlying
|
||||||
else:
|
``files`` attribute directly, this method must be called to
|
||||||
if os.path.exists(path):
|
repair those paths.
|
||||||
self.files.append(path)
|
"""
|
||||||
|
self.files = list(filter(self._safe_path, self.files))
|
||||||
|
|
||||||
|
def _safe_path(self, path):
|
||||||
|
enc_warn = "'%s' not %s encodable -- skipping"
|
||||||
|
|
||||||
|
# To avoid accidental trans-codings errors, first to unicode
|
||||||
|
u_path = unicode_utils.filesys_decode(path)
|
||||||
|
if u_path is None:
|
||||||
|
log.warn("'%s' in unexpected encoding -- skipping" % path)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Must ensure utf-8 encodability
|
||||||
|
utf8_path = unicode_utils.try_encode(u_path, "utf-8")
|
||||||
|
if utf8_path is None:
|
||||||
|
log.warn(enc_warn, path, 'utf-8')
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# accept is either way checks out
|
||||||
|
if os.path.exists(u_path) or os.path.exists(utf8_path):
|
||||||
|
return True
|
||||||
|
# this will catch any encode errors decoding u_path
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
log.warn(enc_warn, path, sys.getfilesystemencoding())
|
||||||
|
|
||||||
|
|
||||||
class manifest_maker(sdist):
|
class manifest_maker(sdist):
|
||||||
|
|
||||||
template = "MANIFEST.in"
|
template = "MANIFEST.in"
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
@@ -241,7 +285,7 @@ class manifest_maker(sdist):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.filelist = FileList()
|
self.filelist = FileList()
|
||||||
if not os.path.exists(self.manifest):
|
if not os.path.exists(self.manifest):
|
||||||
self.write_manifest() # it must exist so it'll get in the list
|
self.write_manifest() # it must exist so it'll get in the list
|
||||||
self.filelist.findall()
|
self.filelist.findall()
|
||||||
self.add_defaults()
|
self.add_defaults()
|
||||||
if os.path.exists(self.template):
|
if os.path.exists(self.template):
|
||||||
@@ -251,30 +295,23 @@ class manifest_maker(sdist):
|
|||||||
self.filelist.remove_duplicates()
|
self.filelist.remove_duplicates()
|
||||||
self.write_manifest()
|
self.write_manifest()
|
||||||
|
|
||||||
|
def _manifest_normalize(self, path):
|
||||||
|
path = unicode_utils.filesys_decode(path)
|
||||||
|
return path.replace(os.sep, '/')
|
||||||
|
|
||||||
def write_manifest(self):
|
def write_manifest(self):
|
||||||
"""Write the file list in 'self.filelist' (presumably as filled in
|
"""
|
||||||
by 'add_defaults()' and 'read_template()') to the manifest file
|
Write the file list in 'self.filelist' to the manifest file
|
||||||
named by 'self.manifest'.
|
named by 'self.manifest'.
|
||||||
"""
|
"""
|
||||||
# The manifest must be UTF-8 encodable. See #303.
|
self.filelist._repair()
|
||||||
if sys.version_info >= (3,):
|
|
||||||
files = []
|
|
||||||
for file in self.filelist.files:
|
|
||||||
try:
|
|
||||||
file.encode("utf-8")
|
|
||||||
except UnicodeEncodeError:
|
|
||||||
log.warn("'%s' not UTF-8 encodable -- skipping" % file)
|
|
||||||
else:
|
|
||||||
files.append(file)
|
|
||||||
self.filelist.files = files
|
|
||||||
|
|
||||||
files = self.filelist.files
|
# Now _repairs should encodability, but not unicode
|
||||||
if os.sep!='/':
|
files = [self._manifest_normalize(f) for f in self.filelist.files]
|
||||||
files = [f.replace(os.sep,'/') for f in files]
|
msg = "writing manifest file '%s'" % self.manifest
|
||||||
self.execute(write_file, (self.manifest, files),
|
self.execute(write_file, (self.manifest, files), msg)
|
||||||
"writing manifest file '%s'" % self.manifest)
|
|
||||||
|
|
||||||
def warn(self, msg): # suppress missing-file warnings from sdist
|
def warn(self, msg): # suppress missing-file warnings from sdist
|
||||||
if not msg.startswith("standard file not found:"):
|
if not msg.startswith("standard file not found:"):
|
||||||
sdist.warn(self, msg)
|
sdist.warn(self, msg)
|
||||||
|
|
||||||
@@ -288,15 +325,41 @@ class manifest_maker(sdist):
|
|||||||
elif os.path.exists(self.manifest):
|
elif os.path.exists(self.manifest):
|
||||||
self.read_manifest()
|
self.read_manifest()
|
||||||
ei_cmd = self.get_finalized_command('egg_info')
|
ei_cmd = self.get_finalized_command('egg_info')
|
||||||
|
self._add_egg_info(cmd=ei_cmd)
|
||||||
self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
|
self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
|
||||||
|
|
||||||
|
def _add_egg_info(self, cmd):
|
||||||
|
"""
|
||||||
|
Add paths for egg-info files for an external egg-base.
|
||||||
|
|
||||||
|
The egg-info files are written to egg-base. If egg-base is
|
||||||
|
outside the current working directory, this method
|
||||||
|
searchs the egg-base directory for files to include
|
||||||
|
in the manifest. Uses distutils.filelist.findall (which is
|
||||||
|
really the version monkeypatched in by setuptools/__init__.py)
|
||||||
|
to perform the search.
|
||||||
|
|
||||||
|
Since findall records relative paths, prefix the returned
|
||||||
|
paths with cmd.egg_base, so add_default's include_pattern call
|
||||||
|
(which is looking for the absolute cmd.egg_info) will match
|
||||||
|
them.
|
||||||
|
"""
|
||||||
|
if cmd.egg_base == os.curdir:
|
||||||
|
# egg-info files were already added by something else
|
||||||
|
return
|
||||||
|
|
||||||
|
discovered = distutils.filelist.findall(cmd.egg_base)
|
||||||
|
resolved = (os.path.join(cmd.egg_base, path) for path in discovered)
|
||||||
|
self.filelist.allfiles.extend(resolved)
|
||||||
|
|
||||||
def prune_file_list(self):
|
def prune_file_list(self):
|
||||||
build = self.get_finalized_command('build')
|
build = self.get_finalized_command('build')
|
||||||
base_dir = self.distribution.get_fullname()
|
base_dir = self.distribution.get_fullname()
|
||||||
self.filelist.exclude_pattern(None, prefix=build.build_base)
|
self.filelist.exclude_pattern(None, prefix=build.build_base)
|
||||||
self.filelist.exclude_pattern(None, prefix=base_dir)
|
self.filelist.exclude_pattern(None, prefix=base_dir)
|
||||||
sep = re.escape(os.sep)
|
sep = re.escape(os.sep)
|
||||||
self.filelist.exclude_pattern(sep+r'(RCS|CVS|\.svn)'+sep, is_regex=1)
|
self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
|
||||||
|
is_regex=1)
|
||||||
|
|
||||||
|
|
||||||
def write_file(filename, contents):
|
def write_file(filename, contents):
|
||||||
@@ -304,11 +367,13 @@ def write_file(filename, contents):
|
|||||||
sequence of strings without line terminators) to it.
|
sequence of strings without line terminators) to it.
|
||||||
"""
|
"""
|
||||||
contents = "\n".join(contents)
|
contents = "\n".join(contents)
|
||||||
if sys.version_info >= (3,):
|
|
||||||
contents = contents.encode("utf-8")
|
# assuming the contents has been vetted for utf-8 encoding
|
||||||
f = open(filename, "wb") # always write POSIX-style manifest
|
contents = contents.encode("utf-8")
|
||||||
f.write(contents)
|
|
||||||
f.close()
|
with open(filename, "wb") as f: # always write POSIX-style manifest
|
||||||
|
f.write(contents)
|
||||||
|
|
||||||
|
|
||||||
def write_pkg_info(cmd, basename, filename):
|
def write_pkg_info(cmd, basename, filename):
|
||||||
log.info("writing %s", filename)
|
log.info("writing %s", filename)
|
||||||
@@ -323,10 +388,12 @@ def write_pkg_info(cmd, basename, filename):
|
|||||||
finally:
|
finally:
|
||||||
metadata.name, metadata.version = oldname, oldver
|
metadata.name, metadata.version = oldname, oldver
|
||||||
|
|
||||||
safe = getattr(cmd.distribution,'zip_safe',None)
|
safe = getattr(cmd.distribution, 'zip_safe', None)
|
||||||
from setuptools.command import bdist_egg
|
from setuptools.command import bdist_egg
|
||||||
|
|
||||||
bdist_egg.write_safety_flag(cmd.egg_info, safe)
|
bdist_egg.write_safety_flag(cmd.egg_info, safe)
|
||||||
|
|
||||||
|
|
||||||
def warn_depends_obsolete(cmd, basename, filename):
|
def warn_depends_obsolete(cmd, basename, filename):
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
log.warn(
|
log.warn(
|
||||||
@@ -335,55 +402,75 @@ def warn_depends_obsolete(cmd, basename, filename):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_requirements(stream, reqs):
|
||||||
|
lines = yield_lines(reqs or ())
|
||||||
|
append_cr = lambda line: line + '\n'
|
||||||
|
lines = map(append_cr, lines)
|
||||||
|
stream.writelines(lines)
|
||||||
|
|
||||||
|
|
||||||
def write_requirements(cmd, basename, filename):
|
def write_requirements(cmd, basename, filename):
|
||||||
dist = cmd.distribution
|
dist = cmd.distribution
|
||||||
data = ['\n'.join(yield_lines(dist.install_requires or ()))]
|
data = StringIO()
|
||||||
for extra,reqs in (dist.extras_require or {}).items():
|
_write_requirements(data, dist.install_requires)
|
||||||
data.append('\n\n[%s]\n%s' % (extra, '\n'.join(yield_lines(reqs))))
|
extras_require = dist.extras_require or {}
|
||||||
cmd.write_or_delete_file("requirements", filename, ''.join(data))
|
for extra in sorted(extras_require):
|
||||||
|
data.write('\n[{extra}]\n'.format(**vars()))
|
||||||
|
_write_requirements(data, extras_require[extra])
|
||||||
|
cmd.write_or_delete_file("requirements", filename, data.getvalue())
|
||||||
|
|
||||||
|
|
||||||
|
def write_setup_requirements(cmd, basename, filename):
|
||||||
|
data = StringIO()
|
||||||
|
_write_requirements(data, cmd.distribution.setup_requires)
|
||||||
|
cmd.write_or_delete_file("setup-requirements", filename, data.getvalue())
|
||||||
|
|
||||||
|
|
||||||
def write_toplevel_names(cmd, basename, filename):
|
def write_toplevel_names(cmd, basename, filename):
|
||||||
pkgs = dict.fromkeys(
|
pkgs = dict.fromkeys(
|
||||||
[
|
[
|
||||||
k.split('.',1)[0]
|
k.split('.', 1)[0]
|
||||||
for k in cmd.distribution.iter_distribution_names()
|
for k in cmd.distribution.iter_distribution_names()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
cmd.write_file("top-level names", filename, '\n'.join(pkgs)+'\n')
|
cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n')
|
||||||
|
|
||||||
|
|
||||||
def overwrite_arg(cmd, basename, filename):
|
def overwrite_arg(cmd, basename, filename):
|
||||||
write_arg(cmd, basename, filename, True)
|
write_arg(cmd, basename, filename, True)
|
||||||
|
|
||||||
|
|
||||||
def write_arg(cmd, basename, filename, force=False):
|
def write_arg(cmd, basename, filename, force=False):
|
||||||
argname = os.path.splitext(basename)[0]
|
argname = os.path.splitext(basename)[0]
|
||||||
value = getattr(cmd.distribution, argname, None)
|
value = getattr(cmd.distribution, argname, None)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
value = '\n'.join(value)+'\n'
|
value = '\n'.join(value) + '\n'
|
||||||
cmd.write_or_delete_file(argname, filename, value, force)
|
cmd.write_or_delete_file(argname, filename, value, force)
|
||||||
|
|
||||||
|
|
||||||
def write_entries(cmd, basename, filename):
|
def write_entries(cmd, basename, filename):
|
||||||
ep = cmd.distribution.entry_points
|
ep = cmd.distribution.entry_points
|
||||||
|
|
||||||
if isinstance(ep,basestring) or ep is None:
|
if isinstance(ep, basestring) or ep is None:
|
||||||
data = ep
|
data = ep
|
||||||
elif ep is not None:
|
elif ep is not None:
|
||||||
data = []
|
data = []
|
||||||
for section, contents in ep.items():
|
for section, contents in sorted(ep.items()):
|
||||||
if not isinstance(contents,basestring):
|
if not isinstance(contents, basestring):
|
||||||
contents = EntryPoint.parse_group(section, contents)
|
contents = EntryPoint.parse_group(section, contents)
|
||||||
contents = '\n'.join(map(str,contents.values()))
|
contents = '\n'.join(sorted(map(str, contents.values())))
|
||||||
data.append('[%s]\n%s\n\n' % (section,contents))
|
data.append('[%s]\n%s\n\n' % (section, contents))
|
||||||
data = ''.join(data)
|
data = ''.join(data)
|
||||||
|
|
||||||
cmd.write_or_delete_file('entry points', filename, data, True)
|
cmd.write_or_delete_file('entry points', filename, data, True)
|
||||||
|
|
||||||
|
|
||||||
def get_pkg_info_revision():
|
def get_pkg_info_revision():
|
||||||
# See if we can get a -r### off of PKG-INFO, in case this is an sdist of
|
# See if we can get a -r### off of PKG-INFO, in case this is an sdist of
|
||||||
# a subversion revision
|
# a subversion revision
|
||||||
#
|
#
|
||||||
if os.path.exists('PKG-INFO'):
|
if os.path.exists('PKG-INFO'):
|
||||||
f = open('PKG-INFO','rU')
|
f = open('PKG-INFO', 'rU')
|
||||||
for line in f:
|
for line in f:
|
||||||
match = re.match(r"Version:.*-r(\d+)\s*$", line)
|
match = re.match(r"Version:.*-r(\d+)\s*$", line)
|
||||||
if match:
|
if match:
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
import setuptools
|
|
||||||
import sys
|
|
||||||
import glob
|
|
||||||
from distutils.command.install import install as _install
|
|
||||||
from distutils.errors import DistutilsArgError
|
from distutils.errors import DistutilsArgError
|
||||||
|
import inspect
|
||||||
|
import glob
|
||||||
|
import warnings
|
||||||
|
import platform
|
||||||
|
import distutils.command.install as orig
|
||||||
|
|
||||||
class install(_install):
|
import setuptools
|
||||||
|
|
||||||
|
# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for
|
||||||
|
# now. See https://bitbucket.org/pypa/setuptools/issue/199/
|
||||||
|
_install = orig.install
|
||||||
|
|
||||||
|
|
||||||
|
class install(orig.install):
|
||||||
"""Use easy_install to install the package, w/dependencies"""
|
"""Use easy_install to install the package, w/dependencies"""
|
||||||
|
|
||||||
user_options = _install.user_options + [
|
user_options = orig.install.user_options + [
|
||||||
('old-and-unmanageable', None, "Try not to use this!"),
|
('old-and-unmanageable', None, "Try not to use this!"),
|
||||||
('single-version-externally-managed', None,
|
('single-version-externally-managed', None,
|
||||||
"used by system package builders to create 'flat' eggs"),
|
"used by system package builders to create 'flat' eggs"),
|
||||||
]
|
]
|
||||||
boolean_options = _install.boolean_options + [
|
boolean_options = orig.install.boolean_options + [
|
||||||
'old-and-unmanageable', 'single-version-externally-managed',
|
'old-and-unmanageable', 'single-version-externally-managed',
|
||||||
]
|
]
|
||||||
new_commands = [
|
new_commands = [
|
||||||
@@ -22,13 +30,12 @@ class install(_install):
|
|||||||
_nc = dict(new_commands)
|
_nc = dict(new_commands)
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
_install.initialize_options(self)
|
orig.install.initialize_options(self)
|
||||||
self.old_and_unmanageable = None
|
self.old_and_unmanageable = None
|
||||||
self.single_version_externally_managed = None
|
self.single_version_externally_managed = None
|
||||||
self.no_compile = None # make DISTUTILS_DEBUG work right!
|
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
_install.finalize_options(self)
|
orig.install.finalize_options(self)
|
||||||
if self.root:
|
if self.root:
|
||||||
self.single_version_externally_managed = True
|
self.single_version_externally_managed = True
|
||||||
elif self.single_version_externally_managed:
|
elif self.single_version_externally_managed:
|
||||||
@@ -41,7 +48,7 @@ class install(_install):
|
|||||||
def handle_extra_path(self):
|
def handle_extra_path(self):
|
||||||
if self.root or self.single_version_externally_managed:
|
if self.root or self.single_version_externally_managed:
|
||||||
# explicit backward-compatibility mode, allow extra_path to work
|
# explicit backward-compatibility mode, allow extra_path to work
|
||||||
return _install.handle_extra_path(self)
|
return orig.install.handle_extra_path(self)
|
||||||
|
|
||||||
# Ignore extra_path when installing an egg (or being run by another
|
# Ignore extra_path when installing an egg (or being run by another
|
||||||
# command without --root or --single-version-externally-managed
|
# command without --root or --single-version-externally-managed
|
||||||
@@ -51,28 +58,41 @@ class install(_install):
|
|||||||
def run(self):
|
def run(self):
|
||||||
# Explicit request for old-style install? Just do it
|
# Explicit request for old-style install? Just do it
|
||||||
if self.old_and_unmanageable or self.single_version_externally_managed:
|
if self.old_and_unmanageable or self.single_version_externally_managed:
|
||||||
return _install.run(self)
|
return orig.install.run(self)
|
||||||
|
|
||||||
# Attempt to detect whether we were called from setup() or by another
|
if not self._called_from_setup(inspect.currentframe()):
|
||||||
# command. If we were called by setup(), our caller will be the
|
# Run in backward-compatibility mode to support bdist_* commands.
|
||||||
# 'run_command' method in 'distutils.dist', and *its* caller will be
|
orig.install.run(self)
|
||||||
# the 'run_commands' method. If we were called any other way, our
|
|
||||||
# immediate caller *might* be 'run_command', but it won't have been
|
|
||||||
# called by 'run_commands'. This is slightly kludgy, but seems to
|
|
||||||
# work.
|
|
||||||
#
|
|
||||||
caller = sys._getframe(2)
|
|
||||||
caller_module = caller.f_globals.get('__name__','')
|
|
||||||
caller_name = caller.f_code.co_name
|
|
||||||
|
|
||||||
if caller_module != 'distutils.dist' or caller_name!='run_commands':
|
|
||||||
# We weren't called from the command line or setup(), so we
|
|
||||||
# should run in backward-compatibility mode to support bdist_*
|
|
||||||
# commands.
|
|
||||||
_install.run(self)
|
|
||||||
else:
|
else:
|
||||||
self.do_egg_install()
|
self.do_egg_install()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _called_from_setup(run_frame):
|
||||||
|
"""
|
||||||
|
Attempt to detect whether run() was called from setup() or by another
|
||||||
|
command. If called by setup(), the parent caller will be the
|
||||||
|
'run_command' method in 'distutils.dist', and *its* caller will be
|
||||||
|
the 'run_commands' method. If called any other way, the
|
||||||
|
immediate caller *might* be 'run_command', but it won't have been
|
||||||
|
called by 'run_commands'. Return True in that case or if a call stack
|
||||||
|
is unavailable. Return False otherwise.
|
||||||
|
"""
|
||||||
|
if run_frame is None:
|
||||||
|
msg = "Call stack not available. bdist_* commands may fail."
|
||||||
|
warnings.warn(msg)
|
||||||
|
if platform.python_implementation() == 'IronPython':
|
||||||
|
msg = "For best results, pass -X:Frames to enable call stack."
|
||||||
|
warnings.warn(msg)
|
||||||
|
return True
|
||||||
|
res = inspect.getouterframes(run_frame)[2]
|
||||||
|
caller, = res[:1]
|
||||||
|
info = inspect.getframeinfo(caller)
|
||||||
|
caller_module = caller.f_globals.get('__name__', '')
|
||||||
|
return (
|
||||||
|
caller_module == 'distutils.dist'
|
||||||
|
and info.function == 'run_commands'
|
||||||
|
)
|
||||||
|
|
||||||
def do_egg_install(self):
|
def do_egg_install(self):
|
||||||
|
|
||||||
easy_install = self.distribution.get_command_class('easy_install')
|
easy_install = self.distribution.get_command_class('easy_install')
|
||||||
@@ -97,7 +117,9 @@ class install(_install):
|
|||||||
cmd.run()
|
cmd.run()
|
||||||
setuptools.bootstrap_install_from = None
|
setuptools.bootstrap_install_from = None
|
||||||
|
|
||||||
|
|
||||||
# XXX Python 3.1 doesn't see _nc if this is inside the class
|
# XXX Python 3.1 doesn't see _nc if this is inside the class
|
||||||
install.sub_commands = [
|
install.sub_commands = (
|
||||||
cmd for cmd in _install.sub_commands if cmd[0] not in install._nc
|
[cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] +
|
||||||
] + install.new_commands
|
install.new_commands
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
from distutils import log, dir_util
|
||||||
|
import os
|
||||||
|
|
||||||
from setuptools import Command
|
from setuptools import Command
|
||||||
from setuptools.archive_util import unpack_archive
|
from setuptools.archive_util import unpack_archive
|
||||||
from distutils import log, dir_util
|
import pkg_resources
|
||||||
import os, shutil, pkg_resources
|
|
||||||
|
|
||||||
class install_egg_info(Command):
|
class install_egg_info(Command):
|
||||||
"""Install an .egg-info directory for the package"""
|
"""Install an .egg-info directory for the package"""
|
||||||
@@ -16,26 +19,26 @@ class install_egg_info(Command):
|
|||||||
self.install_dir = None
|
self.install_dir = None
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
self.set_undefined_options('install_lib',('install_dir','install_dir'))
|
self.set_undefined_options('install_lib',
|
||||||
|
('install_dir', 'install_dir'))
|
||||||
ei_cmd = self.get_finalized_command("egg_info")
|
ei_cmd = self.get_finalized_command("egg_info")
|
||||||
basename = pkg_resources.Distribution(
|
basename = pkg_resources.Distribution(
|
||||||
None, None, ei_cmd.egg_name, ei_cmd.egg_version
|
None, None, ei_cmd.egg_name, ei_cmd.egg_version
|
||||||
).egg_name()+'.egg-info'
|
).egg_name() + '.egg-info'
|
||||||
self.source = ei_cmd.egg_info
|
self.source = ei_cmd.egg_info
|
||||||
self.target = os.path.join(self.install_dir, basename)
|
self.target = os.path.join(self.install_dir, basename)
|
||||||
self.outputs = [self.target]
|
self.outputs = [self.target]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.run_command('egg_info')
|
self.run_command('egg_info')
|
||||||
target = self.target
|
|
||||||
if os.path.isdir(self.target) and not os.path.islink(self.target):
|
if os.path.isdir(self.target) and not os.path.islink(self.target):
|
||||||
dir_util.remove_tree(self.target, dry_run=self.dry_run)
|
dir_util.remove_tree(self.target, dry_run=self.dry_run)
|
||||||
elif os.path.exists(self.target):
|
elif os.path.exists(self.target):
|
||||||
self.execute(os.unlink,(self.target,),"Removing "+self.target)
|
self.execute(os.unlink, (self.target,), "Removing " + self.target)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
pkg_resources.ensure_directory(self.target)
|
pkg_resources.ensure_directory(self.target)
|
||||||
self.execute(self.copytree, (),
|
self.execute(
|
||||||
"Copying %s to %s" % (self.source, self.target)
|
self.copytree, (), "Copying %s to %s" % (self.source, self.target)
|
||||||
)
|
)
|
||||||
self.install_namespaces()
|
self.install_namespaces()
|
||||||
|
|
||||||
@@ -44,82 +47,70 @@ class install_egg_info(Command):
|
|||||||
|
|
||||||
def copytree(self):
|
def copytree(self):
|
||||||
# Copy the .egg-info tree to site-packages
|
# Copy the .egg-info tree to site-packages
|
||||||
def skimmer(src,dst):
|
def skimmer(src, dst):
|
||||||
# filter out source-control directories; note that 'src' is always
|
# filter out source-control directories; note that 'src' is always
|
||||||
# a '/'-separated path, regardless of platform. 'dst' is a
|
# a '/'-separated path, regardless of platform. 'dst' is a
|
||||||
# platform-specific path.
|
# platform-specific path.
|
||||||
for skip in '.svn/','CVS/':
|
for skip in '.svn/', 'CVS/':
|
||||||
if src.startswith(skip) or '/'+skip in src:
|
if src.startswith(skip) or '/' + skip in src:
|
||||||
return None
|
return None
|
||||||
self.outputs.append(dst)
|
self.outputs.append(dst)
|
||||||
log.debug("Copying %s to %s", src, dst)
|
log.debug("Copying %s to %s", src, dst)
|
||||||
return dst
|
return dst
|
||||||
|
|
||||||
unpack_archive(self.source, self.target, skimmer)
|
unpack_archive(self.source, self.target, skimmer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def install_namespaces(self):
|
def install_namespaces(self):
|
||||||
nsp = self._get_all_ns_packages()
|
nsp = self._get_all_ns_packages()
|
||||||
if not nsp: return
|
if not nsp:
|
||||||
filename,ext = os.path.splitext(self.target)
|
return
|
||||||
filename += '-nspkg.pth'; self.outputs.append(filename)
|
filename, ext = os.path.splitext(self.target)
|
||||||
log.info("Installing %s",filename)
|
filename += '-nspkg.pth'
|
||||||
if not self.dry_run:
|
self.outputs.append(filename)
|
||||||
f = open(filename,'wt')
|
log.info("Installing %s", filename)
|
||||||
for pkg in nsp:
|
lines = map(self._gen_nspkg_line, nsp)
|
||||||
# ensure pkg is not a unicode string under Python 2.7
|
|
||||||
pkg = str(pkg)
|
if self.dry_run:
|
||||||
pth = tuple(pkg.split('.'))
|
# always generate the lines, even in dry run
|
||||||
trailer = '\n'
|
list(lines)
|
||||||
if '.' in pkg:
|
return
|
||||||
trailer = (
|
|
||||||
"; m and setattr(sys.modules[%r], %r, m)\n"
|
with open(filename, 'wt') as f:
|
||||||
% ('.'.join(pth[:-1]), pth[-1])
|
f.writelines(lines)
|
||||||
)
|
|
||||||
f.write(
|
_nspkg_tmpl = (
|
||||||
"import sys,types,os; "
|
"import sys, types, os",
|
||||||
"p = os.path.join(sys._getframe(1).f_locals['sitedir'], "
|
"p = os.path.join(sys._getframe(1).f_locals['sitedir'], *%(pth)r)",
|
||||||
"*%(pth)r); "
|
"ie = os.path.exists(os.path.join(p,'__init__.py'))",
|
||||||
"ie = os.path.exists(os.path.join(p,'__init__.py')); "
|
"m = not ie and "
|
||||||
"m = not ie and "
|
"sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
|
||||||
"sys.modules.setdefault(%(pkg)r,types.ModuleType(%(pkg)r)); "
|
"mp = (m or []) and m.__dict__.setdefault('__path__',[])",
|
||||||
"mp = (m or []) and m.__dict__.setdefault('__path__',[]); "
|
"(p not in mp) and mp.append(p)",
|
||||||
"(p not in mp) and mp.append(p)%(trailer)s"
|
)
|
||||||
% locals()
|
"lines for the namespace installer"
|
||||||
)
|
|
||||||
f.close()
|
_nspkg_tmpl_multi = (
|
||||||
|
'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
|
||||||
|
)
|
||||||
|
"additional line(s) when a parent package is indicated"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _gen_nspkg_line(cls, pkg):
|
||||||
|
# ensure pkg is not a unicode string under Python 2.7
|
||||||
|
pkg = str(pkg)
|
||||||
|
pth = tuple(pkg.split('.'))
|
||||||
|
tmpl_lines = cls._nspkg_tmpl
|
||||||
|
parent, sep, child = pkg.rpartition('.')
|
||||||
|
if parent:
|
||||||
|
tmpl_lines += cls._nspkg_tmpl_multi
|
||||||
|
return ';'.join(tmpl_lines) % locals() + '\n'
|
||||||
|
|
||||||
def _get_all_ns_packages(self):
|
def _get_all_ns_packages(self):
|
||||||
nsp = {}
|
"""Return sorted list of all package namespaces"""
|
||||||
|
nsp = set()
|
||||||
for pkg in self.distribution.namespace_packages or []:
|
for pkg in self.distribution.namespace_packages or []:
|
||||||
pkg = pkg.split('.')
|
pkg = pkg.split('.')
|
||||||
while pkg:
|
while pkg:
|
||||||
nsp['.'.join(pkg)] = 1
|
nsp.add('.'.join(pkg))
|
||||||
pkg.pop()
|
pkg.pop()
|
||||||
nsp=list(nsp)
|
return sorted(nsp)
|
||||||
nsp.sort() # set up shorter names first
|
|
||||||
return nsp
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
from distutils.command.install_lib import install_lib as _install_lib
|
|
||||||
import os
|
import os
|
||||||
|
import imp
|
||||||
|
from itertools import product, starmap
|
||||||
|
import distutils.command.install_lib as orig
|
||||||
|
|
||||||
class install_lib(_install_lib):
|
class install_lib(orig.install_lib):
|
||||||
"""Don't add compiled flags to filenames of non-Python files"""
|
"""Don't add compiled flags to filenames of non-Python files"""
|
||||||
|
|
||||||
def _bytecode_filenames (self, py_filenames):
|
|
||||||
bytecode_files = []
|
|
||||||
for py_file in py_filenames:
|
|
||||||
if not py_file.endswith('.py'):
|
|
||||||
continue
|
|
||||||
if self.compile:
|
|
||||||
bytecode_files.append(py_file + "c")
|
|
||||||
if self.optimize > 0:
|
|
||||||
bytecode_files.append(py_file + "o")
|
|
||||||
|
|
||||||
return bytecode_files
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.build()
|
self.build()
|
||||||
outfiles = self.install()
|
outfiles = self.install()
|
||||||
@@ -24,30 +14,81 @@ class install_lib(_install_lib):
|
|||||||
self.byte_compile(outfiles)
|
self.byte_compile(outfiles)
|
||||||
|
|
||||||
def get_exclusions(self):
|
def get_exclusions(self):
|
||||||
exclude = {}
|
"""
|
||||||
nsp = self.distribution.namespace_packages
|
Return a collections.Sized collections.Container of paths to be
|
||||||
|
excluded for single_version_externally_managed installations.
|
||||||
|
"""
|
||||||
|
all_packages = (
|
||||||
|
pkg
|
||||||
|
for ns_pkg in self._get_SVEM_NSPs()
|
||||||
|
for pkg in self._all_packages(ns_pkg)
|
||||||
|
)
|
||||||
|
|
||||||
if (nsp and self.get_finalized_command('install')
|
excl_specs = product(all_packages, self._gen_exclusion_paths())
|
||||||
.single_version_externally_managed
|
return set(starmap(self._exclude_pkg_path, excl_specs))
|
||||||
):
|
|
||||||
for pkg in nsp:
|
def _exclude_pkg_path(self, pkg, exclusion_path):
|
||||||
parts = pkg.split('.')
|
"""
|
||||||
while parts:
|
Given a package name and exclusion path within that package,
|
||||||
pkgdir = os.path.join(self.install_dir, *parts)
|
compute the full exclusion path.
|
||||||
for f in '__init__.py', '__init__.pyc', '__init__.pyo':
|
"""
|
||||||
exclude[os.path.join(pkgdir,f)] = 1
|
parts = pkg.split('.') + [exclusion_path]
|
||||||
parts.pop()
|
return os.path.join(self.install_dir, *parts)
|
||||||
return exclude
|
|
||||||
|
@staticmethod
|
||||||
|
def _all_packages(pkg_name):
|
||||||
|
"""
|
||||||
|
>>> list(install_lib._all_packages('foo.bar.baz'))
|
||||||
|
['foo.bar.baz', 'foo.bar', 'foo']
|
||||||
|
"""
|
||||||
|
while pkg_name:
|
||||||
|
yield pkg_name
|
||||||
|
pkg_name, sep, child = pkg_name.rpartition('.')
|
||||||
|
|
||||||
|
def _get_SVEM_NSPs(self):
|
||||||
|
"""
|
||||||
|
Get namespace packages (list) but only for
|
||||||
|
single_version_externally_managed installations and empty otherwise.
|
||||||
|
"""
|
||||||
|
# TODO: is it necessary to short-circuit here? i.e. what's the cost
|
||||||
|
# if get_finalized_command is called even when namespace_packages is
|
||||||
|
# False?
|
||||||
|
if not self.distribution.namespace_packages:
|
||||||
|
return []
|
||||||
|
|
||||||
|
install_cmd = self.get_finalized_command('install')
|
||||||
|
svem = install_cmd.single_version_externally_managed
|
||||||
|
|
||||||
|
return self.distribution.namespace_packages if svem else []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _gen_exclusion_paths():
|
||||||
|
"""
|
||||||
|
Generate file paths to be excluded for namespace packages (bytecode
|
||||||
|
cache files).
|
||||||
|
"""
|
||||||
|
# always exclude the package module itself
|
||||||
|
yield '__init__.py'
|
||||||
|
|
||||||
|
yield '__init__.pyc'
|
||||||
|
yield '__init__.pyo'
|
||||||
|
|
||||||
|
if not hasattr(imp, 'get_tag'):
|
||||||
|
return
|
||||||
|
|
||||||
|
base = os.path.join('__pycache__', '__init__.' + imp.get_tag())
|
||||||
|
yield base + '.pyc'
|
||||||
|
yield base + '.pyo'
|
||||||
|
|
||||||
def copy_tree(
|
def copy_tree(
|
||||||
self, infile, outfile,
|
self, infile, outfile,
|
||||||
preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
|
preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
|
||||||
):
|
):
|
||||||
assert preserve_mode and preserve_times and not preserve_symlinks
|
assert preserve_mode and preserve_times and not preserve_symlinks
|
||||||
exclude = self.get_exclusions()
|
exclude = self.get_exclusions()
|
||||||
|
|
||||||
if not exclude:
|
if not exclude:
|
||||||
return _install_lib.copy_tree(self, infile, outfile)
|
return orig.install_lib.copy_tree(self, infile, outfile)
|
||||||
|
|
||||||
# Exclude namespace package __init__.py* files from the output
|
# Exclude namespace package __init__.py* files from the output
|
||||||
|
|
||||||
@@ -58,7 +99,8 @@ class install_lib(_install_lib):
|
|||||||
|
|
||||||
def pf(src, dst):
|
def pf(src, dst):
|
||||||
if dst in exclude:
|
if dst in exclude:
|
||||||
log.warn("Skipping installation of %s (namespace package)",dst)
|
log.warn("Skipping installation of %s (namespace package)",
|
||||||
|
dst)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
log.info("copying %s -> %s", src, os.path.dirname(dst))
|
log.info("copying %s -> %s", src, os.path.dirname(dst))
|
||||||
@@ -69,14 +111,8 @@ class install_lib(_install_lib):
|
|||||||
return outfiles
|
return outfiles
|
||||||
|
|
||||||
def get_outputs(self):
|
def get_outputs(self):
|
||||||
outputs = _install_lib.get_outputs(self)
|
outputs = orig.install_lib.get_outputs(self)
|
||||||
exclude = self.get_exclusions()
|
exclude = self.get_exclusions()
|
||||||
if exclude:
|
if exclude:
|
||||||
return [f for f in outputs if f not in exclude]
|
return [f for f in outputs if f not in exclude]
|
||||||
return outputs
|
return outputs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
from distutils.command.install_scripts import install_scripts \
|
|
||||||
as _install_scripts
|
|
||||||
from pkg_resources import Distribution, PathMetadata, ensure_directory
|
|
||||||
import os
|
|
||||||
from distutils import log
|
from distutils import log
|
||||||
|
import distutils.command.install_scripts as orig
|
||||||
|
import os
|
||||||
|
|
||||||
class install_scripts(_install_scripts):
|
from pkg_resources import Distribution, PathMetadata, ensure_directory
|
||||||
|
|
||||||
|
|
||||||
|
class install_scripts(orig.install_scripts):
|
||||||
"""Do normal script install, plus any egg_info wrapper scripts"""
|
"""Do normal script install, plus any egg_info wrapper scripts"""
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
_install_scripts.initialize_options(self)
|
orig.install_scripts.initialize_options(self)
|
||||||
self.no_ep = False
|
self.no_ep = False
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
from setuptools.command.easy_install import get_script_args
|
import setuptools.command.easy_install as ei
|
||||||
from setuptools.command.easy_install import sys_executable
|
|
||||||
|
|
||||||
self.run_command("egg_info")
|
self.run_command("egg_info")
|
||||||
if self.distribution.scripts:
|
if self.distribution.scripts:
|
||||||
_install_scripts.run(self) # run first to set up self.outfiles
|
orig.install_scripts.run(self) # run first to set up self.outfiles
|
||||||
else:
|
else:
|
||||||
self.outfiles = []
|
self.outfiles = []
|
||||||
if self.no_ep:
|
if self.no_ep:
|
||||||
@@ -30,16 +30,23 @@ class install_scripts(_install_scripts):
|
|||||||
ei_cmd.egg_name, ei_cmd.egg_version,
|
ei_cmd.egg_name, ei_cmd.egg_version,
|
||||||
)
|
)
|
||||||
bs_cmd = self.get_finalized_command('build_scripts')
|
bs_cmd = self.get_finalized_command('build_scripts')
|
||||||
executable = getattr(bs_cmd,'executable',sys_executable)
|
exec_param = getattr(bs_cmd, 'executable', None)
|
||||||
is_wininst = getattr(
|
bw_cmd = self.get_finalized_command("bdist_wininst")
|
||||||
self.get_finalized_command("bdist_wininst"), '_is_running', False
|
is_wininst = getattr(bw_cmd, '_is_running', False)
|
||||||
)
|
writer = ei.ScriptWriter
|
||||||
for args in get_script_args(dist, executable, is_wininst):
|
if is_wininst:
|
||||||
|
exec_param = "python.exe"
|
||||||
|
writer = ei.WindowsScriptWriter
|
||||||
|
# resolve the writer to the environment
|
||||||
|
writer = writer.best()
|
||||||
|
cmd = writer.command_spec_class.best().from_param(exec_param)
|
||||||
|
for args in writer.get_args(dist, cmd.as_header()):
|
||||||
self.write_script(*args)
|
self.write_script(*args)
|
||||||
|
|
||||||
def write_script(self, script_name, contents, mode="t", *ignored):
|
def write_script(self, script_name, contents, mode="t", *ignored):
|
||||||
"""Write an executable file to the scripts directory"""
|
"""Write an executable file to the scripts directory"""
|
||||||
from setuptools.command.easy_install import chmod, current_umask
|
from setuptools.command.easy_install import chmod, current_umask
|
||||||
|
|
||||||
log.info("Installing %s script to %s", script_name, self.install_dir)
|
log.info("Installing %s script to %s", script_name, self.install_dir)
|
||||||
target = os.path.join(self.install_dir, script_name)
|
target = os.path.join(self.install_dir, script_name)
|
||||||
self.outfiles.append(target)
|
self.outfiles.append(target)
|
||||||
@@ -47,8 +54,7 @@ class install_scripts(_install_scripts):
|
|||||||
mask = current_umask()
|
mask = current_umask()
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
ensure_directory(target)
|
ensure_directory(target)
|
||||||
f = open(target,"w"+mode)
|
f = open(target, "w" + mode)
|
||||||
f.write(contents)
|
f.write(contents)
|
||||||
f.close()
|
f.close()
|
||||||
chmod(target, 0x1FF-mask) # 0777
|
chmod(target, 0o777 - mask)
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
<assemblyIdentity version="1.0.0.0"
|
<assemblyIdentity version="1.0.0.0"
|
||||||
processorArchitecture="X86"
|
processorArchitecture="X86"
|
||||||
name="%(name)s"
|
name="%(name)s"
|
||||||
type="win32"/>
|
type="win32"/>
|
||||||
<!-- Identify the application security requirements. -->
|
<!-- Identify the application security requirements. -->
|
||||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
<security>
|
<security>
|
||||||
<requestedPrivileges>
|
<requestedPrivileges>
|
||||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||||
</requestedPrivileges>
|
</requestedPrivileges>
|
||||||
</security>
|
</security>
|
||||||
</trustInfo>
|
</trustInfo>
|
||||||
</assembly>
|
</assembly>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from distutils.command.register import register as _register
|
import distutils.command.register as orig
|
||||||
|
|
||||||
class register(_register):
|
|
||||||
__doc__ = _register.__doc__
|
class register(orig.register):
|
||||||
|
__doc__ = orig.register.__doc__
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# Make sure that we are using valid current name/version info
|
# Make sure that we are using valid current name/version info
|
||||||
self.run_command('egg_info')
|
self.run_command('egg_info')
|
||||||
_register.run(self)
|
orig.register.run(self)
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import distutils, os
|
|
||||||
from setuptools import Command
|
|
||||||
from setuptools.compat import basestring
|
|
||||||
from distutils.util import convert_path
|
from distutils.util import convert_path
|
||||||
from distutils import log
|
from distutils import log
|
||||||
from distutils.errors import *
|
from distutils.errors import DistutilsOptionError
|
||||||
|
import os
|
||||||
|
|
||||||
|
from setuptools import Command
|
||||||
|
from setuptools.compat import basestring
|
||||||
|
|
||||||
|
|
||||||
class rotate(Command):
|
class rotate(Command):
|
||||||
"""Delete older distributions"""
|
"""Delete older distributions"""
|
||||||
|
|
||||||
description = "delete older distributions, keeping N newest files"
|
description = "delete older distributions, keeping N newest files"
|
||||||
user_options = [
|
user_options = [
|
||||||
('match=', 'm', "patterns to match (required)"),
|
('match=', 'm', "patterns to match (required)"),
|
||||||
('dist-dir=', 'd', "directory where the distributions are"),
|
('dist-dir=', 'd', "directory where the distributions are"),
|
||||||
('keep=', 'k', "number of matching distributions to keep"),
|
('keep=', 'k', "number of matching distributions to keep"),
|
||||||
]
|
]
|
||||||
|
|
||||||
boolean_options = []
|
boolean_options = []
|
||||||
@@ -29,7 +31,7 @@ class rotate(Command):
|
|||||||
"(e.g. '.zip' or '.egg')"
|
"(e.g. '.zip' or '.egg')"
|
||||||
)
|
)
|
||||||
if self.keep is None:
|
if self.keep is None:
|
||||||
raise DistutilsOptionError("Must specify number of files to keep")
|
raise DistutilsOptionError("Must specify number of files to keep")
|
||||||
try:
|
try:
|
||||||
self.keep = int(self.keep)
|
self.keep = int(self.keep)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -38,46 +40,22 @@ class rotate(Command):
|
|||||||
self.match = [
|
self.match = [
|
||||||
convert_path(p.strip()) for p in self.match.split(',')
|
convert_path(p.strip()) for p in self.match.split(',')
|
||||||
]
|
]
|
||||||
self.set_undefined_options('bdist',('dist_dir', 'dist_dir'))
|
self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.run_command("egg_info")
|
self.run_command("egg_info")
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
for pattern in self.match:
|
for pattern in self.match:
|
||||||
pattern = self.distribution.get_name()+'*'+pattern
|
pattern = self.distribution.get_name() + '*' + pattern
|
||||||
files = glob(os.path.join(self.dist_dir,pattern))
|
files = glob(os.path.join(self.dist_dir, pattern))
|
||||||
files = [(os.path.getmtime(f),f) for f in files]
|
files = [(os.path.getmtime(f), f) for f in files]
|
||||||
files.sort()
|
files.sort()
|
||||||
files.reverse()
|
files.reverse()
|
||||||
|
|
||||||
log.info("%d file(s) matching %s", len(files), pattern)
|
log.info("%d file(s) matching %s", len(files), pattern)
|
||||||
files = files[self.keep:]
|
files = files[self.keep:]
|
||||||
for (t,f) in files:
|
for (t, f) in files:
|
||||||
log.info("Deleting %s", f)
|
log.info("Deleting %s", f)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
os.unlink(f)
|
os.unlink(f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import distutils, os
|
|
||||||
from setuptools import Command
|
|
||||||
from setuptools.command.setopt import edit_config, option_base
|
from setuptools.command.setopt import edit_config, option_base
|
||||||
|
|
||||||
|
|
||||||
class saveopts(option_base):
|
class saveopts(option_base):
|
||||||
"""Save command-line options to a file"""
|
"""Save command-line options to a file"""
|
||||||
|
|
||||||
@@ -13,12 +12,11 @@ class saveopts(option_base):
|
|||||||
|
|
||||||
for cmd in dist.command_options:
|
for cmd in dist.command_options:
|
||||||
|
|
||||||
if cmd=='saveopts':
|
if cmd == 'saveopts':
|
||||||
continue # don't save our own options!
|
continue # don't save our own options!
|
||||||
|
|
||||||
for opt,(src,val) in dist.get_option_dict(cmd).items():
|
for opt, (src, val) in dist.get_option_dict(cmd).items():
|
||||||
if src=="command line":
|
if src == "command line":
|
||||||
settings.setdefault(cmd,{})[opt] = val
|
settings.setdefault(cmd, {})[opt] = val
|
||||||
|
|
||||||
edit_config(self.filename, settings, self.dry_run)
|
edit_config(self.filename, settings, self.dry_run)
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
from distutils import log
|
||||||
|
import distutils.command.sdist as orig
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from setuptools.compat import PY3
|
||||||
|
from setuptools.utils import cs_path_exists
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from distutils.command.sdist import sdist as _sdist
|
|
||||||
from distutils.util import convert_path
|
|
||||||
from distutils import log
|
|
||||||
from setuptools import svn_utils
|
|
||||||
|
|
||||||
READMES = ('README', 'README.rst', 'README.txt')
|
READMES = 'README', 'README.rst', 'README.txt'
|
||||||
|
|
||||||
|
_default_revctrl = list
|
||||||
|
|
||||||
def walk_revctrl(dirname=''):
|
def walk_revctrl(dirname=''):
|
||||||
"""Find all files under revision control"""
|
"""Find all files under revision control"""
|
||||||
@@ -19,60 +20,7 @@ def walk_revctrl(dirname=''):
|
|||||||
yield item
|
yield item
|
||||||
|
|
||||||
|
|
||||||
#TODO will need test case
|
class sdist(orig.sdist):
|
||||||
class re_finder(object):
|
|
||||||
"""
|
|
||||||
Finder that locates files based on entries in a file matched by a
|
|
||||||
regular expression.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, path, pattern, postproc=lambda x: x):
|
|
||||||
self.pattern = pattern
|
|
||||||
self.postproc = postproc
|
|
||||||
self.entries_path = convert_path(path)
|
|
||||||
|
|
||||||
def _finder(self, dirname, filename):
|
|
||||||
f = open(filename,'rU')
|
|
||||||
try:
|
|
||||||
data = f.read()
|
|
||||||
finally:
|
|
||||||
f.close()
|
|
||||||
for match in self.pattern.finditer(data):
|
|
||||||
path = match.group(1)
|
|
||||||
# postproc was formerly used when the svn finder
|
|
||||||
# was an re_finder for calling unescape
|
|
||||||
path = self.postproc(path)
|
|
||||||
yield svn_utils.joinpath(dirname, path)
|
|
||||||
|
|
||||||
def find(self, dirname=''):
|
|
||||||
path = svn_utils.joinpath(dirname, self.entries_path)
|
|
||||||
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
# entries file doesn't exist
|
|
||||||
return
|
|
||||||
for path in self._finder(dirname,path):
|
|
||||||
if os.path.isfile(path):
|
|
||||||
yield path
|
|
||||||
elif os.path.isdir(path):
|
|
||||||
for item in self.find(path):
|
|
||||||
yield item
|
|
||||||
__call__ = find
|
|
||||||
|
|
||||||
|
|
||||||
def _default_revctrl(dirname=''):
|
|
||||||
'Primary svn_cvs entry point'
|
|
||||||
for finder in finders:
|
|
||||||
for item in finder(dirname):
|
|
||||||
yield item
|
|
||||||
|
|
||||||
|
|
||||||
finders = [
|
|
||||||
re_finder('CVS/Entries', re.compile(r"^\w?/([^/]+)/", re.M)),
|
|
||||||
svn_utils.svn_finder,
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class sdist(_sdist):
|
|
||||||
"""Smart sdist that finds anything supported by revision control"""
|
"""Smart sdist that finds anything supported by revision control"""
|
||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
@@ -84,7 +32,7 @@ class sdist(_sdist):
|
|||||||
('dist-dir=', 'd',
|
('dist-dir=', 'd',
|
||||||
"directory to put the source distribution archive(s) in "
|
"directory to put the source distribution archive(s) in "
|
||||||
"[default: dist]"),
|
"[default: dist]"),
|
||||||
]
|
]
|
||||||
|
|
||||||
negative_opt = {}
|
negative_opt = {}
|
||||||
|
|
||||||
@@ -92,7 +40,7 @@ class sdist(_sdist):
|
|||||||
self.run_command('egg_info')
|
self.run_command('egg_info')
|
||||||
ei_cmd = self.get_finalized_command('egg_info')
|
ei_cmd = self.get_finalized_command('egg_info')
|
||||||
self.filelist = ei_cmd.filelist
|
self.filelist = ei_cmd.filelist
|
||||||
self.filelist.append(os.path.join(ei_cmd.egg_info,'SOURCES.txt'))
|
self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))
|
||||||
self.check_readme()
|
self.check_readme()
|
||||||
|
|
||||||
# Run sub commands
|
# Run sub commands
|
||||||
@@ -102,12 +50,13 @@ class sdist(_sdist):
|
|||||||
# Call check_metadata only if no 'check' command
|
# Call check_metadata only if no 'check' command
|
||||||
# (distutils <= 2.6)
|
# (distutils <= 2.6)
|
||||||
import distutils.command
|
import distutils.command
|
||||||
|
|
||||||
if 'check' not in distutils.command.__all__:
|
if 'check' not in distutils.command.__all__:
|
||||||
self.check_metadata()
|
self.check_metadata()
|
||||||
|
|
||||||
self.make_distribution()
|
self.make_distribution()
|
||||||
|
|
||||||
dist_files = getattr(self.distribution,'dist_files',[])
|
dist_files = getattr(self.distribution, 'dist_files', [])
|
||||||
for file in self.archive_files:
|
for file in self.archive_files:
|
||||||
data = ('sdist', '', file)
|
data = ('sdist', '', file)
|
||||||
if data not in dist_files:
|
if data not in dist_files:
|
||||||
@@ -119,17 +68,19 @@ class sdist(_sdist):
|
|||||||
# Doing so prevents an error when easy_install attempts to delete the
|
# Doing so prevents an error when easy_install attempts to delete the
|
||||||
# file.
|
# file.
|
||||||
try:
|
try:
|
||||||
_sdist.read_template(self)
|
orig.sdist.read_template(self)
|
||||||
except:
|
except:
|
||||||
sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
|
_, _, tb = sys.exc_info()
|
||||||
|
tb.tb_next.tb_frame.f_locals['template'].close()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle
|
# Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle
|
||||||
# has been fixed, so only override the method if we're using an earlier
|
# has been fixed, so only override the method if we're using an earlier
|
||||||
# Python.
|
# Python.
|
||||||
has_leaky_handle = (
|
has_leaky_handle = (
|
||||||
sys.version_info < (2,7,2)
|
sys.version_info < (2, 7, 2)
|
||||||
or (3,0) <= sys.version_info < (3,1,4)
|
or (3, 0) <= sys.version_info < (3, 1, 4)
|
||||||
or (3,2) <= sys.version_info < (3,2,1)
|
or (3, 2) <= sys.version_info < (3, 2, 1)
|
||||||
)
|
)
|
||||||
if has_leaky_handle:
|
if has_leaky_handle:
|
||||||
read_template = __read_template_hack
|
read_template = __read_template_hack
|
||||||
@@ -142,7 +93,7 @@ class sdist(_sdist):
|
|||||||
alts = fn
|
alts = fn
|
||||||
got_it = 0
|
got_it = 0
|
||||||
for fn in alts:
|
for fn in alts:
|
||||||
if os.path.exists(fn):
|
if cs_path_exists(fn):
|
||||||
got_it = 1
|
got_it = 1
|
||||||
self.filelist.append(fn)
|
self.filelist.append(fn)
|
||||||
break
|
break
|
||||||
@@ -151,14 +102,14 @@ class sdist(_sdist):
|
|||||||
self.warn("standard file not found: should have one of " +
|
self.warn("standard file not found: should have one of " +
|
||||||
', '.join(alts))
|
', '.join(alts))
|
||||||
else:
|
else:
|
||||||
if os.path.exists(fn):
|
if cs_path_exists(fn):
|
||||||
self.filelist.append(fn)
|
self.filelist.append(fn)
|
||||||
else:
|
else:
|
||||||
self.warn("standard file '%s' not found" % fn)
|
self.warn("standard file '%s' not found" % fn)
|
||||||
|
|
||||||
optional = ['test/test*.py', 'setup.cfg']
|
optional = ['test/test*.py', 'setup.cfg']
|
||||||
for pattern in optional:
|
for pattern in optional:
|
||||||
files = list(filter(os.path.isfile, glob(pattern)))
|
files = list(filter(cs_path_exists, glob(pattern)))
|
||||||
if files:
|
if files:
|
||||||
self.filelist.extend(files)
|
self.filelist.extend(files)
|
||||||
|
|
||||||
@@ -193,15 +144,16 @@ class sdist(_sdist):
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.warn(
|
self.warn(
|
||||||
"standard file not found: should have one of " +', '.join(READMES)
|
"standard file not found: should have one of " +
|
||||||
|
', '.join(READMES)
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_release_tree(self, base_dir, files):
|
def make_release_tree(self, base_dir, files):
|
||||||
_sdist.make_release_tree(self, base_dir, files)
|
orig.sdist.make_release_tree(self, base_dir, files)
|
||||||
|
|
||||||
# Save any egg_info command line options used to create this sdist
|
# Save any egg_info command line options used to create this sdist
|
||||||
dest = os.path.join(base_dir, 'setup.cfg')
|
dest = os.path.join(base_dir, 'setup.cfg')
|
||||||
if hasattr(os,'link') and os.path.exists(dest):
|
if hasattr(os, 'link') and os.path.exists(dest):
|
||||||
# unlink and re-copy, since it might be hard-linked, and
|
# unlink and re-copy, since it might be hard-linked, and
|
||||||
# we don't want to change the source version
|
# we don't want to change the source version
|
||||||
os.unlink(dest)
|
os.unlink(dest)
|
||||||
@@ -219,7 +171,8 @@ class sdist(_sdist):
|
|||||||
first_line = fp.readline()
|
first_line = fp.readline()
|
||||||
finally:
|
finally:
|
||||||
fp.close()
|
fp.close()
|
||||||
return first_line != '# file GENERATED by distutils, do NOT edit\n'.encode()
|
return (first_line !=
|
||||||
|
'# file GENERATED by distutils, do NOT edit\n'.encode())
|
||||||
|
|
||||||
def read_manifest(self):
|
def read_manifest(self):
|
||||||
"""Read the manifest file (named by 'self.manifest') and use it to
|
"""Read the manifest file (named by 'self.manifest') and use it to
|
||||||
@@ -230,7 +183,7 @@ class sdist(_sdist):
|
|||||||
manifest = open(self.manifest, 'rbU')
|
manifest = open(self.manifest, 'rbU')
|
||||||
for line in manifest:
|
for line in manifest:
|
||||||
# The manifest must contain UTF-8. See #303.
|
# The manifest must contain UTF-8. See #303.
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
try:
|
try:
|
||||||
line = line.decode('UTF-8')
|
line = line.decode('UTF-8')
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import distutils, os
|
|
||||||
from setuptools import Command
|
|
||||||
from distutils.util import convert_path
|
from distutils.util import convert_path
|
||||||
from distutils import log
|
from distutils import log
|
||||||
from distutils.errors import *
|
from distutils.errors import DistutilsOptionError
|
||||||
|
import distutils
|
||||||
|
import os
|
||||||
|
|
||||||
|
from setuptools import Command
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
|
__all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
|
||||||
|
|
||||||
@@ -12,33 +15,20 @@ def config_file(kind="local"):
|
|||||||
|
|
||||||
`kind` must be one of "local", "global", or "user"
|
`kind` must be one of "local", "global", or "user"
|
||||||
"""
|
"""
|
||||||
if kind=='local':
|
if kind == 'local':
|
||||||
return 'setup.cfg'
|
return 'setup.cfg'
|
||||||
if kind=='global':
|
if kind == 'global':
|
||||||
return os.path.join(
|
return os.path.join(
|
||||||
os.path.dirname(distutils.__file__),'distutils.cfg'
|
os.path.dirname(distutils.__file__), 'distutils.cfg'
|
||||||
)
|
)
|
||||||
if kind=='user':
|
if kind == 'user':
|
||||||
dot = os.name=='posix' and '.' or ''
|
dot = os.name == 'posix' and '.' or ''
|
||||||
return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot))
|
return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot))
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"config_file() type must be 'local', 'global', or 'user'", kind
|
"config_file() type must be 'local', 'global', or 'user'", kind
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def edit_config(filename, settings, dry_run=False):
|
def edit_config(filename, settings, dry_run=False):
|
||||||
"""Edit a configuration file to include `settings`
|
"""Edit a configuration file to include `settings`
|
||||||
|
|
||||||
@@ -48,6 +38,7 @@ def edit_config(filename, settings, dry_run=False):
|
|||||||
A setting of ``None`` means to delete that setting.
|
A setting of ``None`` means to delete that setting.
|
||||||
"""
|
"""
|
||||||
from setuptools.compat import ConfigParser
|
from setuptools.compat import ConfigParser
|
||||||
|
|
||||||
log.debug("Reading configuration from %s", filename)
|
log.debug("Reading configuration from %s", filename)
|
||||||
opts = ConfigParser.RawConfigParser()
|
opts = ConfigParser.RawConfigParser()
|
||||||
opts.read([filename])
|
opts.read([filename])
|
||||||
@@ -59,46 +50,49 @@ def edit_config(filename, settings, dry_run=False):
|
|||||||
if not opts.has_section(section):
|
if not opts.has_section(section):
|
||||||
log.debug("Adding new section [%s] to %s", section, filename)
|
log.debug("Adding new section [%s] to %s", section, filename)
|
||||||
opts.add_section(section)
|
opts.add_section(section)
|
||||||
for option,value in options.items():
|
for option, value in options.items():
|
||||||
if value is None:
|
if value is None:
|
||||||
log.debug("Deleting %s.%s from %s",
|
log.debug(
|
||||||
|
"Deleting %s.%s from %s",
|
||||||
section, option, filename
|
section, option, filename
|
||||||
)
|
)
|
||||||
opts.remove_option(section,option)
|
opts.remove_option(section, option)
|
||||||
if not opts.options(section):
|
if not opts.options(section):
|
||||||
log.info("Deleting empty [%s] section from %s",
|
log.info("Deleting empty [%s] section from %s",
|
||||||
section, filename)
|
section, filename)
|
||||||
opts.remove_section(section)
|
opts.remove_section(section)
|
||||||
else:
|
else:
|
||||||
log.debug(
|
log.debug(
|
||||||
"Setting %s.%s to %r in %s",
|
"Setting %s.%s to %r in %s",
|
||||||
section, option, value, filename
|
section, option, value, filename
|
||||||
)
|
)
|
||||||
opts.set(section,option,value)
|
opts.set(section, option, value)
|
||||||
|
|
||||||
log.info("Writing %s", filename)
|
log.info("Writing %s", filename)
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
f = open(filename,'w'); opts.write(f); f.close()
|
with open(filename, 'w') as f:
|
||||||
|
opts.write(f)
|
||||||
|
|
||||||
|
|
||||||
class option_base(Command):
|
class option_base(Command):
|
||||||
"""Abstract base class for commands that mess with config files"""
|
"""Abstract base class for commands that mess with config files"""
|
||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
('global-config', 'g',
|
('global-config', 'g',
|
||||||
"save options to the site-wide distutils.cfg file"),
|
"save options to the site-wide distutils.cfg file"),
|
||||||
('user-config', 'u',
|
('user-config', 'u',
|
||||||
"save options to the current user's pydistutils.cfg file"),
|
"save options to the current user's pydistutils.cfg file"),
|
||||||
('filename=', 'f',
|
('filename=', 'f',
|
||||||
"configuration file to use (default=setup.cfg)"),
|
"configuration file to use (default=setup.cfg)"),
|
||||||
]
|
]
|
||||||
|
|
||||||
boolean_options = [
|
boolean_options = [
|
||||||
'global-config', 'user-config',
|
'global-config', 'user-config',
|
||||||
]
|
]
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
self.global_config = None
|
self.global_config = None
|
||||||
self.user_config = None
|
self.user_config = None
|
||||||
self.filename = None
|
self.filename = None
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
@@ -111,14 +105,12 @@ class option_base(Command):
|
|||||||
filenames.append(self.filename)
|
filenames.append(self.filename)
|
||||||
if not filenames:
|
if not filenames:
|
||||||
filenames.append(config_file('local'))
|
filenames.append(config_file('local'))
|
||||||
if len(filenames)>1:
|
if len(filenames) > 1:
|
||||||
raise DistutilsOptionError(
|
raise DistutilsOptionError(
|
||||||
"Must specify only one configuration file option",
|
"Must specify only one configuration file option",
|
||||||
filenames
|
filenames
|
||||||
)
|
)
|
||||||
self.filename, = filenames
|
self.filename, = filenames
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class setopt(option_base):
|
class setopt(option_base):
|
||||||
@@ -128,9 +120,9 @@ class setopt(option_base):
|
|||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
('command=', 'c', 'command to set an option for'),
|
('command=', 'c', 'command to set an option for'),
|
||||||
('option=', 'o', 'option to set'),
|
('option=', 'o', 'option to set'),
|
||||||
('set-value=', 's', 'value of the option'),
|
('set-value=', 's', 'value of the option'),
|
||||||
('remove', 'r', 'remove (unset) the value'),
|
('remove', 'r', 'remove (unset) the value'),
|
||||||
] + option_base.user_options
|
] + option_base.user_options
|
||||||
|
|
||||||
boolean_options = option_base.boolean_options + ['remove']
|
boolean_options = option_base.boolean_options + ['remove']
|
||||||
@@ -152,13 +144,7 @@ class setopt(option_base):
|
|||||||
def run(self):
|
def run(self):
|
||||||
edit_config(
|
edit_config(
|
||||||
self.filename, {
|
self.filename, {
|
||||||
self.command: {self.option.replace('-','_'):self.set_value}
|
self.command: {self.option.replace('-', '_'): self.set_value}
|
||||||
},
|
},
|
||||||
self.dry_run
|
self.dry_run
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
from setuptools import Command
|
|
||||||
from distutils.errors import DistutilsOptionError
|
from distutils.errors import DistutilsOptionError
|
||||||
|
from unittest import TestLoader
|
||||||
|
import unittest
|
||||||
import sys
|
import sys
|
||||||
from pkg_resources import *
|
|
||||||
from pkg_resources import _namespace_packages
|
from pkg_resources import (resource_listdir, resource_exists, normalize_path,
|
||||||
from unittest import TestLoader, main
|
working_set, _namespace_packages,
|
||||||
|
add_activation_listener, require, EntryPoint)
|
||||||
|
from setuptools import Command
|
||||||
|
from setuptools.compat import PY3
|
||||||
|
from setuptools.py31compat import unittest_main
|
||||||
|
|
||||||
|
|
||||||
class ScanningLoader(TestLoader):
|
class ScanningLoader(TestLoader):
|
||||||
|
|
||||||
def loadTestsFromModule(self, module):
|
def loadTestsFromModule(self, module):
|
||||||
"""Return a suite of all tests cases contained in the given module
|
"""Return a suite of all tests cases contained in the given module
|
||||||
|
|
||||||
@@ -15,48 +20,45 @@ class ScanningLoader(TestLoader):
|
|||||||
the return value to the tests.
|
the return value to the tests.
|
||||||
"""
|
"""
|
||||||
tests = []
|
tests = []
|
||||||
if module.__name__!='setuptools.tests.doctest': # ugh
|
tests.append(TestLoader.loadTestsFromModule(self, module))
|
||||||
tests.append(TestLoader.loadTestsFromModule(self,module))
|
|
||||||
|
|
||||||
if hasattr(module, "additional_tests"):
|
if hasattr(module, "additional_tests"):
|
||||||
tests.append(module.additional_tests())
|
tests.append(module.additional_tests())
|
||||||
|
|
||||||
if hasattr(module, '__path__'):
|
if hasattr(module, '__path__'):
|
||||||
for file in resource_listdir(module.__name__, ''):
|
for file in resource_listdir(module.__name__, ''):
|
||||||
if file.endswith('.py') and file!='__init__.py':
|
if file.endswith('.py') and file != '__init__.py':
|
||||||
submodule = module.__name__+'.'+file[:-3]
|
submodule = module.__name__ + '.' + file[:-3]
|
||||||
else:
|
else:
|
||||||
if resource_exists(
|
if resource_exists(module.__name__, file + '/__init__.py'):
|
||||||
module.__name__, file+'/__init__.py'
|
submodule = module.__name__ + '.' + file
|
||||||
):
|
|
||||||
submodule = module.__name__+'.'+file
|
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
tests.append(self.loadTestsFromName(submodule))
|
tests.append(self.loadTestsFromName(submodule))
|
||||||
|
|
||||||
if len(tests)!=1:
|
if len(tests) != 1:
|
||||||
return self.suiteClass(tests)
|
return self.suiteClass(tests)
|
||||||
else:
|
else:
|
||||||
return tests[0] # don't create a nested suite for only one return
|
return tests[0] # don't create a nested suite for only one return
|
||||||
|
|
||||||
|
|
||||||
class test(Command):
|
class test(Command):
|
||||||
|
|
||||||
"""Command to run unit tests after in-place build"""
|
"""Command to run unit tests after in-place build"""
|
||||||
|
|
||||||
description = "run unit tests after in-place build"
|
description = "run unit tests after in-place build"
|
||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
('test-module=','m', "Run 'test_suite' in specified module"),
|
('test-module=', 'm', "Run 'test_suite' in specified module"),
|
||||||
('test-suite=','s',
|
('test-suite=', 's',
|
||||||
"Test suite to run (e.g. 'some_module.test_suite')"),
|
"Test suite to run (e.g. 'some_module.test_suite')"),
|
||||||
|
('test-runner=', 'r', "Test runner to use"),
|
||||||
]
|
]
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
self.test_suite = None
|
self.test_suite = None
|
||||||
self.test_module = None
|
self.test_module = None
|
||||||
self.test_loader = None
|
self.test_loader = None
|
||||||
|
self.test_runner = None
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ class test(Command):
|
|||||||
if self.test_module is None:
|
if self.test_module is None:
|
||||||
self.test_suite = self.distribution.test_suite
|
self.test_suite = self.distribution.test_suite
|
||||||
else:
|
else:
|
||||||
self.test_suite = self.test_module+".test_suite"
|
self.test_suite = self.test_module + ".test_suite"
|
||||||
elif self.test_module:
|
elif self.test_module:
|
||||||
raise DistutilsOptionError(
|
raise DistutilsOptionError(
|
||||||
"You may specify a module or a suite, but not both"
|
"You may specify a module or a suite, but not both"
|
||||||
@@ -73,16 +75,18 @@ class test(Command):
|
|||||||
self.test_args = [self.test_suite]
|
self.test_args = [self.test_suite]
|
||||||
|
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.test_args.insert(0,'--verbose')
|
self.test_args.insert(0, '--verbose')
|
||||||
if self.test_loader is None:
|
if self.test_loader is None:
|
||||||
self.test_loader = getattr(self.distribution,'test_loader',None)
|
self.test_loader = getattr(self.distribution, 'test_loader', None)
|
||||||
if self.test_loader is None:
|
if self.test_loader is None:
|
||||||
self.test_loader = "setuptools.command.test:ScanningLoader"
|
self.test_loader = "setuptools.command.test:ScanningLoader"
|
||||||
|
if self.test_runner is None:
|
||||||
|
self.test_runner = getattr(self.distribution, 'test_runner', None)
|
||||||
|
|
||||||
def with_project_on_sys_path(self, func):
|
def with_project_on_sys_path(self, func):
|
||||||
if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
|
with_2to3 = PY3 and getattr(self.distribution, 'use_2to3', False)
|
||||||
|
|
||||||
|
if with_2to3:
|
||||||
# If we run 2to3 we can not do this inplace:
|
# If we run 2to3 we can not do this inplace:
|
||||||
|
|
||||||
# Ensure metadata is up-to-date
|
# Ensure metadata is up-to-date
|
||||||
@@ -122,10 +126,10 @@ class test(Command):
|
|||||||
sys.modules.update(old_modules)
|
sys.modules.update(old_modules)
|
||||||
working_set.__init__()
|
working_set.__init__()
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.distribution.install_requires:
|
if self.distribution.install_requires:
|
||||||
self.distribution.fetch_build_eggs(self.distribution.install_requires)
|
self.distribution.fetch_build_eggs(
|
||||||
|
self.distribution.install_requires)
|
||||||
if self.distribution.tests_require:
|
if self.distribution.tests_require:
|
||||||
self.distribution.fetch_build_eggs(self.distribution.tests_require)
|
self.distribution.fetch_build_eggs(self.distribution.tests_require)
|
||||||
|
|
||||||
@@ -137,14 +141,11 @@ class test(Command):
|
|||||||
self.announce('running "unittest %s"' % cmd)
|
self.announce('running "unittest %s"' % cmd)
|
||||||
self.with_project_on_sys_path(self.run_tests)
|
self.with_project_on_sys_path(self.run_tests)
|
||||||
|
|
||||||
|
|
||||||
def run_tests(self):
|
def run_tests(self):
|
||||||
import unittest
|
|
||||||
|
|
||||||
# Purge modules under test from sys.modules. The test loader will
|
# Purge modules under test from sys.modules. The test loader will
|
||||||
# re-import them from the build location. Required when 2to3 is used
|
# re-import them from the build location. Required when 2to3 is used
|
||||||
# with namespace packages.
|
# with namespace packages.
|
||||||
if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
|
if PY3 and getattr(self.distribution, 'use_2to3', False):
|
||||||
module = self.test_args[-1].split('.')[0]
|
module = self.test_args[-1].split('.')[0]
|
||||||
if module in _namespace_packages:
|
if module in _namespace_packages:
|
||||||
del_modules = []
|
del_modules = []
|
||||||
@@ -156,43 +157,19 @@ class test(Command):
|
|||||||
del_modules.append(name)
|
del_modules.append(name)
|
||||||
list(map(sys.modules.__delitem__, del_modules))
|
list(map(sys.modules.__delitem__, del_modules))
|
||||||
|
|
||||||
loader_ep = EntryPoint.parse("x="+self.test_loader)
|
unittest_main(
|
||||||
loader_class = loader_ep.load(require=False)
|
None, None, [unittest.__file__] + self.test_args,
|
||||||
cks = loader_class()
|
testLoader=self._resolve_as_ep(self.test_loader),
|
||||||
unittest.main(
|
testRunner=self._resolve_as_ep(self.test_runner),
|
||||||
None, None, [unittest.__file__]+self.test_args,
|
|
||||||
testLoader = cks
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _resolve_as_ep(val):
|
||||||
|
"""
|
||||||
|
Load the indicated attribute value, called, as a as if it were
|
||||||
|
specified as an entry point.
|
||||||
|
"""
|
||||||
|
if val is None:
|
||||||
|
return
|
||||||
|
parsed = EntryPoint.parse("x=" + val)
|
||||||
|
return parsed.resolve()()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ Implements a Distutils 'upload_docs' subcommand (upload documentation to
|
|||||||
PyPI's pythonhosted.org).
|
PyPI's pythonhosted.org).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from base64 import standard_b64encode
|
||||||
|
from distutils import log
|
||||||
|
from distutils.errors import DistutilsOptionError
|
||||||
|
from distutils.command.upload import upload
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import zipfile
|
import zipfile
|
||||||
@@ -12,14 +16,9 @@ import tempfile
|
|||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from base64 import standard_b64encode
|
from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3
|
||||||
from pkg_resources import iter_entry_points
|
from pkg_resources import iter_entry_points
|
||||||
|
|
||||||
from distutils import log
|
|
||||||
from distutils.errors import DistutilsOptionError
|
|
||||||
from distutils.command.upload import upload
|
|
||||||
|
|
||||||
from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3
|
|
||||||
|
|
||||||
errors = 'surrogateescape' if PY3 else 'strict'
|
errors = 'surrogateescape' if PY3 else 'strict'
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ def b(s, encoding='utf-8'):
|
|||||||
|
|
||||||
|
|
||||||
class upload_docs(upload):
|
class upload_docs(upload):
|
||||||
|
|
||||||
description = 'Upload documentation to PyPI'
|
description = 'Upload documentation to PyPI'
|
||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
@@ -42,7 +40,7 @@ class upload_docs(upload):
|
|||||||
('show-response', None,
|
('show-response', None,
|
||||||
'display full response text from server'),
|
'display full response text from server'),
|
||||||
('upload-dir=', None, 'directory to upload'),
|
('upload-dir=', None, 'directory to upload'),
|
||||||
]
|
]
|
||||||
boolean_options = upload.boolean_options
|
boolean_options = upload.boolean_options
|
||||||
|
|
||||||
def has_sphinx(self):
|
def has_sphinx(self):
|
||||||
@@ -159,7 +157,7 @@ class upload_docs(upload):
|
|||||||
elif schema == 'https':
|
elif schema == 'https':
|
||||||
conn = httplib.HTTPSConnection(netloc)
|
conn = httplib.HTTPSConnection(netloc)
|
||||||
else:
|
else:
|
||||||
raise AssertionError("unsupported schema "+schema)
|
raise AssertionError("unsupported schema " + schema)
|
||||||
|
|
||||||
data = ''
|
data = ''
|
||||||
try:
|
try:
|
||||||
@@ -171,8 +169,7 @@ class upload_docs(upload):
|
|||||||
conn.putheader('Authorization', auth)
|
conn.putheader('Authorization', auth)
|
||||||
conn.endheaders()
|
conn.endheaders()
|
||||||
conn.send(body)
|
conn.send(body)
|
||||||
except socket.error:
|
except socket.error as e:
|
||||||
e = sys.exc_info()[1]
|
|
||||||
self.announce(str(e), log.ERROR)
|
self.announce(str(e), log.ERROR)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -190,4 +187,4 @@ class upload_docs(upload):
|
|||||||
self.announce('Upload failed (%s): %s' % (r.status, r.reason),
|
self.announce('Upload failed (%s): %s' % (r.status, r.reason),
|
||||||
log.ERROR)
|
log.ERROR)
|
||||||
if self.show_response:
|
if self.show_response:
|
||||||
print('-'*75, r.read(), '-'*75)
|
print('-' * 75, r.read(), '-' * 75)
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import sys
|
import sys
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
if sys.version_info[0] < 3:
|
PY3 = sys.version_info >= (3,)
|
||||||
PY3 = False
|
PY2 = not PY3
|
||||||
|
|
||||||
|
if PY2:
|
||||||
basestring = basestring
|
basestring = basestring
|
||||||
import __builtin__ as builtins
|
import __builtin__ as builtins
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
BytesIO = StringIO
|
BytesIO = StringIO
|
||||||
execfile = execfile
|
|
||||||
func_code = lambda o: o.func_code
|
func_code = lambda o: o.func_code
|
||||||
func_globals = lambda o: o.func_globals
|
func_globals = lambda o: o.func_globals
|
||||||
im_func = lambda o: o.im_func
|
im_func = lambda o: o.im_func
|
||||||
@@ -21,8 +21,6 @@ if sys.version_info[0] < 3:
|
|||||||
iteritems = lambda o: o.iteritems()
|
iteritems = lambda o: o.iteritems()
|
||||||
long_type = long
|
long_type = long
|
||||||
maxsize = sys.maxint
|
maxsize = sys.maxint
|
||||||
next = lambda o: o.next()
|
|
||||||
numeric_types = (int, long, float)
|
|
||||||
unichr = unichr
|
unichr = unichr
|
||||||
unicode = unicode
|
unicode = unicode
|
||||||
bytes = str
|
bytes = str
|
||||||
@@ -34,9 +32,8 @@ if sys.version_info[0] < 3:
|
|||||||
|
|
||||||
exec("""def reraise(tp, value, tb=None):
|
exec("""def reraise(tp, value, tb=None):
|
||||||
raise tp, value, tb""")
|
raise tp, value, tb""")
|
||||||
else:
|
|
||||||
PY3 = True
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
basestring = str
|
basestring = str
|
||||||
import builtins
|
import builtins
|
||||||
import configparser as ConfigParser
|
import configparser as ConfigParser
|
||||||
@@ -51,8 +48,6 @@ else:
|
|||||||
iteritems = lambda o: o.items()
|
iteritems = lambda o: o.items()
|
||||||
long_type = int
|
long_type = int
|
||||||
maxsize = sys.maxsize
|
maxsize = sys.maxsize
|
||||||
next = next
|
|
||||||
numeric_types = (int, float)
|
|
||||||
unichr = chr
|
unichr = chr
|
||||||
unicode = str
|
unicode = str
|
||||||
bytes = bytes
|
bytes = bytes
|
||||||
@@ -65,18 +60,6 @@ else:
|
|||||||
)
|
)
|
||||||
filterfalse = itertools.filterfalse
|
filterfalse = itertools.filterfalse
|
||||||
|
|
||||||
def execfile(fn, globs=None, locs=None):
|
|
||||||
if globs is None:
|
|
||||||
globs = globals()
|
|
||||||
if locs is None:
|
|
||||||
locs = globs
|
|
||||||
f = open(fn, 'rb')
|
|
||||||
try:
|
|
||||||
source = f.read()
|
|
||||||
finally:
|
|
||||||
f.close()
|
|
||||||
exec(compile(source, fn, 'exec'), globs, locs)
|
|
||||||
|
|
||||||
def reraise(tp, value, tb=None):
|
def reraise(tp, value, tb=None):
|
||||||
if value.__traceback__ is not tb:
|
if value.__traceback__ is not tb:
|
||||||
raise value.with_traceback(tb)
|
raise value.with_traceback(tb)
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
from __future__ import generators
|
import sys
|
||||||
import sys, imp, marshal
|
import imp
|
||||||
|
import marshal
|
||||||
from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN
|
from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN
|
||||||
from distutils.version import StrictVersion, LooseVersion
|
from distutils.version import StrictVersion
|
||||||
|
from setuptools import compat
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Require', 'find_module', 'get_module_constant', 'extract_constant'
|
'Require', 'find_module', 'get_module_constant', 'extract_constant'
|
||||||
@@ -10,9 +12,8 @@ __all__ = [
|
|||||||
class Require:
|
class Require:
|
||||||
"""A prerequisite to building or installing a distribution"""
|
"""A prerequisite to building or installing a distribution"""
|
||||||
|
|
||||||
def __init__(self,name,requested_version,module,homepage='',
|
def __init__(self, name, requested_version, module, homepage='',
|
||||||
attribute=None,format=None
|
attribute=None, format=None):
|
||||||
):
|
|
||||||
|
|
||||||
if format is None and requested_version is not None:
|
if format is None and requested_version is not None:
|
||||||
format = StrictVersion
|
format = StrictVersion
|
||||||
@@ -25,20 +26,17 @@ class Require:
|
|||||||
self.__dict__.update(locals())
|
self.__dict__.update(locals())
|
||||||
del self.self
|
del self.self
|
||||||
|
|
||||||
|
|
||||||
def full_name(self):
|
def full_name(self):
|
||||||
"""Return full package/distribution name, w/version"""
|
"""Return full package/distribution name, w/version"""
|
||||||
if self.requested_version is not None:
|
if self.requested_version is not None:
|
||||||
return '%s-%s' % (self.name,self.requested_version)
|
return '%s-%s' % (self.name,self.requested_version)
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def version_ok(self, version):
|
||||||
def version_ok(self,version):
|
|
||||||
"""Is 'version' sufficiently up-to-date?"""
|
"""Is 'version' sufficiently up-to-date?"""
|
||||||
return self.attribute is None or self.format is None or \
|
return self.attribute is None or self.format is None or \
|
||||||
str(version) != "unknown" and version >= self.requested_version
|
str(version) != "unknown" and version >= self.requested_version
|
||||||
|
|
||||||
|
|
||||||
def get_version(self, paths=None, default="unknown"):
|
def get_version(self, paths=None, default="unknown"):
|
||||||
|
|
||||||
"""Get version number of installed module, 'None', or 'default'
|
"""Get version number of installed module, 'None', or 'default'
|
||||||
@@ -59,20 +57,18 @@ class Require:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
v = get_module_constant(self.module,self.attribute,default,paths)
|
v = get_module_constant(self.module, self.attribute, default, paths)
|
||||||
|
|
||||||
if v is not None and v is not default and self.format is not None:
|
if v is not None and v is not default and self.format is not None:
|
||||||
return self.format(v)
|
return self.format(v)
|
||||||
|
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
def is_present(self, paths=None):
|
||||||
def is_present(self,paths=None):
|
|
||||||
"""Return true if dependency is present on 'paths'"""
|
"""Return true if dependency is present on 'paths'"""
|
||||||
return self.get_version(paths) is not None
|
return self.get_version(paths) is not None
|
||||||
|
|
||||||
|
def is_current(self, paths=None):
|
||||||
def is_current(self,paths=None):
|
|
||||||
"""Return true if dependency is present and up-to-date on 'paths'"""
|
"""Return true if dependency is present and up-to-date on 'paths'"""
|
||||||
version = self.get_version(paths)
|
version = self.get_version(paths)
|
||||||
if version is None:
|
if version is None:
|
||||||
@@ -103,7 +99,7 @@ def _iter_code(code):
|
|||||||
ptr += 3
|
ptr += 3
|
||||||
|
|
||||||
if op==EXTENDED_ARG:
|
if op==EXTENDED_ARG:
|
||||||
extended_arg = arg * long_type(65536)
|
extended_arg = arg * compat.long_type(65536)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -113,14 +109,6 @@ def _iter_code(code):
|
|||||||
yield op,arg
|
yield op,arg
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def find_module(module, paths=None):
|
def find_module(module, paths=None):
|
||||||
"""Just like 'imp.find_module()', but with package support"""
|
"""Just like 'imp.find_module()', but with package support"""
|
||||||
|
|
||||||
@@ -140,28 +128,6 @@ def find_module(module, paths=None):
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_module_constant(module, symbol, default=-1, paths=None):
|
def get_module_constant(module, symbol, default=-1, paths=None):
|
||||||
|
|
||||||
"""Find 'module' by searching 'paths', and extract 'symbol'
|
"""Find 'module' by searching 'paths', and extract 'symbol'
|
||||||
@@ -171,7 +137,7 @@ def get_module_constant(module, symbol, default=-1, paths=None):
|
|||||||
constant. Otherwise, return 'default'."""
|
constant. Otherwise, return 'default'."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f, path, (suffix,mode,kind) = find_module(module,paths)
|
f, path, (suffix, mode, kind) = find_module(module, paths)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# Module doesn't exist
|
# Module doesn't exist
|
||||||
return None
|
return None
|
||||||
@@ -187,23 +153,17 @@ def get_module_constant(module, symbol, default=-1, paths=None):
|
|||||||
else:
|
else:
|
||||||
# Not something we can parse; we'll have to import it. :(
|
# Not something we can parse; we'll have to import it. :(
|
||||||
if module not in sys.modules:
|
if module not in sys.modules:
|
||||||
imp.load_module(module,f,path,(suffix,mode,kind))
|
imp.load_module(module, f, path, (suffix, mode, kind))
|
||||||
return getattr(sys.modules[module],symbol,None)
|
return getattr(sys.modules[module], symbol, None)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if f:
|
if f:
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
return extract_constant(code,symbol,default)
|
return extract_constant(code, symbol, default)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_constant(code, symbol, default=-1):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def extract_constant(code,symbol,default=-1):
|
|
||||||
"""Extract the constant value of 'symbol' from 'code'
|
"""Extract the constant value of 'symbol' from 'code'
|
||||||
|
|
||||||
If the name 'symbol' is bound to a constant value by the Python code
|
If the name 'symbol' is bound to a constant value by the Python code
|
||||||
@@ -236,11 +196,20 @@ def extract_constant(code,symbol,default=-1):
|
|||||||
return const
|
return const
|
||||||
else:
|
else:
|
||||||
const = default
|
const = default
|
||||||
|
|
||||||
if sys.platform.startswith('java') or sys.platform == 'cli':
|
|
||||||
# XXX it'd be better to test assertions about bytecode instead...
|
|
||||||
del extract_constant, get_module_constant
|
|
||||||
__all__.remove('extract_constant')
|
|
||||||
__all__.remove('get_module_constant')
|
|
||||||
|
|
||||||
|
|
||||||
|
def _update_globals():
|
||||||
|
"""
|
||||||
|
Patch the globals to remove the objects not available on some platforms.
|
||||||
|
|
||||||
|
XXX it'd be better to test assertions about bytecode instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not sys.platform.startswith('java') and sys.platform != 'cli':
|
||||||
|
return
|
||||||
|
incompatible = 'extract_constant', 'get_module_constant'
|
||||||
|
for name in incompatible:
|
||||||
|
del globals()[name]
|
||||||
|
__all__.remove(name)
|
||||||
|
|
||||||
|
_update_globals()
|
||||||
|
|||||||
@@ -4,17 +4,23 @@ import re
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
import numbers
|
||||||
import distutils.log
|
import distutils.log
|
||||||
import distutils.core
|
import distutils.core
|
||||||
import distutils.cmd
|
import distutils.cmd
|
||||||
|
import distutils.dist
|
||||||
from distutils.core import Distribution as _Distribution
|
from distutils.core import Distribution as _Distribution
|
||||||
from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
|
from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
|
||||||
DistutilsSetupError)
|
DistutilsSetupError)
|
||||||
|
|
||||||
from setuptools.depends import Require
|
from setuptools.depends import Require
|
||||||
from setuptools.compat import numeric_types, basestring
|
from setuptools.compat import basestring, PY2
|
||||||
|
from setuptools import windows_support
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
|
packaging = pkg_resources.packaging
|
||||||
|
|
||||||
|
|
||||||
def _get_unpatched(cls):
|
def _get_unpatched(cls):
|
||||||
"""Protect against re-patching the distutils if reloaded
|
"""Protect against re-patching the distutils if reloaded
|
||||||
|
|
||||||
@@ -31,6 +37,27 @@ def _get_unpatched(cls):
|
|||||||
|
|
||||||
_Distribution = _get_unpatched(_Distribution)
|
_Distribution = _get_unpatched(_Distribution)
|
||||||
|
|
||||||
|
def _patch_distribution_metadata_write_pkg_info():
|
||||||
|
"""
|
||||||
|
Workaround issue #197 - Python 3 prior to 3.2.2 uses an environment-local
|
||||||
|
encoding to save the pkg_info. Monkey-patch its write_pkg_info method to
|
||||||
|
correct this undesirable behavior.
|
||||||
|
"""
|
||||||
|
environment_local = (3,) <= sys.version_info[:3] < (3, 2, 2)
|
||||||
|
if not environment_local:
|
||||||
|
return
|
||||||
|
|
||||||
|
# from Python 3.4
|
||||||
|
def write_pkg_info(self, base_dir):
|
||||||
|
"""Write the PKG-INFO file into the release tree.
|
||||||
|
"""
|
||||||
|
with open(os.path.join(base_dir, 'PKG-INFO'), 'w',
|
||||||
|
encoding='UTF-8') as pkg_info:
|
||||||
|
self.write_pkg_file(pkg_info)
|
||||||
|
|
||||||
|
distutils.dist.DistributionMetadata.write_pkg_info = write_pkg_info
|
||||||
|
_patch_distribution_metadata_write_pkg_info()
|
||||||
|
|
||||||
sequence = tuple, list
|
sequence = tuple, list
|
||||||
|
|
||||||
def check_importable(dist, attr, value):
|
def check_importable(dist, attr, value):
|
||||||
@@ -104,8 +131,7 @@ def check_entry_points(dist, attr, value):
|
|||||||
"""Verify that entry_points map is parseable"""
|
"""Verify that entry_points map is parseable"""
|
||||||
try:
|
try:
|
||||||
pkg_resources.EntryPoint.parse_map(value)
|
pkg_resources.EntryPoint.parse_map(value)
|
||||||
except ValueError:
|
except ValueError as e:
|
||||||
e = sys.exc_info()[1]
|
|
||||||
raise DistutilsSetupError(e)
|
raise DistutilsSetupError(e)
|
||||||
|
|
||||||
def check_test_suite(dist, attr, value):
|
def check_test_suite(dist, attr, value):
|
||||||
@@ -236,15 +262,36 @@ class Distribution(_Distribution):
|
|||||||
self.dependency_links = attrs.pop('dependency_links', [])
|
self.dependency_links = attrs.pop('dependency_links', [])
|
||||||
assert_string_list(self,'dependency_links',self.dependency_links)
|
assert_string_list(self,'dependency_links',self.dependency_links)
|
||||||
if attrs and 'setup_requires' in attrs:
|
if attrs and 'setup_requires' in attrs:
|
||||||
self.fetch_build_eggs(attrs.pop('setup_requires'))
|
self.fetch_build_eggs(attrs['setup_requires'])
|
||||||
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
|
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
|
||||||
if not hasattr(self,ep.name):
|
if not hasattr(self,ep.name):
|
||||||
setattr(self,ep.name,None)
|
setattr(self,ep.name,None)
|
||||||
_Distribution.__init__(self,attrs)
|
_Distribution.__init__(self,attrs)
|
||||||
if isinstance(self.metadata.version, numeric_types):
|
if isinstance(self.metadata.version, numbers.Number):
|
||||||
# Some people apparently take "version number" too literally :)
|
# Some people apparently take "version number" too literally :)
|
||||||
self.metadata.version = str(self.metadata.version)
|
self.metadata.version = str(self.metadata.version)
|
||||||
|
|
||||||
|
if self.metadata.version is not None:
|
||||||
|
try:
|
||||||
|
ver = packaging.version.Version(self.metadata.version)
|
||||||
|
normalized_version = str(ver)
|
||||||
|
if self.metadata.version != normalized_version:
|
||||||
|
warnings.warn(
|
||||||
|
"The version specified requires normalization, "
|
||||||
|
"consider using '%s' instead of '%s'." % (
|
||||||
|
normalized_version,
|
||||||
|
self.metadata.version,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.metadata.version = normalized_version
|
||||||
|
except (packaging.version.InvalidVersion, TypeError):
|
||||||
|
warnings.warn(
|
||||||
|
"The version specified (%r) is an invalid version, this "
|
||||||
|
"may not work as expected with newer versions of "
|
||||||
|
"setuptools, pip, and PyPI. Please see PEP 440 for more "
|
||||||
|
"details." % self.metadata.version
|
||||||
|
)
|
||||||
|
|
||||||
def parse_command_line(self):
|
def parse_command_line(self):
|
||||||
"""Process features after parsing command line options"""
|
"""Process features after parsing command line options"""
|
||||||
result = _Distribution.parse_command_line(self)
|
result = _Distribution.parse_command_line(self)
|
||||||
@@ -258,12 +305,13 @@ class Distribution(_Distribution):
|
|||||||
|
|
||||||
def fetch_build_eggs(self, requires):
|
def fetch_build_eggs(self, requires):
|
||||||
"""Resolve pre-setup requirements"""
|
"""Resolve pre-setup requirements"""
|
||||||
from pkg_resources import working_set, parse_requirements
|
resolved_dists = pkg_resources.working_set.resolve(
|
||||||
for dist in working_set.resolve(
|
pkg_resources.parse_requirements(requires),
|
||||||
parse_requirements(requires), installer=self.fetch_build_egg,
|
installer=self.fetch_build_egg,
|
||||||
replace_conflicting=True
|
replace_conflicting=True,
|
||||||
):
|
)
|
||||||
working_set.add(dist, replace=True)
|
for dist in resolved_dists:
|
||||||
|
pkg_resources.working_set.add(dist, replace=True)
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
_Distribution.finalize_options(self)
|
_Distribution.finalize_options(self)
|
||||||
@@ -281,6 +329,21 @@ class Distribution(_Distribution):
|
|||||||
else:
|
else:
|
||||||
self.convert_2to3_doctests = []
|
self.convert_2to3_doctests = []
|
||||||
|
|
||||||
|
def get_egg_cache_dir(self):
|
||||||
|
egg_cache_dir = os.path.join(os.curdir, '.eggs')
|
||||||
|
if not os.path.exists(egg_cache_dir):
|
||||||
|
os.mkdir(egg_cache_dir)
|
||||||
|
windows_support.hide_file(egg_cache_dir)
|
||||||
|
readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
|
||||||
|
with open(readme_txt_filename, 'w') as f:
|
||||||
|
f.write('This directory contains eggs that were downloaded '
|
||||||
|
'by setuptools to build, test, and run plug-ins.\n\n')
|
||||||
|
f.write('This directory caches those eggs to prevent '
|
||||||
|
'repeated downloads.\n\n')
|
||||||
|
f.write('However, it is safe to delete this directory.\n\n')
|
||||||
|
|
||||||
|
return egg_cache_dir
|
||||||
|
|
||||||
def fetch_build_egg(self, req):
|
def fetch_build_egg(self, req):
|
||||||
"""Fetch an egg needed for building"""
|
"""Fetch an egg needed for building"""
|
||||||
|
|
||||||
@@ -304,8 +367,9 @@ class Distribution(_Distribution):
|
|||||||
if 'find_links' in opts:
|
if 'find_links' in opts:
|
||||||
links = opts['find_links'][1].split() + links
|
links = opts['find_links'][1].split() + links
|
||||||
opts['find_links'] = ('setup', links)
|
opts['find_links'] = ('setup', links)
|
||||||
|
install_dir = self.get_egg_cache_dir()
|
||||||
cmd = easy_install(
|
cmd = easy_install(
|
||||||
dist, args=["x"], install_dir=os.curdir, exclude_scripts=True,
|
dist, args=["x"], install_dir=install_dir, exclude_scripts=True,
|
||||||
always_copy=False, build_directory=None, editable=False,
|
always_copy=False, build_directory=None, editable=False,
|
||||||
upgrade=False, multi_version=True, no_report=True, user=False
|
upgrade=False, multi_version=True, no_report=True, user=False
|
||||||
)
|
)
|
||||||
@@ -369,7 +433,8 @@ class Distribution(_Distribution):
|
|||||||
def print_commands(self):
|
def print_commands(self):
|
||||||
for ep in pkg_resources.iter_entry_points('distutils.commands'):
|
for ep in pkg_resources.iter_entry_points('distutils.commands'):
|
||||||
if ep.name not in self.cmdclass:
|
if ep.name not in self.cmdclass:
|
||||||
cmdclass = ep.load(False) # don't require extras, we're not running
|
# don't require extras as the commands won't be invoked
|
||||||
|
cmdclass = ep.resolve()
|
||||||
self.cmdclass[ep.name] = cmdclass
|
self.cmdclass[ep.name] = cmdclass
|
||||||
return _Distribution.print_commands(self)
|
return _Distribution.print_commands(self)
|
||||||
|
|
||||||
@@ -608,7 +673,7 @@ class Distribution(_Distribution):
|
|||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info < (3,) or self.help_commands:
|
if PY2 or self.help_commands:
|
||||||
return _Distribution.handle_display_options(self, option_order)
|
return _Distribution.handle_display_options(self, option_order)
|
||||||
|
|
||||||
# Stdout may be StringIO (e.g. in tests)
|
# Stdout may be StringIO (e.g. in tests)
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
|
import functools
|
||||||
import distutils.core
|
import distutils.core
|
||||||
|
import distutils.errors
|
||||||
import distutils.extension
|
import distutils.extension
|
||||||
|
|
||||||
from setuptools.dist import _get_unpatched
|
from .dist import _get_unpatched
|
||||||
|
from . import msvc9_support
|
||||||
|
|
||||||
_Extension = _get_unpatched(distutils.core.Extension)
|
_Extension = _get_unpatched(distutils.core.Extension)
|
||||||
|
|
||||||
|
msvc9_support.patch_for_specialized_compiler()
|
||||||
|
|
||||||
def have_pyrex():
|
def have_pyrex():
|
||||||
"""
|
"""
|
||||||
Return True if Cython or Pyrex can be imported.
|
Return True if Cython or Pyrex can be imported.
|
||||||
@@ -26,16 +32,21 @@ class Extension(_Extension):
|
|||||||
|
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
_Extension.__init__(self, *args, **kw)
|
_Extension.__init__(self, *args, **kw)
|
||||||
if not have_pyrex():
|
self._convert_pyx_sources_to_lang()
|
||||||
self._convert_pyx_sources_to_c()
|
|
||||||
|
|
||||||
def _convert_pyx_sources_to_c(self):
|
def _convert_pyx_sources_to_lang(self):
|
||||||
"convert .pyx extensions to .c"
|
"""
|
||||||
def pyx_to_c(source):
|
Replace sources with .pyx extensions to sources with the target
|
||||||
if source.endswith('.pyx'):
|
language extension. This mechanism allows language authors to supply
|
||||||
source = source[:-4] + '.c'
|
pre-converted sources but to prefer the .pyx sources.
|
||||||
return source
|
"""
|
||||||
self.sources = list(map(pyx_to_c, self.sources))
|
if have_pyrex():
|
||||||
|
# the build has Cython, so allow it to compile the .pyx files
|
||||||
|
return
|
||||||
|
lang = self.language or ''
|
||||||
|
target_ext = '.cpp' if lang.lower() == 'c++' else '.c'
|
||||||
|
sub = functools.partial(re.sub, '.pyx$', target_ext)
|
||||||
|
self.sources = list(map(sub, self.sources))
|
||||||
|
|
||||||
class Library(Extension):
|
class Library(Extension):
|
||||||
"""Just like a regular Extension, but built as a library instead"""
|
"""Just like a regular Extension, but built as a library instead"""
|
||||||
|
|||||||
63
awx/lib/site-packages/setuptools/msvc9_support.py
Normal file
63
awx/lib/site-packages/setuptools/msvc9_support.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
try:
|
||||||
|
import distutils.msvc9compiler
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
unpatched = dict()
|
||||||
|
|
||||||
|
def patch_for_specialized_compiler():
|
||||||
|
"""
|
||||||
|
Patch functions in distutils.msvc9compiler to use the standalone compiler
|
||||||
|
build for Python (Windows only). Fall back to original behavior when the
|
||||||
|
standalone compiler is not available.
|
||||||
|
"""
|
||||||
|
if 'distutils' not in globals():
|
||||||
|
# The module isn't available to be patched
|
||||||
|
return
|
||||||
|
|
||||||
|
if unpatched:
|
||||||
|
# Already patched
|
||||||
|
return
|
||||||
|
|
||||||
|
unpatched.update(vars(distutils.msvc9compiler))
|
||||||
|
|
||||||
|
distutils.msvc9compiler.find_vcvarsall = find_vcvarsall
|
||||||
|
distutils.msvc9compiler.query_vcvarsall = query_vcvarsall
|
||||||
|
|
||||||
|
def find_vcvarsall(version):
|
||||||
|
Reg = distutils.msvc9compiler.Reg
|
||||||
|
VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'
|
||||||
|
key = VC_BASE % ('', version)
|
||||||
|
try:
|
||||||
|
# Per-user installs register the compiler path here
|
||||||
|
productdir = Reg.get_value(key, "installdir")
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
# All-user installs on a 64-bit system register here
|
||||||
|
key = VC_BASE % ('Wow6432Node\\', version)
|
||||||
|
productdir = Reg.get_value(key, "installdir")
|
||||||
|
except KeyError:
|
||||||
|
productdir = None
|
||||||
|
|
||||||
|
if productdir:
|
||||||
|
import os
|
||||||
|
vcvarsall = os.path.join(productdir, "vcvarsall.bat")
|
||||||
|
if os.path.isfile(vcvarsall):
|
||||||
|
return vcvarsall
|
||||||
|
|
||||||
|
return unpatched['find_vcvarsall'](version)
|
||||||
|
|
||||||
|
def query_vcvarsall(version, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return unpatched['query_vcvarsall'](version, *args, **kwargs)
|
||||||
|
except distutils.errors.DistutilsPlatformError as exc:
|
||||||
|
if exc and "vcvarsall.bat" in exc.args[0]:
|
||||||
|
message = 'Microsoft Visual C++ %0.1f is required (%s).' % (version, exc.args[0])
|
||||||
|
if int(version) == 9:
|
||||||
|
# This redirection link is maintained by Microsoft.
|
||||||
|
# Contact vspython@microsoft.com if it needs updating.
|
||||||
|
raise distutils.errors.DistutilsPlatformError(
|
||||||
|
message + ' Get it from http://aka.ms/vcpython27'
|
||||||
|
)
|
||||||
|
raise distutils.errors.DistutilsPlatformError(message)
|
||||||
|
raise
|
||||||
@@ -632,16 +632,15 @@ class PackageIndex(Environment):
|
|||||||
shutil.copy2(filename, dst)
|
shutil.copy2(filename, dst)
|
||||||
filename=dst
|
filename=dst
|
||||||
|
|
||||||
file = open(os.path.join(tmpdir, 'setup.py'), 'w')
|
with open(os.path.join(tmpdir, 'setup.py'), 'w') as file:
|
||||||
file.write(
|
file.write(
|
||||||
"from setuptools import setup\n"
|
"from setuptools import setup\n"
|
||||||
"setup(name=%r, version=%r, py_modules=[%r])\n"
|
"setup(name=%r, version=%r, py_modules=[%r])\n"
|
||||||
% (
|
% (
|
||||||
dists[0].project_name, dists[0].version,
|
dists[0].project_name, dists[0].version,
|
||||||
os.path.splitext(basename)[0]
|
os.path.splitext(basename)[0]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
file.close()
|
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
elif match:
|
elif match:
|
||||||
@@ -660,7 +659,7 @@ class PackageIndex(Environment):
|
|||||||
def _download_to(self, url, filename):
|
def _download_to(self, url, filename):
|
||||||
self.info("Downloading %s", url)
|
self.info("Downloading %s", url)
|
||||||
# Download the file
|
# Download the file
|
||||||
fp, tfp, info = None, None, None
|
fp, info = None, None
|
||||||
try:
|
try:
|
||||||
checker = HashChecker.from_url(url)
|
checker = HashChecker.from_url(url)
|
||||||
fp = self.open_url(strip_fragment(url))
|
fp = self.open_url(strip_fragment(url))
|
||||||
@@ -677,21 +676,20 @@ class PackageIndex(Environment):
|
|||||||
sizes = get_all_headers(headers, 'Content-Length')
|
sizes = get_all_headers(headers, 'Content-Length')
|
||||||
size = max(map(int, sizes))
|
size = max(map(int, sizes))
|
||||||
self.reporthook(url, filename, blocknum, bs, size)
|
self.reporthook(url, filename, blocknum, bs, size)
|
||||||
tfp = open(filename,'wb')
|
with open(filename,'wb') as tfp:
|
||||||
while True:
|
while True:
|
||||||
block = fp.read(bs)
|
block = fp.read(bs)
|
||||||
if block:
|
if block:
|
||||||
checker.feed(block)
|
checker.feed(block)
|
||||||
tfp.write(block)
|
tfp.write(block)
|
||||||
blocknum += 1
|
blocknum += 1
|
||||||
self.reporthook(url, filename, blocknum, bs, size)
|
self.reporthook(url, filename, blocknum, bs, size)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
self.check_hash(checker, filename, tfp)
|
self.check_hash(checker, filename, tfp)
|
||||||
return headers
|
return headers
|
||||||
finally:
|
finally:
|
||||||
if fp: fp.close()
|
if fp: fp.close()
|
||||||
if tfp: tfp.close()
|
|
||||||
|
|
||||||
def reporthook(self, url, filename, blocknum, blksize, size):
|
def reporthook(self, url, filename, blocknum, blksize, size):
|
||||||
pass # no-op
|
pass # no-op
|
||||||
@@ -701,25 +699,21 @@ class PackageIndex(Environment):
|
|||||||
return local_open(url)
|
return local_open(url)
|
||||||
try:
|
try:
|
||||||
return open_with_auth(url, self.opener)
|
return open_with_auth(url, self.opener)
|
||||||
except (ValueError, httplib.InvalidURL):
|
except (ValueError, httplib.InvalidURL) as v:
|
||||||
v = sys.exc_info()[1]
|
|
||||||
msg = ' '.join([str(arg) for arg in v.args])
|
msg = ' '.join([str(arg) for arg in v.args])
|
||||||
if warning:
|
if warning:
|
||||||
self.warn(warning, msg)
|
self.warn(warning, msg)
|
||||||
else:
|
else:
|
||||||
raise DistutilsError('%s %s' % (url, msg))
|
raise DistutilsError('%s %s' % (url, msg))
|
||||||
except urllib2.HTTPError:
|
except urllib2.HTTPError as v:
|
||||||
v = sys.exc_info()[1]
|
|
||||||
return v
|
return v
|
||||||
except urllib2.URLError:
|
except urllib2.URLError as v:
|
||||||
v = sys.exc_info()[1]
|
|
||||||
if warning:
|
if warning:
|
||||||
self.warn(warning, v.reason)
|
self.warn(warning, v.reason)
|
||||||
else:
|
else:
|
||||||
raise DistutilsError("Download error for %s: %s"
|
raise DistutilsError("Download error for %s: %s"
|
||||||
% (url, v.reason))
|
% (url, v.reason))
|
||||||
except httplib.BadStatusLine:
|
except httplib.BadStatusLine as v:
|
||||||
v = sys.exc_info()[1]
|
|
||||||
if warning:
|
if warning:
|
||||||
self.warn(warning, v.line)
|
self.warn(warning, v.line)
|
||||||
else:
|
else:
|
||||||
@@ -728,8 +722,7 @@ class PackageIndex(Environment):
|
|||||||
'down, %s' %
|
'down, %s' %
|
||||||
(url, v.line)
|
(url, v.line)
|
||||||
)
|
)
|
||||||
except httplib.HTTPException:
|
except httplib.HTTPException as v:
|
||||||
v = sys.exc_info()[1]
|
|
||||||
if warning:
|
if warning:
|
||||||
self.warn(warning, v)
|
self.warn(warning, v)
|
||||||
else:
|
else:
|
||||||
@@ -1040,9 +1033,8 @@ def local_open(url):
|
|||||||
files = []
|
files = []
|
||||||
for f in os.listdir(filename):
|
for f in os.listdir(filename):
|
||||||
if f=='index.html':
|
if f=='index.html':
|
||||||
fp = open(os.path.join(filename,f),'r')
|
with open(os.path.join(filename,f),'r') as fp:
|
||||||
body = fp.read()
|
body = fp.read()
|
||||||
fp.close()
|
|
||||||
break
|
break
|
||||||
elif os.path.isdir(os.path.join(filename,f)):
|
elif os.path.isdir(os.path.join(filename,f)):
|
||||||
f+='/'
|
f+='/'
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
__all__ = ['get_config_vars', 'get_path']
|
__all__ = ['get_config_vars', 'get_path']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -9,3 +12,41 @@ except ImportError:
|
|||||||
if name not in ('platlib', 'purelib'):
|
if name not in ('platlib', 'purelib'):
|
||||||
raise ValueError("Name must be purelib or platlib")
|
raise ValueError("Name must be purelib or platlib")
|
||||||
return get_python_lib(name=='platlib')
|
return get_python_lib(name=='platlib')
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Python >=3.2
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
except ImportError:
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
class TemporaryDirectory(object):
|
||||||
|
""""
|
||||||
|
Very simple temporary directory context manager.
|
||||||
|
Will try to delete afterward, but will also ignore OS and similar
|
||||||
|
errors on deletion.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.name = None # Handle mkdtemp raising an exception
|
||||||
|
self.name = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __exit__(self, exctype, excvalue, exctrace):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(self.name, True)
|
||||||
|
except OSError: #removal errors are not the only possible
|
||||||
|
pass
|
||||||
|
self.name = None
|
||||||
|
|
||||||
|
|
||||||
|
unittest_main = unittest.main
|
||||||
|
|
||||||
|
_PY31 = (3, 1) <= sys.version_info[:2] < (3, 2)
|
||||||
|
if _PY31:
|
||||||
|
# on Python 3.1, translate testRunner==None to TextTestRunner
|
||||||
|
# for compatibility with Python 2.6, 2.7, and 3.2+
|
||||||
|
def unittest_main(*args, **kwargs):
|
||||||
|
if 'testRunner' in kwargs and kwargs['testRunner'] is None:
|
||||||
|
kwargs['testRunner'] = unittest.TextTestRunner
|
||||||
|
return unittest.main(*args, **kwargs)
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import operator
|
|||||||
import functools
|
import functools
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
|
import contextlib
|
||||||
|
import pickle
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
@@ -20,58 +22,221 @@ _open = open
|
|||||||
from distutils.errors import DistutilsError
|
from distutils.errors import DistutilsError
|
||||||
from pkg_resources import working_set
|
from pkg_resources import working_set
|
||||||
|
|
||||||
from setuptools.compat import builtins, execfile
|
from setuptools import compat
|
||||||
|
from setuptools.compat import builtins
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup",
|
"AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def _execfile(filename, globals, locals=None):
|
||||||
|
"""
|
||||||
|
Python 3 implementation of execfile.
|
||||||
|
"""
|
||||||
|
mode = 'rb'
|
||||||
|
# Python 2.6 compile requires LF for newlines, so use deprecated
|
||||||
|
# Universal newlines support.
|
||||||
|
if sys.version_info < (2, 7):
|
||||||
|
mode += 'U'
|
||||||
|
with open(filename, mode) as stream:
|
||||||
|
script = stream.read()
|
||||||
|
if locals is None:
|
||||||
|
locals = globals
|
||||||
|
code = compile(script, filename, 'exec')
|
||||||
|
exec(code, globals, locals)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def save_argv():
|
||||||
|
saved = sys.argv[:]
|
||||||
|
try:
|
||||||
|
yield saved
|
||||||
|
finally:
|
||||||
|
sys.argv[:] = saved
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def save_path():
|
||||||
|
saved = sys.path[:]
|
||||||
|
try:
|
||||||
|
yield saved
|
||||||
|
finally:
|
||||||
|
sys.path[:] = saved
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def override_temp(replacement):
|
||||||
|
"""
|
||||||
|
Monkey-patch tempfile.tempdir with replacement, ensuring it exists
|
||||||
|
"""
|
||||||
|
if not os.path.isdir(replacement):
|
||||||
|
os.makedirs(replacement)
|
||||||
|
|
||||||
|
saved = tempfile.tempdir
|
||||||
|
|
||||||
|
tempfile.tempdir = replacement
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
tempfile.tempdir = saved
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def pushd(target):
|
||||||
|
saved = os.getcwd()
|
||||||
|
os.chdir(target)
|
||||||
|
try:
|
||||||
|
yield saved
|
||||||
|
finally:
|
||||||
|
os.chdir(saved)
|
||||||
|
|
||||||
|
|
||||||
|
class UnpickleableException(Exception):
|
||||||
|
"""
|
||||||
|
An exception representing another Exception that could not be pickled.
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def dump(cls, type, exc):
|
||||||
|
"""
|
||||||
|
Always return a dumped (pickled) type and exc. If exc can't be pickled,
|
||||||
|
wrap it in UnpickleableException first.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return pickle.dumps(type), pickle.dumps(exc)
|
||||||
|
except Exception:
|
||||||
|
return cls.dump(cls, cls(repr(exc)))
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptionSaver:
|
||||||
|
"""
|
||||||
|
A Context Manager that will save an exception, serialized, and restore it
|
||||||
|
later.
|
||||||
|
"""
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, type, exc, tb):
|
||||||
|
if not exc:
|
||||||
|
return
|
||||||
|
|
||||||
|
# dump the exception
|
||||||
|
self._saved = UnpickleableException.dump(type, exc)
|
||||||
|
self._tb = tb
|
||||||
|
|
||||||
|
# suppress the exception
|
||||||
|
return True
|
||||||
|
|
||||||
|
def resume(self):
|
||||||
|
"restore and re-raise any exception"
|
||||||
|
|
||||||
|
if '_saved' not in vars(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
type, exc = map(pickle.loads, self._saved)
|
||||||
|
compat.reraise(type, exc, self._tb)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def save_modules():
|
||||||
|
"""
|
||||||
|
Context in which imported modules are saved.
|
||||||
|
|
||||||
|
Translates exceptions internal to the context into the equivalent exception
|
||||||
|
outside the context.
|
||||||
|
"""
|
||||||
|
saved = sys.modules.copy()
|
||||||
|
with ExceptionSaver() as saved_exc:
|
||||||
|
yield saved
|
||||||
|
|
||||||
|
sys.modules.update(saved)
|
||||||
|
# remove any modules imported since
|
||||||
|
del_modules = (
|
||||||
|
mod_name for mod_name in sys.modules
|
||||||
|
if mod_name not in saved
|
||||||
|
# exclude any encodings modules. See #285
|
||||||
|
and not mod_name.startswith('encodings.')
|
||||||
|
)
|
||||||
|
_clear_modules(del_modules)
|
||||||
|
|
||||||
|
saved_exc.resume()
|
||||||
|
|
||||||
|
|
||||||
|
def _clear_modules(module_names):
|
||||||
|
for mod_name in list(module_names):
|
||||||
|
del sys.modules[mod_name]
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def save_pkg_resources_state():
|
||||||
|
saved = pkg_resources.__getstate__()
|
||||||
|
try:
|
||||||
|
yield saved
|
||||||
|
finally:
|
||||||
|
pkg_resources.__setstate__(saved)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def setup_context(setup_dir):
|
||||||
|
temp_dir = os.path.join(setup_dir, 'temp')
|
||||||
|
with save_pkg_resources_state():
|
||||||
|
with save_modules():
|
||||||
|
hide_setuptools()
|
||||||
|
with save_path():
|
||||||
|
with save_argv():
|
||||||
|
with override_temp(temp_dir):
|
||||||
|
with pushd(setup_dir):
|
||||||
|
# ensure setuptools commands are available
|
||||||
|
__import__('setuptools')
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_hiding(mod_name):
|
||||||
|
"""
|
||||||
|
>>> _needs_hiding('setuptools')
|
||||||
|
True
|
||||||
|
>>> _needs_hiding('pkg_resources')
|
||||||
|
True
|
||||||
|
>>> _needs_hiding('setuptools_plugin')
|
||||||
|
False
|
||||||
|
>>> _needs_hiding('setuptools.__init__')
|
||||||
|
True
|
||||||
|
>>> _needs_hiding('distutils')
|
||||||
|
True
|
||||||
|
"""
|
||||||
|
pattern = re.compile('(setuptools|pkg_resources|distutils)(\.|$)')
|
||||||
|
return bool(pattern.match(mod_name))
|
||||||
|
|
||||||
|
|
||||||
|
def hide_setuptools():
|
||||||
|
"""
|
||||||
|
Remove references to setuptools' modules from sys.modules to allow the
|
||||||
|
invocation to import the most appropriate setuptools. This technique is
|
||||||
|
necessary to avoid issues such as #315 where setuptools upgrading itself
|
||||||
|
would fail to find a function declared in the metadata.
|
||||||
|
"""
|
||||||
|
modules = filter(_needs_hiding, sys.modules)
|
||||||
|
_clear_modules(modules)
|
||||||
|
|
||||||
|
|
||||||
def run_setup(setup_script, args):
|
def run_setup(setup_script, args):
|
||||||
"""Run a distutils setup script, sandboxed in its directory"""
|
"""Run a distutils setup script, sandboxed in its directory"""
|
||||||
old_dir = os.getcwd()
|
|
||||||
save_argv = sys.argv[:]
|
|
||||||
save_path = sys.path[:]
|
|
||||||
setup_dir = os.path.abspath(os.path.dirname(setup_script))
|
setup_dir = os.path.abspath(os.path.dirname(setup_script))
|
||||||
temp_dir = os.path.join(setup_dir,'temp')
|
with setup_context(setup_dir):
|
||||||
if not os.path.isdir(temp_dir): os.makedirs(temp_dir)
|
|
||||||
save_tmp = tempfile.tempdir
|
|
||||||
save_modules = sys.modules.copy()
|
|
||||||
pr_state = pkg_resources.__getstate__()
|
|
||||||
try:
|
|
||||||
tempfile.tempdir = temp_dir
|
|
||||||
os.chdir(setup_dir)
|
|
||||||
try:
|
try:
|
||||||
sys.argv[:] = [setup_script]+list(args)
|
sys.argv[:] = [setup_script]+list(args)
|
||||||
sys.path.insert(0, setup_dir)
|
sys.path.insert(0, setup_dir)
|
||||||
# reset to include setup dir, w/clean callback list
|
# reset to include setup dir, w/clean callback list
|
||||||
working_set.__init__()
|
working_set.__init__()
|
||||||
working_set.callbacks.append(lambda dist:dist.activate())
|
working_set.callbacks.append(lambda dist:dist.activate())
|
||||||
DirectorySandbox(setup_dir).run(
|
def runner():
|
||||||
lambda: execfile(
|
ns = dict(__file__=setup_script, __name__='__main__')
|
||||||
"setup.py",
|
_execfile(setup_script, ns)
|
||||||
{'__file__':setup_script, '__name__':'__main__'}
|
DirectorySandbox(setup_dir).run(runner)
|
||||||
)
|
except SystemExit as v:
|
||||||
)
|
|
||||||
except SystemExit:
|
|
||||||
v = sys.exc_info()[1]
|
|
||||||
if v.args and v.args[0]:
|
if v.args and v.args[0]:
|
||||||
raise
|
raise
|
||||||
# Normal exit, just return
|
# Normal exit, just return
|
||||||
finally:
|
|
||||||
pkg_resources.__setstate__(pr_state)
|
|
||||||
sys.modules.update(save_modules)
|
|
||||||
# remove any modules imported within the sandbox
|
|
||||||
del_modules = [
|
|
||||||
mod_name for mod_name in sys.modules
|
|
||||||
if mod_name not in save_modules
|
|
||||||
# exclude any encodings modules. See #285
|
|
||||||
and not mod_name.startswith('encodings.')
|
|
||||||
]
|
|
||||||
list(map(sys.modules.__delitem__, del_modules))
|
|
||||||
os.chdir(old_dir)
|
|
||||||
sys.path[:] = save_path
|
|
||||||
sys.argv[:] = save_argv
|
|
||||||
tempfile.tempdir = save_tmp
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractSandbox:
|
class AbstractSandbox:
|
||||||
@@ -268,7 +433,7 @@ class DirectorySandbox(AbstractSandbox):
|
|||||||
self._violation(operation, src, dst, *args, **kw)
|
self._violation(operation, src, dst, *args, **kw)
|
||||||
return (src,dst)
|
return (src,dst)
|
||||||
|
|
||||||
def open(self, file, flags, mode=0x1FF, *args, **kw): # 0777
|
def open(self, file, flags, mode=0o777, *args, **kw):
|
||||||
"""Called for low-level os.open()"""
|
"""Called for low-level os.open()"""
|
||||||
if flags & WRITE_FLAGS and not self._ok(file):
|
if flags & WRITE_FLAGS and not self._ok(file):
|
||||||
self._violation("os.open", file, flags, mode, *args, **kw)
|
self._violation("os.open", file, flags, mode, *args, **kw)
|
||||||
|
|||||||
5
awx/lib/site-packages/setuptools/script (dev).tmpl
Normal file
5
awx/lib/site-packages/setuptools/script (dev).tmpl
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
|
||||||
|
__requires__ = %(spec)r
|
||||||
|
__import__('pkg_resources').require(%(spec)r)
|
||||||
|
__file__ = %(dev_path)r
|
||||||
|
exec(compile(open(__file__).read(), __file__, 'exec'))
|
||||||
3
awx/lib/site-packages/setuptools/script.tmpl
Normal file
3
awx/lib/site-packages/setuptools/script.tmpl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
|
||||||
|
__requires__ = %(spec)r
|
||||||
|
__import__('pkg_resources').run_script(%(spec)r, %(script_name)r)
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
def __boot():
|
def __boot():
|
||||||
import sys, os, os.path
|
import sys
|
||||||
|
import os
|
||||||
PYTHONPATH = os.environ.get('PYTHONPATH')
|
PYTHONPATH = os.environ.get('PYTHONPATH')
|
||||||
if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH):
|
if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH):
|
||||||
PYTHONPATH = []
|
PYTHONPATH = []
|
||||||
@@ -49,13 +50,13 @@ def __boot():
|
|||||||
addsitedir(item)
|
addsitedir(item)
|
||||||
|
|
||||||
sys.__egginsert += oldpos # restore effective old position
|
sys.__egginsert += oldpos # restore effective old position
|
||||||
|
|
||||||
d,nd = makepath(stdpath[0])
|
d, nd = makepath(stdpath[0])
|
||||||
insert_at = None
|
insert_at = None
|
||||||
new_path = []
|
new_path = []
|
||||||
|
|
||||||
for item in sys.path:
|
for item in sys.path:
|
||||||
p,np = makepath(item)
|
p, np = makepath(item)
|
||||||
|
|
||||||
if np==nd and insert_at is None:
|
if np==nd and insert_at is None:
|
||||||
# We've hit the first 'system' path entry, so added entries go here
|
# We've hit the first 'system' path entry, so added entries go here
|
||||||
@@ -67,17 +68,9 @@ def __boot():
|
|||||||
# new path after the insert point, back-insert it
|
# new path after the insert point, back-insert it
|
||||||
new_path.insert(insert_at, item)
|
new_path.insert(insert_at, item)
|
||||||
insert_at += 1
|
insert_at += 1
|
||||||
|
|
||||||
sys.path[:] = new_path
|
sys.path[:] = new_path
|
||||||
|
|
||||||
if __name__=='site':
|
if __name__=='site':
|
||||||
__boot()
|
__boot()
|
||||||
del __boot
|
del __boot
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -178,12 +178,19 @@ class VerifyingHTTPSConn(HTTPSConnection):
|
|||||||
if hasattr(self, '_tunnel') and getattr(self, '_tunnel_host', None):
|
if hasattr(self, '_tunnel') and getattr(self, '_tunnel_host', None):
|
||||||
self.sock = sock
|
self.sock = sock
|
||||||
self._tunnel()
|
self._tunnel()
|
||||||
|
# http://bugs.python.org/issue7776: Python>=3.4.1 and >=2.7.7
|
||||||
|
# change self.host to mean the proxy server host when tunneling is
|
||||||
|
# being used. Adapt, since we are interested in the destination
|
||||||
|
# host for the match_hostname() comparison.
|
||||||
|
actual_host = self._tunnel_host
|
||||||
|
else:
|
||||||
|
actual_host = self.host
|
||||||
|
|
||||||
self.sock = ssl.wrap_socket(
|
self.sock = ssl.wrap_socket(
|
||||||
sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle
|
sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
match_hostname(self.sock.getpeercert(), self.host)
|
match_hostname(self.sock.getpeercert(), actual_host)
|
||||||
except CertificateError:
|
except CertificateError:
|
||||||
self.sock.shutdown(socket.SHUT_RDWR)
|
self.sock.shutdown(socket.SHUT_RDWR)
|
||||||
self.sock.close()
|
self.sock.close()
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
"""Tests for the 'setuptools' package"""
|
"""Tests for the 'setuptools' package"""
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import unittest
|
|
||||||
from setuptools.tests import doctest
|
|
||||||
import distutils.core
|
import distutils.core
|
||||||
import distutils.cmd
|
import distutils.cmd
|
||||||
from distutils.errors import DistutilsOptionError, DistutilsPlatformError
|
from distutils.errors import DistutilsOptionError, DistutilsPlatformError
|
||||||
@@ -11,24 +9,13 @@ from distutils.core import Extension
|
|||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
from setuptools.compat import func_code
|
from setuptools.compat import func_code
|
||||||
|
|
||||||
from setuptools.compat import func_code
|
import pytest
|
||||||
|
|
||||||
import setuptools.dist
|
import setuptools.dist
|
||||||
import setuptools.depends as dep
|
import setuptools.depends as dep
|
||||||
from setuptools import Feature
|
from setuptools import Feature
|
||||||
from setuptools.depends import Require
|
from setuptools.depends import Require
|
||||||
|
|
||||||
def additional_tests():
|
|
||||||
import doctest, unittest
|
|
||||||
suite = unittest.TestSuite((
|
|
||||||
doctest.DocFileSuite(
|
|
||||||
os.path.join('tests', 'api_tests.txt'),
|
|
||||||
optionflags=doctest.ELLIPSIS, package='pkg_resources',
|
|
||||||
),
|
|
||||||
))
|
|
||||||
if sys.platform == 'win32':
|
|
||||||
suite.addTest(doctest.DocFileSuite('win_script_wrapper.txt'))
|
|
||||||
return suite
|
|
||||||
|
|
||||||
def makeSetup(**args):
|
def makeSetup(**args):
|
||||||
"""Return distribution from 'setup(**args)', without executing commands"""
|
"""Return distribution from 'setup(**args)', without executing commands"""
|
||||||
|
|
||||||
@@ -43,7 +30,12 @@ def makeSetup(**args):
|
|||||||
distutils.core._setup_stop_after = None
|
distutils.core._setup_stop_after = None
|
||||||
|
|
||||||
|
|
||||||
class DependsTests(unittest.TestCase):
|
needs_bytecode = pytest.mark.skipif(
|
||||||
|
not hasattr(dep, 'get_module_constant'),
|
||||||
|
reason="bytecode support not available",
|
||||||
|
)
|
||||||
|
|
||||||
|
class TestDepends:
|
||||||
|
|
||||||
def testExtractConst(self):
|
def testExtractConst(self):
|
||||||
if not hasattr(dep, 'extract_constant'):
|
if not hasattr(dep, 'extract_constant'):
|
||||||
@@ -56,86 +48,77 @@ class DependsTests(unittest.TestCase):
|
|||||||
y = z
|
y = z
|
||||||
|
|
||||||
fc = func_code(f1)
|
fc = func_code(f1)
|
||||||
|
|
||||||
# unrecognized name
|
# unrecognized name
|
||||||
self.assertEqual(dep.extract_constant(fc,'q', -1), None)
|
assert dep.extract_constant(fc,'q', -1) is None
|
||||||
|
|
||||||
# constant assigned
|
# constant assigned
|
||||||
self.assertEqual(dep.extract_constant(fc,'x', -1), "test")
|
dep.extract_constant(fc,'x', -1) == "test"
|
||||||
|
|
||||||
# expression assigned
|
# expression assigned
|
||||||
self.assertEqual(dep.extract_constant(fc,'y', -1), -1)
|
dep.extract_constant(fc,'y', -1) == -1
|
||||||
|
|
||||||
# recognized name, not assigned
|
# recognized name, not assigned
|
||||||
self.assertEqual(dep.extract_constant(fc,'z', -1), None)
|
dep.extract_constant(fc,'z', -1) is None
|
||||||
|
|
||||||
def testFindModule(self):
|
def testFindModule(self):
|
||||||
self.assertRaises(ImportError, dep.find_module, 'no-such.-thing')
|
with pytest.raises(ImportError):
|
||||||
self.assertRaises(ImportError, dep.find_module, 'setuptools.non-existent')
|
dep.find_module('no-such.-thing')
|
||||||
|
with pytest.raises(ImportError):
|
||||||
|
dep.find_module('setuptools.non-existent')
|
||||||
f,p,i = dep.find_module('setuptools.tests')
|
f,p,i = dep.find_module('setuptools.tests')
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
@needs_bytecode
|
||||||
def testModuleExtract(self):
|
def testModuleExtract(self):
|
||||||
if not hasattr(dep, 'get_module_constant'):
|
|
||||||
# skip on non-bytecode platforms
|
|
||||||
return
|
|
||||||
|
|
||||||
from email import __version__
|
from email import __version__
|
||||||
self.assertEqual(
|
assert dep.get_module_constant('email','__version__') == __version__
|
||||||
dep.get_module_constant('email','__version__'), __version__
|
assert dep.get_module_constant('sys','version') == sys.version
|
||||||
)
|
assert dep.get_module_constant('setuptools.tests','__doc__') == __doc__
|
||||||
self.assertEqual(
|
|
||||||
dep.get_module_constant('sys','version'), sys.version
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
dep.get_module_constant('setuptools.tests','__doc__'),__doc__
|
|
||||||
)
|
|
||||||
|
|
||||||
|
@needs_bytecode
|
||||||
def testRequire(self):
|
def testRequire(self):
|
||||||
if not hasattr(dep, 'extract_constant'):
|
|
||||||
# skip on non-bytecode platformsh
|
|
||||||
return
|
|
||||||
|
|
||||||
req = Require('Email','1.0.3','email')
|
req = Require('Email','1.0.3','email')
|
||||||
|
|
||||||
self.assertEqual(req.name, 'Email')
|
assert req.name == 'Email'
|
||||||
self.assertEqual(req.module, 'email')
|
assert req.module == 'email'
|
||||||
self.assertEqual(req.requested_version, '1.0.3')
|
assert req.requested_version == '1.0.3'
|
||||||
self.assertEqual(req.attribute, '__version__')
|
assert req.attribute == '__version__'
|
||||||
self.assertEqual(req.full_name(), 'Email-1.0.3')
|
assert req.full_name() == 'Email-1.0.3'
|
||||||
|
|
||||||
from email import __version__
|
from email import __version__
|
||||||
self.assertEqual(req.get_version(), __version__)
|
assert req.get_version() == __version__
|
||||||
self.assertTrue(req.version_ok('1.0.9'))
|
assert req.version_ok('1.0.9')
|
||||||
self.assertTrue(not req.version_ok('0.9.1'))
|
assert not req.version_ok('0.9.1')
|
||||||
self.assertTrue(not req.version_ok('unknown'))
|
assert not req.version_ok('unknown')
|
||||||
|
|
||||||
self.assertTrue(req.is_present())
|
assert req.is_present()
|
||||||
self.assertTrue(req.is_current())
|
assert req.is_current()
|
||||||
|
|
||||||
req = Require('Email 3000','03000','email',format=LooseVersion)
|
req = Require('Email 3000','03000','email',format=LooseVersion)
|
||||||
self.assertTrue(req.is_present())
|
assert req.is_present()
|
||||||
self.assertTrue(not req.is_current())
|
assert not req.is_current()
|
||||||
self.assertTrue(not req.version_ok('unknown'))
|
assert not req.version_ok('unknown')
|
||||||
|
|
||||||
req = Require('Do-what-I-mean','1.0','d-w-i-m')
|
req = Require('Do-what-I-mean','1.0','d-w-i-m')
|
||||||
self.assertTrue(not req.is_present())
|
assert not req.is_present()
|
||||||
self.assertTrue(not req.is_current())
|
assert not req.is_current()
|
||||||
|
|
||||||
req = Require('Tests', None, 'tests', homepage="http://example.com")
|
req = Require('Tests', None, 'tests', homepage="http://example.com")
|
||||||
self.assertEqual(req.format, None)
|
assert req.format is None
|
||||||
self.assertEqual(req.attribute, None)
|
assert req.attribute is None
|
||||||
self.assertEqual(req.requested_version, None)
|
assert req.requested_version is None
|
||||||
self.assertEqual(req.full_name(), 'Tests')
|
assert req.full_name() == 'Tests'
|
||||||
self.assertEqual(req.homepage, 'http://example.com')
|
assert req.homepage == 'http://example.com'
|
||||||
|
|
||||||
paths = [os.path.dirname(p) for p in __path__]
|
paths = [os.path.dirname(p) for p in __path__]
|
||||||
self.assertTrue(req.is_present(paths))
|
assert req.is_present(paths)
|
||||||
self.assertTrue(req.is_current(paths))
|
assert req.is_current(paths)
|
||||||
|
|
||||||
|
|
||||||
class DistroTests(unittest.TestCase):
|
class TestDistro:
|
||||||
|
|
||||||
def setUp(self):
|
def setup_method(self, method):
|
||||||
self.e1 = Extension('bar.ext',['bar.c'])
|
self.e1 = Extension('bar.ext',['bar.c'])
|
||||||
self.e2 = Extension('c.y', ['y.c'])
|
self.e2 = Extension('c.y', ['y.c'])
|
||||||
|
|
||||||
@@ -147,21 +130,21 @@ class DistroTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def testDistroType(self):
|
def testDistroType(self):
|
||||||
self.assertTrue(isinstance(self.dist,setuptools.dist.Distribution))
|
assert isinstance(self.dist,setuptools.dist.Distribution)
|
||||||
|
|
||||||
def testExcludePackage(self):
|
def testExcludePackage(self):
|
||||||
self.dist.exclude_package('a')
|
self.dist.exclude_package('a')
|
||||||
self.assertEqual(self.dist.packages, ['b','c'])
|
assert self.dist.packages == ['b','c']
|
||||||
|
|
||||||
self.dist.exclude_package('b')
|
self.dist.exclude_package('b')
|
||||||
self.assertEqual(self.dist.packages, ['c'])
|
assert self.dist.packages == ['c']
|
||||||
self.assertEqual(self.dist.py_modules, ['x'])
|
assert self.dist.py_modules == ['x']
|
||||||
self.assertEqual(self.dist.ext_modules, [self.e1, self.e2])
|
assert self.dist.ext_modules == [self.e1, self.e2]
|
||||||
|
|
||||||
self.dist.exclude_package('c')
|
self.dist.exclude_package('c')
|
||||||
self.assertEqual(self.dist.packages, [])
|
assert self.dist.packages == []
|
||||||
self.assertEqual(self.dist.py_modules, ['x'])
|
assert self.dist.py_modules == ['x']
|
||||||
self.assertEqual(self.dist.ext_modules, [self.e1])
|
assert self.dist.ext_modules == [self.e1]
|
||||||
|
|
||||||
# test removals from unspecified options
|
# test removals from unspecified options
|
||||||
makeSetup().exclude_package('x')
|
makeSetup().exclude_package('x')
|
||||||
@@ -169,21 +152,21 @@ class DistroTests(unittest.TestCase):
|
|||||||
def testIncludeExclude(self):
|
def testIncludeExclude(self):
|
||||||
# remove an extension
|
# remove an extension
|
||||||
self.dist.exclude(ext_modules=[self.e1])
|
self.dist.exclude(ext_modules=[self.e1])
|
||||||
self.assertEqual(self.dist.ext_modules, [self.e2])
|
assert self.dist.ext_modules == [self.e2]
|
||||||
|
|
||||||
# add it back in
|
# add it back in
|
||||||
self.dist.include(ext_modules=[self.e1])
|
self.dist.include(ext_modules=[self.e1])
|
||||||
self.assertEqual(self.dist.ext_modules, [self.e2, self.e1])
|
assert self.dist.ext_modules == [self.e2, self.e1]
|
||||||
|
|
||||||
# should not add duplicate
|
# should not add duplicate
|
||||||
self.dist.include(ext_modules=[self.e1])
|
self.dist.include(ext_modules=[self.e1])
|
||||||
self.assertEqual(self.dist.ext_modules, [self.e2, self.e1])
|
assert self.dist.ext_modules == [self.e2, self.e1]
|
||||||
|
|
||||||
def testExcludePackages(self):
|
def testExcludePackages(self):
|
||||||
self.dist.exclude(packages=['c','b','a'])
|
self.dist.exclude(packages=['c','b','a'])
|
||||||
self.assertEqual(self.dist.packages, [])
|
assert self.dist.packages == []
|
||||||
self.assertEqual(self.dist.py_modules, ['x'])
|
assert self.dist.py_modules == ['x']
|
||||||
self.assertEqual(self.dist.ext_modules, [self.e1])
|
assert self.dist.ext_modules == [self.e1]
|
||||||
|
|
||||||
def testEmpty(self):
|
def testEmpty(self):
|
||||||
dist = makeSetup()
|
dist = makeSetup()
|
||||||
@@ -192,49 +175,41 @@ class DistroTests(unittest.TestCase):
|
|||||||
dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2])
|
dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2])
|
||||||
|
|
||||||
def testContents(self):
|
def testContents(self):
|
||||||
self.assertTrue(self.dist.has_contents_for('a'))
|
assert self.dist.has_contents_for('a')
|
||||||
self.dist.exclude_package('a')
|
self.dist.exclude_package('a')
|
||||||
self.assertTrue(not self.dist.has_contents_for('a'))
|
assert not self.dist.has_contents_for('a')
|
||||||
|
|
||||||
self.assertTrue(self.dist.has_contents_for('b'))
|
assert self.dist.has_contents_for('b')
|
||||||
self.dist.exclude_package('b')
|
self.dist.exclude_package('b')
|
||||||
self.assertTrue(not self.dist.has_contents_for('b'))
|
assert not self.dist.has_contents_for('b')
|
||||||
|
|
||||||
self.assertTrue(self.dist.has_contents_for('c'))
|
assert self.dist.has_contents_for('c')
|
||||||
self.dist.exclude_package('c')
|
self.dist.exclude_package('c')
|
||||||
self.assertTrue(not self.dist.has_contents_for('c'))
|
assert not self.dist.has_contents_for('c')
|
||||||
|
|
||||||
def testInvalidIncludeExclude(self):
|
def testInvalidIncludeExclude(self):
|
||||||
self.assertRaises(DistutilsSetupError,
|
with pytest.raises(DistutilsSetupError):
|
||||||
self.dist.include, nonexistent_option='x'
|
self.dist.include(nonexistent_option='x')
|
||||||
)
|
with pytest.raises(DistutilsSetupError):
|
||||||
self.assertRaises(DistutilsSetupError,
|
self.dist.exclude(nonexistent_option='x')
|
||||||
self.dist.exclude, nonexistent_option='x'
|
with pytest.raises(DistutilsSetupError):
|
||||||
)
|
self.dist.include(packages={'x':'y'})
|
||||||
self.assertRaises(DistutilsSetupError,
|
with pytest.raises(DistutilsSetupError):
|
||||||
self.dist.include, packages={'x':'y'}
|
self.dist.exclude(packages={'x':'y'})
|
||||||
)
|
with pytest.raises(DistutilsSetupError):
|
||||||
self.assertRaises(DistutilsSetupError,
|
self.dist.include(ext_modules={'x':'y'})
|
||||||
self.dist.exclude, packages={'x':'y'}
|
with pytest.raises(DistutilsSetupError):
|
||||||
)
|
self.dist.exclude(ext_modules={'x':'y'})
|
||||||
self.assertRaises(DistutilsSetupError,
|
|
||||||
self.dist.include, ext_modules={'x':'y'}
|
|
||||||
)
|
|
||||||
self.assertRaises(DistutilsSetupError,
|
|
||||||
self.dist.exclude, ext_modules={'x':'y'}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertRaises(DistutilsSetupError,
|
with pytest.raises(DistutilsSetupError):
|
||||||
self.dist.include, package_dir=['q']
|
self.dist.include(package_dir=['q'])
|
||||||
)
|
with pytest.raises(DistutilsSetupError):
|
||||||
self.assertRaises(DistutilsSetupError,
|
self.dist.exclude(package_dir=['q'])
|
||||||
self.dist.exclude, package_dir=['q']
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class FeatureTests(unittest.TestCase):
|
class TestFeatures:
|
||||||
|
|
||||||
def setUp(self):
|
def setup_method(self, method):
|
||||||
self.req = Require('Distutils','1.0.3','distutils')
|
self.req = Require('Distutils','1.0.3','distutils')
|
||||||
self.dist = makeSetup(
|
self.dist = makeSetup(
|
||||||
features={
|
features={
|
||||||
@@ -256,80 +231,75 @@ class FeatureTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def testDefaults(self):
|
def testDefaults(self):
|
||||||
self.assertTrue(not
|
assert not Feature(
|
||||||
Feature(
|
"test",standard=True,remove='x',available=False
|
||||||
"test",standard=True,remove='x',available=False
|
).include_by_default()
|
||||||
).include_by_default()
|
assert Feature("test",standard=True,remove='x').include_by_default()
|
||||||
)
|
|
||||||
self.assertTrue(
|
|
||||||
Feature("test",standard=True,remove='x').include_by_default()
|
|
||||||
)
|
|
||||||
# Feature must have either kwargs, removes, or require_features
|
# Feature must have either kwargs, removes, or require_features
|
||||||
self.assertRaises(DistutilsSetupError, Feature, "test")
|
with pytest.raises(DistutilsSetupError):
|
||||||
|
Feature("test")
|
||||||
|
|
||||||
def testAvailability(self):
|
def testAvailability(self):
|
||||||
self.assertRaises(
|
with pytest.raises(DistutilsPlatformError):
|
||||||
DistutilsPlatformError,
|
self.dist.features['dwim'].include_in(self.dist)
|
||||||
self.dist.features['dwim'].include_in, self.dist
|
|
||||||
)
|
|
||||||
|
|
||||||
def testFeatureOptions(self):
|
def testFeatureOptions(self):
|
||||||
dist = self.dist
|
dist = self.dist
|
||||||
self.assertTrue(
|
assert (
|
||||||
('with-dwim',None,'include DWIM') in dist.feature_options
|
('with-dwim',None,'include DWIM') in dist.feature_options
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
assert (
|
||||||
('without-dwim',None,'exclude DWIM (default)') in dist.feature_options
|
('without-dwim',None,'exclude DWIM (default)') in dist.feature_options
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
assert (
|
||||||
('with-bar',None,'include bar (default)') in dist.feature_options
|
('with-bar',None,'include bar (default)') in dist.feature_options
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
assert (
|
||||||
('without-bar',None,'exclude bar') in dist.feature_options
|
('without-bar',None,'exclude bar') in dist.feature_options
|
||||||
)
|
)
|
||||||
self.assertEqual(dist.feature_negopt['without-foo'],'with-foo')
|
assert dist.feature_negopt['without-foo'] == 'with-foo'
|
||||||
self.assertEqual(dist.feature_negopt['without-bar'],'with-bar')
|
assert dist.feature_negopt['without-bar'] == 'with-bar'
|
||||||
self.assertEqual(dist.feature_negopt['without-dwim'],'with-dwim')
|
assert dist.feature_negopt['without-dwim'] == 'with-dwim'
|
||||||
self.assertTrue(not 'without-baz' in dist.feature_negopt)
|
assert (not 'without-baz' in dist.feature_negopt)
|
||||||
|
|
||||||
def testUseFeatures(self):
|
def testUseFeatures(self):
|
||||||
dist = self.dist
|
dist = self.dist
|
||||||
self.assertEqual(dist.with_foo,1)
|
assert dist.with_foo == 1
|
||||||
self.assertEqual(dist.with_bar,0)
|
assert dist.with_bar == 0
|
||||||
self.assertEqual(dist.with_baz,1)
|
assert dist.with_baz == 1
|
||||||
self.assertTrue(not 'bar_et' in dist.py_modules)
|
assert (not 'bar_et' in dist.py_modules)
|
||||||
self.assertTrue(not 'pkg.bar' in dist.packages)
|
assert (not 'pkg.bar' in dist.packages)
|
||||||
self.assertTrue('pkg.baz' in dist.packages)
|
assert ('pkg.baz' in dist.packages)
|
||||||
self.assertTrue('scripts/baz_it' in dist.scripts)
|
assert ('scripts/baz_it' in dist.scripts)
|
||||||
self.assertTrue(('libfoo','foo/foofoo.c') in dist.libraries)
|
assert (('libfoo','foo/foofoo.c') in dist.libraries)
|
||||||
self.assertEqual(dist.ext_modules,[])
|
assert dist.ext_modules == []
|
||||||
self.assertEqual(dist.require_features, [self.req])
|
assert dist.require_features == [self.req]
|
||||||
|
|
||||||
# If we ask for bar, it should fail because we explicitly disabled
|
# If we ask for bar, it should fail because we explicitly disabled
|
||||||
# it on the command line
|
# it on the command line
|
||||||
self.assertRaises(DistutilsOptionError, dist.include_feature, 'bar')
|
with pytest.raises(DistutilsOptionError):
|
||||||
|
dist.include_feature('bar')
|
||||||
|
|
||||||
def testFeatureWithInvalidRemove(self):
|
def testFeatureWithInvalidRemove(self):
|
||||||
self.assertRaises(
|
with pytest.raises(SystemExit):
|
||||||
SystemExit, makeSetup, features = {'x':Feature('x', remove='y')}
|
makeSetup(features={'x':Feature('x', remove='y')})
|
||||||
)
|
|
||||||
|
|
||||||
class TestCommandTests(unittest.TestCase):
|
class TestCommandTests:
|
||||||
|
|
||||||
def testTestIsCommand(self):
|
def testTestIsCommand(self):
|
||||||
test_cmd = makeSetup().get_command_obj('test')
|
test_cmd = makeSetup().get_command_obj('test')
|
||||||
self.assertTrue(isinstance(test_cmd, distutils.cmd.Command))
|
assert (isinstance(test_cmd, distutils.cmd.Command))
|
||||||
|
|
||||||
def testLongOptSuiteWNoDefault(self):
|
def testLongOptSuiteWNoDefault(self):
|
||||||
ts1 = makeSetup(script_args=['test','--test-suite=foo.tests.suite'])
|
ts1 = makeSetup(script_args=['test','--test-suite=foo.tests.suite'])
|
||||||
ts1 = ts1.get_command_obj('test')
|
ts1 = ts1.get_command_obj('test')
|
||||||
ts1.ensure_finalized()
|
ts1.ensure_finalized()
|
||||||
self.assertEqual(ts1.test_suite, 'foo.tests.suite')
|
assert ts1.test_suite == 'foo.tests.suite'
|
||||||
|
|
||||||
def testDefaultSuite(self):
|
def testDefaultSuite(self):
|
||||||
ts2 = makeSetup(test_suite='bar.tests.suite').get_command_obj('test')
|
ts2 = makeSetup(test_suite='bar.tests.suite').get_command_obj('test')
|
||||||
ts2.ensure_finalized()
|
ts2.ensure_finalized()
|
||||||
self.assertEqual(ts2.test_suite, 'bar.tests.suite')
|
assert ts2.test_suite == 'bar.tests.suite'
|
||||||
|
|
||||||
def testDefaultWModuleOnCmdLine(self):
|
def testDefaultWModuleOnCmdLine(self):
|
||||||
ts3 = makeSetup(
|
ts3 = makeSetup(
|
||||||
@@ -337,16 +307,17 @@ class TestCommandTests(unittest.TestCase):
|
|||||||
script_args=['test','-m','foo.tests']
|
script_args=['test','-m','foo.tests']
|
||||||
).get_command_obj('test')
|
).get_command_obj('test')
|
||||||
ts3.ensure_finalized()
|
ts3.ensure_finalized()
|
||||||
self.assertEqual(ts3.test_module, 'foo.tests')
|
assert ts3.test_module == 'foo.tests'
|
||||||
self.assertEqual(ts3.test_suite, 'foo.tests.test_suite')
|
assert ts3.test_suite == 'foo.tests.test_suite'
|
||||||
|
|
||||||
def testConflictingOptions(self):
|
def testConflictingOptions(self):
|
||||||
ts4 = makeSetup(
|
ts4 = makeSetup(
|
||||||
script_args=['test','-m','bar.tests', '-s','foo.tests.suite']
|
script_args=['test','-m','bar.tests', '-s','foo.tests.suite']
|
||||||
).get_command_obj('test')
|
).get_command_obj('test')
|
||||||
self.assertRaises(DistutilsOptionError, ts4.ensure_finalized)
|
with pytest.raises(DistutilsOptionError):
|
||||||
|
ts4.ensure_finalized()
|
||||||
|
|
||||||
def testNoSuite(self):
|
def testNoSuite(self):
|
||||||
ts5 = makeSetup().get_command_obj('test')
|
ts5 = makeSetup().get_command_obj('test')
|
||||||
ts5.ensure_finalized()
|
ts5.ensure_finalized()
|
||||||
self.assertEqual(ts5.test_suite, None)
|
assert ts5.test_suite == None
|
||||||
|
|||||||
93
awx/lib/site-packages/setuptools/tests/contexts.py
Normal file
93
awx/lib/site-packages/setuptools/tests/contexts.py
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import contextlib
|
||||||
|
import site
|
||||||
|
|
||||||
|
from ..compat import StringIO
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def tempdir(cd=lambda dir:None, **kwargs):
|
||||||
|
temp_dir = tempfile.mkdtemp(**kwargs)
|
||||||
|
orig_dir = os.getcwd()
|
||||||
|
try:
|
||||||
|
cd(temp_dir)
|
||||||
|
yield temp_dir
|
||||||
|
finally:
|
||||||
|
cd(orig_dir)
|
||||||
|
shutil.rmtree(temp_dir)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def environment(**replacements):
|
||||||
|
"""
|
||||||
|
In a context, patch the environment with replacements. Pass None values
|
||||||
|
to clear the values.
|
||||||
|
"""
|
||||||
|
saved = dict(
|
||||||
|
(key, os.environ[key])
|
||||||
|
for key in replacements
|
||||||
|
if key in os.environ
|
||||||
|
)
|
||||||
|
|
||||||
|
# remove values that are null
|
||||||
|
remove = (key for (key, value) in replacements.items() if value is None)
|
||||||
|
for key in list(remove):
|
||||||
|
os.environ.pop(key, None)
|
||||||
|
replacements.pop(key)
|
||||||
|
|
||||||
|
os.environ.update(replacements)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield saved
|
||||||
|
finally:
|
||||||
|
for key in replacements:
|
||||||
|
os.environ.pop(key, None)
|
||||||
|
os.environ.update(saved)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def argv(repl):
|
||||||
|
old_argv = sys.argv[:]
|
||||||
|
sys.argv[:] = repl
|
||||||
|
yield
|
||||||
|
sys.argv[:] = old_argv
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def quiet():
|
||||||
|
"""
|
||||||
|
Redirect stdout/stderr to StringIO objects to prevent console output from
|
||||||
|
distutils commands.
|
||||||
|
"""
|
||||||
|
|
||||||
|
old_stdout = sys.stdout
|
||||||
|
old_stderr = sys.stderr
|
||||||
|
new_stdout = sys.stdout = StringIO()
|
||||||
|
new_stderr = sys.stderr = StringIO()
|
||||||
|
try:
|
||||||
|
yield new_stdout, new_stderr
|
||||||
|
finally:
|
||||||
|
new_stdout.seek(0)
|
||||||
|
new_stderr.seek(0)
|
||||||
|
sys.stdout = old_stdout
|
||||||
|
sys.stderr = old_stderr
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def save_user_site_setting():
|
||||||
|
saved = site.ENABLE_USER_SITE
|
||||||
|
try:
|
||||||
|
yield saved
|
||||||
|
finally:
|
||||||
|
site.ENABLE_USER_SITE = saved
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def suppress_exceptions(*excs):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except excs:
|
||||||
|
pass
|
||||||
@@ -1,119 +1,10 @@
|
|||||||
import os
|
import os
|
||||||
import zipfile
|
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
|
||||||
import unittest
|
|
||||||
import shutil
|
|
||||||
import stat
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
from subprocess import Popen as _Popen, PIPE as _PIPE
|
from subprocess import Popen as _Popen, PIPE as _PIPE
|
||||||
|
|
||||||
|
|
||||||
def _extract(self, member, path=None, pwd=None):
|
|
||||||
"""for zipfile py2.5 borrowed from cpython"""
|
|
||||||
if not isinstance(member, zipfile.ZipInfo):
|
|
||||||
member = self.getinfo(member)
|
|
||||||
|
|
||||||
if path is None:
|
|
||||||
path = os.getcwd()
|
|
||||||
|
|
||||||
return _extract_member(self, member, path, pwd)
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_from_zip(self, name, dest_path):
|
|
||||||
dest_file = open(dest_path, 'wb')
|
|
||||||
try:
|
|
||||||
dest_file.write(self.read(name))
|
|
||||||
finally:
|
|
||||||
dest_file.close()
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_member(self, member, targetpath, pwd):
|
|
||||||
"""for zipfile py2.5 borrowed from cpython"""
|
|
||||||
# build the destination pathname, replacing
|
|
||||||
# forward slashes to platform specific separators.
|
|
||||||
# Strip trailing path separator, unless it represents the root.
|
|
||||||
if (targetpath[-1:] in (os.path.sep, os.path.altsep)
|
|
||||||
and len(os.path.splitdrive(targetpath)[1]) > 1):
|
|
||||||
targetpath = targetpath[:-1]
|
|
||||||
|
|
||||||
# don't include leading "/" from file name if present
|
|
||||||
if member.filename[0] == '/':
|
|
||||||
targetpath = os.path.join(targetpath, member.filename[1:])
|
|
||||||
else:
|
|
||||||
targetpath = os.path.join(targetpath, member.filename)
|
|
||||||
|
|
||||||
targetpath = os.path.normpath(targetpath)
|
|
||||||
|
|
||||||
# Create all upper directories if necessary.
|
|
||||||
upperdirs = os.path.dirname(targetpath)
|
|
||||||
if upperdirs and not os.path.exists(upperdirs):
|
|
||||||
os.makedirs(upperdirs)
|
|
||||||
|
|
||||||
if member.filename[-1] == '/':
|
|
||||||
if not os.path.isdir(targetpath):
|
|
||||||
os.mkdir(targetpath)
|
|
||||||
return targetpath
|
|
||||||
|
|
||||||
_extract_from_zip(self, member.filename, targetpath)
|
|
||||||
|
|
||||||
return targetpath
|
|
||||||
|
|
||||||
|
|
||||||
def _remove_dir(target):
|
|
||||||
|
|
||||||
#on windows this seems to a problem
|
|
||||||
for dir_path, dirs, files in os.walk(target):
|
|
||||||
os.chmod(dir_path, stat.S_IWRITE)
|
|
||||||
for filename in files:
|
|
||||||
os.chmod(os.path.join(dir_path, filename), stat.S_IWRITE)
|
|
||||||
shutil.rmtree(target)
|
|
||||||
|
|
||||||
|
|
||||||
class ZippedEnvironment(unittest.TestCase):
|
|
||||||
|
|
||||||
datafile = None
|
|
||||||
dataname = None
|
|
||||||
old_cwd = None
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
if self.datafile is None or self.dataname is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
if not os.path.isfile(self.datafile):
|
|
||||||
self.old_cwd = None
|
|
||||||
return
|
|
||||||
|
|
||||||
self.old_cwd = os.getcwd()
|
|
||||||
|
|
||||||
self.temp_dir = tempfile.mkdtemp()
|
|
||||||
zip_file, source, target = [None, None, None]
|
|
||||||
try:
|
|
||||||
zip_file = zipfile.ZipFile(self.datafile)
|
|
||||||
for files in zip_file.namelist():
|
|
||||||
_extract(zip_file, files, self.temp_dir)
|
|
||||||
finally:
|
|
||||||
if zip_file:
|
|
||||||
zip_file.close()
|
|
||||||
del zip_file
|
|
||||||
|
|
||||||
os.chdir(os.path.join(self.temp_dir, self.dataname))
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
#Assume setUp was never completed
|
|
||||||
if self.dataname is None or self.datafile is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
if self.old_cwd:
|
|
||||||
os.chdir(self.old_cwd)
|
|
||||||
_remove_dir(self.temp_dir)
|
|
||||||
except OSError:
|
|
||||||
#sigh?
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _which_dirs(cmd):
|
def _which_dirs(cmd):
|
||||||
result = set()
|
result = set()
|
||||||
for path in os.environ.get('PATH', '').split(os.pathsep):
|
for path in os.environ.get('PATH', '').split(os.pathsep):
|
||||||
@@ -147,10 +38,13 @@ def run_setup_py(cmd, pypath=None, path=None,
|
|||||||
|
|
||||||
cmd = [sys.executable, "setup.py"] + list(cmd)
|
cmd = [sys.executable, "setup.py"] + list(cmd)
|
||||||
|
|
||||||
#regarding the shell argument, see: http://bugs.python.org/issue8557
|
# http://bugs.python.org/issue8557
|
||||||
|
shell = sys.platform == 'win32'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
proc = _Popen(cmd, stdout=_PIPE, stderr=_PIPE,
|
proc = _Popen(
|
||||||
shell=(sys.platform == 'win32'), env=env)
|
cmd, stdout=_PIPE, stderr=_PIPE, shell=shell, env=env,
|
||||||
|
)
|
||||||
|
|
||||||
data = proc.communicate()[data_stream]
|
data = proc.communicate()[data_stream]
|
||||||
except OSError:
|
except OSError:
|
||||||
@@ -158,7 +52,8 @@ def run_setup_py(cmd, pypath=None, path=None,
|
|||||||
|
|
||||||
#decode the console string if needed
|
#decode the console string if needed
|
||||||
if hasattr(data, "decode"):
|
if hasattr(data, "decode"):
|
||||||
data = data.decode() # should use the preffered encoding
|
# use the default encoding
|
||||||
|
data = data.decode()
|
||||||
data = unicodedata.normalize('NFC', data)
|
data = unicodedata.normalize('NFC', data)
|
||||||
|
|
||||||
#communciate calls wait()
|
#communciate calls wait()
|
||||||
|
|||||||
27
awx/lib/site-packages/setuptools/tests/fixtures.py
Normal file
27
awx/lib/site-packages/setuptools/tests/fixtures.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
try:
|
||||||
|
from unittest import mock
|
||||||
|
except ImportError:
|
||||||
|
import mock
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from . import contexts
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.yield_fixture
|
||||||
|
def user_override():
|
||||||
|
"""
|
||||||
|
Override site.USER_BASE and site.USER_SITE with temporary directories in
|
||||||
|
a context.
|
||||||
|
"""
|
||||||
|
with contexts.tempdir() as user_base:
|
||||||
|
with mock.patch('site.USER_BASE', user_base):
|
||||||
|
with contexts.tempdir() as user_site:
|
||||||
|
with mock.patch('site.USER_SITE', user_site):
|
||||||
|
with contexts.save_user_site_setting():
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.yield_fixture
|
||||||
|
def tmpdir_cwd(tmpdir):
|
||||||
|
with tmpdir.as_cwd() as orig:
|
||||||
|
yield orig
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<html><body>
|
||||||
|
<a href="/foobar-0.1.tar.gz#md5=1__bad_md5___">bad old link</a>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<html><body>
|
||||||
|
<a href="/foobar-0.1.tar.gz#md5=0_correct_md5">foobar-0.1.tar.gz</a><br/>
|
||||||
|
<a href="../../external.html" rel="homepage">external homepage</a><br/>
|
||||||
|
</body></html>
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import unittest
|
import sys
|
||||||
|
import tarfile
|
||||||
|
import contextlib
|
||||||
|
|
||||||
try:
|
def _tarfile_open_ex(*args, **kwargs):
|
||||||
# provide skipIf for Python 2.4-2.6
|
"""
|
||||||
skipIf = unittest.skipIf
|
Extend result as a context manager.
|
||||||
except AttributeError:
|
"""
|
||||||
def skipIf(condition, reason):
|
return contextlib.closing(tarfile.open(*args, **kwargs))
|
||||||
def skipper(func):
|
|
||||||
def skip(*args, **kwargs):
|
if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[:2] < (3, 2):
|
||||||
return
|
tarfile_open = _tarfile_open_ex
|
||||||
if condition:
|
else:
|
||||||
return skip
|
tarfile_open = tarfile.open
|
||||||
return func
|
|
||||||
return skipper
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
"""Basic http server for tests to simulate PyPI or custom indexes
|
"""Basic http server for tests to simulate PyPI or custom indexes
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
from setuptools.compat import BaseHTTPRequestHandler
|
from setuptools.compat import BaseHTTPRequestHandler
|
||||||
from setuptools.compat import (urllib2, URLError, HTTPServer,
|
from setuptools.compat import HTTPServer, SimpleHTTPRequestHandler
|
||||||
SimpleHTTPRequestHandler)
|
|
||||||
|
|
||||||
class IndexServer(HTTPServer):
|
class IndexServer(HTTPServer):
|
||||||
"""Basic single-threaded http server simulating a package index
|
"""Basic single-threaded http server simulating a package index
|
||||||
@@ -23,12 +22,8 @@ class IndexServer(HTTPServer):
|
|||||||
HTTPServer.__init__(self, server_address, RequestHandlerClass)
|
HTTPServer.__init__(self, server_address, RequestHandlerClass)
|
||||||
self._run = True
|
self._run = True
|
||||||
|
|
||||||
def serve(self):
|
|
||||||
while self._run:
|
|
||||||
self.handle_request()
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.thread = threading.Thread(target=self.serve)
|
self.thread = threading.Thread(target=self.serve_forever)
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
@@ -37,19 +32,7 @@ class IndexServer(HTTPServer):
|
|||||||
# Let the server finish the last request and wait for a new one.
|
# Let the server finish the last request and wait for a new one.
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
# self.shutdown is not supported on python < 2.6, so just
|
self.shutdown()
|
||||||
# set _run to false, and make a request, causing it to
|
|
||||||
# terminate.
|
|
||||||
self._run = False
|
|
||||||
url = 'http://127.0.0.1:%(server_port)s/' % vars(self)
|
|
||||||
try:
|
|
||||||
if sys.version_info >= (2, 6):
|
|
||||||
urllib2.urlopen(url, timeout=5)
|
|
||||||
else:
|
|
||||||
urllib2.urlopen(url)
|
|
||||||
except URLError:
|
|
||||||
# ignore any errors; all that's important is the request
|
|
||||||
pass
|
|
||||||
self.thread.join()
|
self.thread.join()
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
|
|
||||||
@@ -77,6 +60,6 @@ class MockServer(HTTPServer, threading.Thread):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.serve_forever()
|
self.serve_forever()
|
||||||
|
|
||||||
|
@property
|
||||||
def url(self):
|
def url(self):
|
||||||
return 'http://localhost:%(server_port)s/' % vars(self)
|
return 'http://localhost:%(server_port)s/' % vars(self)
|
||||||
url = property(url)
|
|
||||||
|
|||||||
@@ -1,50 +1,32 @@
|
|||||||
"""develop tests
|
"""develop tests
|
||||||
"""
|
"""
|
||||||
import sys
|
import os
|
||||||
import os, re, shutil, tempfile, unittest
|
import re
|
||||||
import tempfile
|
|
||||||
import site
|
import pytest
|
||||||
|
|
||||||
from distutils.errors import DistutilsError
|
|
||||||
from setuptools.compat import StringIO
|
|
||||||
from setuptools.command.bdist_egg import bdist_egg
|
|
||||||
from setuptools.command import easy_install as easy_install_pkg
|
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
|
|
||||||
|
from . import contexts
|
||||||
|
|
||||||
SETUP_PY = """\
|
SETUP_PY = """\
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(name='foo', py_modules=['hi'])
|
setup(name='foo', py_modules=['hi'])
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class TestDevelopTest(unittest.TestCase):
|
@pytest.yield_fixture
|
||||||
|
def setup_context(tmpdir):
|
||||||
def setUp(self):
|
with (tmpdir/'setup.py').open('w') as f:
|
||||||
self.dir = tempfile.mkdtemp()
|
|
||||||
self.old_cwd = os.getcwd()
|
|
||||||
os.chdir(self.dir)
|
|
||||||
f = open('setup.py', 'w')
|
|
||||||
f.write(SETUP_PY)
|
f.write(SETUP_PY)
|
||||||
f.close()
|
with (tmpdir/'hi.py').open('w') as f:
|
||||||
f = open('hi.py', 'w')
|
|
||||||
f.write('1\n')
|
f.write('1\n')
|
||||||
f.close()
|
with tmpdir.as_cwd():
|
||||||
if sys.version >= "2.6":
|
yield tmpdir
|
||||||
self.old_base = site.USER_BASE
|
|
||||||
site.USER_BASE = tempfile.mkdtemp()
|
|
||||||
self.old_site = site.USER_SITE
|
|
||||||
site.USER_SITE = tempfile.mkdtemp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
os.chdir(self.old_cwd)
|
|
||||||
shutil.rmtree(self.dir)
|
|
||||||
if sys.version >= "2.6":
|
|
||||||
shutil.rmtree(site.USER_BASE)
|
|
||||||
shutil.rmtree(site.USER_SITE)
|
|
||||||
site.USER_BASE = self.old_base
|
|
||||||
site.USER_SITE = self.old_site
|
|
||||||
|
|
||||||
def test_bdist_egg(self):
|
class Test:
|
||||||
|
def test_bdist_egg(self, setup_context, user_override):
|
||||||
dist = Distribution(dict(
|
dist = Distribution(dict(
|
||||||
script_name='setup.py',
|
script_name='setup.py',
|
||||||
script_args=['bdist_egg'],
|
script_args=['bdist_egg'],
|
||||||
@@ -52,18 +34,10 @@ class TestDevelopTest(unittest.TestCase):
|
|||||||
py_modules=['hi']
|
py_modules=['hi']
|
||||||
))
|
))
|
||||||
os.makedirs(os.path.join('build', 'src'))
|
os.makedirs(os.path.join('build', 'src'))
|
||||||
old_stdout = sys.stdout
|
with contexts.quiet():
|
||||||
sys.stdout = o = StringIO()
|
|
||||||
try:
|
|
||||||
dist.parse_command_line()
|
dist.parse_command_line()
|
||||||
dist.run_commands()
|
dist.run_commands()
|
||||||
finally:
|
|
||||||
sys.stdout = old_stdout
|
|
||||||
|
|
||||||
# let's see if we got our egg link at the right place
|
# let's see if we got our egg link at the right place
|
||||||
[content] = os.listdir('dist')
|
[content] = os.listdir('dist')
|
||||||
self.assertTrue(re.match('foo-0.0.0-py[23].\d.egg$', content))
|
assert re.match('foo-0.0.0-py[23].\d.egg$', content)
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.makeSuite(TestDevelopTest)
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
"""build_ext tests
|
import distutils.command.build_ext as orig
|
||||||
"""
|
|
||||||
import os, shutil, tempfile, unittest
|
|
||||||
from distutils.command.build_ext import build_ext as distutils_build_ext
|
|
||||||
from setuptools.command.build_ext import build_ext
|
from setuptools.command.build_ext import build_ext
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
|
|
||||||
class TestBuildExtTest(unittest.TestCase):
|
class TestBuildExt:
|
||||||
|
|
||||||
def test_get_ext_filename(self):
|
def test_get_ext_filename(self):
|
||||||
# setuptools needs to give back the same
|
"""
|
||||||
# result than distutils, even if the fullname
|
Setuptools needs to give back the same
|
||||||
# is not in ext_map
|
result as distutils, even if the fullname
|
||||||
|
is not in ext_map.
|
||||||
|
"""
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
cmd = build_ext(dist)
|
cmd = build_ext(dist)
|
||||||
cmd.ext_map['foo/bar'] = ''
|
cmd.ext_map['foo/bar'] = ''
|
||||||
res = cmd.get_ext_filename('foo')
|
res = cmd.get_ext_filename('foo')
|
||||||
wanted = distutils_build_ext.get_ext_filename(cmd, 'foo')
|
wanted = orig.build_ext.get_ext_filename(cmd, 'foo')
|
||||||
assert res == wanted
|
assert res == wanted
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
"""develop tests
|
"""develop tests
|
||||||
"""
|
"""
|
||||||
import sys
|
import os
|
||||||
import os, shutil, tempfile, unittest
|
import shutil
|
||||||
import tempfile
|
|
||||||
import site
|
import site
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from distutils.errors import DistutilsError
|
|
||||||
from setuptools.command.develop import develop
|
from setuptools.command.develop import develop
|
||||||
from setuptools.command import easy_install as easy_install_pkg
|
|
||||||
from setuptools.compat import StringIO
|
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
|
|
||||||
SETUP_PY = """\
|
SETUP_PY = """\
|
||||||
@@ -23,10 +21,10 @@ setup(name='foo',
|
|||||||
INIT_PY = """print "foo"
|
INIT_PY = """print "foo"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class TestDevelopTest(unittest.TestCase):
|
class TestDevelopTest:
|
||||||
|
|
||||||
def setUp(self):
|
def setup_method(self, method):
|
||||||
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
|
if hasattr(sys, 'real_prefix'):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Directory structure
|
# Directory structure
|
||||||
@@ -50,8 +48,8 @@ class TestDevelopTest(unittest.TestCase):
|
|||||||
self.old_site = site.USER_SITE
|
self.old_site = site.USER_SITE
|
||||||
site.USER_SITE = tempfile.mkdtemp()
|
site.USER_SITE = tempfile.mkdtemp()
|
||||||
|
|
||||||
def tearDown(self):
|
def teardown_method(self, method):
|
||||||
if sys.version < "2.6" or hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
|
if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
|
||||||
return
|
return
|
||||||
|
|
||||||
os.chdir(self.old_cwd)
|
os.chdir(self.old_cwd)
|
||||||
@@ -62,7 +60,7 @@ class TestDevelopTest(unittest.TestCase):
|
|||||||
site.USER_SITE = self.old_site
|
site.USER_SITE = self.old_site
|
||||||
|
|
||||||
def test_develop(self):
|
def test_develop(self):
|
||||||
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
|
if hasattr(sys, 'real_prefix'):
|
||||||
return
|
return
|
||||||
dist = Distribution(
|
dist = Distribution(
|
||||||
dict(name='foo',
|
dict(name='foo',
|
||||||
@@ -86,7 +84,7 @@ class TestDevelopTest(unittest.TestCase):
|
|||||||
# let's see if we got our egg link at the right place
|
# let's see if we got our egg link at the right place
|
||||||
content = os.listdir(site.USER_SITE)
|
content = os.listdir(site.USER_SITE)
|
||||||
content.sort()
|
content.sort()
|
||||||
self.assertEqual(content, ['easy-install.pth', 'foo.egg-link'])
|
assert content == ['easy-install.pth', 'foo.egg-link']
|
||||||
|
|
||||||
# Check that we are using the right code.
|
# Check that we are using the right code.
|
||||||
egg_link_file = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt')
|
egg_link_file = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt')
|
||||||
@@ -100,23 +98,6 @@ class TestDevelopTest(unittest.TestCase):
|
|||||||
finally:
|
finally:
|
||||||
init_file.close()
|
init_file.close()
|
||||||
if sys.version < "3":
|
if sys.version < "3":
|
||||||
self.assertEqual(init, 'print "foo"')
|
assert init == 'print "foo"'
|
||||||
else:
|
else:
|
||||||
self.assertEqual(init, 'print("foo")')
|
assert init == 'print("foo")'
|
||||||
|
|
||||||
def notest_develop_with_setup_requires(self):
|
|
||||||
|
|
||||||
wanted = ("Could not find suitable distribution for "
|
|
||||||
"Requirement.parse('I-DONT-EXIST')")
|
|
||||||
old_dir = os.getcwd()
|
|
||||||
os.chdir(self.dir)
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
dist = Distribution({'setup_requires': ['I_DONT_EXIST']})
|
|
||||||
except DistutilsError:
|
|
||||||
e = sys.exc_info()[1]
|
|
||||||
error = str(e)
|
|
||||||
if error == wanted:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
os.chdir(old_dir)
|
|
||||||
|
|||||||
@@ -3,28 +3,20 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
|
||||||
import textwrap
|
|
||||||
|
|
||||||
try:
|
import pytest
|
||||||
import ast
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
from .textwrap import DALS
|
||||||
|
|
||||||
from setuptools.tests.py26compat import skipIf
|
|
||||||
|
|
||||||
def DALS(s):
|
class TestDistInfo:
|
||||||
"dedent and left-strip"
|
|
||||||
return textwrap.dedent(s).lstrip()
|
|
||||||
|
|
||||||
class TestDistInfo(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_distinfo(self):
|
def test_distinfo(self):
|
||||||
dists = {}
|
dists = dict(
|
||||||
for d in pkg_resources.find_distributions(self.tmpdir):
|
(d.project_name, d)
|
||||||
dists[d.project_name] = d
|
for d in pkg_resources.find_distributions(self.tmpdir)
|
||||||
|
)
|
||||||
|
|
||||||
assert len(dists) == 2, dists
|
assert len(dists) == 2, dists
|
||||||
|
|
||||||
@@ -34,50 +26,45 @@ class TestDistInfo(unittest.TestCase):
|
|||||||
assert versioned.version == '2.718' # from filename
|
assert versioned.version == '2.718' # from filename
|
||||||
assert unversioned.version == '0.3' # from METADATA
|
assert unversioned.version == '0.3' # from METADATA
|
||||||
|
|
||||||
@skipIf('ast' not in globals(),
|
@pytest.mark.importorskip('ast')
|
||||||
"ast is used to test conditional dependencies (Python >= 2.6)")
|
|
||||||
def test_conditional_dependencies(self):
|
def test_conditional_dependencies(self):
|
||||||
requires = [pkg_resources.Requirement.parse('splort==4'),
|
specs = 'splort==4', 'quux>=1.1'
|
||||||
pkg_resources.Requirement.parse('quux>=1.1')]
|
requires = list(map(pkg_resources.Requirement.parse, specs))
|
||||||
|
|
||||||
for d in pkg_resources.find_distributions(self.tmpdir):
|
for d in pkg_resources.find_distributions(self.tmpdir):
|
||||||
self.assertEqual(d.requires(), requires[:1])
|
assert d.requires() == requires[:1]
|
||||||
self.assertEqual(d.requires(extras=('baz',)), requires)
|
assert d.requires(extras=('baz',)) == requires
|
||||||
self.assertEqual(d.extras, ['baz'])
|
assert d.extras == ['baz']
|
||||||
|
|
||||||
def setUp(self):
|
metadata_template = DALS("""
|
||||||
|
Metadata-Version: 1.2
|
||||||
|
Name: {name}
|
||||||
|
{version}
|
||||||
|
Requires-Dist: splort (==4)
|
||||||
|
Provides-Extra: baz
|
||||||
|
Requires-Dist: quux (>=1.1); extra == 'baz'
|
||||||
|
""")
|
||||||
|
|
||||||
|
def setup_method(self, method):
|
||||||
self.tmpdir = tempfile.mkdtemp()
|
self.tmpdir = tempfile.mkdtemp()
|
||||||
versioned = os.path.join(self.tmpdir,
|
dist_info_name = 'VersionedDistribution-2.718.dist-info'
|
||||||
'VersionedDistribution-2.718.dist-info')
|
versioned = os.path.join(self.tmpdir, dist_info_name)
|
||||||
os.mkdir(versioned)
|
os.mkdir(versioned)
|
||||||
metadata_file = open(os.path.join(versioned, 'METADATA'), 'w+')
|
with open(os.path.join(versioned, 'METADATA'), 'w+') as metadata_file:
|
||||||
try:
|
metadata = self.metadata_template.format(
|
||||||
metadata_file.write(DALS(
|
name='VersionedDistribution',
|
||||||
"""
|
version='',
|
||||||
Metadata-Version: 1.2
|
).replace('\n\n', '\n')
|
||||||
Name: VersionedDistribution
|
metadata_file.write(metadata)
|
||||||
Requires-Dist: splort (4)
|
dist_info_name = 'UnversionedDistribution.dist-info'
|
||||||
Provides-Extra: baz
|
unversioned = os.path.join(self.tmpdir, dist_info_name)
|
||||||
Requires-Dist: quux (>=1.1); extra == 'baz'
|
|
||||||
"""))
|
|
||||||
finally:
|
|
||||||
metadata_file.close()
|
|
||||||
unversioned = os.path.join(self.tmpdir,
|
|
||||||
'UnversionedDistribution.dist-info')
|
|
||||||
os.mkdir(unversioned)
|
os.mkdir(unversioned)
|
||||||
metadata_file = open(os.path.join(unversioned, 'METADATA'), 'w+')
|
with open(os.path.join(unversioned, 'METADATA'), 'w+') as metadata_file:
|
||||||
try:
|
metadata = self.metadata_template.format(
|
||||||
metadata_file.write(DALS(
|
name='UnversionedDistribution',
|
||||||
"""
|
version='Version: 0.3',
|
||||||
Metadata-Version: 1.2
|
)
|
||||||
Name: UnversionedDistribution
|
metadata_file.write(metadata)
|
||||||
Version: 0.3
|
|
||||||
Requires-Dist: splort (==4)
|
|
||||||
Provides-Extra: baz
|
|
||||||
Requires-Dist: quux (>=1.1); extra == 'baz'
|
|
||||||
"""))
|
|
||||||
finally:
|
|
||||||
metadata_file.close()
|
|
||||||
|
|
||||||
def tearDown(self):
|
def teardown_method(self, method):
|
||||||
shutil.rmtree(self.tmpdir)
|
shutil.rmtree(self.tmpdir)
|
||||||
|
|||||||
@@ -1,29 +1,44 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""Easy install Tests
|
"""Easy install Tests
|
||||||
"""
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
|
||||||
import site
|
import site
|
||||||
import contextlib
|
import contextlib
|
||||||
import textwrap
|
|
||||||
import tarfile
|
import tarfile
|
||||||
import logging
|
import logging
|
||||||
import distutils.core
|
import itertools
|
||||||
|
import distutils.errors
|
||||||
|
|
||||||
from setuptools.compat import StringIO, BytesIO, next, urlparse
|
import pytest
|
||||||
from setuptools.sandbox import run_setup, SandboxViolation
|
try:
|
||||||
from setuptools.command.easy_install import (
|
from unittest import mock
|
||||||
easy_install, fix_jython_executable, get_script_args, nt_quote_arg)
|
except ImportError:
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from setuptools import sandbox
|
||||||
|
from setuptools import compat
|
||||||
|
from setuptools.compat import StringIO, BytesIO, urlparse
|
||||||
|
from setuptools.sandbox import run_setup
|
||||||
|
import setuptools.command.easy_install as ei
|
||||||
from setuptools.command.easy_install import PthDistributions
|
from setuptools.command.easy_install import PthDistributions
|
||||||
from setuptools.command import easy_install as easy_install_pkg
|
from setuptools.command import easy_install as easy_install_pkg
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
from pkg_resources import working_set, VersionConflict
|
from pkg_resources import working_set
|
||||||
from pkg_resources import Distribution as PRDistribution
|
from pkg_resources import Distribution as PRDistribution
|
||||||
import setuptools.tests.server
|
import setuptools.tests.server
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
|
from .py26compat import tarfile_open
|
||||||
|
from . import contexts
|
||||||
|
from .textwrap import DALS
|
||||||
|
|
||||||
|
|
||||||
class FakeDist(object):
|
class FakeDist(object):
|
||||||
def get_entry_map(self, group):
|
def get_entry_map(self, group):
|
||||||
if group != 'console_scripts':
|
if group != 'console_scripts':
|
||||||
@@ -33,134 +48,123 @@ class FakeDist(object):
|
|||||||
def as_requirement(self):
|
def as_requirement(self):
|
||||||
return 'spec'
|
return 'spec'
|
||||||
|
|
||||||
WANTED = """\
|
SETUP_PY = DALS("""
|
||||||
#!%s
|
from setuptools import setup
|
||||||
# EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
|
|
||||||
__requires__ = 'spec'
|
|
||||||
import sys
|
|
||||||
from pkg_resources import load_entry_point
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
setup(name='foo')
|
||||||
sys.exit(
|
""")
|
||||||
load_entry_point('spec', 'console_scripts', 'name')()
|
|
||||||
)
|
|
||||||
""" % nt_quote_arg(fix_jython_executable(sys.executable, ""))
|
|
||||||
|
|
||||||
SETUP_PY = """\
|
class TestEasyInstallTest:
|
||||||
from setuptools import setup
|
|
||||||
|
|
||||||
setup(name='foo')
|
|
||||||
"""
|
|
||||||
|
|
||||||
class TestEasyInstallTest(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_install_site_py(self):
|
def test_install_site_py(self):
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
cmd = easy_install(dist)
|
cmd = ei.easy_install(dist)
|
||||||
cmd.sitepy_installed = False
|
cmd.sitepy_installed = False
|
||||||
cmd.install_dir = tempfile.mkdtemp()
|
cmd.install_dir = tempfile.mkdtemp()
|
||||||
try:
|
try:
|
||||||
cmd.install_site_py()
|
cmd.install_site_py()
|
||||||
sitepy = os.path.join(cmd.install_dir, 'site.py')
|
sitepy = os.path.join(cmd.install_dir, 'site.py')
|
||||||
self.assertTrue(os.path.exists(sitepy))
|
assert os.path.exists(sitepy)
|
||||||
finally:
|
finally:
|
||||||
shutil.rmtree(cmd.install_dir)
|
shutil.rmtree(cmd.install_dir)
|
||||||
|
|
||||||
def test_get_script_args(self):
|
def test_get_script_args(self):
|
||||||
|
header = ei.CommandSpec.best().from_environment().as_header()
|
||||||
|
expected = header + DALS("""
|
||||||
|
# EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
|
||||||
|
__requires__ = 'spec'
|
||||||
|
import sys
|
||||||
|
from pkg_resources import load_entry_point
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(
|
||||||
|
load_entry_point('spec', 'console_scripts', 'name')()
|
||||||
|
)
|
||||||
|
""")
|
||||||
dist = FakeDist()
|
dist = FakeDist()
|
||||||
|
|
||||||
old_platform = sys.platform
|
args = next(ei.ScriptWriter.get_args(dist))
|
||||||
try:
|
name, script = itertools.islice(args, 2)
|
||||||
name, script = [i for i in next(get_script_args(dist))][0:2]
|
|
||||||
finally:
|
|
||||||
sys.platform = old_platform
|
|
||||||
|
|
||||||
self.assertEqual(script, WANTED)
|
assert script == expected
|
||||||
|
|
||||||
def test_no_find_links(self):
|
def test_no_find_links(self):
|
||||||
# new option '--no-find-links', that blocks find-links added at
|
# new option '--no-find-links', that blocks find-links added at
|
||||||
# the project level
|
# the project level
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
cmd = easy_install(dist)
|
cmd = ei.easy_install(dist)
|
||||||
cmd.check_pth_processing = lambda: True
|
cmd.check_pth_processing = lambda: True
|
||||||
cmd.no_find_links = True
|
cmd.no_find_links = True
|
||||||
cmd.find_links = ['link1', 'link2']
|
cmd.find_links = ['link1', 'link2']
|
||||||
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
|
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
|
||||||
cmd.args = ['ok']
|
cmd.args = ['ok']
|
||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
self.assertEqual(cmd.package_index.scanned_urls, {})
|
assert cmd.package_index.scanned_urls == {}
|
||||||
|
|
||||||
# let's try without it (default behavior)
|
# let's try without it (default behavior)
|
||||||
cmd = easy_install(dist)
|
cmd = ei.easy_install(dist)
|
||||||
cmd.check_pth_processing = lambda: True
|
cmd.check_pth_processing = lambda: True
|
||||||
cmd.find_links = ['link1', 'link2']
|
cmd.find_links = ['link1', 'link2']
|
||||||
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
|
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
|
||||||
cmd.args = ['ok']
|
cmd.args = ['ok']
|
||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
keys = sorted(cmd.package_index.scanned_urls.keys())
|
keys = sorted(cmd.package_index.scanned_urls.keys())
|
||||||
self.assertEqual(keys, ['link1', 'link2'])
|
assert keys == ['link1', 'link2']
|
||||||
|
|
||||||
|
def test_write_exception(self):
|
||||||
|
"""
|
||||||
|
Test that `cant_write_to_target` is rendered as a DistutilsError.
|
||||||
|
"""
|
||||||
|
dist = Distribution()
|
||||||
|
cmd = ei.easy_install(dist)
|
||||||
|
cmd.install_dir = os.getcwd()
|
||||||
|
with pytest.raises(distutils.errors.DistutilsError):
|
||||||
|
cmd.cant_write_to_target()
|
||||||
|
|
||||||
|
|
||||||
class TestPTHFileWriter(unittest.TestCase):
|
class TestPTHFileWriter:
|
||||||
def test_add_from_cwd_site_sets_dirty(self):
|
def test_add_from_cwd_site_sets_dirty(self):
|
||||||
'''a pth file manager should set dirty
|
'''a pth file manager should set dirty
|
||||||
if a distribution is in site but also the cwd
|
if a distribution is in site but also the cwd
|
||||||
'''
|
'''
|
||||||
pth = PthDistributions('does-not_exist', [os.getcwd()])
|
pth = PthDistributions('does-not_exist', [os.getcwd()])
|
||||||
self.assertTrue(not pth.dirty)
|
assert not pth.dirty
|
||||||
pth.add(PRDistribution(os.getcwd()))
|
pth.add(PRDistribution(os.getcwd()))
|
||||||
self.assertTrue(pth.dirty)
|
assert pth.dirty
|
||||||
|
|
||||||
def test_add_from_site_is_ignored(self):
|
def test_add_from_site_is_ignored(self):
|
||||||
if os.name != 'nt':
|
location = '/test/location/does-not-have-to-exist'
|
||||||
location = '/test/location/does-not-have-to-exist'
|
# PthDistributions expects all locations to be normalized
|
||||||
else:
|
location = pkg_resources.normalize_path(location)
|
||||||
location = 'c:\\does_not_exist'
|
|
||||||
pth = PthDistributions('does-not_exist', [location, ])
|
pth = PthDistributions('does-not_exist', [location, ])
|
||||||
self.assertTrue(not pth.dirty)
|
assert not pth.dirty
|
||||||
pth.add(PRDistribution(location))
|
pth.add(PRDistribution(location))
|
||||||
self.assertTrue(not pth.dirty)
|
assert not pth.dirty
|
||||||
|
|
||||||
|
|
||||||
class TestUserInstallTest(unittest.TestCase):
|
@pytest.yield_fixture
|
||||||
|
def setup_context(tmpdir):
|
||||||
def setUp(self):
|
with (tmpdir/'setup.py').open('w') as f:
|
||||||
self.dir = tempfile.mkdtemp()
|
|
||||||
setup = os.path.join(self.dir, 'setup.py')
|
|
||||||
f = open(setup, 'w')
|
|
||||||
f.write(SETUP_PY)
|
f.write(SETUP_PY)
|
||||||
f.close()
|
with tmpdir.as_cwd():
|
||||||
self.old_cwd = os.getcwd()
|
yield tmpdir
|
||||||
os.chdir(self.dir)
|
|
||||||
|
|
||||||
self.old_enable_site = site.ENABLE_USER_SITE
|
|
||||||
self.old_file = easy_install_pkg.__file__
|
|
||||||
self.old_base = site.USER_BASE
|
|
||||||
site.USER_BASE = tempfile.mkdtemp()
|
|
||||||
self.old_site = site.USER_SITE
|
|
||||||
site.USER_SITE = tempfile.mkdtemp()
|
|
||||||
easy_install_pkg.__file__ = site.USER_SITE
|
|
||||||
|
|
||||||
def tearDown(self):
|
@pytest.mark.usefixtures("user_override")
|
||||||
os.chdir(self.old_cwd)
|
@pytest.mark.usefixtures("setup_context")
|
||||||
shutil.rmtree(self.dir)
|
class TestUserInstallTest:
|
||||||
|
|
||||||
shutil.rmtree(site.USER_BASE)
|
|
||||||
shutil.rmtree(site.USER_SITE)
|
|
||||||
site.USER_BASE = self.old_base
|
|
||||||
site.USER_SITE = self.old_site
|
|
||||||
site.ENABLE_USER_SITE = self.old_enable_site
|
|
||||||
easy_install_pkg.__file__ = self.old_file
|
|
||||||
|
|
||||||
|
@mock.patch('setuptools.command.easy_install.__file__', None)
|
||||||
def test_user_install_implied(self):
|
def test_user_install_implied(self):
|
||||||
|
easy_install_pkg.__file__ = site.USER_SITE
|
||||||
site.ENABLE_USER_SITE = True # disabled sometimes
|
site.ENABLE_USER_SITE = True # disabled sometimes
|
||||||
#XXX: replace with something meaningfull
|
#XXX: replace with something meaningfull
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
dist.script_name = 'setup.py'
|
dist.script_name = 'setup.py'
|
||||||
cmd = easy_install(dist)
|
cmd = ei.easy_install(dist)
|
||||||
cmd.args = ['py']
|
cmd.args = ['py']
|
||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
self.assertTrue(cmd.user, 'user should be implied')
|
assert cmd.user, 'user should be implied'
|
||||||
|
|
||||||
def test_multiproc_atexit(self):
|
def test_multiproc_atexit(self):
|
||||||
try:
|
try:
|
||||||
@@ -178,10 +182,10 @@ class TestUserInstallTest(unittest.TestCase):
|
|||||||
#XXX: replace with something meaningfull
|
#XXX: replace with something meaningfull
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
dist.script_name = 'setup.py'
|
dist.script_name = 'setup.py'
|
||||||
cmd = easy_install(dist)
|
cmd = ei.easy_install(dist)
|
||||||
cmd.args = ['py']
|
cmd.args = ['py']
|
||||||
cmd.initialize_options()
|
cmd.initialize_options()
|
||||||
self.assertFalse(cmd.user, 'NOT user should be implied')
|
assert not cmd.user, 'NOT user should be implied'
|
||||||
|
|
||||||
def test_local_index(self):
|
def test_local_index(self):
|
||||||
# make sure the local index is used
|
# make sure the local index is used
|
||||||
@@ -190,11 +194,8 @@ class TestUserInstallTest(unittest.TestCase):
|
|||||||
new_location = tempfile.mkdtemp()
|
new_location = tempfile.mkdtemp()
|
||||||
target = tempfile.mkdtemp()
|
target = tempfile.mkdtemp()
|
||||||
egg_file = os.path.join(new_location, 'foo-1.0.egg-info')
|
egg_file = os.path.join(new_location, 'foo-1.0.egg-info')
|
||||||
f = open(egg_file, 'w')
|
with open(egg_file, 'w') as f:
|
||||||
try:
|
|
||||||
f.write('Name: foo\n')
|
f.write('Name: foo\n')
|
||||||
finally:
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
sys.path.append(target)
|
sys.path.append(target)
|
||||||
old_ppath = os.environ.get('PYTHONPATH')
|
old_ppath = os.environ.get('PYTHONPATH')
|
||||||
@@ -202,14 +203,15 @@ class TestUserInstallTest(unittest.TestCase):
|
|||||||
try:
|
try:
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
dist.script_name = 'setup.py'
|
dist.script_name = 'setup.py'
|
||||||
cmd = easy_install(dist)
|
cmd = ei.easy_install(dist)
|
||||||
cmd.install_dir = target
|
cmd.install_dir = target
|
||||||
cmd.args = ['foo']
|
cmd.args = ['foo']
|
||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
cmd.local_index.scan([new_location])
|
cmd.local_index.scan([new_location])
|
||||||
res = cmd.easy_install('foo')
|
res = cmd.easy_install('foo')
|
||||||
self.assertEqual(os.path.realpath(res.location),
|
actual = os.path.normcase(os.path.realpath(res.location))
|
||||||
os.path.realpath(new_location))
|
expected = os.path.normcase(os.path.realpath(new_location))
|
||||||
|
assert actual == expected
|
||||||
finally:
|
finally:
|
||||||
sys.path.remove(target)
|
sys.path.remove(target)
|
||||||
for basedir in [new_location, target, ]:
|
for basedir in [new_location, target, ]:
|
||||||
@@ -224,6 +226,25 @@ class TestUserInstallTest(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
del os.environ['PYTHONPATH']
|
del os.environ['PYTHONPATH']
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def user_install_setup_context(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Wrap sandbox.setup_context to patch easy_install in that context to
|
||||||
|
appear as user-installed.
|
||||||
|
"""
|
||||||
|
with self.orig_context(*args, **kwargs):
|
||||||
|
import setuptools.command.easy_install as ei
|
||||||
|
ei.__file__ = site.USER_SITE
|
||||||
|
yield
|
||||||
|
|
||||||
|
def patched_setup_context(self):
|
||||||
|
self.orig_context = sandbox.setup_context
|
||||||
|
|
||||||
|
return mock.patch(
|
||||||
|
'setuptools.sandbox.setup_context',
|
||||||
|
self.user_install_setup_context,
|
||||||
|
)
|
||||||
|
|
||||||
def test_setup_requires(self):
|
def test_setup_requires(self):
|
||||||
"""Regression test for Distribute issue #318
|
"""Regression test for Distribute issue #318
|
||||||
|
|
||||||
@@ -232,18 +253,37 @@ class TestUserInstallTest(unittest.TestCase):
|
|||||||
SandboxViolation.
|
SandboxViolation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
test_pkg = create_setup_requires_package(self.dir)
|
test_pkg = create_setup_requires_package(os.getcwd())
|
||||||
test_setup_py = os.path.join(test_pkg, 'setup.py')
|
test_setup_py = os.path.join(test_pkg, 'setup.py')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with quiet_context():
|
with contexts.quiet():
|
||||||
with reset_setup_stop_context():
|
with self.patched_setup_context():
|
||||||
run_setup(test_setup_py, ['install'])
|
run_setup(test_setup_py, ['install'])
|
||||||
except SandboxViolation:
|
except IndexError:
|
||||||
self.fail('Installation caused SandboxViolation')
|
# Test fails in some cases due to bugs in Python
|
||||||
|
# See https://bitbucket.org/pypa/setuptools/issue/201
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestSetupRequires(unittest.TestCase):
|
@pytest.yield_fixture
|
||||||
|
def distutils_package():
|
||||||
|
distutils_setup_py = SETUP_PY.replace(
|
||||||
|
'from setuptools import setup',
|
||||||
|
'from distutils.core import setup',
|
||||||
|
)
|
||||||
|
with contexts.tempdir(cd=os.chdir):
|
||||||
|
with open('setup.py', 'w') as f:
|
||||||
|
f.write(distutils_setup_py)
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
class TestDistutilsPackage:
|
||||||
|
def test_bdist_egg_available_on_distutils_pkg(self, distutils_package):
|
||||||
|
run_setup('setup.py', ['bdist_egg'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetupRequires:
|
||||||
|
|
||||||
def test_setup_requires_honors_fetch_params(self):
|
def test_setup_requires_honors_fetch_params(self):
|
||||||
"""
|
"""
|
||||||
@@ -260,25 +300,27 @@ class TestSetupRequires(unittest.TestCase):
|
|||||||
# Some platforms (Jython) don't find a port to which to bind,
|
# Some platforms (Jython) don't find a port to which to bind,
|
||||||
# so skip this test for them.
|
# so skip this test for them.
|
||||||
return
|
return
|
||||||
with quiet_context():
|
with contexts.quiet():
|
||||||
# create an sdist that has a build-time dependency.
|
# create an sdist that has a build-time dependency.
|
||||||
with TestSetupRequires.create_sdist() as dist_file:
|
with TestSetupRequires.create_sdist() as dist_file:
|
||||||
with tempdir_context() as temp_install_dir:
|
with contexts.tempdir() as temp_install_dir:
|
||||||
with environment_context(PYTHONPATH=temp_install_dir):
|
with contexts.environment(PYTHONPATH=temp_install_dir):
|
||||||
ei_params = ['--index-url', p_index.url,
|
ei_params = [
|
||||||
|
'--index-url', p_index.url,
|
||||||
'--allow-hosts', p_index_loc,
|
'--allow-hosts', p_index_loc,
|
||||||
'--exclude-scripts', '--install-dir', temp_install_dir,
|
'--exclude-scripts',
|
||||||
dist_file]
|
'--install-dir', temp_install_dir,
|
||||||
with reset_setup_stop_context():
|
dist_file,
|
||||||
with argv_context(['easy_install']):
|
]
|
||||||
# attempt to install the dist. It should fail because
|
with contexts.argv(['easy_install']):
|
||||||
# it doesn't exist.
|
# attempt to install the dist. It should fail because
|
||||||
self.assertRaises(SystemExit,
|
# it doesn't exist.
|
||||||
easy_install_pkg.main, ei_params)
|
with pytest.raises(SystemExit):
|
||||||
|
easy_install_pkg.main(ei_params)
|
||||||
# there should have been two or three requests to the server
|
# there should have been two or three requests to the server
|
||||||
# (three happens on Python 3.3a)
|
# (three happens on Python 3.3a)
|
||||||
self.assertTrue(2 <= len(p_index.requests) <= 3)
|
assert 2 <= len(p_index.requests) <= 3
|
||||||
self.assertEqual(p_index.requests[0].path, '/does-not-exist/')
|
assert p_index.requests[0].path == '/does-not-exist/'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
@@ -287,18 +329,17 @@ class TestSetupRequires(unittest.TestCase):
|
|||||||
Return an sdist with a setup_requires dependency (of something that
|
Return an sdist with a setup_requires dependency (of something that
|
||||||
doesn't exist)
|
doesn't exist)
|
||||||
"""
|
"""
|
||||||
with tempdir_context() as dir:
|
with contexts.tempdir() as dir:
|
||||||
dist_path = os.path.join(dir, 'setuptools-test-fetcher-1.0.tar.gz')
|
dist_path = os.path.join(dir, 'setuptools-test-fetcher-1.0.tar.gz')
|
||||||
make_trivial_sdist(
|
script = DALS("""
|
||||||
dist_path,
|
import setuptools
|
||||||
textwrap.dedent("""
|
setuptools.setup(
|
||||||
import setuptools
|
name="setuptools-test-fetcher",
|
||||||
setuptools.setup(
|
version="1.0",
|
||||||
name="setuptools-test-fetcher",
|
setup_requires = ['does-not-exist'],
|
||||||
version="1.0",
|
)
|
||||||
setup_requires = ['does-not-exist'],
|
""")
|
||||||
)
|
make_trivial_sdist(dist_path, script)
|
||||||
""").lstrip())
|
|
||||||
yield dist_path
|
yield dist_path
|
||||||
|
|
||||||
def test_setup_requires_overrides_version_conflict(self):
|
def test_setup_requires_overrides_version_conflict(self):
|
||||||
@@ -316,22 +357,17 @@ class TestSetupRequires(unittest.TestCase):
|
|||||||
working_set.add(fake_dist)
|
working_set.add(fake_dist)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with tempdir_context() as temp_dir:
|
with contexts.tempdir() as temp_dir:
|
||||||
test_pkg = create_setup_requires_package(temp_dir)
|
test_pkg = create_setup_requires_package(temp_dir)
|
||||||
test_setup_py = os.path.join(test_pkg, 'setup.py')
|
test_setup_py = os.path.join(test_pkg, 'setup.py')
|
||||||
with quiet_context() as (stdout, stderr):
|
with contexts.quiet() as (stdout, stderr):
|
||||||
with reset_setup_stop_context():
|
# Don't even need to install the package, just
|
||||||
try:
|
# running the setup.py at all is sufficient
|
||||||
# Don't even need to install the package, just
|
run_setup(test_setup_py, ['--name'])
|
||||||
# running the setup.py at all is sufficient
|
|
||||||
run_setup(test_setup_py, ['--name'])
|
|
||||||
except VersionConflict:
|
|
||||||
self.fail('Installing setup.py requirements '
|
|
||||||
'caused a VersionConflict')
|
|
||||||
|
|
||||||
lines = stdout.readlines()
|
lines = stdout.readlines()
|
||||||
self.assertTrue(len(lines) > 0)
|
assert len(lines) > 0
|
||||||
self.assertTrue(lines[-1].strip(), 'test_pkg')
|
assert lines[-1].strip(), 'test_pkg'
|
||||||
finally:
|
finally:
|
||||||
pkg_resources.__setstate__(pr_state)
|
pkg_resources.__setstate__(pr_state)
|
||||||
|
|
||||||
@@ -352,17 +388,16 @@ def create_setup_requires_package(path):
|
|||||||
test_setup_py = os.path.join(test_pkg, 'setup.py')
|
test_setup_py = os.path.join(test_pkg, 'setup.py')
|
||||||
os.mkdir(test_pkg)
|
os.mkdir(test_pkg)
|
||||||
|
|
||||||
f = open(test_setup_py, 'w')
|
with open(test_setup_py, 'w') as f:
|
||||||
f.write(textwrap.dedent("""\
|
f.write(DALS("""
|
||||||
import setuptools
|
import setuptools
|
||||||
setuptools.setup(**%r)
|
setuptools.setup(**%r)
|
||||||
""" % test_setup_attrs))
|
""" % test_setup_attrs))
|
||||||
f.close()
|
|
||||||
|
|
||||||
foobar_path = os.path.join(path, 'foobar-0.1.tar.gz')
|
foobar_path = os.path.join(path, 'foobar-0.1.tar.gz')
|
||||||
make_trivial_sdist(
|
make_trivial_sdist(
|
||||||
foobar_path,
|
foobar_path,
|
||||||
textwrap.dedent("""\
|
DALS("""
|
||||||
import setuptools
|
import setuptools
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name='foobar',
|
name='foobar',
|
||||||
@@ -386,71 +421,127 @@ def make_trivial_sdist(dist_path, setup_py):
|
|||||||
MemFile = StringIO
|
MemFile = StringIO
|
||||||
setup_py_bytes = MemFile(setup_py.encode('utf-8'))
|
setup_py_bytes = MemFile(setup_py.encode('utf-8'))
|
||||||
setup_py_file.size = len(setup_py_bytes.getvalue())
|
setup_py_file.size = len(setup_py_bytes.getvalue())
|
||||||
dist = tarfile.open(dist_path, 'w:gz')
|
with tarfile_open(dist_path, 'w:gz') as dist:
|
||||||
try:
|
|
||||||
dist.addfile(setup_py_file, fileobj=setup_py_bytes)
|
dist.addfile(setup_py_file, fileobj=setup_py_bytes)
|
||||||
finally:
|
|
||||||
dist.close()
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
class TestScriptHeader:
|
||||||
def tempdir_context(cd=lambda dir:None):
|
non_ascii_exe = '/Users/José/bin/python'
|
||||||
temp_dir = tempfile.mkdtemp()
|
exe_with_spaces = r'C:\Program Files\Python33\python.exe'
|
||||||
orig_dir = os.getcwd()
|
|
||||||
try:
|
|
||||||
cd(temp_dir)
|
|
||||||
yield temp_dir
|
|
||||||
finally:
|
|
||||||
cd(orig_dir)
|
|
||||||
shutil.rmtree(temp_dir)
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@pytest.mark.skipif(
|
||||||
def environment_context(**updates):
|
sys.platform.startswith('java') and ei.is_sh(sys.executable),
|
||||||
old_env = os.environ.copy()
|
reason="Test cannot run under java when executable is sh"
|
||||||
os.environ.update(updates)
|
)
|
||||||
try:
|
def test_get_script_header(self):
|
||||||
yield
|
expected = '#!%s\n' % ei.nt_quote_arg(os.path.normpath(sys.executable))
|
||||||
finally:
|
actual = ei.ScriptWriter.get_script_header('#!/usr/local/bin/python')
|
||||||
for key in updates:
|
assert actual == expected
|
||||||
del os.environ[key]
|
|
||||||
os.environ.update(old_env)
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
expected = '#!%s -x\n' % ei.nt_quote_arg(os.path.normpath
|
||||||
def argv_context(repl):
|
(sys.executable))
|
||||||
old_argv = sys.argv[:]
|
actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python -x')
|
||||||
sys.argv[:] = repl
|
assert actual == expected
|
||||||
yield
|
|
||||||
sys.argv[:] = old_argv
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python',
|
||||||
def reset_setup_stop_context():
|
executable=self.non_ascii_exe)
|
||||||
"""
|
expected = '#!%s -x\n' % self.non_ascii_exe
|
||||||
When the setuptools tests are run using setup.py test, and then
|
assert actual == expected
|
||||||
one wants to invoke another setup() command (such as easy_install)
|
|
||||||
within those tests, it's necessary to reset the global variable
|
actual = ei.ScriptWriter.get_script_header('#!/usr/bin/python',
|
||||||
in distutils.core so that the setup() command will run naturally.
|
executable='"'+self.exe_with_spaces+'"')
|
||||||
"""
|
expected = '#!"%s"\n' % self.exe_with_spaces
|
||||||
setup_stop_after = distutils.core._setup_stop_after
|
assert actual == expected
|
||||||
distutils.core._setup_stop_after = None
|
|
||||||
yield
|
@pytest.mark.xfail(
|
||||||
distutils.core._setup_stop_after = setup_stop_after
|
compat.PY3 and os.environ.get("LC_CTYPE") in ("C", "POSIX"),
|
||||||
|
reason="Test fails in this locale on Python 3"
|
||||||
|
)
|
||||||
|
@mock.patch.dict(sys.modules, java=mock.Mock(lang=mock.Mock(System=
|
||||||
|
mock.Mock(getProperty=mock.Mock(return_value="")))))
|
||||||
|
@mock.patch('sys.platform', 'java1.5.0_13')
|
||||||
|
def test_get_script_header_jython_workaround(self, tmpdir):
|
||||||
|
# Create a mock sys.executable that uses a shebang line
|
||||||
|
header = DALS("""
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
""")
|
||||||
|
exe = tmpdir / 'exe.py'
|
||||||
|
with exe.open('w') as f:
|
||||||
|
f.write(header)
|
||||||
|
exe = str(exe)
|
||||||
|
|
||||||
|
header = ei.ScriptWriter.get_script_header('#!/usr/local/bin/python',
|
||||||
|
executable=exe)
|
||||||
|
assert header == '#!/usr/bin/env %s\n' % exe
|
||||||
|
|
||||||
|
expect_out = 'stdout' if sys.version_info < (2,7) else 'stderr'
|
||||||
|
|
||||||
|
with contexts.quiet() as (stdout, stderr):
|
||||||
|
# When options are included, generate a broken shebang line
|
||||||
|
# with a warning emitted
|
||||||
|
candidate = ei.ScriptWriter.get_script_header('#!/usr/bin/python -x',
|
||||||
|
executable=exe)
|
||||||
|
assert candidate == '#!%s -x\n' % exe
|
||||||
|
output = locals()[expect_out]
|
||||||
|
assert 'Unable to adapt shebang line' in output.getvalue()
|
||||||
|
|
||||||
|
with contexts.quiet() as (stdout, stderr):
|
||||||
|
candidate = ei.ScriptWriter.get_script_header('#!/usr/bin/python',
|
||||||
|
executable=self.non_ascii_exe)
|
||||||
|
assert candidate == '#!%s -x\n' % self.non_ascii_exe
|
||||||
|
output = locals()[expect_out]
|
||||||
|
assert 'Unable to adapt shebang line' in output.getvalue()
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
class TestCommandSpec:
|
||||||
def quiet_context():
|
def test_custom_launch_command(self):
|
||||||
"""
|
"""
|
||||||
Redirect stdout/stderr to StringIO objects to prevent console output from
|
Show how a custom CommandSpec could be used to specify a #! executable
|
||||||
distutils commands.
|
which takes parameters.
|
||||||
"""
|
"""
|
||||||
|
cmd = ei.CommandSpec(['/usr/bin/env', 'python3'])
|
||||||
|
assert cmd.as_header() == '#!/usr/bin/env python3\n'
|
||||||
|
|
||||||
old_stdout = sys.stdout
|
def test_from_param_for_CommandSpec_is_passthrough(self):
|
||||||
old_stderr = sys.stderr
|
"""
|
||||||
new_stdout = sys.stdout = StringIO()
|
from_param should return an instance of a CommandSpec
|
||||||
new_stderr = sys.stderr = StringIO()
|
"""
|
||||||
try:
|
cmd = ei.CommandSpec(['python'])
|
||||||
yield new_stdout, new_stderr
|
cmd_new = ei.CommandSpec.from_param(cmd)
|
||||||
finally:
|
assert cmd is cmd_new
|
||||||
new_stdout.seek(0)
|
|
||||||
new_stderr.seek(0)
|
def test_from_environment_with_spaces_in_executable(self):
|
||||||
sys.stdout = old_stdout
|
with mock.patch('sys.executable', TestScriptHeader.exe_with_spaces):
|
||||||
sys.stderr = old_stderr
|
cmd = ei.CommandSpec.from_environment()
|
||||||
|
assert len(cmd) == 1
|
||||||
|
assert cmd.as_header().startswith('#!"')
|
||||||
|
|
||||||
|
def test_from_simple_string_uses_shlex(self):
|
||||||
|
"""
|
||||||
|
In order to support `executable = /usr/bin/env my-python`, make sure
|
||||||
|
from_param invokes shlex on that input.
|
||||||
|
"""
|
||||||
|
cmd = ei.CommandSpec.from_param('/usr/bin/env my-python')
|
||||||
|
assert len(cmd) == 2
|
||||||
|
assert '"' not in cmd.as_header()
|
||||||
|
|
||||||
|
def test_sys_executable(self):
|
||||||
|
"""
|
||||||
|
CommandSpec.from_string(sys.executable) should contain just that param.
|
||||||
|
"""
|
||||||
|
writer = ei.ScriptWriter.best()
|
||||||
|
cmd = writer.command_spec_class.from_string(sys.executable)
|
||||||
|
assert len(cmd) == 1
|
||||||
|
assert cmd[0] == sys.executable
|
||||||
|
|
||||||
|
|
||||||
|
class TestWindowsScriptWriter:
|
||||||
|
def test_header(self):
|
||||||
|
hdr = ei.WindowsScriptWriter.get_script_header('')
|
||||||
|
assert hdr.startswith('#!')
|
||||||
|
assert hdr.endswith('\n')
|
||||||
|
hdr = hdr.lstrip('#!')
|
||||||
|
hdr = hdr.rstrip('\n')
|
||||||
|
# header should not start with an escaped quote
|
||||||
|
assert not hdr.startswith('\\"')
|
||||||
|
|||||||
@@ -1,173 +1,98 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import stat
|
||||||
import tempfile
|
|
||||||
import shutil
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
import pkg_resources
|
import pytest
|
||||||
import warnings
|
|
||||||
from setuptools.command import egg_info
|
|
||||||
from setuptools import svn_utils
|
|
||||||
from setuptools.tests import environment, test_svn
|
|
||||||
from setuptools.tests.py26compat import skipIf
|
|
||||||
|
|
||||||
ENTRIES_V10 = pkg_resources.resource_string(__name__, 'entries-v10')
|
from . import environment
|
||||||
"An entries file generated with svn 1.6.17 against the legacy Setuptools repo"
|
from .textwrap import DALS
|
||||||
|
from . import contexts
|
||||||
|
|
||||||
|
|
||||||
class TestEggInfo(unittest.TestCase):
|
class TestEggInfo:
|
||||||
|
|
||||||
def setUp(self):
|
setup_script = DALS("""
|
||||||
self.test_dir = tempfile.mkdtemp()
|
from setuptools import setup
|
||||||
os.mkdir(os.path.join(self.test_dir, '.svn'))
|
|
||||||
|
|
||||||
self.old_cwd = os.getcwd()
|
setup(
|
||||||
os.chdir(self.test_dir)
|
name='foo',
|
||||||
|
py_modules=['hello'],
|
||||||
|
entry_points={'console_scripts': ['hi = hello.run']},
|
||||||
|
zip_safe=False,
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
def tearDown(self):
|
def _create_project(self):
|
||||||
os.chdir(self.old_cwd)
|
with open('setup.py', 'w') as f:
|
||||||
shutil.rmtree(self.test_dir)
|
f.write(self.setup_script)
|
||||||
|
|
||||||
def _write_entries(self, entries):
|
with open('hello.py', 'w') as f:
|
||||||
fn = os.path.join(self.test_dir, '.svn', 'entries')
|
f.write(DALS("""
|
||||||
entries_f = open(fn, 'wb')
|
def run():
|
||||||
entries_f.write(entries)
|
print('hello')
|
||||||
entries_f.close()
|
"""))
|
||||||
|
|
||||||
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
|
|
||||||
def test_version_10_format(self):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
#keeping this set for 1.6 is a good check on the get_svn_revision
|
|
||||||
#to ensure I return using svnversion what would had been returned
|
|
||||||
version_str = svn_utils.SvnInfo.get_svn_version()
|
|
||||||
version = [int(x) for x in version_str.split('.')[:2]]
|
|
||||||
if version != [1, 6]:
|
|
||||||
if hasattr(self, 'skipTest'):
|
|
||||||
self.skipTest('')
|
|
||||||
else:
|
|
||||||
sys.stderr.write('\n Skipping due to SVN Version\n')
|
|
||||||
return
|
|
||||||
|
|
||||||
self._write_entries(ENTRIES_V10)
|
@pytest.yield_fixture
|
||||||
rev = egg_info.egg_info.get_svn_revision()
|
def env(self):
|
||||||
self.assertEqual(rev, '89000')
|
class Environment(str): pass
|
||||||
|
|
||||||
def test_version_10_format_legacy_parser(self):
|
with contexts.tempdir(prefix='setuptools-test.') as env_dir:
|
||||||
"""
|
env = Environment(env_dir)
|
||||||
"""
|
os.chmod(env_dir, stat.S_IRWXU)
|
||||||
path_variable = None
|
subs = 'home', 'lib', 'scripts', 'data', 'egg-base'
|
||||||
for env in os.environ:
|
env.paths = dict(
|
||||||
if env.lower() == 'path':
|
(dirname, os.path.join(env_dir, dirname))
|
||||||
path_variable = env
|
for dirname in subs
|
||||||
|
)
|
||||||
|
list(map(os.mkdir, env.paths.values()))
|
||||||
|
config = os.path.join(env.paths['home'], '.pydistutils.cfg')
|
||||||
|
with open(config, 'w') as f:
|
||||||
|
f.write(DALS("""
|
||||||
|
[egg_info]
|
||||||
|
egg-base = %(egg-base)s
|
||||||
|
""" % env.paths
|
||||||
|
))
|
||||||
|
yield env
|
||||||
|
|
||||||
if path_variable:
|
def test_egg_base_installed_egg_info(self, tmpdir_cwd, env):
|
||||||
old_path = os.environ[path_variable]
|
self._create_project()
|
||||||
os.environ[path_variable] = ''
|
|
||||||
#catch_warnings not available until py26
|
|
||||||
warning_filters = warnings.filters
|
|
||||||
warnings.filters = warning_filters[:]
|
|
||||||
try:
|
|
||||||
warnings.simplefilter("ignore", DeprecationWarning)
|
|
||||||
self._write_entries(ENTRIES_V10)
|
|
||||||
rev = egg_info.egg_info.get_svn_revision()
|
|
||||||
finally:
|
|
||||||
#restore the warning filters
|
|
||||||
warnings.filters = warning_filters
|
|
||||||
#restore the os path
|
|
||||||
if path_variable:
|
|
||||||
os.environ[path_variable] = old_path
|
|
||||||
|
|
||||||
self.assertEqual(rev, '89000')
|
environ = os.environ.copy().update(
|
||||||
|
HOME=env.paths['home'],
|
||||||
DUMMY_SOURCE_TXT = """CHANGES.txt
|
)
|
||||||
CONTRIBUTORS.txt
|
cmd = [
|
||||||
HISTORY.txt
|
'install',
|
||||||
LICENSE
|
'--home', env.paths['home'],
|
||||||
MANIFEST.in
|
'--install-lib', env.paths['lib'],
|
||||||
README.txt
|
'--install-scripts', env.paths['scripts'],
|
||||||
setup.py
|
'--install-data', env.paths['data'],
|
||||||
dummy/__init__.py
|
]
|
||||||
dummy/test.txt
|
code, data = environment.run_setup_py(
|
||||||
dummy.egg-info/PKG-INFO
|
cmd=cmd,
|
||||||
dummy.egg-info/SOURCES.txt
|
pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]),
|
||||||
dummy.egg-info/dependency_links.txt
|
data_stream=1,
|
||||||
dummy.egg-info/top_level.txt"""
|
env=environ,
|
||||||
|
)
|
||||||
|
|
||||||
class TestSvnDummy(environment.ZippedEnvironment):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
version = svn_utils.SvnInfo.get_svn_version()
|
|
||||||
if not version: # None or Empty
|
|
||||||
return None
|
|
||||||
|
|
||||||
self.base_version = tuple([int(x) for x in version.split('.')][:2])
|
|
||||||
|
|
||||||
if not self.base_version:
|
|
||||||
raise ValueError('No SVN tools installed')
|
|
||||||
elif self.base_version < (1, 3):
|
|
||||||
raise ValueError('Insufficient SVN Version %s' % version)
|
|
||||||
elif self.base_version >= (1, 9):
|
|
||||||
#trying the latest version
|
|
||||||
self.base_version = (1, 8)
|
|
||||||
|
|
||||||
self.dataname = "dummy%i%i" % self.base_version
|
|
||||||
self.datafile = os.path.join('setuptools', 'tests',
|
|
||||||
'svn_data', self.dataname + ".zip")
|
|
||||||
super(TestSvnDummy, self).setUp()
|
|
||||||
|
|
||||||
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
|
|
||||||
def test_sources(self):
|
|
||||||
code, data = environment.run_setup_py(["sdist"],
|
|
||||||
pypath=self.old_cwd,
|
|
||||||
data_stream=1)
|
|
||||||
if code:
|
if code:
|
||||||
raise AssertionError(data)
|
raise AssertionError(data)
|
||||||
|
|
||||||
sources = os.path.join('dummy.egg-info', 'SOURCES.txt')
|
actual = self._find_egg_info_files(env.paths['lib'])
|
||||||
infile = open(sources, 'r')
|
|
||||||
try:
|
|
||||||
read_contents = infile.read()
|
|
||||||
finally:
|
|
||||||
infile.close()
|
|
||||||
del infile
|
|
||||||
|
|
||||||
self.assertEqual(DUMMY_SOURCE_TXT, read_contents)
|
expected = [
|
||||||
|
'PKG-INFO',
|
||||||
|
'SOURCES.txt',
|
||||||
|
'dependency_links.txt',
|
||||||
|
'entry_points.txt',
|
||||||
|
'not-zip-safe',
|
||||||
|
'top_level.txt',
|
||||||
|
]
|
||||||
|
assert sorted(actual) == expected
|
||||||
|
|
||||||
return data
|
def _find_egg_info_files(self, root):
|
||||||
|
results = (
|
||||||
|
filenames
|
||||||
class TestSvnDummyLegacy(environment.ZippedEnvironment):
|
for dirpath, dirnames, filenames in os.walk(root)
|
||||||
|
if os.path.basename(dirpath) == 'EGG-INFO'
|
||||||
def setUp(self):
|
)
|
||||||
self.base_version = (1, 6)
|
# expect exactly one result
|
||||||
self.dataname = "dummy%i%i" % self.base_version
|
result, = results
|
||||||
self.datafile = os.path.join('setuptools', 'tests',
|
return result
|
||||||
'svn_data', self.dataname + ".zip")
|
|
||||||
super(TestSvnDummyLegacy, self).setUp()
|
|
||||||
|
|
||||||
def test_sources(self):
|
|
||||||
code, data = environment.run_setup_py(["sdist"],
|
|
||||||
pypath=self.old_cwd,
|
|
||||||
path="",
|
|
||||||
data_stream=1)
|
|
||||||
if code:
|
|
||||||
raise AssertionError(data)
|
|
||||||
|
|
||||||
sources = os.path.join('dummy.egg-info', 'SOURCES.txt')
|
|
||||||
infile = open(sources, 'r')
|
|
||||||
try:
|
|
||||||
read_contents = infile.read()
|
|
||||||
finally:
|
|
||||||
infile.close()
|
|
||||||
del infile
|
|
||||||
|
|
||||||
self.assertEqual(DUMMY_SOURCE_TXT, read_contents)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
|||||||
170
awx/lib/site-packages/setuptools/tests/test_find_packages.py
Normal file
170
awx/lib/site-packages/setuptools/tests/test_find_packages.py
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
"""Tests for setuptools.find_packages()."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
import platform
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import setuptools
|
||||||
|
from setuptools import find_packages
|
||||||
|
|
||||||
|
find_420_packages = setuptools.PEP420PackageFinder.find
|
||||||
|
|
||||||
|
# modeled after CPython's test.support.can_symlink
|
||||||
|
def can_symlink():
|
||||||
|
TESTFN = tempfile.mktemp()
|
||||||
|
symlink_path = TESTFN + "can_symlink"
|
||||||
|
try:
|
||||||
|
os.symlink(TESTFN, symlink_path)
|
||||||
|
can = True
|
||||||
|
except (OSError, NotImplementedError, AttributeError):
|
||||||
|
can = False
|
||||||
|
else:
|
||||||
|
os.remove(symlink_path)
|
||||||
|
globals().update(can_symlink=lambda: can)
|
||||||
|
return can
|
||||||
|
|
||||||
|
def has_symlink():
|
||||||
|
bad_symlink = (
|
||||||
|
# Windows symlink directory detection is broken on Python 3.2
|
||||||
|
platform.system() == 'Windows' and sys.version_info[:2] == (3,2)
|
||||||
|
)
|
||||||
|
return can_symlink() and not bad_symlink
|
||||||
|
|
||||||
|
class TestFindPackages:
|
||||||
|
|
||||||
|
def setup_method(self, method):
|
||||||
|
self.dist_dir = tempfile.mkdtemp()
|
||||||
|
self._make_pkg_structure()
|
||||||
|
|
||||||
|
def teardown_method(self, method):
|
||||||
|
shutil.rmtree(self.dist_dir)
|
||||||
|
|
||||||
|
def _make_pkg_structure(self):
|
||||||
|
"""Make basic package structure.
|
||||||
|
|
||||||
|
dist/
|
||||||
|
docs/
|
||||||
|
conf.py
|
||||||
|
pkg/
|
||||||
|
__pycache__/
|
||||||
|
nspkg/
|
||||||
|
mod.py
|
||||||
|
subpkg/
|
||||||
|
assets/
|
||||||
|
asset
|
||||||
|
__init__.py
|
||||||
|
setup.py
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.docs_dir = self._mkdir('docs', self.dist_dir)
|
||||||
|
self._touch('conf.py', self.docs_dir)
|
||||||
|
self.pkg_dir = self._mkdir('pkg', self.dist_dir)
|
||||||
|
self._mkdir('__pycache__', self.pkg_dir)
|
||||||
|
self.ns_pkg_dir = self._mkdir('nspkg', self.pkg_dir)
|
||||||
|
self._touch('mod.py', self.ns_pkg_dir)
|
||||||
|
self.sub_pkg_dir = self._mkdir('subpkg', self.pkg_dir)
|
||||||
|
self.asset_dir = self._mkdir('assets', self.sub_pkg_dir)
|
||||||
|
self._touch('asset', self.asset_dir)
|
||||||
|
self._touch('__init__.py', self.sub_pkg_dir)
|
||||||
|
self._touch('setup.py', self.dist_dir)
|
||||||
|
|
||||||
|
def _mkdir(self, path, parent_dir=None):
|
||||||
|
if parent_dir:
|
||||||
|
path = os.path.join(parent_dir, path)
|
||||||
|
os.mkdir(path)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def _touch(self, path, dir_=None):
|
||||||
|
if dir_:
|
||||||
|
path = os.path.join(dir_, path)
|
||||||
|
fp = open(path, 'w')
|
||||||
|
fp.close()
|
||||||
|
return path
|
||||||
|
|
||||||
|
def test_regular_package(self):
|
||||||
|
self._touch('__init__.py', self.pkg_dir)
|
||||||
|
packages = find_packages(self.dist_dir)
|
||||||
|
assert packages == ['pkg', 'pkg.subpkg']
|
||||||
|
|
||||||
|
def test_exclude(self):
|
||||||
|
self._touch('__init__.py', self.pkg_dir)
|
||||||
|
packages = find_packages(self.dist_dir, exclude=('pkg.*',))
|
||||||
|
assert packages == ['pkg']
|
||||||
|
|
||||||
|
def test_include_excludes_other(self):
|
||||||
|
"""
|
||||||
|
If include is specified, other packages should be excluded.
|
||||||
|
"""
|
||||||
|
self._touch('__init__.py', self.pkg_dir)
|
||||||
|
alt_dir = self._mkdir('other_pkg', self.dist_dir)
|
||||||
|
self._touch('__init__.py', alt_dir)
|
||||||
|
packages = find_packages(self.dist_dir, include=['other_pkg'])
|
||||||
|
assert packages == ['other_pkg']
|
||||||
|
|
||||||
|
def test_dir_with_dot_is_skipped(self):
|
||||||
|
shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
|
||||||
|
data_dir = self._mkdir('some.data', self.pkg_dir)
|
||||||
|
self._touch('__init__.py', data_dir)
|
||||||
|
self._touch('file.dat', data_dir)
|
||||||
|
packages = find_packages(self.dist_dir)
|
||||||
|
assert 'pkg.some.data' not in packages
|
||||||
|
|
||||||
|
def test_dir_with_packages_in_subdir_is_excluded(self):
|
||||||
|
"""
|
||||||
|
Ensure that a package in a non-package such as build/pkg/__init__.py
|
||||||
|
is excluded.
|
||||||
|
"""
|
||||||
|
build_dir = self._mkdir('build', self.dist_dir)
|
||||||
|
build_pkg_dir = self._mkdir('pkg', build_dir)
|
||||||
|
self._touch('__init__.py', build_pkg_dir)
|
||||||
|
packages = find_packages(self.dist_dir)
|
||||||
|
assert 'build.pkg' not in packages
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not has_symlink(), reason='Symlink support required')
|
||||||
|
def test_symlinked_packages_are_included(self):
|
||||||
|
"""
|
||||||
|
A symbolically-linked directory should be treated like any other
|
||||||
|
directory when matched as a package.
|
||||||
|
|
||||||
|
Create a link from lpkg -> pkg.
|
||||||
|
"""
|
||||||
|
self._touch('__init__.py', self.pkg_dir)
|
||||||
|
linked_pkg = os.path.join(self.dist_dir, 'lpkg')
|
||||||
|
os.symlink('pkg', linked_pkg)
|
||||||
|
assert os.path.isdir(linked_pkg)
|
||||||
|
packages = find_packages(self.dist_dir)
|
||||||
|
assert 'lpkg' in packages
|
||||||
|
|
||||||
|
def _assert_packages(self, actual, expected):
|
||||||
|
assert set(actual) == set(expected)
|
||||||
|
|
||||||
|
def test_pep420_ns_package(self):
|
||||||
|
packages = find_420_packages(
|
||||||
|
self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets'])
|
||||||
|
self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
|
||||||
|
|
||||||
|
def test_pep420_ns_package_no_includes(self):
|
||||||
|
packages = find_420_packages(
|
||||||
|
self.dist_dir, exclude=['pkg.subpkg.assets'])
|
||||||
|
self._assert_packages(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])
|
||||||
|
|
||||||
|
def test_pep420_ns_package_no_includes_or_excludes(self):
|
||||||
|
packages = find_420_packages(self.dist_dir)
|
||||||
|
expected = [
|
||||||
|
'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
|
||||||
|
self._assert_packages(packages, expected)
|
||||||
|
|
||||||
|
def test_regular_package_with_nested_pep420_ns_packages(self):
|
||||||
|
self._touch('__init__.py', self.pkg_dir)
|
||||||
|
packages = find_420_packages(
|
||||||
|
self.dist_dir, exclude=['docs', 'pkg.subpkg.assets'])
|
||||||
|
self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
|
||||||
|
|
||||||
|
def test_pep420_ns_package_no_non_package_dirs(self):
|
||||||
|
shutil.rmtree(self.docs_dir)
|
||||||
|
shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
|
||||||
|
packages = find_420_packages(self.dist_dir)
|
||||||
|
self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
|
||||||
99
awx/lib/site-packages/setuptools/tests/test_integration.py
Normal file
99
awx/lib/site-packages/setuptools/tests/test_integration.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
"""Run some integration tests.
|
||||||
|
|
||||||
|
Try to install a few packages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from setuptools.command.easy_install import easy_install
|
||||||
|
from setuptools.command import easy_install as easy_install_pkg
|
||||||
|
from setuptools.dist import Distribution
|
||||||
|
from setuptools.compat import urlopen
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(module):
|
||||||
|
packages = 'stevedore', 'virtualenvwrapper', 'pbr', 'novaclient'
|
||||||
|
for pkg in packages:
|
||||||
|
try:
|
||||||
|
__import__(pkg)
|
||||||
|
tmpl = "Integration tests cannot run when {pkg} is installed"
|
||||||
|
pytest.skip(tmpl.format(**locals()))
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
urlopen('https://pypi.python.org/pypi')
|
||||||
|
except Exception as exc:
|
||||||
|
pytest.skip(reason=str(exc))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def install_context(request, tmpdir, monkeypatch):
|
||||||
|
"""Fixture to set up temporary installation directory.
|
||||||
|
"""
|
||||||
|
# Save old values so we can restore them.
|
||||||
|
new_cwd = tmpdir.mkdir('cwd')
|
||||||
|
user_base = tmpdir.mkdir('user_base')
|
||||||
|
user_site = tmpdir.mkdir('user_site')
|
||||||
|
install_dir = tmpdir.mkdir('install_dir')
|
||||||
|
|
||||||
|
def fin():
|
||||||
|
# undo the monkeypatch, particularly needed under
|
||||||
|
# windows because of kept handle on cwd
|
||||||
|
monkeypatch.undo()
|
||||||
|
new_cwd.remove()
|
||||||
|
user_base.remove()
|
||||||
|
user_site.remove()
|
||||||
|
install_dir.remove()
|
||||||
|
request.addfinalizer(fin)
|
||||||
|
|
||||||
|
# Change the environment and site settings to control where the
|
||||||
|
# files are installed and ensure we do not overwrite anything.
|
||||||
|
monkeypatch.chdir(new_cwd)
|
||||||
|
monkeypatch.setattr(easy_install_pkg, '__file__', user_site.strpath)
|
||||||
|
monkeypatch.setattr('site.USER_BASE', user_base.strpath)
|
||||||
|
monkeypatch.setattr('site.USER_SITE', user_site.strpath)
|
||||||
|
monkeypatch.setattr('sys.path', sys.path + [install_dir.strpath])
|
||||||
|
monkeypatch.setenv('PYTHONPATH', os.path.pathsep.join(sys.path))
|
||||||
|
|
||||||
|
# Set up the command for performing the installation.
|
||||||
|
dist = Distribution()
|
||||||
|
cmd = easy_install(dist)
|
||||||
|
cmd.install_dir = install_dir.strpath
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
|
def _install_one(requirement, cmd, pkgname, modulename):
|
||||||
|
cmd.args = [requirement]
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
cmd.run()
|
||||||
|
target = cmd.install_dir
|
||||||
|
dest_path = glob.glob(os.path.join(target, pkgname + '*.egg'))
|
||||||
|
assert dest_path
|
||||||
|
assert os.path.exists(os.path.join(dest_path[0], pkgname, modulename))
|
||||||
|
|
||||||
|
|
||||||
|
def test_stevedore(install_context):
|
||||||
|
_install_one('stevedore', install_context,
|
||||||
|
'stevedore', 'extension.py')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail
|
||||||
|
def test_virtualenvwrapper(install_context):
|
||||||
|
_install_one('virtualenvwrapper', install_context,
|
||||||
|
'virtualenvwrapper', 'hook_loader.py')
|
||||||
|
|
||||||
|
|
||||||
|
def test_pbr(install_context):
|
||||||
|
_install_one('pbr', install_context,
|
||||||
|
'pbr', 'core.py')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail
|
||||||
|
def test_python_novaclient(install_context):
|
||||||
|
_install_one('python-novaclient', install_context,
|
||||||
|
'novaclient', 'base.py')
|
||||||
@@ -1,48 +1,43 @@
|
|||||||
import os
|
import os
|
||||||
import unittest
|
|
||||||
from setuptools.tests.py26compat import skipIf
|
|
||||||
|
|
||||||
try:
|
import pytest
|
||||||
import ast
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
class TestMarkerlib(unittest.TestCase):
|
|
||||||
|
|
||||||
@skipIf('ast' not in globals(),
|
class TestMarkerlib:
|
||||||
"ast not available (Python < 2.6?)")
|
|
||||||
|
@pytest.mark.importorskip('ast')
|
||||||
def test_markers(self):
|
def test_markers(self):
|
||||||
from _markerlib import interpret, default_environment, compile
|
from _markerlib import interpret, default_environment, compile
|
||||||
|
|
||||||
os_name = os.name
|
os_name = os.name
|
||||||
|
|
||||||
self.assertTrue(interpret(""))
|
assert interpret("")
|
||||||
|
|
||||||
self.assertTrue(interpret("os.name != 'buuuu'"))
|
assert interpret("os.name != 'buuuu'")
|
||||||
self.assertTrue(interpret("os_name != 'buuuu'"))
|
assert interpret("os_name != 'buuuu'")
|
||||||
self.assertTrue(interpret("python_version > '1.0'"))
|
assert interpret("python_version > '1.0'")
|
||||||
self.assertTrue(interpret("python_version < '5.0'"))
|
assert interpret("python_version < '5.0'")
|
||||||
self.assertTrue(interpret("python_version <= '5.0'"))
|
assert interpret("python_version <= '5.0'")
|
||||||
self.assertTrue(interpret("python_version >= '1.0'"))
|
assert interpret("python_version >= '1.0'")
|
||||||
self.assertTrue(interpret("'%s' in os.name" % os_name))
|
assert interpret("'%s' in os.name" % os_name)
|
||||||
self.assertTrue(interpret("'%s' in os_name" % os_name))
|
assert interpret("'%s' in os_name" % os_name)
|
||||||
self.assertTrue(interpret("'buuuu' not in os.name"))
|
assert interpret("'buuuu' not in os.name")
|
||||||
|
|
||||||
self.assertFalse(interpret("os.name == 'buuuu'"))
|
assert not interpret("os.name == 'buuuu'")
|
||||||
self.assertFalse(interpret("os_name == 'buuuu'"))
|
assert not interpret("os_name == 'buuuu'")
|
||||||
self.assertFalse(interpret("python_version < '1.0'"))
|
assert not interpret("python_version < '1.0'")
|
||||||
self.assertFalse(interpret("python_version > '5.0'"))
|
assert not interpret("python_version > '5.0'")
|
||||||
self.assertFalse(interpret("python_version >= '5.0'"))
|
assert not interpret("python_version >= '5.0'")
|
||||||
self.assertFalse(interpret("python_version <= '1.0'"))
|
assert not interpret("python_version <= '1.0'")
|
||||||
self.assertFalse(interpret("'%s' not in os.name" % os_name))
|
assert not interpret("'%s' not in os.name" % os_name)
|
||||||
self.assertFalse(interpret("'buuuu' in os.name and python_version >= '5.0'"))
|
assert not interpret("'buuuu' in os.name and python_version >= '5.0'")
|
||||||
self.assertFalse(interpret("'buuuu' in os_name and python_version >= '5.0'"))
|
assert not interpret("'buuuu' in os_name and python_version >= '5.0'")
|
||||||
|
|
||||||
environment = default_environment()
|
environment = default_environment()
|
||||||
environment['extra'] = 'test'
|
environment['extra'] = 'test'
|
||||||
self.assertTrue(interpret("extra == 'test'", environment))
|
assert interpret("extra == 'test'", environment)
|
||||||
self.assertFalse(interpret("extra == 'doc'", environment))
|
assert not interpret("extra == 'doc'", environment)
|
||||||
|
|
||||||
def raises_nameError():
|
def raises_nameError():
|
||||||
try:
|
try:
|
||||||
interpret("python.version == '42'")
|
interpret("python.version == '42'")
|
||||||
@@ -50,9 +45,9 @@ class TestMarkerlib(unittest.TestCase):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise Exception("Expected NameError")
|
raise Exception("Expected NameError")
|
||||||
|
|
||||||
raises_nameError()
|
raises_nameError()
|
||||||
|
|
||||||
def raises_syntaxError():
|
def raises_syntaxError():
|
||||||
try:
|
try:
|
||||||
interpret("(x for x in (4,))")
|
interpret("(x for x in (4,))")
|
||||||
@@ -60,9 +55,9 @@ class TestMarkerlib(unittest.TestCase):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise Exception("Expected SyntaxError")
|
raise Exception("Expected SyntaxError")
|
||||||
|
|
||||||
raises_syntaxError()
|
raises_syntaxError()
|
||||||
|
|
||||||
statement = "python_version == '5'"
|
statement = "python_version == '5'"
|
||||||
self.assertEqual(compile(statement).__doc__, statement)
|
assert compile(statement).__doc__ == statement
|
||||||
|
|
||||||
|
|||||||
179
awx/lib/site-packages/setuptools/tests/test_msvc9compiler.py
Normal file
179
awx/lib/site-packages/setuptools/tests/test_msvc9compiler.py
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
"""
|
||||||
|
Tests for msvc9compiler.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import contextlib
|
||||||
|
import distutils.errors
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
try:
|
||||||
|
from unittest import mock
|
||||||
|
except ImportError:
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from . import contexts
|
||||||
|
|
||||||
|
# importing only setuptools should apply the patch
|
||||||
|
__import__('setuptools')
|
||||||
|
|
||||||
|
pytest.importorskip("distutils.msvc9compiler")
|
||||||
|
|
||||||
|
|
||||||
|
def mock_reg(hkcu=None, hklm=None):
|
||||||
|
"""
|
||||||
|
Return a mock for distutils.msvc9compiler.Reg, patched
|
||||||
|
to mock out the functions that access the registry.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_winreg = getattr(distutils.msvc9compiler, '_winreg', None)
|
||||||
|
winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg)
|
||||||
|
|
||||||
|
hives = {
|
||||||
|
winreg.HKEY_CURRENT_USER: hkcu or {},
|
||||||
|
winreg.HKEY_LOCAL_MACHINE: hklm or {},
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_keys(cls, base, key):
|
||||||
|
"""Return list of registry keys."""
|
||||||
|
hive = hives.get(base, {})
|
||||||
|
return [
|
||||||
|
k.rpartition('\\')[2]
|
||||||
|
for k in hive if k.startswith(key.lower())
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def read_values(cls, base, key):
|
||||||
|
"""Return dict of registry keys and values."""
|
||||||
|
hive = hives.get(base, {})
|
||||||
|
return dict(
|
||||||
|
(k.rpartition('\\')[2], hive[k])
|
||||||
|
for k in hive if k.startswith(key.lower())
|
||||||
|
)
|
||||||
|
|
||||||
|
return mock.patch.multiple(distutils.msvc9compiler.Reg,
|
||||||
|
read_keys=read_keys, read_values=read_values)
|
||||||
|
|
||||||
|
|
||||||
|
class TestModulePatch:
|
||||||
|
"""
|
||||||
|
Ensure that importing setuptools is sufficient to replace
|
||||||
|
the standard find_vcvarsall function with a version that
|
||||||
|
recognizes the "Visual C++ for Python" package.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir'
|
||||||
|
key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir'
|
||||||
|
|
||||||
|
def test_patched(self):
|
||||||
|
"Test the module is actually patched"
|
||||||
|
mod_name = distutils.msvc9compiler.find_vcvarsall.__module__
|
||||||
|
assert mod_name == "setuptools.msvc9_support", "find_vcvarsall unpatched"
|
||||||
|
|
||||||
|
def test_no_registry_entryies_means_nothing_found(self):
|
||||||
|
"""
|
||||||
|
No registry entries or environment variable should lead to an error
|
||||||
|
directing the user to download vcpython27.
|
||||||
|
"""
|
||||||
|
find_vcvarsall = distutils.msvc9compiler.find_vcvarsall
|
||||||
|
query_vcvarsall = distutils.msvc9compiler.query_vcvarsall
|
||||||
|
|
||||||
|
with contexts.environment(VS90COMNTOOLS=None):
|
||||||
|
with mock_reg():
|
||||||
|
assert find_vcvarsall(9.0) is None
|
||||||
|
|
||||||
|
expected = distutils.errors.DistutilsPlatformError
|
||||||
|
with pytest.raises(expected) as exc:
|
||||||
|
query_vcvarsall(9.0)
|
||||||
|
assert 'aka.ms/vcpython27' in str(exc)
|
||||||
|
|
||||||
|
@pytest.yield_fixture
|
||||||
|
def user_preferred_setting(self):
|
||||||
|
"""
|
||||||
|
Set up environment with different install dirs for user vs. system
|
||||||
|
and yield the user_install_dir for the expected result.
|
||||||
|
"""
|
||||||
|
with self.mock_install_dir() as user_install_dir:
|
||||||
|
with self.mock_install_dir() as system_install_dir:
|
||||||
|
reg = mock_reg(
|
||||||
|
hkcu={
|
||||||
|
self.key_32: user_install_dir,
|
||||||
|
},
|
||||||
|
hklm={
|
||||||
|
self.key_32: system_install_dir,
|
||||||
|
self.key_64: system_install_dir,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
with reg:
|
||||||
|
yield user_install_dir
|
||||||
|
|
||||||
|
def test_prefer_current_user(self, user_preferred_setting):
|
||||||
|
"""
|
||||||
|
Ensure user's settings are preferred.
|
||||||
|
"""
|
||||||
|
result = distutils.msvc9compiler.find_vcvarsall(9.0)
|
||||||
|
expected = os.path.join(user_preferred_setting, 'vcvarsall.bat')
|
||||||
|
assert expected == result
|
||||||
|
|
||||||
|
@pytest.yield_fixture
|
||||||
|
def local_machine_setting(self):
|
||||||
|
"""
|
||||||
|
Set up environment with only the system environment configured.
|
||||||
|
"""
|
||||||
|
with self.mock_install_dir() as system_install_dir:
|
||||||
|
reg = mock_reg(
|
||||||
|
hklm={
|
||||||
|
self.key_32: system_install_dir,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
with reg:
|
||||||
|
yield system_install_dir
|
||||||
|
|
||||||
|
def test_local_machine_recognized(self, local_machine_setting):
|
||||||
|
"""
|
||||||
|
Ensure machine setting is honored if user settings are not present.
|
||||||
|
"""
|
||||||
|
result = distutils.msvc9compiler.find_vcvarsall(9.0)
|
||||||
|
expected = os.path.join(local_machine_setting, 'vcvarsall.bat')
|
||||||
|
assert expected == result
|
||||||
|
|
||||||
|
@pytest.yield_fixture
|
||||||
|
def x64_preferred_setting(self):
|
||||||
|
"""
|
||||||
|
Set up environment with 64-bit and 32-bit system settings configured
|
||||||
|
and yield the canonical location.
|
||||||
|
"""
|
||||||
|
with self.mock_install_dir() as x32_dir:
|
||||||
|
with self.mock_install_dir() as x64_dir:
|
||||||
|
reg = mock_reg(
|
||||||
|
hklm={
|
||||||
|
# This *should* only exist on 32-bit machines
|
||||||
|
self.key_32: x32_dir,
|
||||||
|
# This *should* only exist on 64-bit machines
|
||||||
|
self.key_64: x64_dir,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
with reg:
|
||||||
|
yield x32_dir
|
||||||
|
|
||||||
|
def test_ensure_64_bit_preferred(self, x64_preferred_setting):
|
||||||
|
"""
|
||||||
|
Ensure 64-bit system key is preferred.
|
||||||
|
"""
|
||||||
|
result = distutils.msvc9compiler.find_vcvarsall(9.0)
|
||||||
|
expected = os.path.join(x64_preferred_setting, 'vcvarsall.bat')
|
||||||
|
assert expected == result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def mock_install_dir():
|
||||||
|
"""
|
||||||
|
Make a mock install dir in a unique location so that tests can
|
||||||
|
distinguish which dir was detected in a given scenario.
|
||||||
|
"""
|
||||||
|
with contexts.tempdir() as result:
|
||||||
|
vcvarsall = os.path.join(result, 'vcvarsall.bat')
|
||||||
|
with open(vcvarsall, 'w'):
|
||||||
|
pass
|
||||||
|
yield result
|
||||||
@@ -1,26 +1,24 @@
|
|||||||
"""Package Index Tests
|
|
||||||
"""
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
|
||||||
import unittest
|
|
||||||
import pkg_resources
|
|
||||||
from setuptools.compat import urllib2, httplib, HTTPError, unicode, pathname2url
|
|
||||||
import distutils.errors
|
import distutils.errors
|
||||||
|
|
||||||
|
from setuptools.compat import httplib, HTTPError, unicode, pathname2url
|
||||||
|
|
||||||
|
import pkg_resources
|
||||||
import setuptools.package_index
|
import setuptools.package_index
|
||||||
from setuptools.tests.server import IndexServer
|
from setuptools.tests.server import IndexServer
|
||||||
|
|
||||||
class TestPackageIndex(unittest.TestCase):
|
|
||||||
|
class TestPackageIndex:
|
||||||
|
|
||||||
def test_bad_url_bad_port(self):
|
def test_bad_url_bad_port(self):
|
||||||
index = setuptools.package_index.PackageIndex()
|
index = setuptools.package_index.PackageIndex()
|
||||||
url = 'http://127.0.0.1:0/nonesuch/test_package_index'
|
url = 'http://127.0.0.1:0/nonesuch/test_package_index'
|
||||||
try:
|
try:
|
||||||
v = index.open_url(url)
|
v = index.open_url(url)
|
||||||
except Exception:
|
except Exception as v:
|
||||||
v = sys.exc_info()[1]
|
assert url in str(v)
|
||||||
self.assertTrue(url in str(v))
|
|
||||||
else:
|
else:
|
||||||
self.assertTrue(isinstance(v, HTTPError))
|
assert isinstance(v, HTTPError)
|
||||||
|
|
||||||
def test_bad_url_typo(self):
|
def test_bad_url_typo(self):
|
||||||
# issue 16
|
# issue 16
|
||||||
@@ -33,11 +31,10 @@ class TestPackageIndex(unittest.TestCase):
|
|||||||
url = 'url:%20https://svn.plone.org/svn/collective/inquant.contentmirror.plone/trunk'
|
url = 'url:%20https://svn.plone.org/svn/collective/inquant.contentmirror.plone/trunk'
|
||||||
try:
|
try:
|
||||||
v = index.open_url(url)
|
v = index.open_url(url)
|
||||||
except Exception:
|
except Exception as v:
|
||||||
v = sys.exc_info()[1]
|
assert url in str(v)
|
||||||
self.assertTrue(url in str(v))
|
|
||||||
else:
|
else:
|
||||||
self.assertTrue(isinstance(v, HTTPError))
|
assert isinstance(v, HTTPError)
|
||||||
|
|
||||||
def test_bad_url_bad_status_line(self):
|
def test_bad_url_bad_status_line(self):
|
||||||
index = setuptools.package_index.PackageIndex(
|
index = setuptools.package_index.PackageIndex(
|
||||||
@@ -51,9 +48,8 @@ class TestPackageIndex(unittest.TestCase):
|
|||||||
url = 'http://example.com'
|
url = 'http://example.com'
|
||||||
try:
|
try:
|
||||||
v = index.open_url(url)
|
v = index.open_url(url)
|
||||||
except Exception:
|
except Exception as v:
|
||||||
v = sys.exc_info()[1]
|
assert 'line' in str(v)
|
||||||
self.assertTrue('line' in str(v))
|
|
||||||
else:
|
else:
|
||||||
raise AssertionError('Should have raise here!')
|
raise AssertionError('Should have raise here!')
|
||||||
|
|
||||||
@@ -69,8 +65,7 @@ class TestPackageIndex(unittest.TestCase):
|
|||||||
url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk'
|
url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk'
|
||||||
try:
|
try:
|
||||||
index.open_url(url)
|
index.open_url(url)
|
||||||
except distutils.errors.DistutilsError:
|
except distutils.errors.DistutilsError as error:
|
||||||
error = sys.exc_info()[1]
|
|
||||||
msg = unicode(error)
|
msg = unicode(error)
|
||||||
assert 'nonnumeric port' in msg or 'getaddrinfo failed' in msg or 'Name or service not known' in msg
|
assert 'nonnumeric port' in msg or 'getaddrinfo failed' in msg or 'Name or service not known' in msg
|
||||||
return
|
return
|
||||||
@@ -94,7 +89,7 @@ class TestPackageIndex(unittest.TestCase):
|
|||||||
hosts=('www.example.com',)
|
hosts=('www.example.com',)
|
||||||
)
|
)
|
||||||
url = 'file:///tmp/test_package_index'
|
url = 'file:///tmp/test_package_index'
|
||||||
self.assertTrue(index.url_ok(url, True))
|
assert index.url_ok(url, True)
|
||||||
|
|
||||||
def test_links_priority(self):
|
def test_links_priority(self):
|
||||||
"""
|
"""
|
||||||
@@ -127,21 +122,30 @@ class TestPackageIndex(unittest.TestCase):
|
|||||||
server.stop()
|
server.stop()
|
||||||
|
|
||||||
# the distribution has been found
|
# the distribution has been found
|
||||||
self.assertTrue('foobar' in pi)
|
assert 'foobar' in pi
|
||||||
# we have only one link, because links are compared without md5
|
# we have only one link, because links are compared without md5
|
||||||
self.assertTrue(len(pi['foobar'])==1)
|
assert len(pi['foobar'])==1
|
||||||
# the link should be from the index
|
# the link should be from the index
|
||||||
self.assertTrue('correct_md5' in pi['foobar'][0].location)
|
assert 'correct_md5' in pi['foobar'][0].location
|
||||||
|
|
||||||
def test_parse_bdist_wininst(self):
|
def test_parse_bdist_wininst(self):
|
||||||
self.assertEqual(setuptools.package_index.parse_bdist_wininst(
|
parse = setuptools.package_index.parse_bdist_wininst
|
||||||
'reportlab-2.5.win32-py2.4.exe'), ('reportlab-2.5', '2.4', 'win32'))
|
|
||||||
self.assertEqual(setuptools.package_index.parse_bdist_wininst(
|
actual = parse('reportlab-2.5.win32-py2.4.exe')
|
||||||
'reportlab-2.5.win32.exe'), ('reportlab-2.5', None, 'win32'))
|
expected = 'reportlab-2.5', '2.4', 'win32'
|
||||||
self.assertEqual(setuptools.package_index.parse_bdist_wininst(
|
assert actual == expected
|
||||||
'reportlab-2.5.win-amd64-py2.7.exe'), ('reportlab-2.5', '2.7', 'win-amd64'))
|
|
||||||
self.assertEqual(setuptools.package_index.parse_bdist_wininst(
|
actual = parse('reportlab-2.5.win32.exe')
|
||||||
'reportlab-2.5.win-amd64.exe'), ('reportlab-2.5', None, 'win-amd64'))
|
expected = 'reportlab-2.5', None, 'win32'
|
||||||
|
assert actual == expected
|
||||||
|
|
||||||
|
actual = parse('reportlab-2.5.win-amd64-py2.7.exe')
|
||||||
|
expected = 'reportlab-2.5', '2.7', 'win-amd64'
|
||||||
|
assert actual == expected
|
||||||
|
|
||||||
|
actual = parse('reportlab-2.5.win-amd64.exe')
|
||||||
|
expected = 'reportlab-2.5', None, 'win-amd64'
|
||||||
|
assert actual == expected
|
||||||
|
|
||||||
def test__vcs_split_rev_from_url(self):
|
def test__vcs_split_rev_from_url(self):
|
||||||
"""
|
"""
|
||||||
@@ -149,55 +153,51 @@ class TestPackageIndex(unittest.TestCase):
|
|||||||
"""
|
"""
|
||||||
vsrfu = setuptools.package_index.PackageIndex._vcs_split_rev_from_url
|
vsrfu = setuptools.package_index.PackageIndex._vcs_split_rev_from_url
|
||||||
url, rev = vsrfu('https://example.com/bar@2995')
|
url, rev = vsrfu('https://example.com/bar@2995')
|
||||||
self.assertEqual(url, 'https://example.com/bar')
|
assert url == 'https://example.com/bar'
|
||||||
self.assertEqual(rev, '2995')
|
assert rev == '2995'
|
||||||
|
|
||||||
def test_local_index(self):
|
def test_local_index(self, tmpdir):
|
||||||
"""
|
"""
|
||||||
local_open should be able to read an index from the file system.
|
local_open should be able to read an index from the file system.
|
||||||
"""
|
"""
|
||||||
f = open('index.html', 'w')
|
index_file = tmpdir / 'index.html'
|
||||||
f.write('<div>content</div>')
|
with index_file.open('w') as f:
|
||||||
f.close()
|
f.write('<div>content</div>')
|
||||||
try:
|
url = 'file:' + pathname2url(str(tmpdir)) + '/'
|
||||||
url = 'file:' + pathname2url(os.getcwd()) + '/'
|
res = setuptools.package_index.local_open(url)
|
||||||
res = setuptools.package_index.local_open(url)
|
|
||||||
finally:
|
|
||||||
os.remove('index.html')
|
|
||||||
assert 'content' in res.read()
|
assert 'content' in res.read()
|
||||||
|
|
||||||
|
|
||||||
class TestContentCheckers(unittest.TestCase):
|
class TestContentCheckers:
|
||||||
|
|
||||||
def test_md5(self):
|
def test_md5(self):
|
||||||
checker = setuptools.package_index.HashChecker.from_url(
|
checker = setuptools.package_index.HashChecker.from_url(
|
||||||
'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478')
|
'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478')
|
||||||
checker.feed('You should probably not be using MD5'.encode('ascii'))
|
checker.feed('You should probably not be using MD5'.encode('ascii'))
|
||||||
self.assertEqual(checker.hash.hexdigest(),
|
assert checker.hash.hexdigest() == 'f12895fdffbd45007040d2e44df98478'
|
||||||
'f12895fdffbd45007040d2e44df98478')
|
assert checker.is_valid()
|
||||||
self.assertTrue(checker.is_valid())
|
|
||||||
|
|
||||||
def test_other_fragment(self):
|
def test_other_fragment(self):
|
||||||
"Content checks should succeed silently if no hash is present"
|
"Content checks should succeed silently if no hash is present"
|
||||||
checker = setuptools.package_index.HashChecker.from_url(
|
checker = setuptools.package_index.HashChecker.from_url(
|
||||||
'http://foo/bar#something%20completely%20different')
|
'http://foo/bar#something%20completely%20different')
|
||||||
checker.feed('anything'.encode('ascii'))
|
checker.feed('anything'.encode('ascii'))
|
||||||
self.assertTrue(checker.is_valid())
|
assert checker.is_valid()
|
||||||
|
|
||||||
def test_blank_md5(self):
|
def test_blank_md5(self):
|
||||||
"Content checks should succeed if a hash is empty"
|
"Content checks should succeed if a hash is empty"
|
||||||
checker = setuptools.package_index.HashChecker.from_url(
|
checker = setuptools.package_index.HashChecker.from_url(
|
||||||
'http://foo/bar#md5=')
|
'http://foo/bar#md5=')
|
||||||
checker.feed('anything'.encode('ascii'))
|
checker.feed('anything'.encode('ascii'))
|
||||||
self.assertTrue(checker.is_valid())
|
assert checker.is_valid()
|
||||||
|
|
||||||
def test_get_hash_name_md5(self):
|
def test_get_hash_name_md5(self):
|
||||||
checker = setuptools.package_index.HashChecker.from_url(
|
checker = setuptools.package_index.HashChecker.from_url(
|
||||||
'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478')
|
'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478')
|
||||||
self.assertEqual(checker.hash_name, 'md5')
|
assert checker.hash_name == 'md5'
|
||||||
|
|
||||||
def test_report(self):
|
def test_report(self):
|
||||||
checker = setuptools.package_index.HashChecker.from_url(
|
checker = setuptools.package_index.HashChecker.from_url(
|
||||||
'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478')
|
'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478')
|
||||||
rep = checker.report(lambda x: x, 'My message about %s')
|
rep = checker.report(lambda x: x, 'My message about %s')
|
||||||
self.assertEqual(rep, 'My message about md5')
|
assert rep == 'My message about md5'
|
||||||
|
|||||||
@@ -1,69 +1,43 @@
|
|||||||
"""develop tests
|
"""develop tests
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import unittest
|
|
||||||
import tempfile
|
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
import setuptools.sandbox
|
import setuptools.sandbox
|
||||||
from setuptools.sandbox import DirectorySandbox, SandboxViolation
|
from setuptools.sandbox import DirectorySandbox
|
||||||
|
|
||||||
def has_win32com():
|
|
||||||
"""
|
|
||||||
Run this to determine if the local machine has win32com, and if it
|
|
||||||
does, include additional tests.
|
|
||||||
"""
|
|
||||||
if not sys.platform.startswith('win32'):
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
mod = __import__('win32com')
|
|
||||||
except ImportError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
class TestSandbox(unittest.TestCase):
|
class TestSandbox:
|
||||||
|
|
||||||
def setUp(self):
|
def test_devnull(self, tmpdir):
|
||||||
self.dir = tempfile.mkdtemp()
|
sandbox = DirectorySandbox(str(tmpdir))
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
shutil.rmtree(self.dir)
|
|
||||||
|
|
||||||
def test_devnull(self):
|
|
||||||
if sys.version < '2.4':
|
|
||||||
return
|
|
||||||
sandbox = DirectorySandbox(self.dir)
|
|
||||||
sandbox.run(self._file_writer(os.devnull))
|
sandbox.run(self._file_writer(os.devnull))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def _file_writer(path):
|
def _file_writer(path):
|
||||||
def do_write():
|
def do_write():
|
||||||
f = open(path, 'w')
|
with open(path, 'w') as f:
|
||||||
f.write('xxx')
|
f.write('xxx')
|
||||||
f.close()
|
|
||||||
return do_write
|
return do_write
|
||||||
|
|
||||||
_file_writer = staticmethod(_file_writer)
|
def test_win32com(self, tmpdir):
|
||||||
|
"""
|
||||||
if has_win32com():
|
win32com should not be prevented from caching COM interfaces
|
||||||
def test_win32com(self):
|
in gen_py.
|
||||||
"""
|
"""
|
||||||
win32com should not be prevented from caching COM interfaces
|
win32com = pytest.importorskip('win32com')
|
||||||
in gen_py.
|
gen_py = win32com.__gen_path__
|
||||||
"""
|
target = os.path.join(gen_py, 'test_write')
|
||||||
import win32com
|
sandbox = DirectorySandbox(str(tmpdir))
|
||||||
gen_py = win32com.__gen_path__
|
try:
|
||||||
target = os.path.join(gen_py, 'test_write')
|
# attempt to create gen_py file
|
||||||
sandbox = DirectorySandbox(self.dir)
|
sandbox.run(self._file_writer(target))
|
||||||
try:
|
finally:
|
||||||
try:
|
if os.path.exists(target):
|
||||||
sandbox.run(self._file_writer(target))
|
os.remove(target)
|
||||||
except SandboxViolation:
|
|
||||||
self.fail("Could not create gen_py file due to SandboxViolation")
|
|
||||||
finally:
|
|
||||||
if os.path.exists(target): os.remove(target)
|
|
||||||
|
|
||||||
def test_setup_py_with_BOM(self):
|
def test_setup_py_with_BOM(self):
|
||||||
"""
|
"""
|
||||||
@@ -72,8 +46,57 @@ class TestSandbox(unittest.TestCase):
|
|||||||
target = pkg_resources.resource_filename(__name__,
|
target = pkg_resources.resource_filename(__name__,
|
||||||
'script-with-bom.py')
|
'script-with-bom.py')
|
||||||
namespace = types.ModuleType('namespace')
|
namespace = types.ModuleType('namespace')
|
||||||
setuptools.sandbox.execfile(target, vars(namespace))
|
setuptools.sandbox._execfile(target, vars(namespace))
|
||||||
assert namespace.result == 'passed'
|
assert namespace.result == 'passed'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def test_setup_py_with_CRLF(self, tmpdir):
|
||||||
unittest.main()
|
setup_py = tmpdir / 'setup.py'
|
||||||
|
with setup_py.open('wb') as stream:
|
||||||
|
stream.write(b'"degenerate script"\r\n')
|
||||||
|
setuptools.sandbox._execfile(str(setup_py), globals())
|
||||||
|
|
||||||
|
|
||||||
|
class TestExceptionSaver:
|
||||||
|
def test_exception_trapped(self):
|
||||||
|
with setuptools.sandbox.ExceptionSaver():
|
||||||
|
raise ValueError("details")
|
||||||
|
|
||||||
|
def test_exception_resumed(self):
|
||||||
|
with setuptools.sandbox.ExceptionSaver() as saved_exc:
|
||||||
|
raise ValueError("details")
|
||||||
|
|
||||||
|
with pytest.raises(ValueError) as caught:
|
||||||
|
saved_exc.resume()
|
||||||
|
|
||||||
|
assert isinstance(caught.value, ValueError)
|
||||||
|
assert str(caught.value) == 'details'
|
||||||
|
|
||||||
|
def test_exception_reconstructed(self):
|
||||||
|
orig_exc = ValueError("details")
|
||||||
|
|
||||||
|
with setuptools.sandbox.ExceptionSaver() as saved_exc:
|
||||||
|
raise orig_exc
|
||||||
|
|
||||||
|
with pytest.raises(ValueError) as caught:
|
||||||
|
saved_exc.resume()
|
||||||
|
|
||||||
|
assert isinstance(caught.value, ValueError)
|
||||||
|
assert caught.value is not orig_exc
|
||||||
|
|
||||||
|
def test_no_exception_passes_quietly(self):
|
||||||
|
with setuptools.sandbox.ExceptionSaver() as saved_exc:
|
||||||
|
pass
|
||||||
|
|
||||||
|
saved_exc.resume()
|
||||||
|
|
||||||
|
def test_unpickleable_exception(self):
|
||||||
|
class CantPickleThis(Exception):
|
||||||
|
"This Exception is unpickleable because it's not in globals"
|
||||||
|
|
||||||
|
with setuptools.sandbox.ExceptionSaver() as saved_exc:
|
||||||
|
raise CantPickleThis('detail')
|
||||||
|
|
||||||
|
with pytest.raises(setuptools.sandbox.UnpickleableException) as caught:
|
||||||
|
saved_exc.resume()
|
||||||
|
|
||||||
|
assert str(caught.value) == "CantPickleThis('detail',)"
|
||||||
|
|||||||
@@ -6,18 +6,16 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import re
|
import contextlib
|
||||||
from setuptools.tests import environment, test_svn
|
|
||||||
from setuptools.tests.py26compat import skipIf
|
|
||||||
|
|
||||||
from setuptools.compat import StringIO, unicode
|
import pytest
|
||||||
from setuptools.tests.py26compat import skipIf
|
|
||||||
from setuptools.command.sdist import sdist, walk_revctrl
|
import pkg_resources
|
||||||
|
from setuptools.compat import StringIO, unicode, PY3, PY2
|
||||||
|
from setuptools.command.sdist import sdist
|
||||||
from setuptools.command.egg_info import manifest_maker
|
from setuptools.command.egg_info import manifest_maker
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
from setuptools import svn_utils
|
|
||||||
|
|
||||||
SETUP_ATTRS = {
|
SETUP_ATTRS = {
|
||||||
'name': 'sdist_test',
|
'name': 'sdist_test',
|
||||||
@@ -34,32 +32,33 @@ setup(**%r)
|
|||||||
""" % SETUP_ATTRS
|
""" % SETUP_ATTRS
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
LATIN1_FILENAME = 'smörbröd.py'.encode('latin-1')
|
LATIN1_FILENAME = 'smörbröd.py'.encode('latin-1')
|
||||||
else:
|
else:
|
||||||
LATIN1_FILENAME = 'sm\xf6rbr\xf6d.py'
|
LATIN1_FILENAME = 'sm\xf6rbr\xf6d.py'
|
||||||
|
|
||||||
|
|
||||||
# Cannot use context manager because of Python 2.4
|
# Cannot use context manager because of Python 2.4
|
||||||
|
@contextlib.contextmanager
|
||||||
def quiet():
|
def quiet():
|
||||||
global old_stdout, old_stderr
|
|
||||||
old_stdout, old_stderr = sys.stdout, sys.stderr
|
old_stdout, old_stderr = sys.stdout, sys.stderr
|
||||||
sys.stdout, sys.stderr = StringIO(), StringIO()
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
||||||
|
try:
|
||||||
def unquiet():
|
yield
|
||||||
sys.stdout, sys.stderr = old_stdout, old_stderr
|
finally:
|
||||||
|
sys.stdout, sys.stderr = old_stdout, old_stderr
|
||||||
|
|
||||||
|
|
||||||
# Fake byte literals for Python <= 2.5
|
# Fake byte literals for Python <= 2.5
|
||||||
def b(s, encoding='utf-8'):
|
def b(s, encoding='utf-8'):
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
return s.encode(encoding)
|
return s.encode(encoding)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
# Convert to POSIX path
|
# Convert to POSIX path
|
||||||
def posix(path):
|
def posix(path):
|
||||||
if sys.version_info >= (3,) and not isinstance(path, str):
|
if PY3 and not isinstance(path, str):
|
||||||
return path.replace(os.sep.encode('ascii'), b('/'))
|
return path.replace(os.sep.encode('ascii'), b('/'))
|
||||||
else:
|
else:
|
||||||
return path.replace(os.sep, '/')
|
return path.replace(os.sep, '/')
|
||||||
@@ -74,17 +73,18 @@ def decompose(path):
|
|||||||
path = unicodedata.normalize('NFD', path)
|
path = unicodedata.normalize('NFD', path)
|
||||||
path = path.encode('utf-8')
|
path = path.encode('utf-8')
|
||||||
except UnicodeError:
|
except UnicodeError:
|
||||||
pass # Not UTF-8
|
pass # Not UTF-8
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
class TestSdistTest(unittest.TestCase):
|
class TestSdistTest:
|
||||||
|
|
||||||
def setUp(self):
|
def setup_method(self, method):
|
||||||
self.temp_dir = tempfile.mkdtemp()
|
self.temp_dir = tempfile.mkdtemp()
|
||||||
f = open(os.path.join(self.temp_dir, 'setup.py'), 'w')
|
f = open(os.path.join(self.temp_dir, 'setup.py'), 'w')
|
||||||
f.write(SETUP_PY)
|
f.write(SETUP_PY)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
# Set up the rest of the test package
|
# Set up the rest of the test package
|
||||||
test_pkg = os.path.join(self.temp_dir, 'sdist_test')
|
test_pkg = os.path.join(self.temp_dir, 'sdist_test')
|
||||||
os.mkdir(test_pkg)
|
os.mkdir(test_pkg)
|
||||||
@@ -97,7 +97,7 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
self.old_cwd = os.getcwd()
|
self.old_cwd = os.getcwd()
|
||||||
os.chdir(self.temp_dir)
|
os.chdir(self.temp_dir)
|
||||||
|
|
||||||
def tearDown(self):
|
def teardown_method(self, method):
|
||||||
os.chdir(self.old_cwd)
|
os.chdir(self.old_cwd)
|
||||||
shutil.rmtree(self.temp_dir)
|
shutil.rmtree(self.temp_dir)
|
||||||
|
|
||||||
@@ -112,17 +112,40 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
cmd = sdist(dist)
|
cmd = sdist(dist)
|
||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
|
|
||||||
# squelch output
|
with quiet():
|
||||||
quiet()
|
|
||||||
try:
|
|
||||||
cmd.run()
|
cmd.run()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
manifest = cmd.filelist.files
|
manifest = cmd.filelist.files
|
||||||
self.assertTrue(os.path.join('sdist_test', 'a.txt') in manifest)
|
assert os.path.join('sdist_test', 'a.txt') in manifest
|
||||||
self.assertTrue(os.path.join('sdist_test', 'b.txt') in manifest)
|
assert os.path.join('sdist_test', 'b.txt') in manifest
|
||||||
self.assertTrue(os.path.join('sdist_test', 'c.rst') not in manifest)
|
assert os.path.join('sdist_test', 'c.rst') not in manifest
|
||||||
|
|
||||||
|
|
||||||
|
def test_defaults_case_sensitivity(self):
|
||||||
|
"""
|
||||||
|
Make sure default files (README.*, etc.) are added in a case-sensitive
|
||||||
|
way to avoid problems with packages built on Windows.
|
||||||
|
"""
|
||||||
|
|
||||||
|
open(os.path.join(self.temp_dir, 'readme.rst'), 'w').close()
|
||||||
|
open(os.path.join(self.temp_dir, 'SETUP.cfg'), 'w').close()
|
||||||
|
|
||||||
|
dist = Distribution(SETUP_ATTRS)
|
||||||
|
# the extension deliberately capitalized for this test
|
||||||
|
# to make sure the actual filename (not capitalized) gets added
|
||||||
|
# to the manifest
|
||||||
|
dist.script_name = 'setup.PY'
|
||||||
|
cmd = sdist(dist)
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
|
||||||
|
with quiet():
|
||||||
|
cmd.run()
|
||||||
|
|
||||||
|
# lowercase all names so we can test in a case-insensitive way to make sure the files are not included
|
||||||
|
manifest = map(lambda x: x.lower(), cmd.filelist.files)
|
||||||
|
assert 'readme.rst' not in manifest, manifest
|
||||||
|
assert 'setup.py' not in manifest, manifest
|
||||||
|
assert 'setup.cfg' not in manifest, manifest
|
||||||
|
|
||||||
def test_manifest_is_written_with_utf8_encoding(self):
|
def test_manifest_is_written_with_utf8_encoding(self):
|
||||||
# Test for #303.
|
# Test for #303.
|
||||||
@@ -135,34 +158,31 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
# UTF-8 filename
|
# UTF-8 filename
|
||||||
filename = os.path.join('sdist_test', 'smörbröd.py')
|
filename = os.path.join('sdist_test', 'smörbröd.py')
|
||||||
|
|
||||||
|
# Must create the file or it will get stripped.
|
||||||
|
open(filename, 'w').close()
|
||||||
|
|
||||||
# Add UTF-8 filename and write manifest
|
# Add UTF-8 filename and write manifest
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
mm.run()
|
mm.run()
|
||||||
mm.filelist.files.append(filename)
|
mm.filelist.append(filename)
|
||||||
mm.write_manifest()
|
mm.write_manifest()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
manifest = open(mm.manifest, 'rbU')
|
manifest = open(mm.manifest, 'rbU')
|
||||||
contents = manifest.read()
|
contents = manifest.read()
|
||||||
manifest.close()
|
manifest.close()
|
||||||
|
|
||||||
# The manifest should be UTF-8 encoded
|
# The manifest should be UTF-8 encoded
|
||||||
try:
|
u_contents = contents.decode('UTF-8')
|
||||||
u_contents = contents.decode('UTF-8')
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
e = sys.exc_info()[1]
|
|
||||||
self.fail(e)
|
|
||||||
|
|
||||||
# The manifest should contain the UTF-8 filename
|
# The manifest should contain the UTF-8 filename
|
||||||
if sys.version_info >= (3,):
|
if PY2:
|
||||||
self.assertTrue(posix(filename) in u_contents)
|
fs_enc = sys.getfilesystemencoding()
|
||||||
else:
|
filename = filename.decode(fs_enc)
|
||||||
self.assertTrue(posix(filename) in contents)
|
|
||||||
|
assert posix(filename) in u_contents
|
||||||
|
|
||||||
# Python 3 only
|
# Python 3 only
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
|
|
||||||
def test_write_manifest_allows_utf8_filenames(self):
|
def test_write_manifest_allows_utf8_filenames(self):
|
||||||
# Test for #303.
|
# Test for #303.
|
||||||
@@ -175,36 +195,37 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
# UTF-8 filename
|
# UTF-8 filename
|
||||||
filename = os.path.join(b('sdist_test'), b('smörbröd.py'))
|
filename = os.path.join(b('sdist_test'), b('smörbröd.py'))
|
||||||
|
|
||||||
|
# Must touch the file or risk removal
|
||||||
|
open(filename, "w").close()
|
||||||
|
|
||||||
# Add filename and write manifest
|
# Add filename and write manifest
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
mm.run()
|
mm.run()
|
||||||
u_filename = filename.decode('utf-8')
|
u_filename = filename.decode('utf-8')
|
||||||
mm.filelist.files.append(u_filename)
|
mm.filelist.files.append(u_filename)
|
||||||
# Re-write manifest
|
# Re-write manifest
|
||||||
mm.write_manifest()
|
mm.write_manifest()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
manifest = open(mm.manifest, 'rbU')
|
manifest = open(mm.manifest, 'rbU')
|
||||||
contents = manifest.read()
|
contents = manifest.read()
|
||||||
manifest.close()
|
manifest.close()
|
||||||
|
|
||||||
# The manifest should be UTF-8 encoded
|
# The manifest should be UTF-8 encoded
|
||||||
try:
|
contents.decode('UTF-8')
|
||||||
contents.decode('UTF-8')
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
e = sys.exc_info()[1]
|
|
||||||
self.fail(e)
|
|
||||||
|
|
||||||
# The manifest should contain the UTF-8 filename
|
# The manifest should contain the UTF-8 filename
|
||||||
self.assertTrue(posix(filename) in contents)
|
assert posix(filename) in contents
|
||||||
|
|
||||||
# The filelist should have been updated as well
|
# The filelist should have been updated as well
|
||||||
self.assertTrue(u_filename in mm.filelist.files)
|
assert u_filename in mm.filelist.files
|
||||||
|
|
||||||
def test_write_manifest_skips_non_utf8_filenames(self):
|
def test_write_manifest_skips_non_utf8_filenames(self):
|
||||||
# Test for #303.
|
"""
|
||||||
|
Files that cannot be encoded to UTF-8 (specifically, those that
|
||||||
|
weren't originally successfully decoded and have surrogate
|
||||||
|
escapes) should be omitted from the manifest.
|
||||||
|
See https://bitbucket.org/tarek/distribute/issue/303 for history.
|
||||||
|
"""
|
||||||
dist = Distribution(SETUP_ATTRS)
|
dist = Distribution(SETUP_ATTRS)
|
||||||
dist.script_name = 'setup.py'
|
dist.script_name = 'setup.py'
|
||||||
mm = manifest_maker(dist)
|
mm = manifest_maker(dist)
|
||||||
@@ -215,32 +236,25 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
|
filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
|
||||||
|
|
||||||
# Add filename with surrogates and write manifest
|
# Add filename with surrogates and write manifest
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
mm.run()
|
mm.run()
|
||||||
u_filename = filename.decode('utf-8', 'surrogateescape')
|
u_filename = filename.decode('utf-8', 'surrogateescape')
|
||||||
mm.filelist.files.append(u_filename)
|
mm.filelist.append(u_filename)
|
||||||
# Re-write manifest
|
# Re-write manifest
|
||||||
mm.write_manifest()
|
mm.write_manifest()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
manifest = open(mm.manifest, 'rbU')
|
manifest = open(mm.manifest, 'rbU')
|
||||||
contents = manifest.read()
|
contents = manifest.read()
|
||||||
manifest.close()
|
manifest.close()
|
||||||
|
|
||||||
# The manifest should be UTF-8 encoded
|
# The manifest should be UTF-8 encoded
|
||||||
try:
|
contents.decode('UTF-8')
|
||||||
contents.decode('UTF-8')
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
e = sys.exc_info()[1]
|
|
||||||
self.fail(e)
|
|
||||||
|
|
||||||
# The Latin-1 filename should have been skipped
|
# The Latin-1 filename should have been skipped
|
||||||
self.assertFalse(posix(filename) in contents)
|
assert posix(filename) not in contents
|
||||||
|
|
||||||
# The filelist should have been updated as well
|
# The filelist should have been updated as well
|
||||||
self.assertFalse(u_filename in mm.filelist.files)
|
assert u_filename not in mm.filelist.files
|
||||||
|
|
||||||
def test_manifest_is_read_with_utf8_encoding(self):
|
def test_manifest_is_read_with_utf8_encoding(self):
|
||||||
# Test for #303.
|
# Test for #303.
|
||||||
@@ -250,17 +264,14 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
|
|
||||||
# Create manifest
|
# Create manifest
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
cmd.run()
|
cmd.run()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
# Add UTF-8 filename to manifest
|
# Add UTF-8 filename to manifest
|
||||||
filename = os.path.join(b('sdist_test'), b('smörbröd.py'))
|
filename = os.path.join(b('sdist_test'), b('smörbröd.py'))
|
||||||
cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt')
|
cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt')
|
||||||
manifest = open(cmd.manifest, 'ab')
|
manifest = open(cmd.manifest, 'ab')
|
||||||
manifest.write(b('\n')+filename)
|
manifest.write(b('\n') + filename)
|
||||||
manifest.close()
|
manifest.close()
|
||||||
|
|
||||||
# The file must exist to be included in the filelist
|
# The file must exist to be included in the filelist
|
||||||
@@ -268,19 +279,16 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
|
|
||||||
# Re-read manifest
|
# Re-read manifest
|
||||||
cmd.filelist.files = []
|
cmd.filelist.files = []
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
cmd.read_manifest()
|
cmd.read_manifest()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
# The filelist should contain the UTF-8 filename
|
# The filelist should contain the UTF-8 filename
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
filename = filename.decode('utf-8')
|
filename = filename.decode('utf-8')
|
||||||
self.assertTrue(filename in cmd.filelist.files)
|
assert filename in cmd.filelist.files
|
||||||
|
|
||||||
# Python 3 only
|
# Python 3 only
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
|
|
||||||
def test_read_manifest_skips_non_utf8_filenames(self):
|
def test_read_manifest_skips_non_utf8_filenames(self):
|
||||||
# Test for #303.
|
# Test for #303.
|
||||||
@@ -290,17 +298,14 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
|
|
||||||
# Create manifest
|
# Create manifest
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
cmd.run()
|
cmd.run()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
# Add Latin-1 filename to manifest
|
# Add Latin-1 filename to manifest
|
||||||
filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
|
filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
|
||||||
cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt')
|
cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt')
|
||||||
manifest = open(cmd.manifest, 'ab')
|
manifest = open(cmd.manifest, 'ab')
|
||||||
manifest.write(b('\n')+filename)
|
manifest.write(b('\n') + filename)
|
||||||
manifest.close()
|
manifest.close()
|
||||||
|
|
||||||
# The file must exist to be included in the filelist
|
# The file must exist to be included in the filelist
|
||||||
@@ -308,22 +313,16 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
|
|
||||||
# Re-read manifest
|
# Re-read manifest
|
||||||
cmd.filelist.files = []
|
cmd.filelist.files = []
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
cmd.read_manifest()
|
||||||
try:
|
|
||||||
cmd.read_manifest()
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
e = sys.exc_info()[1]
|
|
||||||
self.fail(e)
|
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
# The Latin-1 filename should have been skipped
|
# The Latin-1 filename should have been skipped
|
||||||
filename = filename.decode('latin-1')
|
filename = filename.decode('latin-1')
|
||||||
self.assertFalse(filename in cmd.filelist.files)
|
assert filename not in cmd.filelist.files
|
||||||
|
|
||||||
@skipIf(sys.version_info >= (3,) and locale.getpreferredencoding() != 'UTF-8',
|
@pytest.mark.skipif(PY3 and locale.getpreferredencoding() != 'UTF-8',
|
||||||
'Unittest fails if locale is not utf-8 but the manifests is recorded correctly')
|
reason='Unittest fails if locale is not utf-8 but the manifests is '
|
||||||
|
'recorded correctly')
|
||||||
def test_sdist_with_utf8_encoded_filename(self):
|
def test_sdist_with_utf8_encoded_filename(self):
|
||||||
# Test for #303.
|
# Test for #303.
|
||||||
dist = Distribution(SETUP_ATTRS)
|
dist = Distribution(SETUP_ATTRS)
|
||||||
@@ -335,31 +334,28 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
filename = os.path.join(b('sdist_test'), b('smörbröd.py'))
|
filename = os.path.join(b('sdist_test'), b('smörbröd.py'))
|
||||||
open(filename, 'w').close()
|
open(filename, 'w').close()
|
||||||
|
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
cmd.run()
|
cmd.run()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
filename = decompose(filename)
|
filename = decompose(filename)
|
||||||
|
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
fs_enc = sys.getfilesystemencoding()
|
fs_enc = sys.getfilesystemencoding()
|
||||||
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
if fs_enc == 'cp1252':
|
if fs_enc == 'cp1252':
|
||||||
# Python 3 mangles the UTF-8 filename
|
# Python 3 mangles the UTF-8 filename
|
||||||
filename = filename.decode('cp1252')
|
filename = filename.decode('cp1252')
|
||||||
self.assertTrue(filename in cmd.filelist.files)
|
assert filename in cmd.filelist.files
|
||||||
else:
|
else:
|
||||||
filename = filename.decode('mbcs')
|
filename = filename.decode('mbcs')
|
||||||
self.assertTrue(filename in cmd.filelist.files)
|
assert filename in cmd.filelist.files
|
||||||
else:
|
else:
|
||||||
filename = filename.decode('utf-8')
|
filename = filename.decode('utf-8')
|
||||||
self.assertTrue(filename in cmd.filelist.files)
|
assert filename in cmd.filelist.files
|
||||||
else:
|
else:
|
||||||
self.assertTrue(filename in cmd.filelist.files)
|
assert filename in cmd.filelist.files
|
||||||
|
|
||||||
def test_sdist_with_latin1_encoded_filename(self):
|
def test_sdist_with_latin1_encoded_filename(self):
|
||||||
# Test for #303.
|
# Test for #303.
|
||||||
@@ -371,16 +367,13 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
# Latin-1 filename
|
# Latin-1 filename
|
||||||
filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
|
filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
|
||||||
open(filename, 'w').close()
|
open(filename, 'w').close()
|
||||||
self.assertTrue(os.path.isfile(filename))
|
assert os.path.isfile(filename)
|
||||||
|
|
||||||
quiet()
|
with quiet():
|
||||||
try:
|
|
||||||
cmd.run()
|
cmd.run()
|
||||||
finally:
|
|
||||||
unquiet()
|
|
||||||
|
|
||||||
if sys.version_info >= (3,):
|
if PY3:
|
||||||
#not all windows systems have a default FS encoding of cp1252
|
# not all windows systems have a default FS encoding of cp1252
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
# Latin-1 is similar to Windows-1252 however
|
# Latin-1 is similar to Windows-1252 however
|
||||||
# on mbcs filesys it is not in latin-1 encoding
|
# on mbcs filesys it is not in latin-1 encoding
|
||||||
@@ -390,146 +383,37 @@ class TestSdistTest(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
filename = filename.decode('latin-1')
|
filename = filename.decode('latin-1')
|
||||||
|
|
||||||
self.assertTrue(filename in cmd.filelist.files)
|
assert filename in cmd.filelist.files
|
||||||
else:
|
else:
|
||||||
# The Latin-1 filename should have been skipped
|
# The Latin-1 filename should have been skipped
|
||||||
filename = filename.decode('latin-1')
|
filename = filename.decode('latin-1')
|
||||||
self.assertFalse(filename in cmd.filelist.files)
|
filename not in cmd.filelist.files
|
||||||
else:
|
else:
|
||||||
# No conversion takes place under Python 2 and the file
|
# Under Python 2 there seems to be no decoded string in the
|
||||||
# is included. We shall keep it that way for BBB.
|
# filelist. However, due to decode and encoding of the
|
||||||
self.assertTrue(filename in cmd.filelist.files)
|
# file name to get utf-8 Manifest the latin1 maybe excluded
|
||||||
|
try:
|
||||||
|
# fs_enc should match how one is expect the decoding to
|
||||||
|
# be proformed for the manifest output.
|
||||||
|
fs_enc = sys.getfilesystemencoding()
|
||||||
|
filename.decode(fs_enc)
|
||||||
|
assert filename in cmd.filelist.files
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
filename not in cmd.filelist.files
|
||||||
|
|
||||||
|
|
||||||
class TestDummyOutput(environment.ZippedEnvironment):
|
def test_default_revctrl():
|
||||||
|
"""
|
||||||
|
When _default_revctrl was removed from the `setuptools.command.sdist`
|
||||||
|
module in 10.0, it broke some systems which keep an old install of
|
||||||
|
setuptools (Distribute) around. Those old versions require that the
|
||||||
|
setuptools package continue to implement that interface, so this
|
||||||
|
function provides that interface, stubbed. See #320 for details.
|
||||||
|
|
||||||
def setUp(self):
|
This interface must be maintained until Ubuntu 12.04 is no longer
|
||||||
self.datafile = os.path.join('setuptools', 'tests',
|
supported (by Setuptools).
|
||||||
'svn_data', "dummy.zip")
|
"""
|
||||||
self.dataname = "dummy"
|
ep_def = 'svn_cvs = setuptools.command.sdist:_default_revctrl'
|
||||||
super(TestDummyOutput, self).setUp()
|
ep = pkg_resources.EntryPoint.parse(ep_def)
|
||||||
|
res = ep.resolve()
|
||||||
def _run(self):
|
assert hasattr(res, '__iter__')
|
||||||
code, data = environment.run_setup_py(["sdist"],
|
|
||||||
pypath=self.old_cwd,
|
|
||||||
data_stream=0)
|
|
||||||
if code:
|
|
||||||
info = "DIR: " + os.path.abspath('.')
|
|
||||||
info += "\n SDIST RETURNED: %i\n\n" % code
|
|
||||||
info += data
|
|
||||||
raise AssertionError(info)
|
|
||||||
|
|
||||||
datalines = data.splitlines()
|
|
||||||
|
|
||||||
possible = (
|
|
||||||
"running sdist",
|
|
||||||
"running egg_info",
|
|
||||||
"creating dummy\.egg-info",
|
|
||||||
"writing dummy\.egg-info",
|
|
||||||
"writing top-level names to dummy\.egg-info",
|
|
||||||
"writing dependency_links to dummy\.egg-info",
|
|
||||||
"writing manifest file 'dummy\.egg-info",
|
|
||||||
"reading manifest file 'dummy\.egg-info",
|
|
||||||
"reading manifest template 'MANIFEST\.in'",
|
|
||||||
"writing manifest file 'dummy\.egg-info",
|
|
||||||
"creating dummy-0.1.1",
|
|
||||||
"making hard links in dummy-0\.1\.1",
|
|
||||||
"copying files to dummy-0\.1\.1",
|
|
||||||
"copying \S+ -> dummy-0\.1\.1",
|
|
||||||
"copying dummy",
|
|
||||||
"copying dummy\.egg-info",
|
|
||||||
"hard linking \S+ -> dummy-0\.1\.1",
|
|
||||||
"hard linking dummy",
|
|
||||||
"hard linking dummy\.egg-info",
|
|
||||||
"Writing dummy-0\.1\.1",
|
|
||||||
"creating dist",
|
|
||||||
"creating 'dist",
|
|
||||||
"Creating tar archive",
|
|
||||||
"running check",
|
|
||||||
"adding 'dummy-0\.1\.1",
|
|
||||||
"tar .+ dist/dummy-0\.1\.1\.tar dummy-0\.1\.1",
|
|
||||||
"gzip .+ dist/dummy-0\.1\.1\.tar",
|
|
||||||
"removing 'dummy-0\.1\.1' \\(and everything under it\\)",
|
|
||||||
)
|
|
||||||
|
|
||||||
print(" DIR: " + os.path.abspath('.'))
|
|
||||||
for line in datalines:
|
|
||||||
found = False
|
|
||||||
for pattern in possible:
|
|
||||||
if re.match(pattern, line):
|
|
||||||
print(" READ: " + line)
|
|
||||||
found = True
|
|
||||||
break
|
|
||||||
if not found:
|
|
||||||
raise AssertionError("Unexpexected: %s\n-in-\n%s"
|
|
||||||
% (line, data))
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def test_sources(self):
|
|
||||||
self._run()
|
|
||||||
|
|
||||||
|
|
||||||
class TestSvn(environment.ZippedEnvironment):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
version = svn_utils.SvnInfo.get_svn_version()
|
|
||||||
if not version: # None or Empty
|
|
||||||
return
|
|
||||||
|
|
||||||
self.base_version = tuple([int(x) for x in version.split('.')][:2])
|
|
||||||
|
|
||||||
if not self.base_version:
|
|
||||||
raise ValueError('No SVN tools installed')
|
|
||||||
elif self.base_version < (1, 3):
|
|
||||||
raise ValueError('Insufficient SVN Version %s' % version)
|
|
||||||
elif self.base_version >= (1, 9):
|
|
||||||
#trying the latest version
|
|
||||||
self.base_version = (1, 8)
|
|
||||||
|
|
||||||
self.dataname = "svn%i%i_example" % self.base_version
|
|
||||||
self.datafile = os.path.join('setuptools', 'tests',
|
|
||||||
'svn_data', self.dataname + ".zip")
|
|
||||||
super(TestSvn, self).setUp()
|
|
||||||
|
|
||||||
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
|
|
||||||
def test_walksvn(self):
|
|
||||||
if self.base_version >= (1, 6):
|
|
||||||
folder2 = 'third party2'
|
|
||||||
folder3 = 'third party3'
|
|
||||||
else:
|
|
||||||
folder2 = 'third_party2'
|
|
||||||
folder3 = 'third_party3'
|
|
||||||
|
|
||||||
#TODO is this right
|
|
||||||
expected = set([
|
|
||||||
os.path.join('a file'),
|
|
||||||
os.path.join(folder2, 'Changes.txt'),
|
|
||||||
os.path.join(folder2, 'MD5SUMS'),
|
|
||||||
os.path.join(folder2, 'README.txt'),
|
|
||||||
os.path.join(folder3, 'Changes.txt'),
|
|
||||||
os.path.join(folder3, 'MD5SUMS'),
|
|
||||||
os.path.join(folder3, 'README.txt'),
|
|
||||||
os.path.join(folder3, 'TODO.txt'),
|
|
||||||
os.path.join(folder3, 'fin'),
|
|
||||||
os.path.join('third_party', 'README.txt'),
|
|
||||||
os.path.join('folder', folder2, 'Changes.txt'),
|
|
||||||
os.path.join('folder', folder2, 'MD5SUMS'),
|
|
||||||
os.path.join('folder', folder2, 'WatashiNiYomimasu.txt'),
|
|
||||||
os.path.join('folder', folder3, 'Changes.txt'),
|
|
||||||
os.path.join('folder', folder3, 'fin'),
|
|
||||||
os.path.join('folder', folder3, 'MD5SUMS'),
|
|
||||||
os.path.join('folder', folder3, 'oops'),
|
|
||||||
os.path.join('folder', folder3, 'WatashiNiYomimasu.txt'),
|
|
||||||
os.path.join('folder', folder3, 'ZuMachen.txt'),
|
|
||||||
os.path.join('folder', 'third_party', 'WatashiNiYomimasu.txt'),
|
|
||||||
os.path.join('folder', 'lalala.txt'),
|
|
||||||
os.path.join('folder', 'quest.txt'),
|
|
||||||
# The example will have a deleted file
|
|
||||||
# (or should) but shouldn't return it
|
|
||||||
])
|
|
||||||
self.assertEqual(set(x for x in walk_revctrl()), expected)
|
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
|||||||
@@ -1,124 +1,91 @@
|
|||||||
# -*- coding: UTF-8 -*-
|
# -*- coding: UTF-8 -*-
|
||||||
|
|
||||||
"""develop tests
|
from __future__ import unicode_literals
|
||||||
"""
|
|
||||||
import sys
|
import os
|
||||||
import os, shutil, tempfile, unittest
|
|
||||||
import tempfile
|
|
||||||
import site
|
import site
|
||||||
|
|
||||||
from distutils.errors import DistutilsError
|
import pytest
|
||||||
from setuptools.compat import StringIO
|
|
||||||
from setuptools.command.test import test
|
from setuptools.command.test import test
|
||||||
from setuptools.command import easy_install as easy_install_pkg
|
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
|
|
||||||
SETUP_PY = """\
|
from .textwrap import DALS
|
||||||
from setuptools import setup
|
from . import contexts
|
||||||
|
|
||||||
setup(name='foo',
|
SETUP_PY = DALS("""
|
||||||
packages=['name', 'name.space', 'name.space.tests'],
|
from setuptools import setup
|
||||||
namespace_packages=['name'],
|
|
||||||
test_suite='name.space.tests.test_suite',
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
NS_INIT = """# -*- coding: Latin-1 -*-
|
setup(name='foo',
|
||||||
# Söme Arbiträry Ünicode to test Issüé 310
|
packages=['name', 'name.space', 'name.space.tests'],
|
||||||
try:
|
namespace_packages=['name'],
|
||||||
__import__('pkg_resources').declare_namespace(__name__)
|
test_suite='name.space.tests.test_suite',
|
||||||
except ImportError:
|
)
|
||||||
from pkgutil import extend_path
|
""")
|
||||||
__path__ = extend_path(__path__, __name__)
|
|
||||||
"""
|
|
||||||
# Make sure this is Latin-1 binary, before writing:
|
|
||||||
if sys.version_info < (3,):
|
|
||||||
NS_INIT = NS_INIT.decode('UTF-8')
|
|
||||||
NS_INIT = NS_INIT.encode('Latin-1')
|
|
||||||
|
|
||||||
TEST_PY = """import unittest
|
NS_INIT = DALS("""
|
||||||
|
# -*- coding: Latin-1 -*-
|
||||||
|
# Söme Arbiträry Ünicode to test Distribute Issüé 310
|
||||||
|
try:
|
||||||
|
__import__('pkg_resources').declare_namespace(__name__)
|
||||||
|
except ImportError:
|
||||||
|
from pkgutil import extend_path
|
||||||
|
__path__ = extend_path(__path__, __name__)
|
||||||
|
""")
|
||||||
|
|
||||||
class TestTest(unittest.TestCase):
|
TEST_PY = DALS("""
|
||||||
def test_test(self):
|
import unittest
|
||||||
print "Foo" # Should fail under Python 3 unless 2to3 is used
|
|
||||||
|
|
||||||
test_suite = unittest.makeSuite(TestTest)
|
class TestTest(unittest.TestCase):
|
||||||
"""
|
def test_test(self):
|
||||||
|
print "Foo" # Should fail under Python 3 unless 2to3 is used
|
||||||
|
|
||||||
class TestTestTest(unittest.TestCase):
|
test_suite = unittest.makeSuite(TestTest)
|
||||||
|
""")
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Directory structure
|
@pytest.fixture
|
||||||
self.dir = tempfile.mkdtemp()
|
def sample_test(tmpdir_cwd):
|
||||||
os.mkdir(os.path.join(self.dir, 'name'))
|
os.makedirs('name/space/tests')
|
||||||
os.mkdir(os.path.join(self.dir, 'name', 'space'))
|
|
||||||
os.mkdir(os.path.join(self.dir, 'name', 'space', 'tests'))
|
# setup.py
|
||||||
# setup.py
|
with open('setup.py', 'wt') as f:
|
||||||
setup = os.path.join(self.dir, 'setup.py')
|
|
||||||
f = open(setup, 'wt')
|
|
||||||
f.write(SETUP_PY)
|
f.write(SETUP_PY)
|
||||||
f.close()
|
|
||||||
self.old_cwd = os.getcwd()
|
# name/__init__.py
|
||||||
# name/__init__.py
|
with open('name/__init__.py', 'wb') as f:
|
||||||
init = os.path.join(self.dir, 'name', '__init__.py')
|
f.write(NS_INIT.encode('Latin-1'))
|
||||||
f = open(init, 'wb')
|
|
||||||
f.write(NS_INIT)
|
# name/space/__init__.py
|
||||||
f.close()
|
with open('name/space/__init__.py', 'wt') as f:
|
||||||
# name/space/__init__.py
|
|
||||||
init = os.path.join(self.dir, 'name', 'space', '__init__.py')
|
|
||||||
f = open(init, 'wt')
|
|
||||||
f.write('#empty\n')
|
f.write('#empty\n')
|
||||||
f.close()
|
|
||||||
# name/space/tests/__init__.py
|
# name/space/tests/__init__.py
|
||||||
init = os.path.join(self.dir, 'name', 'space', 'tests', '__init__.py')
|
with open('name/space/tests/__init__.py', 'wt') as f:
|
||||||
f = open(init, 'wt')
|
|
||||||
f.write(TEST_PY)
|
f.write(TEST_PY)
|
||||||
f.close()
|
|
||||||
|
|
||||||
os.chdir(self.dir)
|
|
||||||
self.old_base = site.USER_BASE
|
|
||||||
site.USER_BASE = tempfile.mkdtemp()
|
|
||||||
self.old_site = site.USER_SITE
|
|
||||||
site.USER_SITE = tempfile.mkdtemp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
@pytest.mark.skipif('hasattr(sys, "real_prefix")')
|
||||||
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
|
@pytest.mark.usefixtures('user_override')
|
||||||
return
|
@pytest.mark.usefixtures('sample_test')
|
||||||
|
class TestTestTest:
|
||||||
os.chdir(self.old_cwd)
|
|
||||||
shutil.rmtree(self.dir)
|
|
||||||
shutil.rmtree(site.USER_BASE)
|
|
||||||
shutil.rmtree(site.USER_SITE)
|
|
||||||
site.USER_BASE = self.old_base
|
|
||||||
site.USER_SITE = self.old_site
|
|
||||||
|
|
||||||
def test_test(self):
|
def test_test(self):
|
||||||
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
|
params = dict(
|
||||||
return
|
|
||||||
|
|
||||||
dist = Distribution(dict(
|
|
||||||
name='foo',
|
name='foo',
|
||||||
packages=['name', 'name.space', 'name.space.tests'],
|
packages=['name', 'name.space', 'name.space.tests'],
|
||||||
namespace_packages=['name'],
|
namespace_packages=['name'],
|
||||||
test_suite='name.space.tests.test_suite',
|
test_suite='name.space.tests.test_suite',
|
||||||
use_2to3=True,
|
use_2to3=True,
|
||||||
))
|
)
|
||||||
|
dist = Distribution(params)
|
||||||
dist.script_name = 'setup.py'
|
dist.script_name = 'setup.py'
|
||||||
cmd = test(dist)
|
cmd = test(dist)
|
||||||
cmd.user = 1
|
cmd.user = 1
|
||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
cmd.install_dir = site.USER_SITE
|
cmd.install_dir = site.USER_SITE
|
||||||
cmd.user = 1
|
cmd.user = 1
|
||||||
old_stdout = sys.stdout
|
with contexts.quiet():
|
||||||
sys.stdout = StringIO()
|
# The test runner calls sys.exit
|
||||||
try:
|
with contexts.suppress_exceptions(SystemExit):
|
||||||
try: # try/except/finally doesn't work in Python 2.4, so we need nested try-statements.
|
|
||||||
cmd.run()
|
cmd.run()
|
||||||
except SystemExit: # The test runner calls sys.exit, stop that making an error.
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
sys.stdout = old_stdout
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +1,59 @@
|
|||||||
"""build_ext tests
|
import os
|
||||||
"""
|
import zipfile
|
||||||
import sys, os, shutil, tempfile, unittest, site, zipfile
|
import contextlib
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from setuptools.command.upload_docs import upload_docs
|
from setuptools.command.upload_docs import upload_docs
|
||||||
from setuptools.dist import Distribution
|
from setuptools.dist import Distribution
|
||||||
|
|
||||||
SETUP_PY = """\
|
from .textwrap import DALS
|
||||||
from setuptools import setup
|
from . import contexts
|
||||||
|
|
||||||
setup(name='foo')
|
|
||||||
"""
|
|
||||||
|
|
||||||
class TestUploadDocsTest(unittest.TestCase):
|
SETUP_PY = DALS(
|
||||||
def setUp(self):
|
"""
|
||||||
self.dir = tempfile.mkdtemp()
|
from setuptools import setup
|
||||||
setup = os.path.join(self.dir, 'setup.py')
|
|
||||||
f = open(setup, 'w')
|
setup(name='foo')
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def sample_project(tmpdir_cwd):
|
||||||
|
# setup.py
|
||||||
|
with open('setup.py', 'wt') as f:
|
||||||
f.write(SETUP_PY)
|
f.write(SETUP_PY)
|
||||||
f.close()
|
|
||||||
self.old_cwd = os.getcwd()
|
|
||||||
os.chdir(self.dir)
|
|
||||||
|
|
||||||
self.upload_dir = os.path.join(self.dir, 'build')
|
os.mkdir('build')
|
||||||
os.mkdir(self.upload_dir)
|
|
||||||
|
|
||||||
# A test document.
|
# A test document.
|
||||||
f = open(os.path.join(self.upload_dir, 'index.html'), 'w')
|
with open('build/index.html', 'w') as f:
|
||||||
f.write("Hello world.")
|
f.write("Hello world.")
|
||||||
f.close()
|
|
||||||
|
|
||||||
# An empty folder.
|
# An empty folder.
|
||||||
os.mkdir(os.path.join(self.upload_dir, 'empty'))
|
os.mkdir('build/empty')
|
||||||
|
|
||||||
if sys.version >= "2.6":
|
|
||||||
self.old_base = site.USER_BASE
|
|
||||||
site.USER_BASE = upload_docs.USER_BASE = tempfile.mkdtemp()
|
|
||||||
self.old_site = site.USER_SITE
|
|
||||||
site.USER_SITE = upload_docs.USER_SITE = tempfile.mkdtemp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
@pytest.mark.usefixtures('sample_project')
|
||||||
os.chdir(self.old_cwd)
|
@pytest.mark.usefixtures('user_override')
|
||||||
shutil.rmtree(self.dir)
|
class TestUploadDocsTest:
|
||||||
if sys.version >= "2.6":
|
|
||||||
shutil.rmtree(site.USER_BASE)
|
|
||||||
shutil.rmtree(site.USER_SITE)
|
|
||||||
site.USER_BASE = self.old_base
|
|
||||||
site.USER_SITE = self.old_site
|
|
||||||
|
|
||||||
def test_create_zipfile(self):
|
def test_create_zipfile(self):
|
||||||
# Test to make sure zipfile creation handles common cases.
|
"""
|
||||||
# This explicitly includes a folder containing an empty folder.
|
Ensure zipfile creation handles common cases, including a folder
|
||||||
|
containing an empty folder.
|
||||||
|
"""
|
||||||
|
|
||||||
dist = Distribution()
|
dist = Distribution()
|
||||||
|
|
||||||
cmd = upload_docs(dist)
|
cmd = upload_docs(dist)
|
||||||
cmd.upload_dir = self.upload_dir
|
cmd.target_dir = cmd.upload_dir = 'build'
|
||||||
cmd.target_dir = self.upload_dir
|
with contexts.tempdir() as tmp_dir:
|
||||||
tmp_dir = tempfile.mkdtemp()
|
tmp_file = os.path.join(tmp_dir, 'foo.zip')
|
||||||
tmp_file = os.path.join(tmp_dir, 'foo.zip')
|
|
||||||
try:
|
|
||||||
zip_file = cmd.create_zipfile(tmp_file)
|
zip_file = cmd.create_zipfile(tmp_file)
|
||||||
|
|
||||||
assert zipfile.is_zipfile(tmp_file)
|
assert zipfile.is_zipfile(tmp_file)
|
||||||
|
|
||||||
zip_file = zipfile.ZipFile(tmp_file) # woh...
|
with contextlib.closing(zipfile.ZipFile(tmp_file)) as zip_file:
|
||||||
|
assert zip_file.namelist() == ['index.html']
|
||||||
assert zip_file.namelist() == ['index.html']
|
|
||||||
|
|
||||||
zip_file.close()
|
|
||||||
finally:
|
|
||||||
shutil.rmtree(tmp_dir)
|
|
||||||
|
|
||||||
|
|||||||
183
awx/lib/site-packages/setuptools/tests/test_windows_wrappers.py
Normal file
183
awx/lib/site-packages/setuptools/tests/test_windows_wrappers.py
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
"""
|
||||||
|
Python Script Wrapper for Windows
|
||||||
|
=================================
|
||||||
|
|
||||||
|
setuptools includes wrappers for Python scripts that allows them to be
|
||||||
|
executed like regular windows programs. There are 2 wrappers, one
|
||||||
|
for command-line programs, cli.exe, and one for graphical programs,
|
||||||
|
gui.exe. These programs are almost identical, function pretty much
|
||||||
|
the same way, and are generated from the same source file. The
|
||||||
|
wrapper programs are used by copying them to the directory containing
|
||||||
|
the script they are to wrap and with the same name as the script they
|
||||||
|
are to wrap.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from setuptools.command.easy_install import nt_quote_arg
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.skipif(sys.platform != 'win32', reason="Windows only")
|
||||||
|
|
||||||
|
|
||||||
|
class WrapperTester:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prep_script(cls, template):
|
||||||
|
python_exe = nt_quote_arg(sys.executable)
|
||||||
|
return template % locals()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_script(cls, tmpdir):
|
||||||
|
"""
|
||||||
|
Create a simple script, foo-script.py
|
||||||
|
|
||||||
|
Note that the script starts with a Unix-style '#!' line saying which
|
||||||
|
Python executable to run. The wrapper will use this line to find the
|
||||||
|
correct Python executable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
script = cls.prep_script(cls.script_tmpl)
|
||||||
|
|
||||||
|
with (tmpdir / cls.script_name).open('w') as f:
|
||||||
|
f.write(script)
|
||||||
|
|
||||||
|
# also copy cli.exe to the sample directory
|
||||||
|
with (tmpdir / cls.wrapper_name).open('wb') as f:
|
||||||
|
w = pkg_resources.resource_string('setuptools', cls.wrapper_source)
|
||||||
|
f.write(w)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCLI(WrapperTester):
|
||||||
|
script_name = 'foo-script.py'
|
||||||
|
wrapper_source = 'cli-32.exe'
|
||||||
|
wrapper_name = 'foo.exe'
|
||||||
|
script_tmpl = textwrap.dedent("""
|
||||||
|
#!%(python_exe)s
|
||||||
|
import sys
|
||||||
|
input = repr(sys.stdin.read())
|
||||||
|
print(sys.argv[0][-14:])
|
||||||
|
print(sys.argv[1:])
|
||||||
|
print(input)
|
||||||
|
if __debug__:
|
||||||
|
print('non-optimized')
|
||||||
|
""").lstrip()
|
||||||
|
|
||||||
|
def test_basic(self, tmpdir):
|
||||||
|
"""
|
||||||
|
When the copy of cli.exe, foo.exe in this example, runs, it examines
|
||||||
|
the path name it was run with and computes a Python script path name
|
||||||
|
by removing the '.exe' suffix and adding the '-script.py' suffix. (For
|
||||||
|
GUI programs, the suffix '-script.pyw' is added.) This is why we
|
||||||
|
named out script the way we did. Now we can run out script by running
|
||||||
|
the wrapper:
|
||||||
|
|
||||||
|
This example was a little pathological in that it exercised windows
|
||||||
|
(MS C runtime) quoting rules:
|
||||||
|
|
||||||
|
- Strings containing spaces are surrounded by double quotes.
|
||||||
|
|
||||||
|
- Double quotes in strings need to be escaped by preceding them with
|
||||||
|
back slashes.
|
||||||
|
|
||||||
|
- One or more backslashes preceding double quotes need to be escaped
|
||||||
|
by preceding each of them with back slashes.
|
||||||
|
"""
|
||||||
|
self.create_script(tmpdir)
|
||||||
|
cmd = [
|
||||||
|
str(tmpdir / 'foo.exe'),
|
||||||
|
'arg1',
|
||||||
|
'arg 2',
|
||||||
|
'arg "2\\"',
|
||||||
|
'arg 4\\',
|
||||||
|
'arg5 a\\\\b',
|
||||||
|
]
|
||||||
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
|
stdout, stderr = proc.communicate('hello\nworld\n'.encode('ascii'))
|
||||||
|
actual = stdout.decode('ascii').replace('\r\n', '\n')
|
||||||
|
expected = textwrap.dedent(r"""
|
||||||
|
\foo-script.py
|
||||||
|
['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b']
|
||||||
|
'hello\nworld\n'
|
||||||
|
non-optimized
|
||||||
|
""").lstrip()
|
||||||
|
assert actual == expected
|
||||||
|
|
||||||
|
def test_with_options(self, tmpdir):
|
||||||
|
"""
|
||||||
|
Specifying Python Command-line Options
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
You can specify a single argument on the '#!' line. This can be used
|
||||||
|
to specify Python options like -O, to run in optimized mode or -i
|
||||||
|
to start the interactive interpreter. You can combine multiple
|
||||||
|
options as usual. For example, to run in optimized mode and
|
||||||
|
enter the interpreter after running the script, you could use -Oi:
|
||||||
|
"""
|
||||||
|
self.create_script(tmpdir)
|
||||||
|
tmpl = textwrap.dedent("""
|
||||||
|
#!%(python_exe)s -Oi
|
||||||
|
import sys
|
||||||
|
input = repr(sys.stdin.read())
|
||||||
|
print(sys.argv[0][-14:])
|
||||||
|
print(sys.argv[1:])
|
||||||
|
print(input)
|
||||||
|
if __debug__:
|
||||||
|
print('non-optimized')
|
||||||
|
sys.ps1 = '---'
|
||||||
|
""").lstrip()
|
||||||
|
with (tmpdir / 'foo-script.py').open('w') as f:
|
||||||
|
f.write(self.prep_script(tmpl))
|
||||||
|
cmd = [str(tmpdir / 'foo.exe')]
|
||||||
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
stdout, stderr = proc.communicate()
|
||||||
|
actual = stdout.decode('ascii').replace('\r\n', '\n')
|
||||||
|
expected = textwrap.dedent(r"""
|
||||||
|
\foo-script.py
|
||||||
|
[]
|
||||||
|
''
|
||||||
|
---
|
||||||
|
""").lstrip()
|
||||||
|
assert actual == expected
|
||||||
|
|
||||||
|
|
||||||
|
class TestGUI(WrapperTester):
|
||||||
|
"""
|
||||||
|
Testing the GUI Version
|
||||||
|
-----------------------
|
||||||
|
"""
|
||||||
|
script_name = 'bar-script.pyw'
|
||||||
|
wrapper_source = 'gui-32.exe'
|
||||||
|
wrapper_name = 'bar.exe'
|
||||||
|
|
||||||
|
script_tmpl = textwrap.dedent("""
|
||||||
|
#!%(python_exe)s
|
||||||
|
import sys
|
||||||
|
f = open(sys.argv[1], 'wb')
|
||||||
|
bytes_written = f.write(repr(sys.argv[2]).encode('utf-8'))
|
||||||
|
f.close()
|
||||||
|
""").strip()
|
||||||
|
|
||||||
|
def test_basic(self, tmpdir):
|
||||||
|
"""Test the GUI version with the simple scipt, bar-script.py"""
|
||||||
|
self.create_script(tmpdir)
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
str(tmpdir / 'bar.exe'),
|
||||||
|
str(tmpdir / 'test_output.txt'),
|
||||||
|
'Test Argument',
|
||||||
|
]
|
||||||
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
stdout, stderr = proc.communicate()
|
||||||
|
assert not stdout
|
||||||
|
assert not stderr
|
||||||
|
with (tmpdir / 'test_output.txt').open('rb') as f_out:
|
||||||
|
actual = f_out.read().decode('ascii')
|
||||||
|
assert actual == repr('Test Argument')
|
||||||
8
awx/lib/site-packages/setuptools/tests/textwrap.py
Normal file
8
awx/lib/site-packages/setuptools/tests/textwrap.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
|
||||||
|
def DALS(s):
|
||||||
|
"dedent and left-strip"
|
||||||
|
return textwrap.dedent(s).lstrip()
|
||||||
41
awx/lib/site-packages/setuptools/unicode_utils.py
Normal file
41
awx/lib/site-packages/setuptools/unicode_utils.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import unicodedata
|
||||||
|
import sys
|
||||||
|
from setuptools.compat import unicode as decoded_string
|
||||||
|
|
||||||
|
|
||||||
|
# HFS Plus uses decomposed UTF-8
|
||||||
|
def decompose(path):
|
||||||
|
if isinstance(path, decoded_string):
|
||||||
|
return unicodedata.normalize('NFD', path)
|
||||||
|
try:
|
||||||
|
path = path.decode('utf-8')
|
||||||
|
path = unicodedata.normalize('NFD', path)
|
||||||
|
path = path.encode('utf-8')
|
||||||
|
except UnicodeError:
|
||||||
|
pass # Not UTF-8
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def filesys_decode(path):
|
||||||
|
"""
|
||||||
|
Ensure that the given path is decoded,
|
||||||
|
NONE when no expected encoding works
|
||||||
|
"""
|
||||||
|
|
||||||
|
fs_enc = sys.getfilesystemencoding()
|
||||||
|
if isinstance(path, decoded_string):
|
||||||
|
return path
|
||||||
|
|
||||||
|
for enc in (fs_enc, "utf-8"):
|
||||||
|
try:
|
||||||
|
return path.decode(enc)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
def try_encode(string, enc):
|
||||||
|
"turn unicode encoding into a functional routine"
|
||||||
|
try:
|
||||||
|
return string.encode(enc)
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
return None
|
||||||
11
awx/lib/site-packages/setuptools/utils.py
Normal file
11
awx/lib/site-packages/setuptools/utils.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
|
||||||
|
def cs_path_exists(fspath):
|
||||||
|
if not os.path.exists(fspath):
|
||||||
|
return False
|
||||||
|
# make absolute so we always have a directory
|
||||||
|
abspath = os.path.abspath(fspath)
|
||||||
|
directory, filename = os.path.split(abspath)
|
||||||
|
return filename in os.listdir(directory)
|
||||||
@@ -1 +1 @@
|
|||||||
__version__ = '2.2'
|
__version__ = '12.0.5'
|
||||||
|
|||||||
29
awx/lib/site-packages/setuptools/windows_support.py
Normal file
29
awx/lib/site-packages/setuptools/windows_support.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import platform
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
|
||||||
|
def windows_only(func):
|
||||||
|
if platform.system() != 'Windows':
|
||||||
|
return lambda *args, **kwargs: None
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
@windows_only
|
||||||
|
def hide_file(path):
|
||||||
|
"""
|
||||||
|
Set the hidden attribute on a file or directory.
|
||||||
|
|
||||||
|
From http://stackoverflow.com/questions/19622133/
|
||||||
|
|
||||||
|
`path` must be text.
|
||||||
|
"""
|
||||||
|
__import__('ctypes.wintypes')
|
||||||
|
SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW
|
||||||
|
SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD
|
||||||
|
SetFileAttributes.restype = ctypes.wintypes.BOOL
|
||||||
|
|
||||||
|
FILE_ATTRIBUTE_HIDDEN = 0x02
|
||||||
|
|
||||||
|
ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN)
|
||||||
|
if not ret:
|
||||||
|
raise ctypes.WinError()
|
||||||
Reference in New Issue
Block a user