diff options
author | Elena ``of Valhalla'' Grandi <valhalla@trueelena.org> | 2020-10-01 22:26:48 +0200 |
---|---|---|
committer | Elena ``of Valhalla'' Grandi <valhalla@trueelena.org> | 2020-10-01 22:26:48 +0200 |
commit | 5e045d665f5057d3111939c1fa13133e53d7fb8d (patch) | |
tree | 2d0a9c3018baca10ffe18d636a1de861743f61dc | |
parent | 83b92c51a863c09946c3da55b0b53490027bf723 (diff) |
More types
-rw-r--r-- | lesana/types.py | 46 | ||||
-rw-r--r-- | setup.py | 1 | ||||
-rw-r--r-- | tests/test_types.py | 54 |
3 files changed, 101 insertions, 0 deletions
diff --git a/lesana/types.py b/lesana/types.py index db6b661..4d3910c 100644 --- a/lesana/types.py +++ b/lesana/types.py @@ -4,8 +4,11 @@ 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 datetime import decimal +import dateutil.parser + class LesanaType: """ @@ -100,6 +103,49 @@ class LesanaDecimal(LesanaType): return decimal.Decimal(0) +class LesanaTimestamp(LesanaType): + """ + A datetime + """ + name = "timestamp" + + def load(self, data): + if not data: + return data + if isinstance(data, datetime.datetime) or \ + isinstance(data, datetime.date): + return data + try: + return dateutil.parser.parse(data) + except dateutil.parser.ParserError: + raise LesanaValueError( + "Invalid value for datetime field: {}".format(data) + ) + + def empty(self): + return None + + +class LesanaBoolean(LesanaType): + """ + A boolean value + """ + name = 'boolean' + + def load(self, data): + if not data: + return data + if isinstance(data, bool): + return data + else: + raise LesanaValueError( + "Invalid value for boolean field: {}".format(data) + ) + + def empty(self): + return None + + class LesanaValueError(ValueError): """ Raised in case of validation errors. @@ -20,6 +20,7 @@ setup( # 'xapian >= 1.4', 'ruamel.yaml', 'jinja2', + 'dateutil', ], python_requires='>=3', # Metadata diff --git a/tests/test_types.py b/tests/test_types.py index 7aff73f..cc2ff3b 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,3 +1,4 @@ +import datetime import decimal import unittest @@ -11,6 +12,16 @@ class testTypes(unittest.TestCase): def tearDown(self): pass + def test_base(self): + checker = types.LesanaType() + + # The base class does not implement empty nor load + with self.assertRaises(NotImplementedError): + checker.empty() + + with self.assertRaises(NotImplementedError): + checker.load("") + def test_string(self): checker = types.LesanaString() @@ -98,6 +109,49 @@ class testTypes(unittest.TestCase): v = checker.load(None) self.assertEqual(v, None) + def test_timestamp(self): + checker = types.LesanaTimestamp() + + v = checker.empty() + self.assertEqual(v, None) + + now = datetime.datetime.now() + v = checker.load(now) + self.assertEqual(v, now) + + today = datetime.date.today() + v = checker.load(today) + self.assertEqual(v, today) + + v = checker.load("2020-01-01") + self.assertEqual(v, datetime.datetime(2020, 1, 1)) + + v = checker.load("2020-01-01 10:00") + self.assertEqual(v, datetime.datetime(2020, 1, 1, 10, 0)) + + for d in ("today", "2020-13-01"): + with self.assertRaises(types.LesanaValueError): + checker.load(d) + + v = checker.load(None) + self.assertEqual(v, None) + + def test_boolean(self): + checker = types.LesanaBoolean() + + v = checker.empty() + self.assertEqual(v, None) + + v = checker.load(True) + self.assertEqual(v, True) + + for d in ("maybe", "yes", "no"): + with self.assertRaises(types.LesanaValueError): + checker.load(d) + + v = checker.load(None) + self.assertEqual(v, None) + if __name__ == '__main__': unittest.main() |