Path: blob/main/test/lib/python3.9/site-packages/setuptools/_distutils/versionpredicate.py
4799 views
"""Module for parsing and testing package version predicate strings.1"""2import re3import distutils.version4import operator567re_validPackage = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)",8re.ASCII)9# (package) (rest)1011re_paren = re.compile(r"^\s*\((.*)\)\s*$") # (list) inside of parentheses12re_splitComparison = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$")13# (comp) (version)141516def splitUp(pred):17"""Parse a single version comparison.1819Return (comparison string, StrictVersion)20"""21res = re_splitComparison.match(pred)22if not res:23raise ValueError("bad package restriction syntax: %r" % pred)24comp, verStr = res.groups()25with distutils.version.suppress_known_deprecation():26other = distutils.version.StrictVersion(verStr)27return (comp, other)2829compmap = {"<": operator.lt, "<=": operator.le, "==": operator.eq,30">": operator.gt, ">=": operator.ge, "!=": operator.ne}3132class VersionPredicate:33"""Parse and test package version predicates.3435>>> v = VersionPredicate('pyepat.abc (>1.0, <3333.3a1, !=1555.1b3)')3637The `name` attribute provides the full dotted name that is given::3839>>> v.name40'pyepat.abc'4142The str() of a `VersionPredicate` provides a normalized43human-readable version of the expression::4445>>> print(v)46pyepat.abc (> 1.0, < 3333.3a1, != 1555.1b3)4748The `satisfied_by()` method can be used to determine with a given49version number is included in the set described by the version50restrictions::5152>>> v.satisfied_by('1.1')53True54>>> v.satisfied_by('1.4')55True56>>> v.satisfied_by('1.0')57False58>>> v.satisfied_by('4444.4')59False60>>> v.satisfied_by('1555.1b3')61False6263`VersionPredicate` is flexible in accepting extra whitespace::6465>>> v = VersionPredicate(' pat( == 0.1 ) ')66>>> v.name67'pat'68>>> v.satisfied_by('0.1')69True70>>> v.satisfied_by('0.2')71False7273If any version numbers passed in do not conform to the74restrictions of `StrictVersion`, a `ValueError` is raised::7576>>> v = VersionPredicate('p1.p2.p3.p4(>=1.0, <=1.3a1, !=1.2zb3)')77Traceback (most recent call last):78...79ValueError: invalid version number '1.2zb3'8081It the module or package name given does not conform to what's82allowed as a legal module or package name, `ValueError` is83raised::8485>>> v = VersionPredicate('foo-bar')86Traceback (most recent call last):87...88ValueError: expected parenthesized list: '-bar'8990>>> v = VersionPredicate('foo bar (12.21)')91Traceback (most recent call last):92...93ValueError: expected parenthesized list: 'bar (12.21)'9495"""9697def __init__(self, versionPredicateStr):98"""Parse a version predicate string.99"""100# Fields:101# name: package name102# pred: list of (comparison string, StrictVersion)103104versionPredicateStr = versionPredicateStr.strip()105if not versionPredicateStr:106raise ValueError("empty package restriction")107match = re_validPackage.match(versionPredicateStr)108if not match:109raise ValueError("bad package name in %r" % versionPredicateStr)110self.name, paren = match.groups()111paren = paren.strip()112if paren:113match = re_paren.match(paren)114if not match:115raise ValueError("expected parenthesized list: %r" % paren)116str = match.groups()[0]117self.pred = [splitUp(aPred) for aPred in str.split(",")]118if not self.pred:119raise ValueError("empty parenthesized list in %r"120% versionPredicateStr)121else:122self.pred = []123124def __str__(self):125if self.pred:126seq = [cond + " " + str(ver) for cond, ver in self.pred]127return self.name + " (" + ", ".join(seq) + ")"128else:129return self.name130131def satisfied_by(self, version):132"""True if version is compatible with all the predicates in self.133The parameter version must be acceptable to the StrictVersion134constructor. It may be either a string or StrictVersion.135"""136for cond, ver in self.pred:137if not compmap[cond](version, ver):138return False139return True140141142_provision_rx = None143144def split_provision(value):145"""Return the name and optional version number of a provision.146147The version number, if given, will be returned as a `StrictVersion`148instance, otherwise it will be `None`.149150>>> split_provision('mypkg')151('mypkg', None)152>>> split_provision(' mypkg( 1.2 ) ')153('mypkg', StrictVersion ('1.2'))154"""155global _provision_rx156if _provision_rx is None:157_provision_rx = re.compile(158r"([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$",159re.ASCII)160value = value.strip()161m = _provision_rx.match(value)162if not m:163raise ValueError("illegal provides specification: %r" % value)164ver = m.group(2) or None165if ver:166with distutils.version.suppress_known_deprecation():167ver = distutils.version.StrictVersion(ver)168return m.group(1), ver169170171