Source code for versions.requirements

import re

from .errors import Error
from .constraints import Constraints


class InvalidRequirement(Error):
    """Raised when trying to add a requirement with a different package name.
    """
    def __init__(self, requirement):
        #: The bogus requirement
        self.requirement = requirement
        message = 'Invalid requirement: %s' % requirement
        super(InvalidRequirement, self).__init__(message)


class InvalidRequirementExpression(Error):
    """Raised when trying to add a requirement with a different package name.
    """
    def __init__(self, requirement_expression):
        #: The bogus requirement expression
        self.requirement_expression = requirement_expression
        message = 'Invalid requirement expression: %s' % requirement_expression
        super(InvalidRequirementExpression, self).__init__(message)


# Regular expression user to parse package requirements.
RE = re.compile("""
^
\s*
(?P<name>[A-Za-z0-9_\-]+)
\s*
(?:
    \[
    \s*
    (?P<build_metadata>[A-Za-z0-9_\-, ]+)
    \s*
    \]
)?
\s*
(?P<version_constraints>[A-Za-z0-9_\-,!=\>\<\. ]+)*
\s*
$
""", re.X)


[docs]class Requirement(object): """Package requirements are used to define a dependency from a :class:`Package` to another. :param str name: The required package name. :param version_constraints: Constraints on the package version. :type version_constraints: :class:`Version` or ``None`` :param build_options: Required build options. :type build_options: ``set`` of ``str`` or ``None`` """ def __init__(self, name, version_constraints=None, build_options=None): #: Name of the required package. self.name = name #: :class:`Constraints` on the required package version. self.version_constraints = version_constraints #: `set` of required build options self.build_options = build_options def __hash__(self): build_options_h = hash(tuple(self.build_options) if self.build_options else None) return hash(self.name) ^ hash(self.version_constraints) ^ \ build_options_h def __eq__(self, other): if isinstance(other, str): try: other = Requirement.parse(other) except Error: return False return hash(self) == hash(other) def __str__(self): version_constraints = \ self.version_constraints if self.version_constraints else '' if self.build_options: build_options = '[' + ','.join(sorted(self.build_options)) + ']' else: build_options = '' return '%s%s%s' % (self.name, build_options, version_constraints) def __repr__(self): return 'Requirement.parse(%r)' % str(self) def __add__(self, requirement): if isinstance(requirement, str): requirement = Requirement.parse(requirement) if self.name != requirement.name: raise InvalidRequirement(requirement) if self.version_constraints is None: version_constraints = requirement.version_constraints elif requirement.version_constraints is None: version_constraints = self.version_constraints else: version_constraints = \ self.version_constraints + requirement.version_constraints if self.build_options is None: build_options = requirement.build_options elif requirement.build_options is None: build_options = self.build_options else: build_options = self.build_options | requirement.build_options return Requirement(self.name, version_constraints, build_options)
[docs] def match(self, package): """Match ``package`` with the requirement. :param package: Package to test with the requirement. :type package: package expression string or :class:`Package` :returns: ``True`` if ``package`` satisfies the requirement. :rtype: bool """ if isinstance(package, str): from .packages import Package package = Package.parse(package) if self.name != package.name: return False if self.version_constraints and \ package.version not in self.version_constraints: return False if self.build_options: if package.build_options: if self.build_options - package.build_options: return False else: return True else: return False else: return True
__contains__ = match @classmethod
[docs] def parse(cls, requirement_expression): """Parses a :ref:`requirement_expression <requirement-expressions>` into a :class:`Requirement` object. :param requirement_expression: A package requirement expression. :type requirement_expression: \ :ref:`requirement_expression <requirement-expressions>` :rtype: :class:`Requirement` """ match = RE.match(requirement_expression) if match: name, build_metadata, version_constraints_str = match.groups() if version_constraints_str: version_constraints = \ Constraints.parse(version_constraints_str) else: version_constraints = None if build_metadata: build_options = \ set(o.strip() for o in build_metadata.split(',')) else: build_options = None return cls(name, version_constraints, build_options) else: raise InvalidRequirementExpression(requirement_expression)