Commits

Andriy Kornatskyy  committed f22815c

Refactor rules to support __slots__.

  • Participants
  • Parent commits 3a2a052

Comments (0)

Files changed (1)

File src/wheezy/validation/rules.py

 class RequiredRule(object):
     """ Any value evaluated to boolean ``True`` pass this rule.
     """
+    __slots__ = ('message_template')
 
     def __init__(self, message_template=None):
         self.message_template = message_template or _(
 class MissingRule(object):
     """ Any value evaluated to boolean ``False`` pass this rule.
     """
+    __slots__ = ('message_template')
 
     def __init__(self, message_template=None):
         self.message_template = message_template or _(
     """ Result of python function ``len()`` must fall within a range
         defined by this rule.
     """
+    __slots__ = ('validate', 'min', 'max', 'message_template')
 
     def __init__(self, min=None, max=None, message_template=None):
         """
             strategy.
 
             >>> r = LengthRule(min=2)
-            >>> assert r.check == r.check_min
+            >>> assert r.validate == r.check_min
             >>> r = LengthRule(max=2)
-            >>> assert r.check == r.check_max
+            >>> assert r.validate == r.check_max
             >>> r = LengthRule()
-            >>> assert r.check == r.succeed
+            >>> assert r.validate == r.succeed
             >>> r = LengthRule(min=1, max=2)
         """
         if min:
             self.min = min
             if not max:
                 self.min = min
-                self.check = self.check_min
+                self.validate = self.check_min
                 self.message_template = message_template or _(
                         'Required to be a minimum of %(min)d characters'
                         ' in length.')
             else:
                 self.max = max
+                self.validate = self.check
                 self.message_template = message_template or _(
                         'The length must fall within the range %(min)d'
                         ' - %(max)d characters.')
         else:
             if max:
                 self.max = max
-                self.check = self.check_max
+                self.validate = self.check_max
                 self.message_template = message_template or _(
                         'Exceeds maximum length of %(max)d.')
             else:
-                self.check = self.succeed
+                self.validate = self.succeed
 
     def succeed(self, value, name, model, result, gettext):
-        return True
-
-    def check_min(self, value, name, model, result, gettext):
-        if len(value) < self.min:
-            result.append(gettext(self.message_template)
-                    % {'min': self.min})
-            return False
-        return True
-
-    def check_max(self, value, name, model, result, gettext):
-        if len(value) > self.max:
-            result.append(gettext(self.message_template)
-                    % {'max': self.max})
-            return False
-        return True
-
-    def check(self, value, name, model, result, gettext):
-        l = len(value)
-        if l < self.min or l > self.max:
-            result.append(gettext(self.message_template)
-                    % {'min': self.min, 'max': self.max})
-            return False
-        return True
-
-    def validate(self, value, name, model, result, gettext):
         """
             >>> r = LengthRule()
 
 
             >>> r.validate('abc', None, None, None, _)
             True
+        """
+        return True
 
-            ``check_min`` strategy fails
+    def check_min(self, value, name, model, result, gettext):
+        """ ``check_min`` strategy fails
 
             >>> result = []
             >>> r = LengthRule(min=2, message_template='min %(min)d')
 
             >>> result = []
             >>> r = LengthRule(min=2)
+            >>> r.validate(None, None, None, result, _)
+            True
             >>> r.validate('ab', None, None, result, _)
             True
             >>> result
             []
+        """
+        if value is None:
+            return True
+        if len(value) < self.min:
+            result.append(gettext(self.message_template)
+                    % {'min': self.min})
+            return False
+        return True
 
-            ``check_max`` strategy fails
+    def check_max(self, value, name, model, result, gettext):
+        """ ``check_max`` strategy fails
 
             >>> result = []
             >>> r = LengthRule(max=2, message_template='max %(max)d')
 
             >>> result = []
             >>> r = LengthRule(max=2)
+            >>> r.validate(None, None, None, result, _)
+            True
             >>> r.validate('ab', None, None, result, _)
             True
             >>> result
             []
+        """
+        if value is None:
+            return True
+        if len(value) > self.max:
+            result.append(gettext(self.message_template)
+                    % {'max': self.max})
+            return False
+        return True
 
-            ``check`` strategy fails
+    def check(self, value, name, model, result, gettext):
+        """ ``check`` strategy fails
 
             >>> r = LengthRule(min=2, max=3,
             ...         message_template='range %(min)d-%(max)d')
 
             >>> result = []
             >>> r = LengthRule(min=1, max=2)
+            >>> r.validate(None, None, None, result, _)
+            True
             >>> r.validate('ab', None, None, result, _)
             True
             >>> result
 
             >>> assert length is LengthRule
         """
-        return value is None or self.check(value, name, model,
-                result, gettext)
+        if value is None:
+            return True
+        l = len(value)
+        if l < self.min or l > self.max:
+            result.append(gettext(self.message_template)
+                    % {'min': self.min, 'max': self.max})
+            return False
+        return True
 
 
 class CompareRule(object):
     """ Compares attribute being validated with some other attribute value.
     """
+    __slots__ = ('validate', 'comparand', 'message_template')
 
     def __init__(self, equal=None, not_equal=None, message_template=None):
         """
             strategy.
 
             >>> r = CompareRule(equal='confirm_password')
-            >>> assert r.check == r.check_equal
+            >>> assert r.validate == r.check_equal
 
             >>> r = CompareRule(not_equal='other')
-            >>> assert r.check == r.check_not_equal
+            >>> assert r.validate == r.check_not_equal
         """
         if equal:
             self.comparand = equal
-            self.check = self.check_equal
+            self.validate = self.check_equal
             self.message_template = message_template or _(
                     'The value failed equality comparison'
                     ' with "%(comparand)s".')
         elif not_equal:
             self.comparand = not_equal
-            self.check = self.check_not_equal
+            self.validate = self.check_not_equal
             self.message_template = message_template or _(
                     'The value failed not equal comparison'
                     ' with "%(comparand)s".')
+        else:
+            self.validate = self.check
 
     def check(self, value, name, model, result, gettext):
-        return True
-
-    def check_equal(self, value, name, model, result, gettext):
-        getter = ref_getter(model)
-        comparand_value = getter(model, self.comparand)
-        if value != comparand_value:
-            result.append(gettext(self.message_template)
-                    % {'comparand': self.comparand})
-            return False
-        return True
-
-    def check_not_equal(self, value, name, model, result, gettext):
-        getter = ref_getter(model)
-        comparand_value = getter(model, self.comparand)
-        if value == comparand_value:
-            result.append(gettext(self.message_template)
-                    % {'comparand': self.comparand})
-            return False
-        return True
-
-    def validate(self, value, name, model, result, gettext):
         """
             No any comparer selected
 
             >>> r = CompareRule()
             >>> r.validate('abc', None, None, None, _)
             True
+        """
+        return True
 
+    def check_equal(self, value, name, model, result, gettext):
+        """
             ``check_equal`` strategy succeed.
 
             >>> result = []
             >>> result = []
             >>> r.validate('z', None, model, result, _)
             False
+        """
+        getter = ref_getter(model)
+        comparand_value = getter(model, self.comparand)
+        if value != comparand_value:
+            result.append(gettext(self.message_template)
+                    % {'comparand': self.comparand})
+            return False
+        return True
 
-            ``check_not_equal`` strategy succeed.
+    def check_not_equal(self, value, name, model, result, gettext):
+        """ ``check_not_equal`` strategy succeed.
 
             >>> result = []
             >>> r = CompareRule(not_equal='previous_password')
             >>> r.validate('x', None, model, result, _)
             False
         """
-        return self.check(value, None, model, result, gettext)
+        getter = ref_getter(model)
+        comparand_value = getter(model, self.comparand)
+        if value == comparand_value:
+            result.append(gettext(self.message_template)
+                    % {'comparand': self.comparand})
+            return False
+        return True
 
 
 class RegexRule(object):
     """ Search for regular expression pattern.
     """
+    __slots__ = ('validate', 'regex', 'message_template')
 
     def __init__(self, regex=None, negated=False, message_template=None):
         """
         """
             >>> result = []
             >>> r = RegexRule(r'\d+')
+            >>> r.validate(None, None, None, result, _)
+            True
             >>> r.validate('1234', None, None, result, _)
             True
             >>> r.validate('x', None, None, result, _)
             False
         """
+        if value is None:
+            return True
         if not self.regex.search(value):
             result.append(gettext(self.message_template))
             return False
         """
             >>> result = []
             >>> r = RegexRule(r'\d+', negated=True)
+            >>> r.validate(None, None, None, result, _)
+            True
+            >>> r.validate('x', None, None, result, _)
+            True
             >>> r.validate('1234', None, None, result, _)
             False
-            >>> r.validate('x', None, None, result, _)
-            True
         """
+        if value is None:
+            return True
         if self.regex.search(value):
             result.append(gettext(self.message_template))
             return False
         >>> r.validate('x%', None, None, result, _)
         False
     """
+    __slots__ = ()
 
     def __init__(self, message_template=None):
         super(SlugRule, self).__init__(r'^[-\w]+$', False,
         >>> r.validate('x%', None, None, result, _)
         False
     """
+    __slots__ = ()
 
     def __init__(self, message_template=None):
         super(EmailRule, self).__init__(
         >>> r.validate(Decimal('20'), None, None, result, _)
         False
     """
+    __slots__ = ('validate', 'min', 'max', 'message_template')
 
     def __init__(self, min=None, max=None, message_template=None):
         """
             strategy.
 
             >>> r = RangeRule(min=2)
-            >>> assert r.check == r.check_min
+            >>> assert r.validate == r.check_min
             >>> r = RangeRule(max=2)
-            >>> assert r.check == r.check_max
+            >>> assert r.validate == r.check_max
             >>> r = RangeRule()
-            >>> assert r.check == r.succeed
+            >>> assert r.validate == r.succeed
             >>> r = RangeRule(min=1, max=2)
         """
         if min:
             self.min = min
             if not max:
                 self.min = min
-                self.check = self.check_min
+                self.validate = self.check_min
                 self.message_template = message_template or _(
                         'Required to be greater or equal to %(min)s.')
             else:
                 self.max = max
+                self.validate = self.check
                 self.message_template = message_template or _(
                         'The value must fall within the range %(min)s'
                         ' - %(max)s')
         else:
             if max:
                 self.max = max
-                self.check = self.check_max
+                self.validate = self.check_max
                 self.message_template = message_template or _(
                         'Exceeds maximum allowed value of %(max)s.')
             else:
-                self.check = self.succeed
+                self.validate = self.succeed
 
     def succeed(self, value, name, model, result, gettext):
-        return True
-
-    def check_min(self, value, name, model, result, gettext):
-        if value < self.min:
-            result.append(gettext(self.message_template)
-                    % {'min': self.min})
-            return False
-        return True
-
-    def check_max(self, value, name, model, result, gettext):
-        if value > self.max:
-            result.append(gettext(self.message_template)
-                    % {'max': self.max})
-            return False
-        return True
-
-    def check(self, value, name, model, result, gettext):
-        if value < self.min or value > self.max:
-            result.append(gettext(self.message_template)
-                    % {'min': self.min, 'max': self.max})
-            return False
-        return True
-
-    def validate(self, value, name, model, result, gettext):
         """
             >>> r = RangeRule()
 
 
             >>> r.validate(100, None, None, None, _)
             True
+        """
+        return True
 
-            ``check_min`` strategy fails
+    def check_min(self, value, name, model, result, gettext):
+        """ ``check_min`` strategy fails
 
             >>> result = []
             >>> r = RangeRule(min=10, message_template='min %(min)s')
 
             >>> result = []
             >>> r = RangeRule(min=10)
+            >>> r.validate(None, None, None, result, _)
+            True
             >>> r.validate(10, None, None, result, _)
             True
             >>> result
             []
+        """
+        if value is None:
+            return True
+        if value < self.min:
+            result.append(gettext(self.message_template)
+                    % {'min': self.min})
+            return False
+        return True
 
-            ``check_max`` strategy fails
+    def check_max(self, value, name, model, result, gettext):
+        """ ``check_max`` strategy fails
 
             >>> result = []
             >>> r = RangeRule(max=10, message_template='max %(max)s')
 
             >>> result = []
             >>> r = RangeRule(max=10)
+            >>> r.validate(None, None, None, result, _)
+            True
             >>> r.validate(10, None, None, result, _)
             True
             >>> result
             []
+        """
+        if value is None:
+            return True
+        if value > self.max:
+            result.append(gettext(self.message_template)
+                    % {'max': self.max})
+            return False
+        return True
 
-            ``check`` strategy fails
+    def check(self, value, name, model, result, gettext):
+        """ ``check`` strategy fails
 
             >>> r = RangeRule(min=2, max=3,
             ...         message_template='range %(min)s-%(max)s')
 
             >>> result = []
             >>> r = RangeRule(min=1, max=2)
+            >>> r.validate(None, None, None, result, _)
+            True
             >>> r.validate(2, None, None, result, _)
             True
             >>> result
 
             >>> assert length is LengthRule
         """
-        return value is None or self.check(value, name, model,
-                result, gettext)
+        if value is None:
+            return True
+        if value < self.min or value > self.max:
+            result.append(gettext(self.message_template)
+                    % {'min': self.min, 'max': self.max})
+            return False
+        return True
 
 
 class AndRule(object):
         >>> len(result)
         2
     """
+    __slots__ = ('rules')
 
     def __init__(self, *rules):
         """ Initializes rule by converting ``rules`` to tuple.
         """
+        assert len(rules) > 1
         self.rules = tuple(rules)
 
     def validate(self, value, name, model, result, gettext):
         >>> len(result)
         2
     """
+    __slots__ = ('rules')
 
     def __init__(self, *rules):
         """ Initializes rule by converting ``rules`` to tuple.
         """
+        assert len(rules) > 1
         self.rules = tuple(rules)
 
     def validate(self, value, name, model, result, gettext):
 
         >>> result = []
         >>> r = iterator([required, range(1, 5)])
+        >>> r.validate(None, None, None, result, _)
+        True
         >>> r.validate([1, 2, 3], None, None, result, _)
         True
         >>> r.validate([1, 7], None, None, result, _)
         False
     """
+    __slots__ = ('rules', 'stop')
 
     def __init__(self, rules, stop=True):
         """ Initializes rule by converting ``rules`` to tuple.
         """
+        assert rules
         self.rules = tuple(rules)
         self.stop = stop
 
 
             ``value`` - iteratable.
         """
+        if value is None:
+            return True
         succeed = True
         for rule in self.rules:
             for item in value:
     """ Value must match at least one element from ``items``.
 
         >>> result = []
-        >>> r = one_of([1, 2, 3])
+        >>> r = one_of([1, 2, 3, None])
         >>> r.validate(3, None, None, result, _)
         True
+        >>> r.validate(None, None, None, result, _)
+        True
         >>> r.validate(7, None, None, result, _)
         False
+        >>> r = one_of([1, 2, 3])
+        >>> r.validate(None, None, None, result, _)
+        False
     """
+    __slots__ = ('items', 'message_template')
 
     def __init__(self, items, message_template=None):
         """
             ...
         NotImplementedError: ...
     """
+    __slots__ = ('validate', 'min', 'max', 'message_template')
 
     def __init__(self, min=None, max=None, message_template=None):
         """
             self.min = min
             if not max:
                 self.min = min
-                self.check = self.check_min
+                self.validate = self.check_min
                 self.message_template = message_template or _(
                         'Required to be above a minimum allowed.')
             else:
                 self.max = max
+                self.validate = self.check
                 self.message_template = message_template or _(
                         'Must fall within a valid range.')
         else:
             if max:
                 self.max = max
-                self.check = self.check_max
+                self.validate = self.check_max
                 self.message_template = message_template or _(
                         'Exceeds maximum allowed.')
             else:
-                self.check = self.succeed
+                self.validate = self.succeed
 
     def now(self):
         raise NotImplementedError('Subclasses must override method now()')
         return True
 
     def check_min(self, value, name, model, result, gettext):
+        if value is None:
+            return True
         if value < self.now() + self.min:
             result.append(gettext(self.message_template)
                     % {'min': self.min})
         return True
 
     def check_max(self, value, name, model, result, gettext):
+        if value is None:
+            return True
         if value > self.now() + self.max:
             result.append(gettext(self.message_template)
                     % {'max': self.max})
         return True
 
     def check(self, value, name, model, result, gettext):
+        if value is None:
+            return True
         now = self.now()
         if value < now + self.min or value > now + self.max:
             result.append(gettext(self.message_template)
             return False
         return True
 
-    def validate(self, value, name, model, result, gettext):
-        """
-        """
-        return value is None or self.check(value, name, model,
-                result, gettext)
-
 
 class RelativeDateDeltaRule(RelativeDeltaRule):
     """
         >>> from datetime import timedelta
         >>> result = []
         >>> r = relative_date(min=timedelta(days=-7))
+        >>> r.validate(None, None, None, result, _)
+        True
         >>> r.validate(date.today(), None, None, result, _)
         True
         >>> d = date.today() - timedelta(days=8)
         Max range strategy
 
         >>> r = relative_date(max=timedelta(days=7))
+        >>> r.validate(None, None, None, result, _)
+        True
         >>> r.validate(date.today(), None, None, result, _)
         True
         >>> d = date.today() + timedelta(days=8)
 
         >>> result = []
         >>> r = relative_date(min=timedelta(days=-7), max=timedelta(days=7))
+        >>> r.validate(None, None, None, result, _)
+        True
         >>> r.validate(date.today(), None, None, result, _)
         True
         >>> d = date.today() - timedelta(days=8)
         >>> r.validate(d, None, None, result, _)
         False
     """
+    __slots__ = ()
 
     def now(self):
         return date.today()
         >>> r.validate(d, None, None, result, _)
         False
     """
+    __slots__ = ()
 
     def now(self):
         return datetime.now()
 
 
 required = RequiredRule()
-missing = optional = MissingRule()
+missing = optional = empty = MissingRule()
 length = LengthRule
 compare = CompareRule
 regex = RegexRule