diff options
| author | PJ Eby <distutils-sig@python.org> | 2005-05-21 21:42:57 +0000 |
|---|---|---|
| committer | PJ Eby <distutils-sig@python.org> | 2005-05-21 21:42:57 +0000 |
| commit | 9511ddad57df2a1c5c0bfed2967d773cdd536607 (patch) | |
| tree | ddcf83d260442fa1845735b50d43fa4fa5adef62 | |
| parent | 58217442d62882e5afef276ae9f7ad1a8bcba4de (diff) | |
| download | python-setuptools-git-9511ddad57df2a1c5c0bfed2967d773cdd536607.tar.gz | |
Add basic "Requirement" class that can tell whether a distribution or
version meets its version requirements.
--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4041005
| -rw-r--r-- | pkg_resources.py | 67 | ||||
| -rw-r--r-- | setuptools/tests/test_resources.py | 47 |
2 files changed, 98 insertions, 16 deletions
diff --git a/pkg_resources.py b/pkg_resources.py index a3f9ee7c..f3669f6e 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -19,7 +19,7 @@ __all__ = [ 'resource_stream', 'resource_filename', 'set_extraction_path', 'cleanup_resources', 'parse_requirements', 'parse_version', 'compatible_platforms', 'get_platform', - 'Distribution', # 'glob_resources' + 'Distribution', 'Requirement', # 'glob_resources' ] import sys, os, zipimport, time, re @@ -740,7 +740,7 @@ def parse_requirements(strs): """Yield ``Requirement`` objects for each specification in `strs` `strs` must be an instance of ``basestring``, or a (possibly-nested) - sequence thereof. + iterable thereof. """ # create a steppable iterator, so we can handle \-continuations lines = iter(yield_lines(strs)) @@ -772,11 +772,62 @@ def parse_requirements(strs): elif not LINE_END(line,p): raise ValueError("Expected ',' or EOL in",line,"at",line[p:]) - yield distname.replace('_','-'), specs + yield Requirement(distname.replace('_','-'), specs) +class Requirement: + + def __init__(self, distname, specs=()): + self.distname = distname + self.key = distname.lower() + index = [(parse_version(v),state_machine[op],op,v) for op,v in specs] + index.sort() + self.specs = [(op,ver) for parsed,trans,op,ver in index] + self.index = index + + def __str__(self): + return self.distname + ','.join([''.join(s) for s in self.specs]) + + def __repr__(self): + return "Requirement(%r, %r)" % (self.distname, self.specs) + + def __eq__(self,other): + return isinstance(other,Requirement) \ + and self.key==other.key and self.specs==other.specs + + def __contains__(self,item): + if isinstance(item,Distribution): + if item.key <> self.key: + return False + item = item.parsed_version + elif isinstance(item,basestring): + item = parse_version(item) + last = True + for parsed,trans,op,ver in self.index: + action = trans[cmp(item,parsed)] + if action=='F': + return False + elif action=='T': + return True + elif action=='+': + last = True + elif action=='-': + last = False + return last + + +state_machine = { + # =>< + '<' : '--T', + '<=': 'T-T', + '>' : 'F+F', + '>=': 'T+F', + '==': 'T..', + '!=': 'F..', +} + def _get_mro(cls): """Get an mro for a type or classic class""" if not isinstance(cls,type): @@ -808,13 +859,3 @@ def _initialize(g): _initialize(globals()) - - - - - - - - - - diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py index b2b5c2ce..52197fe9 100644 --- a/setuptools/tests/test_resources.py +++ b/setuptools/tests/test_resources.py @@ -80,6 +80,47 @@ class DistroTests(TestCase): +class RequirementsTests(TestCase): + + def testBasics(self): + r = Requirement("Twisted", [('>=','1.2')]) + self.assertEqual(str(r),"Twisted>=1.2") + self.assertEqual(repr(r),"Requirement('Twisted', [('>=', '1.2')])") + self.assertEqual(r, Requirement("Twisted", [('>=','1.2')])) + self.assertEqual(r, Requirement("twisTed", [('>=','1.2')])) + self.assertNotEqual(r, Requirement("Twisted", [('>=','2.0')])) + self.assertNotEqual(r, Requirement("Zope", [('>=','1.2')])) + self.assertNotEqual(r, Requirement("Zope", [('>=','3.0')])) + + def testOrdering(self): + r1 = Requirement("Twisted", [('==','1.2c1'),('>=','1.2')]) + r2 = Requirement("Twisted", [('>=','1.2'),('==','1.2c1')]) + self.assertEqual(r1,r2) + self.assertEqual(str(r1),str(r2)) + self.assertEqual(str(r2),"Twisted==1.2c1,>=1.2") + + def testBasicContains(self): + r = Requirement("Twisted", [('>=','1.2')]) + foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg") + twist11 = Distribution.from_filename("Twisted-1.1.egg") + twist12 = Distribution.from_filename("Twisted-1.2.egg") + self.failUnless(parse_version('1.2') in r) + self.failUnless(parse_version('1.1') not in r) + self.failUnless('1.2' in r) + self.failUnless('1.1' not in r) + self.failUnless(foo_dist not in r) + self.failUnless(twist11 not in r) + self.failUnless(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.failUnless(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.failUnless(v not in r, (v,r)) + + + class ParseTests(TestCase): def testEmptyParse(self): @@ -92,14 +133,14 @@ class ParseTests(TestCase): ]: self.assertEqual(list(pkg_resources.yield_lines(inp)),out) - def testSimple(self): + def testSimpleRequirements(self): self.assertEqual( list(parse_requirements('Twis-Ted>=1.2-1')), - [('Twis-Ted',[('>=','1.2-1')])] + [Requirement('Twis-Ted',[('>=','1.2-1')])] ) self.assertEqual( list(parse_requirements('Twisted >=1.2, \ # more\n<2.0')), - [('Twisted',[('>=','1.2'),('<','2.0')])] + [Requirement('Twisted',[('>=','1.2'),('<','2.0')])] ) self.assertRaises(ValueError,lambda:list(parse_requirements(">=2.3"))) self.assertRaises(ValueError,lambda:list(parse_requirements("x\\"))) |
