handle none or unset attribute in BoundaryConstraint

example: Date(constraints=[BoundaryConstraint('<=', Attribute('end_date'))]) if end_date is not defined, the constraint is satisfied

Date(constraints=[BoundaryConstraint('<=', None))]) if the constraint limit is none, the constraint is satisfied

Closes #288556

authorErica Marco <erica.marco@logilab.fr>
changeset53c8caa43cc0
branchdefault
phasepublic
hiddenno
parent revision#9a7c7df423ca [schema2sql] properly consider skip_relations parameters. Closes #286912
child revision#9e0e59671d5f [constraints] provide proper comparison and hashability between constraints
files modified by this revision
constraints.py
test/unittest_constraints.py
# HG changeset patch
# User Erica Marco <erica.marco@logilab.fr>
# Date 1426601974 -3600
# Tue Mar 17 15:19:34 2015 +0100
# Node ID 53c8caa43cc0ef55a254300ec20427e6bf4b70fb
# Parent 9a7c7df423caeac7fc6068a0d9b5b95cd0010267
handle none or unset attribute in BoundaryConstraint

example:
Date(constraints=[BoundaryConstraint('<=', Attribute('end_date'))])
if end_date is not defined, the constraint is satisfied

Date(constraints=[BoundaryConstraint('<=', None))])
if the constraint limit is none, the constraint is satisfied


Closes #288556

diff --git a/constraints.py b/constraints.py
@@ -237,10 +237,12 @@
1                                        "final entity type")
2 
3      def check(self, entity, rtype, value):
4          """return true if the value satisfies the constraint, else false"""
5          boundary = actual_value(self.boundary, entity)
6 +        if boundary is None:
7 +            return True
8          return OPERATORS[self.operator](value, boundary)
9 
10      def failed_message(self, key, value):
11          return _("value %(KEY-value)s must be %(KEY-op)s %(KEY-boundary)s"), {
12              key+'-value': value,
diff --git a/test/unittest_constraints.py b/test/unittest_constraints.py
@@ -104,20 +104,25 @@
13          self.assertTrue(cstr2.check(mock_object(hop=date.today()), 'hip', date.today()))
14          # fail, value > maxvalue
15          self.assertFalse(cstr2.check(mock_object(hop=date.today()),
16                                  'hip', date.today() + timedelta(days=1)))
17 
18 -
19      def test_bound_with_date(self):
20          cstr = BoundaryConstraint('<=', TODAY())
21          cstr2 = BoundaryConstraint.deserialize(cstr.serialize())
22          self.assertEqual(cstr2.boundary.offset, None)
23          self.assertEqual(cstr2.operator, '<=')
24          self.assertTrue(cstr2.check(None, 'hip', date.today()))
25          # fail, value > maxvalue
26          self.assertFalse(cstr2.check(None, 'hip', date.today() + timedelta(days=1)))
27 
28 +    def test_bound_with_unset_attribute(self):
29 +        cstr = BoundaryConstraint('<=', None)
30 +        self.assertTrue(cstr.check(None, 'hip', date.today()))
31 +        cstr = BoundaryConstraint('<=', Attribute('unset_attr'))
32 +        self.assertTrue(cstr.check(mock_object(unset_attr=None), 'hip', date.today()))
33 +
34      def test_vocab_constraint_serialization(self):
35          cstr = StaticVocabularyConstraint(['a, b', 'c'])
36          self.assertEqual(StaticVocabularyConstraint.deserialize(cstr.serialize()).values,
37                           ('a, b', 'c'))
38