def meets_requirements(version, requirements): # type: (str, str) -> bool """Verify if a given version satisfies all the requirements. Supported version identifiers are: * '==' * '!=' * '>' * '>=' * '<' * '<=' * '*' Each requirement is delimited by ','. """ op_map = { '!=': operator.ne, '==': operator.eq, '=': operator.eq, '>=': operator.ge, '>': operator.gt, '<=': operator.le, '<': operator.lt, } for req in requirements.split(','): op_pos = 2 if len(req) > 1 and req[1] == '=' else 1 op = op_map.get(req[:op_pos]) requirement = req[op_pos:] if not op: requirement = req op = operator.eq if requirement == '*' or version == '*': continue if not op( SemanticVersion(version), SemanticVersion.from_loose_version(LooseVersion(requirement)), ): break else: return True # The loop was broken early, it does not meet all the requirements return False
from collections.abc import Set try: from resolvelib import AbstractProvider from resolvelib import __version__ as resolvelib_version except ImportError: class AbstractProvider: # type: ignore[no-redef] pass resolvelib_version = '0.0.0' # TODO: add python requirements to ansible-test's ansible-core distribution info and remove the hardcoded lowerbound/upperbound fallback RESOLVELIB_LOWERBOUND = SemanticVersion("0.5.3") RESOLVELIB_UPPERBOUND = SemanticVersion("0.6.0") RESOLVELIB_VERSION = SemanticVersion.from_loose_version( LooseVersion(resolvelib_version)) class PinnedCandidateRequests(Set): """Custom set class to store Candidate objects. Excludes the 'signatures' attribute when determining if a Candidate instance is in the set.""" CANDIDATE_ATTRS = ('fqcn', 'ver', 'src', 'type') def __init__(self, candidates): self._candidates = set(candidates) def __iter__(self): return iter(self._candidates) def __contains__(self, value): if not isinstance(value, Candidate): raise ValueError(f"Expected a Candidate object but got {value!r}")
def test_from_loose_version(value, expected): assert SemanticVersion.from_loose_version(value) == expected