diff options
-rw-r--r-- | lesana/types.py | 98 | ||||
-rw-r--r-- | tests/test_types.py | 88 |
2 files changed, 186 insertions, 0 deletions
diff --git a/lesana/types.py b/lesana/types.py new file mode 100644 index 0000000..e093c9f --- /dev/null +++ b/lesana/types.py @@ -0,0 +1,98 @@ +""" +Type checkers for lesana fields. + +Warning: this part of the code is still in flux and it may change +significantly in a future release. +""" +import decimal + + +class LesanaType: + """ + Base class for lesana field types. + """ + def load(self, data): + raise NotImplementedError + + def empty(self): + raise NotImplementedError + + +class LesanaString(LesanaType): + """ + A string of unicode text + """ + name = 'string' + + def load(self, data): + return str(data) + + def empty(self): + return "" + + +class LesanaText(LesanaString): + """ + A longer block of unicode text + """ + name = 'text' + + +class LesanaInt(LesanaType): + """ + An integer number + """ + name = "integer" + + def load(self, data): + try: + return int(data) + except ValueError: + raise LesanaValueError( + "Invalid value for integer field: {}".format(data) + ) + + def empty(self): + return 0 + + +class LesanaFloat(LesanaType): + """ + A floating point number + """ + name = "float" + + def load(self, data): + try: + return float(data) + except ValueError: + raise LesanaValueError( + "Invalid value for float field: {}".format(data) + ) + + def empty(self): + return 0.0 + + +class LesanaDecimal(LesanaType): + """ + A floating point number + """ + name = "float" + + def load(self, data): + try: + return decimal.Decimal(data) + except decimal.InvalidOperation: + raise LesanaValueError( + "Invalid value for float field: {}".format(data) + ) + + def empty(self): + return decimal.Decimal(0) + + +class LesanaValueError(ValueError): + """ + Raised in case of validation errors. + """ diff --git a/tests/test_types.py b/tests/test_types.py new file mode 100644 index 0000000..907be20 --- /dev/null +++ b/tests/test_types.py @@ -0,0 +1,88 @@ +import decimal +import unittest + +from lesana import types + + +class testTypes(unittest.TestCase): + def setUp(self): + pass + + def tearDown(self): + pass + + def test_string(self): + checker = types.LesanaString() + + s = checker.empty() + self.assertEqual(s, "") + + s = checker.load("Hello World!") + self.assertEqual(s, "Hello World!") + + def test_text(self): + checker = types.LesanaText() + + s = checker.empty() + self.assertEqual(s, "") + + s = checker.load("Hello World!") + self.assertEqual(s, "Hello World!") + + def test_int(self): + checker = types.LesanaInt() + + v = checker.empty() + self.assertEqual(v, 0) + + v = checker.load("10") + self.assertEqual(v, 10) + + v = checker.load(10.5) + self.assertEqual(v, 10) + + for d in ("ten", "10.5"): + with self.assertRaises(types.LesanaValueError): + checker.load(d) + + def test_float(self): + checker = types.LesanaFloat() + + v = checker.empty() + self.assertEqual(v, 0.0) + + v = checker.load("10") + self.assertEqual(v, 10) + + v = checker.load(10.5) + self.assertEqual(v, 10.5) + + v = checker.load("10.5") + self.assertEqual(v, 10.5) + + for d in ("ten"): + with self.assertRaises(types.LesanaValueError): + checker.load(d) + + def test_decimal(self): + checker = types.LesanaDecimal() + + v = checker.empty() + self.assertEqual(v, decimal.Decimal(0)) + + v = checker.load("10") + self.assertEqual(v, decimal.Decimal(10)) + + v = checker.load(10.5) + self.assertEqual(v, decimal.Decimal(10.5)) + + v = checker.load("10.5") + self.assertEqual(v, decimal.Decimal(10.5)) + + for d in ("ten"): + with self.assertRaises(types.LesanaValueError): + checker.load(d) + + +if __name__ == '__main__': + unittest.main() |