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)