Source code for versions.packages

import re

from .requirements import Requirement
from .version import Version
from .compat import cmp
from .errors import Error


RE = re.compile(r"""
^
\s*
(?P<name>[A-Za-z0-9_\-]+)
\s*
-
\s*
(?P<version>
    # major version number
    \d+
    (?:
        \.
        # minor version number
        \d+
        (?:
            \.
            # patch version number
            \d+
        )?
    )?
    (?:
        -
        # pre-release version number
        [0-9a-zA-Z.-]*
    )?
    (?:
        \+
        # build metadata
        [0-9a-zA-Z.-]*
    )?
)
\s*
$
""", re.X)


class InvalidPackageExpression(Error):
    """Raised failing to parse a package expression.
    """
    def __init__(self, expression):
        self.expression = expression
        message = 'Invalid package expression: %s' % expression
        super(InvalidPackageExpression, self).__init__(message)


class InvalidPackageInfo(Error):
    """Raised failing to parse a package expression info.
    """
    def __init__(self, info):
        self.info = info
        message = 'Invalid package expression info: %s' % info
        super(InvalidPackageInfo, self).__init__(message)


[docs]class Package(object): """A package. :param str name: Package name. :param version: Package version. :type version: :class:`Version` """ def __init__(self, name, version, dependencies=None): #: Package name. self.name = name #: Package version. self.version = version #: ``set`` of :class:`Requirement` objects self.dependencies = dependencies or set() @property
[docs] def build_options(self): """The package build options. :returns: :func:`set` of build options strings. """ if self.version.build_metadata: return set(self.version.build_metadata.split('.')) else: return set()
def __hash__(self): return hash(self.name) ^ hash(self.version) def __eq__(self, other): if isinstance(other, str): other = Package.parse(other) return self.name == other.name and self.version == other.version and \ self.build_options == other.build_options def __lt__(self, other): if self.name < other.name: return True elif self.version < other.version: return True else: return False def __str__(self): if self.dependencies: dependencies = ';depends ' + \ ';depends '.join(sorted(map(str, self.dependencies))) else: dependencies = '' return '%s-%s%s' % (self.name, self.version, dependencies) def __repr__(self): return 'Package.parse(%r)' % str(self) @classmethod
[docs] def parse(self, package_expression): """Parse a ``package_expression`` into a :class:`Package` object. """ parts = re.split(r'\s*;\s*', package_expression) name_ver_str = parts[0] infos = parts[1:] dependencies = set() name_ver_match = RE.match(name_ver_str) if not name_ver_match: raise InvalidPackageExpression(name_ver_str) name, version_str = name_ver_match.groups() version = Version.parse(version_str) for info in infos: if info.startswith('depends '): dependency_str = info.split(' ', 1)[1] dependency = Requirement.parse(dependency_str) dependencies.add(dependency) else: raise InvalidPackageInfo(info) return Package(name, version, dependencies)