diff options
author | Donald Stufft <donald@stufft.io> | 2014-12-13 18:36:50 -0500 |
---|---|---|
committer | Donald Stufft <donald@stufft.io> | 2014-12-13 18:36:50 -0500 |
commit | 18fc31b1516b4493ff1925497d4a6b8bd0110809 (patch) | |
tree | c2574b5e00a5bafd6e05838b4a79a4433796288d | |
parent | b3203c3fd58476f0bead1436bf83ef05d3288d26 (diff) | |
download | external_python_setuptools-18fc31b1516b4493ff1925497d4a6b8bd0110809.tar.gz external_python_setuptools-18fc31b1516b4493ff1925497d4a6b8bd0110809.tar.bz2 external_python_setuptools-18fc31b1516b4493ff1925497d4a6b8bd0110809.zip |
Restore iterating over Version objects for compat with buildout
-rw-r--r-- | pkg_resources.py | 71 | ||||
-rw-r--r-- | setuptools/tests/test_resources.py | 19 |
2 files changed, 88 insertions, 2 deletions
diff --git a/pkg_resources.py b/pkg_resources.py index a3eef28f..e1109608 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -79,8 +79,75 @@ import setuptools._vendor.packaging.version import setuptools._vendor.packaging.specifiers packaging = setuptools._vendor.packaging -# For compatibility, expose packaging.version.parse as parse_version -parse_version = packaging.version.parse + +class _SetuptoolsVersionMixin(object): + def __iter__(self): + 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 old_parse_version(s): + 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) + + # Warn for use of this function + warnings.warn( + "You have iterated over the result of " + "pkg_resources.parse_version. This is a legacy behavior which is " + "inconsistent with the new version class introduced in setuptools " + "8.0. That class should be used directly instead of attempting to " + "iterate over the result.", + RuntimeWarning, + stacklevel=1, + ) + + for part in old_parse_version(str(self)): + yield part + + +class SetuptoolsVersion(_SetuptoolsVersionMixin, packaging.version.Version): + pass + + +class SetuptoolsLegacyVersion(_SetuptoolsVersionMixin, + packaging.version.LegacyVersion): + pass + + +def parse_version(v): + try: + return SetuptoolsVersion(v) + except packaging.version.InvalidVersion: + return SetuptoolsLegacyVersion(v) _state_vars = {} diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py index 356e1ed4..23872e5d 100644 --- a/setuptools/tests/test_resources.py +++ b/setuptools/tests/test_resources.py @@ -488,6 +488,25 @@ class ParseTests(TestCase): 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) + + self.assertTrue(buildout(parse_version("1.0"))) + self.assertFalse(buildout(parse_version("1.0a1"))) + class ScriptHeaderTests(TestCase): non_ascii_exe = '/Users/José/bin/python' |