Commits

Andriy Kornatskyy committed 7b653c7

Added support for nested validator (an object validator for attribute)

Comments (0)

Files changed (1)

src/wheezy/validation/validator.py

 """
 
 from wheezy.validation.comp import iteritems
-from wheezy.validation.comp import iterkeys
 from wheezy.validation.comp import null_translations
 from wheezy.validation.comp import ref_gettext
 from wheezy.validation.comp import ref_getter
     """ Container of validation rules that all together provide
         object validation.
     """
+    __SLOTS__ = ['rules', 'inner']
+
     def __init__(self, mapping):
-        self.mapping = mapping
+        # Split mapping by one that holds iteratable of rules and
+        # the other with nested validator
+        rules = []
+        inner = []
+        for (name, value) in iteritems(mapping):
+            if hasattr(value, '__iter__'):
+                rules.append((name, tuple(value)))
+            else:
+                inner.append((name, value))
+        self.rules = tuple(rules)
+        self.inner = tuple(inner)
 
-    def validate(self, model, results, stop=True, translations=None):
+    def validate(self, model, results, stop=True, translations=None,
+            gettext=None):
         """
             Here is a class and object we are going to validate.
 
             >>> len(results['name'])
             2
 
+            You can nest other validator for composite objects
+
+            >>> class Registration(object):
+            ...     user = User()
+            >>> registration_validator = Validator({
+            ...         'user': v
+            ... })
+            >>> r = Registration()
+            >>> registration_validator.validate(r, results)
+            False
+
             Validation succeed
 
             >>> user.name = 'abcde'
             True
             >>> results
             {}
+            >>> r.user.name = 'abcde'
+            >>> registration_validator.validate(r, results)
+            True
 
             Validatable can be a dict.
 
             >>> v.validate(user, results)
             False
         """
-        if translations is None:
-            translations = null_translations
-        gettext = ref_gettext(translations)
+        if gettext is None:
+            if translations is None:
+                translations = null_translations
+            gettext = ref_gettext(translations)
         succeed = True
         getter = ref_getter(model)
-        for (name, rules) in iteritems(self.mapping):
+        for name, rules in self.rules:
             value = getter(model, name)
             result = []
             for rule in rules:
                     break
             if result:
                 results[name] = result
+        for name, validator in self.inner:
+            value = getter(model, name)
+            succeed &= validator.validate(value, results, stop,
+                                        gettext=gettext)
         return succeed