Michele Lacchia committed 3e22471

Removed parse_version from, added a test for pick_best

Comments (0)

Files changed (3)

 from email.parser import Parser
 from .decorator import reify
-from .util import urlsafe_b64encode, utf8, to_json, parse_version
+from .util import urlsafe_b64encode, utf8, to_json
 # The next major version after this version of the 'wheel' tool:
 class WheelFile(object):
     """Parse wheel-specific attributes from a wheel (.whl) file"""    
 def pick_best(candidates, supported, top=True):
-    # XXX: Are candidates Wheels or paths (strings)?
-    # For now I'll assume they're already wheels.
+    '''Pick the best supported wheel among the candidates.
+    The algorithm ranks each candidate wheel with respect to the supported
+    ones. A list of supported tags can be automatically generated with
+    :func:`wheel.util.generate_supported`.
+    :param candidates: A list of wheels that can be installed.
+    :param supported: A list of tags which represent wheels that can be
+        installed on the current system. Each tag is as follows::
+            (python_implementation, abi, architecture)
+        For example: ``('cp27', 'cp27m', 'linux_i686')``.
+    :param top: If True, only return the best wheel. Otherwise return all the
+        wheels among the candidates which are supported, sorted from best to
+        worst.
+    '''
     ranked = []
     for whl in candidates:
             preference, arity = whl.compatibility_rank(supported)
-        except ValueError:  # when preferences is empty
+        except ValueError:  # When preferences is empty
         ranked.append((preference, arity, whl))
     if top:
     except AttributeError:
         raise Exception("This alpha version of wheel will only install into a virtualenv")
     wf = WheelFile(wheel_path)
 from import assert_true, assert_false, assert_equal, raises
 from .install import WheelFile
 def test_findable():
     """Make sure pkg_resources can find us."""
     assert pkg_resources.working_set.by_key['wheel'].version
 def test_egg_re():
     """Make sure egg_info_re matches."""
     from . import egg2wheel
         if not line: continue
         assert egg2wheel.egg_info_re.match(line), line
 def test_compatibility_tags():
     wf = WheelFile("package-1.0.0-cp32.cp33-noabi-noarch.whl")
     wf2_info = wf2.parsed_filename.groupdict()
     assert wf2_info['build'] == '1st', wf2_info
 def test_bdist_wheel():
     import distutils
     distutils.core.run_setup("", ["bdist_wheel"])
 def test_util():
     import wheel.util
     for i in range(10):
         assert not encoded.endswith(b'=')
         after = wheel.util.urlsafe_b64decode(encoded)
         assert before == after
+def test_pick_best():
+    def get_tags(res):
+        info = res[-1].parsed_filename.groupdict()
+        return info['pyver'], info['abi'], info['plat']
+    from wheel.install import pick_best, WheelFile
+    cand_tags = [('py27', 'noabi', 'noarch'), ('py26', 'noabi', 'noarch'),
+                 ('cp27', 'noabi', 'linux_i686'), ('cp26', 'noabi', 'linux_i686'),
+                 ('cp27', 'noabi', 'linux_x86_64'), ('cp26', 'noabi', 'linux_x86_64')]
+    cand_wheels = [WheelFile('testpkg-1.0-%s-%s-%s.whl' % t) for t in cand_tags]
+    supported = [('cp27', 'noabi', 'linux_i686'), ('py27', 'noabi', 'noarch')]
+    supported2 = [('cp27', 'noabi', 'linux_i686'), ('py27', 'noabi', 'noarch'),
+                  ('cp26', 'noabi', 'linux_i686'), ('py26', 'noabi', 'noarch')]
+    supported3 = [('cp26', 'noabi', 'linux_i686'), ('py26', 'noabi', 'noarch'),
+                  ('cp27', 'noabi', 'linux_i686'), ('py27', 'noabi', 'noarch')]
+    for supp in (supported, supported2, supported3):
+        assert_equal(get_tags(pick_best(cand_wheels, supp)), supp[0])
+        assert_equal(map(get_tags, pick_best(cand_wheels, supp, top=False)), supp)
+if __name__ == '__main__':
+    import nose
+    nose.main()
 import sysconfig
 from distutils.util import get_platform
-__all__ = ['urlsafe_b64encode', 'urlsafe_b64decode', 'utf8', 
-           'to_json', 'from_json', 'parse_version', 'generate_supported',
-           'get_abbr_impl']
-component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
-replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
+__all__ = ['urlsafe_b64encode', 'urlsafe_b64decode', 'utf8', 'to_json',
+           'from_json', 'generate_supported', 'get_abbr_impl', 'get_impl_ver']
 def urlsafe_b64encode(data):
     if not impl_ver:
         impl_ver = ''.join(map(str, sys.version_info[:2]))
     return impl_ver
-# Next two functions from distribute's
-def _parse_version_parts(s):
-    for part in component_re.split(s):
-        part = replace(part,part)
-        if part in ['', '.']:
-            continue
-        if part[:1] in '0123456789':
-            yield part.zfill(8)    # pad for numeric comparison
-        else:
-            yield '*'+part
-    yield '*final'  # ensure that alpha/beta/candidate are before 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 trailing zeros from each series of numeric parts
-            while parts and parts[-1]=='00000000':
-                parts.pop()
-        parts.append(part)
-    return tuple(parts)
 def generate_supported(versions=None):