diff options
author | PJ Eby <distutils-sig@python.org> | 2005-04-03 00:46:58 +0000 |
---|---|---|
committer | PJ Eby <distutils-sig@python.org> | 2005-04-03 00:46:58 +0000 |
commit | 7311c34af4aa1ab305021fa9df99eaf63bb15ebe (patch) | |
tree | a0d8d65cd261e613ae17fffd80c437bb29836581 | |
parent | 1a7cff662b734fed26360983b961ce70b889767e (diff) | |
download | external_python_setuptools-7311c34af4aa1ab305021fa9df99eaf63bb15ebe.tar.gz external_python_setuptools-7311c34af4aa1ab305021fa9df99eaf63bb15ebe.tar.bz2 external_python_setuptools-7311c34af4aa1ab305021fa9df99eaf63bb15ebe.zip |
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
-rw-r--r-- | pkg_resources.py | 98 | ||||
-rw-r--r-- | setuptools/tests/test_resources.py | 83 |
2 files changed, 168 insertions, 13 deletions
diff --git a/pkg_resources.py b/pkg_resources.py index 5fd6362a..d4b1f27b 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -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` diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py index 8797cda9..7cde4013 100644 --- a/setuptools/tests/test_resources.py +++ b/setuptools/tests/test_resources.py @@ -1,13 +1,46 @@ 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') - + + + + + + + + + + + + + + + |