Commit 7311c34a authored by PJ Eby's avatar PJ Eby

Add a "Distribution" object that wraps a sys.path entry with metadata, and

can extract its name/version/pythonversion/platform if built from a .egg
filename.  Later, distributions will be able to add themselves to sys.path
and request that their dependencies be added as well.  Also, added some
real-life version test cases supplied by jemfinch.

--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4041001
parent 1a7cff66
......@@ -17,7 +17,8 @@ __all__ = [
'register_loader_type', 'get_provider', 'IResourceProvider',
'ResourceManager', 'iter_distributions', 'require', 'resource_string',
'resource_stream', 'resource_filename', 'set_extraction_path',
'cleanup_resources', 'parse_requirements', 'parse_version'# 'glob_resources'
'cleanup_resources', 'parse_requirements', 'parse_version',
'Distribution', # 'glob_resources'
]
import sys, os, zipimport, time, re
......@@ -38,7 +39,6 @@ def get_provider(moduleName):
loader = getattr(module, '__loader__', None)
return _find_adapter(_provider_factories, loader)(module)
class IResourceProvider:
"""An object that provides access to package resources"""
......@@ -508,6 +508,12 @@ DISTRO = re.compile(r"\s*(\w+)").match # Distribution name
VERSION = re.compile(r"\s*(<=?|>=?|==|!=)\s*((\w|\.)+)").match # version info
COMMA = re.compile(r"\s*,").match # comma between items
EGG_NAME = re.compile(
r"(?P<name>[^-]+)"
r"( -(?P<ver>[^-]+) (-py(?P<pyver>[^-]+) (-(?P<plat>.+))? )? )?",
re.VERBOSE | re.IGNORECASE
).match
component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c'}.get
......@@ -525,12 +531,6 @@ def _parse_version_parts(s):
def parse_version(s):
"""Convert a version string to a sortable key
......@@ -572,6 +572,88 @@ def parse_version(s):
class Distribution(object):
"""Wrap an actual or potential sys.path entry w/metadata"""
def __init__(self,
path_str, metadata=None, name=None, version=None,
py_version=sys.version[:3]
):
if name:
self.name = name
if version:
self.version = version
self.py_version = py_version
self.path = path_str
self.normalized_path = os.path.normpath(os.path.normcase(path_str))
def installed_on(self,path=None):
"""Is this distro installed on `path`? (defaults to ``sys.path``)"""
if path is None:
path = sys.path
if self.path in path or self.normalized_path in path:
return True
for item in path:
normalized = os.path.normpath(os.path.normcase(item))
if normalized == self.normalized_path:
return True
return False
#@classmethod
def from_filename(cls,filename,metadata=None):
name,version,py_version,platform = [None]*4
basename,ext = os.path.splitext(os.path.basename(filename))
if ext.lower()==".egg":
match = EGG_NAME(basename)
if match:
name,version,py_version,platform = match.group(
'name','ver','pyver','plat'
)
if version and '_' in version:
version = version.replace('_','-')
return cls(
filename,metadata,name=name,version=version,py_version=py_version
)
from_filename = classmethod(from_filename)
# These properties have to be lazy so that we don't have to load any
# metadata until/unless it's actually needed. (i.e., some distributions
# may not know their name or version without loading PKG-INFO)
#@property
def key(self):
try:
return self._key
except AttributeError:
self._key = key = self.name.lower()
return key
key = property(key)
#@property
def parsed_version(self):
try:
return self._parsed_version
except AttributeError:
self._parsed_version = pv = parse_version(self.version)
return pv
parsed_version = property(parsed_version)
def parse_requirements(strs):
"""Yield ``Requirement`` objects for each specification in `strs`
......
from unittest import TestCase, makeSuite
from pkg_resources import *
import pkg_resources
import pkg_resources, sys
class DistroTests(TestCase):
def testEmptyiter(self):
# empty path should produce no distributions
self.assertEqual(list(iter_distributions(path=[])), [])
def checkFooPkg(self,d):
self.assertEqual(d.name, "FooPkg")
self.assertEqual(d.key, "foopkg")
self.assertEqual(d.version, "1.3-1")
self.assertEqual(d.py_version, "2.4")
self.assertEqual(d.parsed_version, parse_version("1.3-1"))
def testDistroBasics(self):
d = Distribution(
"/some/path",
name="FooPkg",version="1.3-1",py_version="2.4"
)
self.checkFooPkg(d)
self.failUnless(d.installed_on(["/some/path"]))
self.failIf(d.installed_on([]))
d = Distribution("/some/path")
self.assertEqual(d.py_version, sys.version[:3])
def testDistroParse(self):
d = Distribution.from_filename("FooPkg-1.3_1-py2.4-win32.egg")
self.checkFooPkg(d)
class ParseTests(TestCase):
def testEmptyParse(self):
self.assertEqual(list(parse_requirements('')), [])
......@@ -39,14 +72,22 @@ class ParseTests(TestCase):
def testVersionOrdering(self):
def c(s1,s2):
p1, p2 = parse_version(s1),parse_version(s2)
self.failUnless(p1<p2, (s1,s2,p1,p2))
c('2.1','2.1.1')
c('2a1','2b0')
c('2a1','2.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')
......@@ -61,12 +102,30 @@ class ParseTests(TestCase):
c('0.0.4', '0.4.0')
c('0pl1', '0.4pl1')
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 testVersionEquality(self):
def c(s1,s2):
p1, p2 = parse_version(s1),parse_version(s2)
self.assertEqual(p1,p2, (s1,s2,p1,p2))
c('0.4', '0.4.0')
c('0.4.0.0', '0.4.0')
c('0.4.0-0', '0.4-0')
......@@ -75,7 +134,21 @@ class ParseTests(TestCase):
c('0.0.0preview1', '0c1')
c('0.0c1', '0rc1')
......
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