From b75c00bf5a7f650ff53a407b47a96407ac277d8e Mon Sep 17 00:00:00 2001 From: Elena ``of Valhalla'' Grandi Date: Fri, 2 Oct 2020 09:07:49 +0200 Subject: Add date and datetime types, enforce timestamps to be unix timestamps --- docs/field_types.rst | 4 ++++ lesana/types.py | 51 +++++++++++++++++++++++++++++++++++++++++++--- tests/test_types.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 3 deletions(-) diff --git a/docs/field_types.rst b/docs/field_types.rst index baf2c5e..81e86ab 100644 --- a/docs/field_types.rst +++ b/docs/field_types.rst @@ -14,6 +14,10 @@ decimal: . timestamp: . +datetime: + . +date: + . boolean: . file: diff --git a/lesana/types.py b/lesana/types.py index 4d3910c..e5c556c 100644 --- a/lesana/types.py +++ b/lesana/types.py @@ -105,16 +105,39 @@ class LesanaDecimal(LesanaType): class LesanaTimestamp(LesanaType): """ - A datetime + A unix timestamp """ name = "timestamp" def load(self, data): if not data: return data - if isinstance(data, datetime.datetime) or \ - isinstance(data, datetime.date): + if isinstance(data, datetime.datetime): + return data + try: + return datetime.datetime.fromtimestamp(int(data)) + except (TypeError, ValueError): + raise LesanaValueError( + "Invalid value for timestamp field: {}".format(data) + ) + + def empty(self): + return None + + +class LesanaDatetime(LesanaType): + """ + A datetime + """ + name = "datetime" + + def load(self, data): + if not data: + return data + if isinstance(data, datetime.datetime): return data + if isinstance(data, datetime.date): + return datetime.datetime(data.year, data.month, data.day) try: return dateutil.parser.parse(data) except dateutil.parser.ParserError: @@ -126,6 +149,28 @@ class LesanaTimestamp(LesanaType): return None +class LesanaDate(LesanaType): + """ + A date + """ + name = "date" + + def load(self, data): + if not data: + return data + if isinstance(data, datetime.date): + return data + try: + return dateutil.parser.parse(data) + except dateutil.parser.ParserError: + raise LesanaValueError( + "Invalid value for date field: {}".format(data) + ) + + def empty(self): + return None + + class LesanaBoolean(LesanaType): """ A boolean value diff --git a/tests/test_types.py b/tests/test_types.py index cc2ff3b..2d6b744 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -119,6 +119,63 @@ class testTypes(unittest.TestCase): v = checker.load(now) self.assertEqual(v, now) + v = checker.load("1600000000") + self.assertEqual(v, datetime.datetime(2020, 9, 13, 14, 26, 40)) + + today = datetime.date.today() + for d in ( + today, + "today", + "2020-13-01", "2020-01-01", + "2020-01-01 10:00" + ): + with self.assertRaises(types.LesanaValueError): + checker.load(d) + + v = checker.load(None) + self.assertEqual(v, None) + + def test_datetime(self): + checker = types.LesanaDatetime() + + 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.assertIsInstance(v, datetime.datetime) + for part in ('year', 'month', 'day'): + self.assertEqual(getattr(v, part), getattr(today, part)) + + 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_date(self): + checker = types.LesanaDate() + + v = checker.empty() + self.assertEqual(v, None) + + now = datetime.datetime.now() + v = checker.load(now) + self.assertIsInstance(v, datetime.date) + for part in ('year', 'month', 'day'): + self.assertEqual(getattr(v, part), getattr(now, part)) + today = datetime.date.today() v = checker.load(today) self.assertEqual(v, today) -- cgit v1.2.3