summaryrefslogtreecommitdiff
path: root/linaropy/vers.py
diff options
context:
space:
mode:
Diffstat (limited to 'linaropy/vers.py')
-rw-r--r--linaropy/vers.py615
1 files changed, 615 insertions, 0 deletions
diff --git a/linaropy/vers.py b/linaropy/vers.py
new file mode 100644
index 0000000..6126a01
--- /dev/null
+++ b/linaropy/vers.py
@@ -0,0 +1,615 @@
+import unittest
+import logging
+
+# Abstract baseclass for Vendor and Package that provides some basic
+# typechecking.
+class PV(object):
+ def __init__(self, pv=None):
+ if isinstance(pv, basestring):
+ self.pv=pv
+ else:
+ raise TypeError("Input to PV must be of type basestring.")
+
+ def __str__(self):
+ return self.pv
+
+ def lower(self):
+ return self.pv.lower()
+
+class Vendor(PV):
+ def __init__(self, vendor="Linaro"):
+ try:
+ super(Vendor,self).__init__(vendor)
+ except TypeError:
+ raise TypeError("Input 'vendor' must be of type basestring.")
+
+class Version(object):
+ # @major - required int or str representation of int.
+ # @minor - optional int or str representation of int, otherwise None.
+ # If None, then minor will not be output.
+ # @point - optional int or str representation of int, otherwise None.
+ # If None, then point will not be output.
+ def __init__(self, major, minor=None, point=None):
+
+ if isinstance(major, int) or isinstance(major, basestring):
+ # This will throw an exception if 'major' is an empty string.
+ self.major=int(major)
+ else:
+ raise TypeError("major must be of type int, string.")
+
+ if isinstance(minor, int) or isinstance(minor, basestring):
+ # This will throw an exception if 'minor' is an empty string.
+ self.minor=int(minor)
+ elif not minor:
+ self.minor=None
+ else:
+ raise TypeError("minor must be of type int, string, or None.")
+
+ if isinstance(point, int) or isinstance(point, basestring):
+
+ # This is illegal, as it'd mess up the output and make it look like
+ # there's a minor that's really a point.
+ if not minor and point:
+ raise RuntimeError("minor must be specified if point is specified.")
+
+ # This will throw an exception if 'minor' is an empty string.
+ self.point=int(point)
+ elif not point:
+ self.point=None
+ else:
+ raise TypeError("point must be of type int, string, or None.")
+
+ def __str__(self):
+ ver=str(self.major)
+ if self.minor:
+ ver=ver + u'.' + str(self.minor)
+ if self.point:
+ ver=ver + u'.' + str(self.point)
+ return ver
+
+ # TODO: I'm sure there's a more pythonic way to do this but this is
+ # quick and dirty.
+ # %M - Major
+ # %m - Minor
+ # %p - Point
+ # delimiter - Delimiter character to use in output: space or dash.
+ # TODO: Use a dictionary with replace
+ def strfversion(self, formatstr, delimiter='.'):
+ toks=[str(x) for x in formatstr.split('%') if x.strip()]
+
+ delstoks=len(toks)
+ verstoks=0
+
+ if self.major:
+ verstoks=verstoks+1
+ if self.minor:
+ verstoks=verstoks+1
+ if self.point:
+ verstoks=verstoks+1
+
+ if delstoks > verstoks:
+ numtoks=verstoks - 1
+ else:
+ numtoks=delstoks - 1
+
+ vers=u''
+ for tok in toks:
+ if tok == 'M':
+ vers=vers + str(self.major)
+ elif tok == 'm':
+ vers=vers + str(self.minor)
+ elif tok == 'p':
+ vers=vers + str(self.point)
+ if numtoks > 0:
+ vers=vers + delimiter
+ numtoks=numtoks-1
+ return vers
+
+# Helper function which returns a Version.
+def versionFromStr(version):
+ if not isinstance(version, basestring):
+ raise TypeError('input must be of type basestring')
+
+ major=version.split('.', 1)[0]
+
+ # split('.',1) will return index error on "5" but will return empty string on "5."
+ # Any empty string is not a valid input into Version.
+ if major == u'':
+ major=None
+
+ try:
+ minor=version.split('.', 2)[1]
+ except IndexError:
+ minor=None
+
+ if minor == u'':
+ minor=None
+
+ try:
+ point=version.split('.', 3)[2]
+ except IndexError:
+ point=None
+
+ if point == u'':
+ point=None
+
+ return Version(major, minor, point)
+
+class Package(PV):
+ # @package - default = GCC
+ # @version - required. Either a string representing a version or a Version
+ # instance.
+ def __init__(self, package="GCC", version=None):
+ #TODO: Make sure package is not None.
+ if package == u'':
+ raise TypeError("Package must not be an empty string")
+
+ # TODO: Provide a list of known inputs and test against those?
+ try:
+ super(Package,self).__init__(package)
+ except TypeError:
+ raise TypeError("Input 'package' must be of type basestring.")
+
+ if not version:
+ raise RuntimeError("Package requires a version.")
+ elif isinstance(version, Version):
+ self.version=version
+ else:
+ self.version=versionFromStr(version)
+
+ def get_package(self):
+ return super(Package,self).__str__()
+
+ def get_version(self):
+ return str(self.version)
+
+ def __str__(self):
+ return super(Package,self).__str__() + u'-' + str(self.version)
+
+ def lower(self):
+ return super(Package,self).lower() + u'-' + str(self.version)
+
+ #TODO: Create format function which can change the separator to ' ' or to '-'.
+
+def packageFromStr(package=None):
+ if not isinstance(package, basestring):
+ raise TypeError('packageFromStr requires a string as input')
+
+ # Get the part before the version numbers. That's the package
+ try:
+ package_name=package.rsplit('-', 1)[0]
+ except IndexError:
+ raise RuntimeError('string must be <package_name>-<package_version>')
+
+ try:
+ package_version=package.rsplit('-', 1)[1]
+ except IndexError:
+ raise RuntimeError('string must be <package_name>-<package_version>')
+
+ if package_name == u'':
+ raise TypeError("Couldn't parse a package name from input string")
+ if package_version == u'':
+ raise TypeError("Couldn't parse a package version from input string")
+
+ # This will throw exceptions if the input are malformed.
+ package=Package(package_name, package_version)
+ return package
+
+class Vers(object):
+ def __init__(self, val=None):
+
+ if val is None:
+ self.val=0
+ return
+
+ if isinstance(val, int) or isinstance(val, basestring):
+ # This should raise an exception if the string can't be converted
+ # to an int. If val is already an int it's a nop.
+ intval=int(val)
+
+ if intval < 0:
+ raise ValueError('Input val must not be negative')
+ self.val=intval
+ else:
+ raise TypeError("Input val must be of type int or string.")
+
+ def increment(self):
+ self.val=self.val+1
+
+ # Return the "-<val>" string or an empty string.
+ def __str__(self):
+ # Don't return
+ if self.val is None or self.val == 0:
+ return ""
+ else:
+ return "-" + str(self.val)
+
+class Spin(Vers):
+ def __init__(self, spin=None):
+ try:
+ super(Spin,self).__init__(spin)
+ except ValueError:
+ raise ValueError('Input spin must not be negative')
+
+class Rc(Vers):
+ def __init__(self, rc=None):
+ try:
+ super(Rc,self).__init__(rc)
+ except ValueError:
+ raise ValueError('Input rc must not be negative')
+
+ # The string representation differs slighty from Spin
+ def __str__(self):
+ # Don't return
+ if self.val is None or self.val == 0:
+ return ""
+ else:
+ return "-rc" + str(self.val)
+
+class TestVersion(unittest.TestCase):
+ def test_no_major(self):
+ with self.assertRaises(TypeError):
+ version=Version(major=None)
+ with self.assertRaises(TypeError):
+ version=Version()
+
+ def test_empty_major(self):
+ with self.assertRaises(ValueError):
+ version=Version(major="")
+
+ def test_empty_minor(self):
+ with self.assertRaises(ValueError):
+ version=Version(major=5, minor="")
+
+ def test_empty_point(self):
+ with self.assertRaises(ValueError):
+ version=Version(major=5, minor=3, point="")
+
+ def test_non_int_major(self):
+ with self.assertRaises(ValueError):
+ version=Version('A')
+
+ def test_int_major(self):
+ version=Version(5)
+ self.assertEqual(str(version), "5")
+ version2=Version(major=5)
+ self.assertEqual(str(version2), "5")
+
+ def test_intstr_major(self):
+ version=Version("5")
+ self.assertEqual(str(version), "5")
+ version2=Version(major="5")
+ self.assertEqual(str(version2), "5")
+
+ def test_non_int_minor(self):
+ with self.assertRaises(ValueError):
+ version=Version(major="5", minor="A")
+
+ def test_int_minor(self):
+ version=Version(major=5, minor=3)
+ self.assertEqual(str(version), "5.3")
+
+ def test_intstr_minor(self):
+ version=Version(major="5", minor="3")
+ self.assertEqual(str(version), "5.3")
+
+ def test_no_minor(self):
+ version=Version(major="5", minor=None)
+ self.assertEqual(str(version), "5")
+
+ def test_point_no_minor(self):
+ with self.assertRaises(RuntimeError):
+ version=Version(major=5, minor=None, point=1)
+
+ def test_int_point(self):
+ version=Version(major=5, minor=3, point=1)
+ self.assertEqual(str(version), "5.3.1")
+
+ def test_non_int_point(self):
+ with self.assertRaises(ValueError):
+ version=Version(major=5, minor=3, point="A")
+
+ def test_intstr_point(self):
+ version=Version(major="5", minor="3", point="1")
+ self.assertEqual(str(version), "5.3.1")
+
+ def test_no_point(self):
+ version=Version(major="5", minor="3", point=None)
+ self.assertEqual(str(version), "5.3")
+
+ def test_strfversion(self):
+ version=Version(major="5", minor="3", point="1")
+ self.assertEqual(version.strfversion("%M%m%p", delimiter='-'),"5-3-1")
+ self.assertEqual(version.strfversion("%M%m%p"),"5.3.1")
+
+class TestVendor(unittest.TestCase):
+ def test_vendor_default(self):
+ vendor=Vendor()
+ self.assertEqual(str(vendor), "Linaro")
+ self.assertEqual(vendor.lower(), "linaro")
+
+ def test_none_input(self):
+ with self.assertRaises(TypeError):
+ vendor=Vendor(vendor=None)
+
+ def test_str_input(self):
+ vendor=Vendor("TestVendor")
+ self.assertEqual(str(vendor), "TestVendor")
+ self.assertEqual(vendor.lower(), "testvendor")
+
+class TestPackage(unittest.TestCase):
+
+ def test_package_no_version(self):
+ with self.assertRaises(RuntimeError):
+ # We require a version.
+ package=Package()
+
+ def test_package_default(self):
+ package=Package(version="5.3.1")
+ self.assertEqual(str(package), "GCC-5.3.1")
+ self.assertEqual(package.lower(), "gcc-5.3.1")
+ self.assertEqual(package.pv, "GCC")
+
+ def test_none_package(self):
+ with self.assertRaises(TypeError):
+ package=Package(package=None, version="5.3.1")
+
+ def test_none_version(self):
+ with self.assertRaises(RuntimeError):
+ package=Package(package="GCC", version=None)
+
+ def test_with_Version(self):
+ version=Version(5,3,1)
+ package=Package(version=version)
+ self.assertEqual(str(package), "GCC-5.3.1")
+ self.assertEqual(package.lower(), "gcc-5.3.1")
+
+ def test_package_version(self):
+ version=Version(5,3,1)
+ package=Package(version=version)
+ self.assertEqual(str(package.version), "5.3.1")
+ self.assertEqual(package.get_version(), "5.3.1")
+ self.assertEqual(package.get_package(), "GCC")
+
+ def test_str_input(self):
+ package=Package("TestPackage", version="5.3.1")
+ self.assertEqual(str(package), "TestPackage-5.3.1")
+ self.assertEqual(package.lower(), "testpackage-5.3.1")
+
+ def test_empty_package_name(self):
+ with self.assertRaises(TypeError):
+ package=Package(package="", version="5.3.1")
+
+class TestSpin(unittest.TestCase):
+
+ def test_spin_val(self):
+ spin=Spin(1)
+ self.assertEqual(spin.val, 1)
+
+ def test_spin_val_str(self):
+ spin=Spin(1)
+ self.assertEqual(str(spin), "-1")
+
+ def test_spin_increment_val(self):
+ spin=Spin(1)
+ spin.increment()
+ self.assertEqual(spin.val, 2)
+
+ def test_spin_increment_str(self):
+ spin=Spin(1)
+ spin.increment()
+ self.assertEqual(str(spin), "-2")
+
+ def test_zero_spin(self):
+ spin=Spin(0)
+ self.assertEqual(spin.val, 0)
+
+ def test_zero_spin_str(self):
+ spin=Spin(0)
+ self.assertEqual(str(spin), "")
+
+ def test_none_spin(self):
+ spin=Spin(None)
+ self.assertEqual(spin.val, 0)
+
+ def test_none_spin_increment(self):
+ spin=Spin(None)
+ spin.increment()
+ self.assertEqual(spin.val, 1)
+
+ def test_none_spin_str(self):
+ spin=Spin(None)
+ self.assertEqual(str(spin), "")
+
+ def test_default_spin(self):
+ spin=Spin()
+ self.assertEqual(spin.val, 0)
+
+ def test_default_spin_str(self):
+ spin=Spin()
+ self.assertEqual(str(spin), "")
+
+ def test_negative_val(self):
+ with self.assertRaises(ValueError):
+ spin=Spin(-1)
+
+ def test_default_spin_str(self):
+ spin=Spin()
+ self.assertEqual(str(spin), "")
+
+ def test_spin_string_input(self):
+ spin=Spin("9")
+ self.assertEqual(spin.val, 9)
+ self.assertEqual(str(spin), "-9")
+
+ def test_spin_negative_string_input(self):
+ with self.assertRaises(ValueError):
+ spin=Spin("-9")
+
+ def test_float_type(self):
+ with self.assertRaises(TypeError):
+ spin=Spin(7.0)
+
+class TestRc(unittest.TestCase):
+ def test_rc_val(self):
+ rc=Rc(1)
+ self.assertEqual(rc.val, 1)
+
+ def test_rc_str(self):
+ rc=Rc(1)
+ self.assertEqual(str(rc), "-rc1")
+
+ def test_negative_val(self):
+ with self.assertRaises(ValueError):
+ rc=Rc(-1)
+
+ def test_zero_rc_str(self):
+ rc=Rc(0)
+ self.assertEqual(str(rc), "")
+
+ def test_none_rc_str(self):
+ rc=Rc(None)
+ self.assertEqual(str(rc), "")
+
+ def test_default_rc_str(self):
+ rc=Rc()
+ self.assertEqual(str(rc), "")
+
+ def test_rc_increment_val(self):
+ rc=Rc(1)
+ rc.increment()
+ self.assertEqual(rc.val, 2)
+
+ def test_rc_increment_str(self):
+ rc=Rc(1)
+ rc.increment()
+ self.assertEqual(str(rc), "-rc2")
+
+ def test_none_rc_increment_str(self):
+ rc=Rc(None)
+ rc.increment()
+ self.assertEqual(str(rc), "-rc1")
+
+ def test_default_rc_str(self):
+ rc=Rc()
+ self.assertEqual(str(rc), "")
+
+ def test_rc_string_input(self):
+ rc=Rc("9")
+ self.assertEqual(rc.val, 9)
+ self.assertEqual(str(rc), "-rc9")
+
+ def test_rc_negative_string_input(self):
+ with self.assertRaises(ValueError):
+ rc=Rc("-9")
+
+ def test_float_type(self):
+ with self.assertRaises(TypeError):
+ rc=Rc(7.0)
+
+class TestPackageFromString(unittest.TestCase):
+
+ def test_none(self):
+ with self.assertRaises(TypeError):
+ package=packageFromStr(package=None)
+
+ def test_with_package(self):
+ package=Package("GCC", "5.3.1")
+ with self.assertRaises(TypeError):
+ package=packageFromStr(package=package)
+
+ def test_with_no_package_name(self):
+ with self.assertRaises(TypeError):
+ package=packageFromStr(package="-5.3.1")
+
+ with self.assertRaises(RuntimeError):
+ package=packageFromStr(package="5.3.1")
+
+ def test_with_no_package_version(self):
+ with self.assertRaises(TypeError):
+ package=packageFromStr(package="GCC-")
+
+ with self.assertRaises(RuntimeError):
+ package=packageFromStr(package="GCC")
+
+ def test_with_space(self):
+ with self.assertRaises(RuntimeError):
+ package=packageFromStr(package="GCC 5.3.1")
+
+ def test_correct_usage(self):
+ package=packageFromStr(package="GCC-5.3.1")
+ self.assertEqual(str(package), "GCC-5.3.1")
+ self.assertEqual(package.lower(), "gcc-5.3.1")
+ self.assertEqual(package.pv, "GCC")
+ self.assertEqual(str(package.version), "5.3.1")
+ self.assertEqual(package.version.major, 5)
+ self.assertEqual(package.version.minor, 3)
+ self.assertEqual(package.version.point, 1)
+
+class TestVersionFromStr(unittest.TestCase):
+
+ def test_extra_dot(self):
+ version=versionFromStr("5.3.1.4")
+ self.assertEqual(version.major, 5)
+ self.assertEqual(version.minor, 3)
+ self.assertEqual(version.point, 1)
+
+ def test_major_minor_point(self):
+ version=versionFromStr("5.3.1")
+ self.assertEqual(version.major, 5)
+ self.assertEqual(version.minor, 3)
+ self.assertEqual(version.point, 1)
+
+ def test_major_minor_dot(self):
+ version=versionFromStr("5.3.")
+ self.assertEqual(version.major, 5)
+ self.assertEqual(version.minor, 3)
+ self.assertEqual(version.point, None)
+
+ def test_major_minor(self):
+ version=versionFromStr("5.3")
+ self.assertEqual(version.major, 5)
+ self.assertEqual(version.minor, 3)
+ self.assertEqual(version.point, None)
+
+ def test_major_dot(self):
+ version=versionFromStr("5.")
+ self.assertEqual(version.major, 5)
+ self.assertEqual(version.minor, None)
+ self.assertEqual(version.point, None)
+
+ def test_major(self):
+ version=versionFromStr("5")
+ self.assertEqual(version.major, 5)
+ self.assertEqual(version.minor, None)
+ self.assertEqual(version.point, None)
+
+ def test_empty(self):
+ with self.assertRaises(TypeError):
+ version=versionFromStr("")
+
+ def test_non_int_major(self):
+ with self.assertRaises(ValueError):
+ version=versionFromStr("a.b.c")
+
+ def test_non_int_minor(self):
+ with self.assertRaises(ValueError):
+ version=versionFromStr("5.b.1")
+
+ def test_non_int_point(self):
+ with self.assertRaises(ValueError):
+ version=versionFromStr("5.3.a")
+
+ def test_non_string(self):
+ version=Version(5,3,1)
+ with self.assertRaises(TypeError):
+ version=versionFromStr(version)
+
+ def test_none(self):
+ with self.assertRaises(TypeError):
+ version=versionFromStr(version=None)
+
+if __name__ == '__main__':
+ #logging.basicConfig(level="INFO")
+ unittest.main()
+