summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPJ Eby <distutils-sig@python.org>2005-05-21 21:42:57 +0000
committerPJ Eby <distutils-sig@python.org>2005-05-21 21:42:57 +0000
commit9511ddad57df2a1c5c0bfed2967d773cdd536607 (patch)
treeddcf83d260442fa1845735b50d43fa4fa5adef62
parent58217442d62882e5afef276ae9f7ad1a8bcba4de (diff)
downloadpython-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.py67
-rw-r--r--setuptools/tests/test_resources.py47
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\\")))