Source code for versions.packages

import re

from .requirements import Requirement
from .version import Version
from .compat import basestring
from .errors import Error
from .operators import gt
from .constraints import Constraints
from .constraint import Constraint
from .version import Version


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 __ne__(self, other): return not (self == other) def __eq__(self, other): if isinstance(other, basestring): 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) @property def upgrade_requirement(self): # create a copy of current version version = Version(self.version.major, self.version.minor, self.version.patch, self.version.prerelease, self.version.build_metadata) # strip the build metadata version.build_metadata = None constraint = Constraint(gt, version) return Requirement(self.name, Constraints([constraint]), self.build_options) @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)