From 227e8ffa20f7c2c3c1d1080da20c397bca51976d Mon Sep 17 00:00:00 2001 From: Fred Drake Date: Mon, 21 Mar 2005 06:36:32 +0000 Subject: - rename check_provision() to split_revision() - fix indentation to conform to the Python style guide - add more tests and documentation --- Lib/distutils/dist.py | 6 +- Lib/distutils/versionpredicate.py | 227 ++++++++++++++++++++++++-------------- 2 files changed, 145 insertions(+), 88 deletions(-) diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py index c5dd5cb..f015874 100644 --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -1181,11 +1181,7 @@ class DistributionMetadata: value = [v.strip() for v in value] for v in value: import distutils.versionpredicate - ver = distutils.versionpredicate.check_provision(v) - if ver: - import distutils.version - sv = distutils.version.StrictVersion() - sv.parse(ver.strip()[1:-1]) + distutils.versionpredicate.split_provision(v) self.provides = value def get_obsoletes(self): diff --git a/Lib/distutils/versionpredicate.py b/Lib/distutils/versionpredicate.py index 5126ebf..8922b13 100644 --- a/Lib/distutils/versionpredicate.py +++ b/Lib/distutils/versionpredicate.py @@ -1,9 +1,10 @@ """Module for parsing and testing package version predicate strings. """ import re -import version +import distutils.version import operator + re_validPackage = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)") # (package) (rest) @@ -11,93 +12,153 @@ re_paren = re.compile(r"^\s*\((.*)\)\s*$") # (list) inside of parentheses re_splitComparison = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$") # (comp) (version) + def splitUp(pred): - """Parse a single version comparison. - Return (comparison string, StrictVersion) - """ - res = re_splitComparison.match(pred) - if not res: - raise ValueError, "Bad package restriction syntax: " + pred - comp, verStr = res.groups() - return (comp, version.StrictVersion(verStr)) + """Parse a single version comparison. + + Return (comparison string, StrictVersion) + """ + res = re_splitComparison.match(pred) + if not res: + raise ValueError("bad package restriction syntax: %r" % pred) + comp, verStr = res.groups() + return (comp, distutils.version.StrictVersion(verStr)) compmap = {"<": operator.lt, "<=": operator.le, "==": operator.eq, ">": operator.gt, ">=": operator.ge, "!=": operator.ne} class VersionPredicate: - """Parse and test package version predicates. - - >>> v = VersionPredicate("pyepat.abc (>1.0, <3333.3a1, !=1555.1b3)") - >>> print v - pyepat.abc (> 1.0, < 3333.3a1, != 1555.1b3) - >>> v.satisfied_by("1.1") - True - >>> v.satisfied_by("1.4") - True - >>> v.satisfied_by("1.0") - False - >>> v.satisfied_by("4444.4") - False - >>> v.satisfied_by("1555.1b3") - False - >>> v = VersionPredicate("pat( == 0.1 ) ") - >>> v.satisfied_by("0.1") - True - >>> v.satisfied_by("0.2") - False - >>> v = VersionPredicate("p1.p2.p3.p4(>=1.0, <=1.3a1, !=1.2zb3)") - Traceback (most recent call last): - ... - ValueError: invalid version number '1.2zb3' - - """ - - def __init__(self, versionPredicateStr): - """Parse a version predicate string. - """ - # Fields: - # name: package name - # pred: list of (comparison string, StrictVersion) - - versionPredicateStr = versionPredicateStr.strip() - if not versionPredicateStr: - raise ValueError, "Empty package restriction" - match = re_validPackage.match(versionPredicateStr) - if not match: - raise ValueError, "Bad package name in " + versionPredicateStr - self.name, paren = match.groups() - paren = paren.strip() - if paren: - match = re_paren.match(paren) - if not match: - raise ValueError, "Expected parenthesized list: " + paren - str = match.groups()[0] - self.pred = [splitUp(aPred) for aPred in str.split(",")] - if not self.pred: - raise ValueError("Empty Parenthesized list in %r" - % versionPredicateStr ) - else: - self.pred=[] - - def __str__(self): - if self.pred: - seq = [cond + " " + str(ver) for cond, ver in self.pred] - return self.name + " (" + ", ".join(seq) + ")" - else: - return self.name - - def satisfied_by(self, version): - """True if version is compatible with all the predicates in self. - The parameter version must be acceptable to the StrictVersion - constructor. It may be either a string or StrictVersion. - """ - for cond, ver in self.pred: - if not compmap[cond](version, ver): - return False - return True - - -def check_provision(value): - m = re.match("[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*(\s*\([^)]+\))?$", value) + """Parse and test package version predicates. + + >>> v = VersionPredicate('pyepat.abc (>1.0, <3333.3a1, !=1555.1b3)') + + The `name` attribute provides the full dotted name that is given:: + + >>> v.name + 'pyepat.abc' + + The str() of a `VersionPredicate` provides a normalized + human-readable version of the expression:: + + >>> print v + pyepat.abc (> 1.0, < 3333.3a1, != 1555.1b3) + + The `satisfied_by()` method can be used to determine with a given + version number is included in the set described by the version + restrictions:: + + >>> v.satisfied_by('1.1') + True + >>> v.satisfied_by('1.4') + True + >>> v.satisfied_by('1.0') + False + >>> v.satisfied_by('4444.4') + False + >>> v.satisfied_by('1555.1b3') + False + + `VersionPredicate` is flexible in accepting extra whitespace:: + + >>> v = VersionPredicate(' pat( == 0.1 ) ') + >>> v.name + 'pat' + >>> v.satisfied_by('0.1') + True + >>> v.satisfied_by('0.2') + False + + If any version numbers passed in do not conform to the + restrictions of `StrictVersion`, a `ValueError` is raised:: + + >>> v = VersionPredicate('p1.p2.p3.p4(>=1.0, <=1.3a1, !=1.2zb3)') + Traceback (most recent call last): + ... + ValueError: invalid version number '1.2zb3' + + It the module or package name given does not conform to what's + allowed as a legal module or package name, `ValueError` is + raised:: + + >>> v = VersionPredicate('foo-bar') + Traceback (most recent call last): + ... + ValueError: expected parenthesized list: '-bar' + + >>> v = VersionPredicate('foo bar (12.21)') + Traceback (most recent call last): + ... + ValueError: expected parenthesized list: 'bar (12.21)' + + """ + + def __init__(self, versionPredicateStr): + """Parse a version predicate string. + """ + # Fields: + # name: package name + # pred: list of (comparison string, StrictVersion) + + versionPredicateStr = versionPredicateStr.strip() + if not versionPredicateStr: + raise ValueError("empty package restriction") + match = re_validPackage.match(versionPredicateStr) + if not match: + raise ValueError("bad package name in %r" % versionPredicateStr) + self.name, paren = match.groups() + paren = paren.strip() + if paren: + match = re_paren.match(paren) + if not match: + raise ValueError("expected parenthesized list: %r" % paren) + str = match.groups()[0] + self.pred = [splitUp(aPred) for aPred in str.split(",")] + if not self.pred: + raise ValueError("empty parenthesized list in %r" + % versionPredicateStr) + else: + self.pred=[] + + def __str__(self): + if self.pred: + seq = [cond + " " + str(ver) for cond, ver in self.pred] + return self.name + " (" + ", ".join(seq) + ")" + else: + return self.name + + def satisfied_by(self, version): + """True if version is compatible with all the predicates in self. + The parameter version must be acceptable to the StrictVersion + constructor. It may be either a string or StrictVersion. + """ + for cond, ver in self.pred: + if not compmap[cond](version, ver): + return False + return True + + +_provision_rx = None + +def split_provision(value): + """Return the name and optional version number of a provision. + + The version number, if given, will be returned as a `StrictVersion` + instance, otherwise it will be `None`. + + >>> split_provision('mypkg') + ('mypkg', None) + >>> split_provision(' mypkg( 1.2 ) ') + ('mypkg', StrictVersion ('1.2')) + """ + global _provision_rx + if _provision_rx is None: + _provision_rx = re.compile( + "([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$") + value = value.strip() + m = _provision_rx.match(value) if not m: raise ValueError("illegal provides specification: %r" % value) + ver = m.group(2) or None + if ver: + ver = distutils.version.StrictVersion(ver) + return m.group(1), ver -- cgit v0.12