diff --git a/CHANGELOG b/CHANGELOG index 75f9d0f56f..063aaf0d4f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Support PYSON comparison of date and datetime * Add cron task to clean old queue tasks * Add option to run cron once * Add defaults option to route diff --git a/trytond/pyson.py b/trytond/pyson.py index 0d2c54f2f2..601323e70a 100644 --- a/trytond/pyson.py +++ b/trytond/pyson.py @@ -302,11 +302,15 @@ class Greater(PYSON): super(Greater, self).__init__() for i in (statement1, statement2): if isinstance(i, PYSON): - assert i.types().issubset({int, float, type(None)}), \ - 'statement must be an integer or a float' + assert i.types().issubset({ + int, float, type(None), + datetime.datetime, datetime.date}), \ + 'statement must be an integer, float, date or datetime' else: - assert isinstance(i, (int, float, type(None))), \ - 'statement must be an integer or a float' + assert isinstance(i, ( + int, float, type(None), + datetime.datetime, datetime.date)), \ + 'statement must be an integer, float, date or datetime' if isinstance(equal, PYSON): if equal.types() != {bool}: equal = Bool(equal) @@ -338,11 +342,19 @@ class Greater(PYSON): dct[i] = 0.0 if not isinstance(dct[i], (int, float)): dct = dct.copy() - dct[i] = float(dct[i]) + stmt = dct[i] + if isinstance(stmt, datetime.datetime): + stmt = stmt.timestamp() + elif isinstance(stmt, datetime.date): + time = datetime.time(0, 0) + stmt = datetime.datetime.combine(stmt, time).timestamp() + dct[i] = float(stmt) return dct @staticmethod def eval(dct, context): + if dct['s1'] is None or dct['s2'] is None: + return False dct = Greater._convert(dct) if dct['e']: return dct['s1'] >= dct['s2'] @@ -359,6 +371,8 @@ class Less(Greater): @staticmethod def eval(dct, context): + if dct['s1'] is None or dct['s2'] is None: + return False dct = Less._convert(dct) if dct['e']: return dct['s1'] <= dct['s2'] diff --git a/trytond/tests/test_pyson.py b/trytond/tests/test_pyson.py index 1e1773c2bd..66aae94eb5 100644 --- a/trytond/tests/test_pyson.py +++ b/trytond/tests/test_pyson.py @@ -226,6 +226,10 @@ class PYSONTestCase(unittest.TestCase): self.assertRaises(AssertionError, pyson.Greater, 1, 'test') self.assertRaises( AssertionError, pyson.Greater, pyson.Eval('foo'), 0) + self.assertRaises(AssertionError, pyson.Greater, + 'test', pyson.DateTime()) + self.assertRaises(AssertionError, pyson.Greater, + pyson.DateTime(), 'test') self.assertEqual(pyson.Greater(1, 0).types(), set([bool])) @@ -251,10 +255,54 @@ class PYSONTestCase(unittest.TestCase): self.assertFalse(pyson.PYSONDecoder().decode(eval)) eval = pyson.PYSONEncoder().encode(pyson.Greater(1, None)) - self.assertTrue(pyson.PYSONDecoder().decode(eval)) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) self.assertEqual(repr(pyson.Greater(1, 0)), 'Greater(1, 0, False)') + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + datetime.date(2020, 1, 2))) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 1), + datetime.date(2020, 1, 1))) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + datetime.date(2020, 1, 1), True)) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0))) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.Date(2020, 1, 1), + datetime.date(2020, 1, 1))) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.Date(2020, 1, 1), + pyson.DateTime(2020, 1, 1, 0, 0, 0, 1))) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.DateTime(2020, 1, 1, 0, 0, 1), + pyson.Date(2020, 1, 1), True)) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + pyson.Date(2020, 1, 1), True)) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Greater( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), 90000)) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + eval = pyson.PYSONEncoder().encode( pyson.Greater(pyson.Eval('i', 0), 0)) self.assertTrue(pyson.PYSONDecoder({'i': 1}).decode(eval)) @@ -271,6 +319,10 @@ class PYSONTestCase(unittest.TestCase): if not sys.flags.optimize: self.assertRaises(AssertionError, pyson.Less, 'test', 1) self.assertRaises(AssertionError, pyson.Less, 0, 'test') + self.assertRaises(AssertionError, pyson.Less, + 'test', pyson.DateTime()) + self.assertRaises(AssertionError, pyson.Less, + pyson.DateTime(), 'test') self.assertEqual(pyson.Less(0, 1).types(), set([bool])) @@ -293,13 +345,47 @@ class PYSONTestCase(unittest.TestCase): self.assertTrue(pyson.PYSONDecoder().decode(eval)) eval = pyson.PYSONEncoder().encode(pyson.Less(None, 1)) - self.assertTrue(pyson.PYSONDecoder().decode(eval)) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) eval = pyson.PYSONEncoder().encode(pyson.Less(1, None)) self.assertFalse(pyson.PYSONDecoder().decode(eval)) self.assertEqual(repr(pyson.Less(0, 1)), 'Less(0, 1, False)') + eval = pyson.PYSONEncoder().encode(pyson.Less( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + datetime.date(2020, 1, 1))) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Less( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + datetime.date(2020, 1, 2), True)) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Less( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0))) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Less( + pyson.Date(2020, 1, 1), + datetime.date(2020, 1, 2))) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Less( + pyson.Date(2020, 1, 1), + pyson.DateTime(2020, 1, 1, 0, 0, 0, 1))) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Less( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), + pyson.Date(2020, 1, 1), True)) + self.assertTrue(pyson.PYSONDecoder().decode(eval)) + + eval = pyson.PYSONEncoder().encode(pyson.Less( + pyson.DateTime(2020, 1, 1, 0, 0, 0, 0), 90000)) + self.assertFalse(pyson.PYSONDecoder().decode(eval)) + def test_If(self): 'Test pyson.If' self.assertEqual(pyson.If(True, 'foo', 'bar').pyson(), {