Commit c5d53df9 authored by Jason R. Coombs's avatar Jason R. Coombs

Merge github pull request #13 (dstufft/setuptools:use-packaging).

parents 2b5d7f13 9382fa0c
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
CHANGES CHANGES
======= =======
---
7.0
---
* Implement PEP 440 within pkg_resources and setuptools. This will cause some
versions to no longer be installable without using the ``===`` escape hatch.
----- -----
6.0.1 6.0.1
----- -----
......
empty:
exit 1
update-vendored:
rm -rf setuptools/_vendor/packaging
pip install -r setuptools/_vendor/vendored.txt -t setuptools/_vendor/
rm -rf setuptools/_vendor/*.{egg,dist}-info
...@@ -594,7 +594,7 @@ Requirements Parsing ...@@ -594,7 +594,7 @@ Requirements Parsing
requirement ::= project_name versionspec? extras? requirement ::= project_name versionspec? extras?
versionspec ::= comparison version (',' comparison version)* versionspec ::= comparison version (',' comparison version)*
comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>' comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>' | '~=' | '==='
extras ::= '[' extralist? ']' extras ::= '[' extralist? ']'
extralist ::= identifier (',' identifier)* extralist ::= identifier (',' identifier)*
project_name ::= identifier project_name ::= identifier
...@@ -646,13 +646,10 @@ Requirements Parsing ...@@ -646,13 +646,10 @@ Requirements Parsing
The ``Requirement`` object's version specifiers (``.specs``) are internally The ``Requirement`` object's version specifiers (``.specs``) are internally
sorted into ascending version order, and used to establish what ranges of sorted into ascending version order, and used to establish what ranges of
versions are acceptable. Adjacent redundant conditions are effectively versions are acceptable. Adjacent redundant conditions are effectively
consolidated (e.g. ``">1, >2"`` produces the same results as ``">1"``, and consolidated (e.g. ``">1, >2"`` produces the same results as ``">2"``, and
``"<2,<3"`` produces the same results as``"<3"``). ``"!="`` versions are ``"<2,<3"`` produces the same results as``"<2"``). ``"!="`` versions are
excised from the ranges they fall within. The version being tested for excised from the ranges they fall within. The version being tested for
acceptability is then checked for membership in the resulting ranges. acceptability is then checked for membership in the resulting ranges.
(Note that providing conflicting conditions for the same version (e.g.
``"<2,>=2"`` or ``"==2,!=2"``) is meaningless and may therefore produce
bizarre results when compared with actual version number(s).)
``__eq__(other_requirement)`` ``__eq__(other_requirement)``
A requirement compares equal to another requirement if they have A requirement compares equal to another requirement if they have
...@@ -681,10 +678,7 @@ Requirements Parsing ...@@ -681,10 +678,7 @@ Requirements Parsing
``specs`` ``specs``
A list of ``(op,version)`` tuples, sorted in ascending parsed-version A list of ``(op,version)`` tuples, sorted in ascending parsed-version
order. The `op` in each tuple is a comparison operator, represented as order. The `op` in each tuple is a comparison operator, represented as
a string. The `version` is the (unparsed) version number. The relative a string. The `version` is the (unparsed) version number.
order of tuples containing the same version numbers is undefined, since
having more than one operator for a given version is either redundant or
self-contradictory.
Entry Points Entry Points
...@@ -967,7 +961,7 @@ version ...@@ -967,7 +961,7 @@ version
``ValueError`` is raised. ``ValueError`` is raised.
parsed_version parsed_version
The ``parsed_version`` is a tuple representing a "parsed" form of the The ``parsed_version`` is an object representing a "parsed" form of the
distribution's ``version``. ``dist.parsed_version`` is a shortcut for distribution's ``version``. ``dist.parsed_version`` is a shortcut for
calling ``parse_version(dist.version)``. It is used to compare or sort calling ``parse_version(dist.version)``. It is used to compare or sort
distributions by version. (See the `Parsing Utilities`_ section below for distributions by version. (See the `Parsing Utilities`_ section below for
...@@ -1541,40 +1535,12 @@ Parsing Utilities ...@@ -1541,40 +1535,12 @@ Parsing Utilities
----------------- -----------------
``parse_version(version)`` ``parse_version(version)``
Parse a project's version string, returning a value that can be used to Parsed a project's version string as defined by PEP 440. The returned
compare versions by chronological order. Semantically, the format is a value will be an object that represents the version. These objects may
rough cross between distutils' ``StrictVersion`` and ``LooseVersion`` be compared to each other and sorted. The sorting algorithm is as defined
classes; if you give it versions that would work with ``StrictVersion``, by PEP 440 with the addition that any version which is not a valid PEP 440
then they will compare the same way. Otherwise, comparisons are more like version will be considered less than any valid PEP 440 version and the
a "smarter" form of ``LooseVersion``. It is *possible* to create invalid versions will continue sorting using the original algorithm.
pathological version coding schemes that will fool this parser, but they
should be very rare in practice.
The returned value will be a tuple of strings. Numeric portions of the
version are padded to 8 digits so they will compare numerically, but
without relying on how numbers compare relative to strings. Dots are
dropped, but dashes are retained. Trailing zeros between alpha segments
or dashes are suppressed, so that e.g. "2.4.0" is considered the same as
"2.4". Alphanumeric parts are lower-cased.
The algorithm assumes that strings like "-" and any alpha string that
alphabetically follows "final" represents a "patch level". So, "2.4-1"
is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is
considered newer than "2.4-1", which in turn is newer than "2.4".
Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that
come before "final" alphabetically) are assumed to be pre-release versions,
so that the version "2.4" is considered newer than "2.4a1". Any "-"
characters preceding a pre-release indicator are removed. (In versions of
setuptools prior to 0.6a9, "-" characters were not removed, leading to the
unintuitive result that "0.2-rc1" was considered a newer version than
"0.2".)
Finally, to handle miscellaneous cases, the strings "pre", "preview", and
"rc" are treated as if they were "c", i.e. as though they were release
candidates, and therefore are not as new as a version string that does not
contain them. And the string "dev" is treated as if it were an "@" sign;
that is, a version coming before even "a" or "alpha".
.. _yield_lines(): .. _yield_lines():
...@@ -1629,10 +1595,12 @@ Parsing Utilities ...@@ -1629,10 +1595,12 @@ Parsing Utilities
See ``to_filename()``. See ``to_filename()``.
``safe_version(version)`` ``safe_version(version)``
Similar to ``safe_name()`` except that spaces in the input become dots, and This will return the normalized form of any PEP 440 version, if the version
dots are allowed to exist in the output. As with ``safe_name()``, if you string is not PEP 440 compatible than it is similar to ``safe_name()``
are generating a filename from this you should replace any "-" characters except that spaces in the input become dots, and dots are allowed to exist
in the output with underscores. in the output. As with ``safe_name()``, if you are generating a filename
from this you should replace any "-" characters in the output with
underscores.
``safe_extra(extra)`` ``safe_extra(extra)``
Return a "safe" form of an extra's name, suitable for use in a requirement Return a "safe" form of an extra's name, suitable for use in a requirement
......
...@@ -73,6 +73,14 @@ try: ...@@ -73,6 +73,14 @@ try:
except ImportError: except ImportError:
pass pass
# Import packaging.version.parse as parse_version for a compat shim with the
# old parse_version that used to be defined in this file.
from setuptools._vendor.packaging.version import parse as parse_version
from setuptools._vendor.packaging.version import (
Version, InvalidVersion, Specifier,
)
_state_vars = {} _state_vars = {}
...@@ -1143,11 +1151,12 @@ def safe_name(name): ...@@ -1143,11 +1151,12 @@ def safe_name(name):
def safe_version(version): def safe_version(version):
"""Convert an arbitrary string to a standard version string
Spaces become dots, and all other non-alphanumeric characters become
dashes, with runs of multiple dashes condensed to a single dash.
""" """
Convert an arbitrary string to a standard version string
"""
try:
return str(Version(version)) # this will normalize the version
except InvalidVersion:
version = version.replace(' ','.') version = version.replace(' ','.')
return re.sub('[^A-Za-z0-9.]+', '-', version) return re.sub('[^A-Za-z0-9.]+', '-', version)
...@@ -2067,7 +2076,7 @@ CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match ...@@ -2067,7 +2076,7 @@ CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match
# Distribution or extra # Distribution or extra
DISTRO = re.compile(r"\s*((\w|[-.])+)").match DISTRO = re.compile(r"\s*((\w|[-.])+)").match
# ver. info # ver. info
VERSION = re.compile(r"\s*(<=?|>=?|==|!=)\s*((\w|[-.])+)").match VERSION = re.compile(r"\s*(<=?|>=?|===?|!=|~=)\s*((\w|[-.*_!+])+)").match
# comma between items # comma between items
COMMA = re.compile(r"\s*,").match COMMA = re.compile(r"\s*,").match
OBRACKET = re.compile(r"\s*\[").match OBRACKET = re.compile(r"\s*\[").match
...@@ -2079,67 +2088,6 @@ EGG_NAME = re.compile( ...@@ -2079,67 +2088,6 @@ EGG_NAME = re.compile(
re.VERBOSE | re.IGNORECASE re.VERBOSE | re.IGNORECASE
).match ).match
component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
def _parse_version_parts(s):
for part in component_re.split(s):
part = replace(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 parse_version(s):
"""Convert a version string to a chronologically-sortable key
This is a rough cross between distutils' StrictVersion and LooseVersion;
if you give it versions that would work with StrictVersion, then it behaves
the same; otherwise it acts like a slightly-smarter LooseVersion. It is
*possible* to create pathological version coding schemes that will fool
this parser, but they should be very rare in practice.
The returned value will be a tuple of strings. Numeric portions of the
version are padded to 8 digits so they will compare numerically, but
without relying on how numbers compare relative to strings. Dots are
dropped, but dashes are retained. Trailing zeros between alpha segments
or dashes are suppressed, so that e.g. "2.4.0" is considered the same as
"2.4". Alphanumeric parts are lower-cased.
The algorithm assumes that strings like "-" and any alpha string that
alphabetically follows "final" represents a "patch level". So, "2.4-1"
is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is
considered newer than "2.4-1", which in turn is newer than "2.4".
Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that
come before "final" alphabetically) are assumed to be pre-release versions,
so that the version "2.4" is considered newer than "2.4a1".
Finally, to handle miscellaneous cases, the strings "pre", "preview", and
"rc" are treated as if they were "c", i.e. as though they were release
candidates, and therefore are not as new as a version string that does not
contain them, and "dev" is replaced with an '@' so that it sorts lower than
than any other pre-release tag.
"""
parts = []
for part in _parse_version_parts(s.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)
return tuple(parts)
class EntryPoint(object): class EntryPoint(object):
"""Object representing an advertised importable object""" """Object representing an advertised importable object"""
...@@ -2292,7 +2240,7 @@ class Distribution(object): ...@@ -2292,7 +2240,7 @@ class Distribution(object):
@property @property
def hashcmp(self): def hashcmp(self):
return ( return (
getattr(self, 'parsed_version', ()), self.parsed_version,
self.precedence, self.precedence,
self.key, self.key,
_remove_md5_fragment(self.location), _remove_md5_fragment(self.location),
...@@ -2338,11 +2286,10 @@ class Distribution(object): ...@@ -2338,11 +2286,10 @@ class Distribution(object):
@property @property
def parsed_version(self): def parsed_version(self):
try: if not hasattr(self, "_parsed_version"):
self._parsed_version = parse_version(self.version)
return self._parsed_version return self._parsed_version
except AttributeError:
self._parsed_version = pv = parse_version(self.version)
return pv
@property @property
def version(self): def version(self):
...@@ -2447,7 +2394,12 @@ class Distribution(object): ...@@ -2447,7 +2394,12 @@ class Distribution(object):
def as_requirement(self): def as_requirement(self):
"""Return a ``Requirement`` that matches this distribution exactly""" """Return a ``Requirement`` that matches this distribution exactly"""
return Requirement.parse('%s==%s' % (self.project_name, self.version)) if isinstance(self.parsed_version, Version):
spec = "%s==%s" % (self.project_name, self.parsed_version)
else:
spec = "%s===%s" % (self.project_name, self.parsed_version)
return Requirement.parse(spec)
def load_entry_point(self, group, name): def load_entry_point(self, group, name):
"""Return the `name` entry point of `group` or raise ImportError""" """Return the `name` entry point of `group` or raise ImportError"""
...@@ -2699,7 +2651,7 @@ def parse_requirements(strs): ...@@ -2699,7 +2651,7 @@ def parse_requirements(strs):
line, p, specs = scan_list(VERSION, LINE_END, line, p, (1, 2), line, p, specs = scan_list(VERSION, LINE_END, line, p, (1, 2),
"version spec") "version spec")
specs = [(op, safe_version(val)) for op, val in specs] specs = [(op, val) for op, val in specs]
yield Requirement(project_name, specs, extras) yield Requirement(project_name, specs, extras)
...@@ -2708,26 +2660,23 @@ class Requirement: ...@@ -2708,26 +2660,23 @@ class Requirement:
"""DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
self.unsafe_name, project_name = project_name, safe_name(project_name) self.unsafe_name, project_name = project_name, safe_name(project_name)
self.project_name, self.key = project_name, project_name.lower() self.project_name, self.key = project_name, project_name.lower()
index = [ self.specifier = Specifier(
(parse_version(v), state_machine[op], op, v) ",".join(["".join([x, y]) for x, y in specs])
for op, v in specs )
] self.specs = specs
index.sort() self.extras = tuple(map(safe_extra, extras))
self.specs = [(op, ver) for parsed, trans, op, ver in index]
self.index, self.extras = index, tuple(map(safe_extra, extras))
self.hashCmp = ( self.hashCmp = (
self.key, self.key,
tuple((op, parsed) for parsed, trans, op, ver in index), self.specifier,
frozenset(self.extras), frozenset(self.extras),
) )
self.__hash = hash(self.hashCmp) self.__hash = hash(self.hashCmp)
def __str__(self): def __str__(self):
specs = ','.join([''.join(s) for s in self.specs])
extras = ','.join(self.extras) extras = ','.join(self.extras)
if extras: if extras:
extras = '[%s]' % extras extras = '[%s]' % extras
return '%s%s%s' % (self.project_name, extras, specs) return '%s%s%s' % (self.project_name, extras, self.specifier)
def __eq__(self, other): def __eq__(self, other):
return ( return (
...@@ -2739,29 +2688,13 @@ class Requirement: ...@@ -2739,29 +2688,13 @@ class Requirement:
if isinstance(item, Distribution): if isinstance(item, Distribution):
if item.key != self.key: if item.key != self.key:
return False return False
# only get if we need it
if self.index: item = item.version
item = item.parsed_version
elif isinstance(item, string_types): # Allow prereleases always in order to match the previous behavior of
item = parse_version(item) # this method. In the future this should be smarter and follow PEP 440
last = None # more accurately.
# -1, 0, 1 return self.specifier.contains(item, prereleases=True)
compare = lambda a, b: (a > b) - (a < b)
for parsed, trans, op, ver in self.index:
# Indexing: 0, 1, -1
action = trans[compare(item, parsed)]
if action == 'F':
return False
elif action == 'T':
return True
elif action == '+':
last = True
elif action == '-' or last is None:
last = False
# no rules encountered
if last is None:
last = True
return last
def __hash__(self): def __hash__(self):
return self.__hash return self.__hash
...@@ -2777,16 +2710,6 @@ class Requirement: ...@@ -2777,16 +2710,6 @@ class Requirement:
raise ValueError("Expected only one requirement", s) raise ValueError("Expected only one requirement", s)
raise ValueError("No requirements found", s) raise ValueError("No requirements found", s)
state_machine = {
# =><
'<': '--T',
'<=': 'T-T',
'>': 'F+F',
'>=': 'T+F',
'==': 'T..',
'!=': 'F++',
}
def _get_mro(cls): def _get_mro(cls):
"""Get an mro for a type or classic class""" """Get an mro for a type or classic class"""
......
# 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__ = "14.2"
__author__ = "Donald Stufft"
__email__ = "donald@stufft.io"
__license__ = "Apache License, Version 2.0"
__copyright__ = "Copyright 2014 %s" % __author__
# 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__",
]
# 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,
# 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()
This diff is collapsed.
...@@ -15,6 +15,7 @@ from setuptools.command.sdist import sdist ...@@ -15,6 +15,7 @@ from setuptools.command.sdist import sdist
from setuptools.compat import basestring, PY3, StringIO from setuptools.compat import basestring, PY3, StringIO
from setuptools import svn_utils from setuptools import svn_utils
from setuptools.command.sdist import walk_revctrl from setuptools.command.sdist import walk_revctrl
from setuptools._vendor.packaging.version import Version
from pkg_resources import ( from pkg_resources import (
parse_requirements, safe_name, parse_version, parse_requirements, safe_name, parse_version,
safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
...@@ -68,9 +69,14 @@ class egg_info(Command): ...@@ -68,9 +69,14 @@ 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:
spec = (
"%s==%s" if isinstance(parsed_version, Version) else "%s===%s"
)
list( list(
parse_requirements('%s==%s' % (self.egg_name, parse_requirements(spec % (self.egg_name,
self.egg_version)) self.egg_version))
) )
except ValueError: except ValueError:
......
...@@ -15,6 +15,7 @@ from distutils.errors import (DistutilsOptionError, DistutilsPlatformError, ...@@ -15,6 +15,7 @@ from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
from setuptools.depends import Require from setuptools.depends import Require
from setuptools.compat import basestring, PY2 from setuptools.compat import basestring, PY2
from setuptools._vendor.packaging.version import Version, InvalidVersion
import pkg_resources import pkg_resources
def _get_unpatched(cls): def _get_unpatched(cls):
...@@ -268,6 +269,26 @@ class Distribution(_Distribution): ...@@ -268,6 +269,26 @@ class Distribution(_Distribution):
# 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:
normalized_version = str(Version(self.metadata.version))
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 (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)
......
...@@ -155,7 +155,7 @@ class TestSvnDummy(environment.ZippedEnvironment): ...@@ -155,7 +155,7 @@ class TestSvnDummy(environment.ZippedEnvironment):
infile.close() infile.close()
del infile del infile
self.assertTrue("Version: 0.1.1-r1\n" in read_contents) self.assertTrue("Version: 0.1.1.post1\n" in read_contents)
@skipIf(not test_svn._svn_check, "No SVN to text, in the first place") @skipIf(not test_svn._svn_check, "No SVN to text, in the first place")
def test_no_tags(self): def test_no_tags(self):
......
...@@ -16,6 +16,7 @@ from pkg_resources import (parse_requirements, VersionConflict, parse_version, ...@@ -16,6 +16,7 @@ from pkg_resources import (parse_requirements, VersionConflict, parse_version,
from setuptools.command.easy_install import (get_script_header, is_sh, from setuptools.command.easy_install import (get_script_header, is_sh,
nt_quote_arg) nt_quote_arg)
from setuptools.compat import StringIO, iteritems, PY3 from setuptools.compat import StringIO, iteritems, PY3
from setuptools._vendor.packaging.version import Specifier
from .py26compat import skipIf from .py26compat import skipIf
def safe_repr(obj, short=False): def safe_repr(obj, short=False):
...@@ -103,7 +104,7 @@ class DistroTests(TestCase): ...@@ -103,7 +104,7 @@ class DistroTests(TestCase):
def checkFooPkg(self,d): def checkFooPkg(self,d):
self.assertEqual(d.project_name, "FooPkg") self.assertEqual(d.project_name, "FooPkg")
self.assertEqual(d.key, "foopkg") self.assertEqual(d.key, "foopkg")
self.assertEqual(d.version, "1.3-1") self.assertEqual(d.version, "1.3.post1")
self.assertEqual(d.py_version, "2.4") self.assertEqual(d.py_version, "2.4")
self.assertEqual(d.platform, "win32") self.assertEqual(d.platform, "win32")
self.assertEqual(d.parsed_version, parse_version("1.3-1")) self.assertEqual(d.parsed_version, parse_version("1.3-1"))
...@@ -120,9 +121,9 @@ class DistroTests(TestCase): ...@@ -120,9 +121,9 @@ class DistroTests(TestCase):
self.assertEqual(d.platform, None) self.assertEqual(d.platform, None)
def testDistroParse(self): def testDistroParse(self):
d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg") d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg")
self.checkFooPkg(d) self.checkFooPkg(d)
d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg-info") d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg-info")
self.checkFooPkg(d) self.checkFooPkg(d)
def testDistroMetadata(self): def testDistroMetadata(self):
...@@ -330,24 +331,15 @@ class RequirementsTests(TestCase): ...@@ -330,24 +331,15 @@ class RequirementsTests(TestCase):
self.assertTrue(twist11 not in r) self.assertTrue(twist11 not in r)
self.assertTrue(twist12 in r) self.assertTrue(twist12 in r)
def testAdvancedContains(self):
r, = parse_requirements("Foo>=1.2,<=1.3,==1.9,>2.0,!=2.5,<3.0,==4.5")
for v in ('1.2','1.2.2','1.3','1.9','2.0.1','2.3','2.6','3.0c1','4.5'):
self.assertTrue(v in r, (v,r))
for v in ('1.2c1','1.3.1','1.5','1.9.1','2.0','2.5','3.0','4.0'):
self.assertTrue(v not in r, (v,r))
def testOptionsAndHashing(self): def testOptionsAndHashing(self):
r1 = Requirement.parse("Twisted[foo,bar]>=1.2") r1 = Requirement.parse("Twisted[foo,bar]>=1.2")
r2 = Requirement.parse("Twisted[bar,FOO]>=1.2") r2 = Requirement.parse("Twisted[bar,FOO]>=1.2")
r3 = Requirement.parse("Twisted[BAR,FOO]>=1.2.0")
self.assertEqual(r1,r2) self.assertEqual(r1,r2)
self.assertEqual(r1,r3)
self.assertEqual(r1.extras, ("foo","bar")) self.assertEqual(r1.extras, ("foo","bar"))
self.assertEqual(r2.extras, ("bar","foo")) # extras are normalized self.assertEqual(r2.extras, ("bar","foo")) # extras are normalized
self.assertEqual(hash(r1), hash(r2)) self.assertEqual(hash(r1), hash(r2))
self.assertEqual( self.assertEqual(
hash(r1), hash(("twisted", ((">=",parse_version("1.2")),), hash(r1), hash(("twisted", Specifier(">=1.2"),
frozenset(["foo","bar"]))) frozenset(["foo","bar"])))
) )
...@@ -420,7 +412,7 @@ class ParseTests(TestCase): ...@@ -420,7 +412,7 @@ class ParseTests(TestCase):
self.assertNotEqual(safe_name("peak.web"), "peak-web") self.assertNotEqual(safe_name("peak.web"), "peak-web")
def testSafeVersion(self): def testSafeVersion(self):
self.assertEqual(safe_version("1.2-1"), "1.2-1") self.assertEqual(safe_version("1.2-1"), "1.2.post1")
self.assertEqual(safe_version("1.2 alpha"), "1.2.alpha") self.assertEqual(safe_version("1.2 alpha"), "1.2.alpha")
self.assertEqual(safe_version("2.3.4 20050521"), "2.3.4.20050521") self.assertEqual(safe_version("2.3.4 20050521"), "2.3.4.20050521")
self.assertEqual(safe_version("Money$$$Maker"), "Money-Maker") self.assertEqual(safe_version("Money$$$Maker"), "Money-Maker")
...@@ -454,12 +446,12 @@ class ParseTests(TestCase): ...@@ -454,12 +446,12 @@ class ParseTests(TestCase):
c('0.4', '0.4.0') c('0.4', '0.4.0')
c('0.4.0.0', '0.4.0') c('0.4.0.0', '0.4.0')
c('0.4.0-0', '0.4-0') c('0.4.0-0', '0.4-0')
c('0pl1', '0.0pl1') c('0post1', '0.0post1')
c('0pre1', '0.0c1') c('0pre1', '0.0c1')
c('0.0.0preview1', '0c1') c('0.0.0preview1', '0c1')
c('0.0c1', '0-rc1') c('0.0c1', '0-rc1')
c('1.2a1', '1.2.a.1') c('1.2a1', '1.2.a.1')
c('1.2...a', '1.2a') c('1.2.a', '1.2a')
def testVersionOrdering(self): def testVersionOrdering(self):
def c(s1,s2): def c(s1,s2):
...@@ -472,16 +464,14 @@ class ParseTests(TestCase): ...@@ -472,16 +464,14 @@ class ParseTests(TestCase):
c('2.3a1', '2.3') c('2.3a1', '2.3')
c('2.1-1', '2.1-2') c('2.1-1', '2.1-2')
c('2.1-1', '2.1.1') c('2.1-1', '2.1.1')
c('2.1', '2.1pl4') c('2.1', '2.1post4')
c('2.1a0-20040501', '2.1') c('2.1a0-20040501', '2.1')
c('1.1', '02.1') c('1.1', '02.1')
c('A56','B27') c('3.2', '3.2.post0')
c('3.2', '3.2.pl0') c('3.2post1', '3.2post2')
c('3.2-1', '3.2pl1')
c('3.2pl1', '3.2pl1-1')
c('0.4', '4.0') c('0.4', '4.0')
c('0.0.4', '0.4.0') c('0.0.4', '0.4.0')
c('0pl1', '0.4pl1') c('0post1', '0.4post1')
c('2.1.0-rc1','2.1.0') c('2.1.0-rc1','2.1.0')
c('2.1dev','2.1a0') c('2.1dev','2.1a0')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment