Advertisement
andreymal

Cerberus i18n and customization

Dec 9th, 2017
804
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.93 KB | None | 0 0
  1. import copy
  2. import cerberus
  3. from cerberus import errors as cerrors
  4. from flask_babel import lazy_gettext
  5.  
  6.  
  7. class CustomErrorHandler(cerberus.errors.BasicErrorHandler):
  8.     messages = cerberus.errors.BasicErrorHandler.messages.copy()
  9.     messages.update({
  10.         cerrors.REQUIRED_FIELD.code: lazy_gettext("Required field"),
  11.         cerrors.UNKNOWN_FIELD.code: lazy_gettext("Unknown field"),
  12.         cerrors.DEPENDENCIES_FIELD.code: lazy_gettext("Field '{0}' is required"),
  13.         cerrors.DEPENDENCIES_FIELD_VALUE.code: lazy_gettext("Depends on these values: {constraint}"),
  14.         cerrors.EXCLUDES_FIELD.code: lazy_gettext("{0} must not be present with '{field}'"),
  15.  
  16.         cerrors.EMPTY_NOT_ALLOWED.code: lazy_gettext("Field should not be empty"),
  17.         cerrors.NOT_NULLABLE.code: lazy_gettext("Field should not be empty"),
  18.         cerrors.BAD_TYPE.code: lazy_gettext("Must be of {constraint} type"),
  19.         cerrors.ITEMS_LENGTH.code: lazy_gettext("Length of list should be {constraint}, it is {0}"),
  20.         cerrors.MIN_LENGTH.code: lazy_gettext("Min length is {constraint}"),
  21.         cerrors.MAX_LENGTH.code: lazy_gettext("Max length is {constraint}"),
  22.  
  23.         cerrors.REGEX_MISMATCH.code: lazy_gettext("Value does not match regex '{constraint}'"),
  24.         cerrors.MIN_VALUE.code: lazy_gettext("Min value is {constraint}"),
  25.         cerrors.MAX_VALUE.code: lazy_gettext("Max value is {constraint}"),
  26.         cerrors.UNALLOWED_VALUE.code: lazy_gettext("Unallowed value {value}"),
  27.         cerrors.UNALLOWED_VALUES.code: lazy_gettext("Unallowed values {0}"),
  28.         cerrors.FORBIDDEN_VALUE.code: lazy_gettext("Unallowed value {value}"),
  29.         cerrors.FORBIDDEN_VALUES.code: lazy_gettext("Unallowed values {0}"),
  30.  
  31.         cerrors.COERCION_FAILED.code: lazy_gettext("Field '{field}' cannot be coerced"),
  32.         cerrors.RENAMING_FAILED.code: lazy_gettext("Field '{field}' cannot be renamed"),
  33.         cerrors.READONLY_FIELD.code: lazy_gettext("Field is read-only"),
  34.         cerrors.SETTING_DEFAULT_FAILED.code: lazy_gettext("Default value for '{field}' cannot be set: {0}"),
  35.  
  36.         cerrors.MAPPING_SCHEMA.code: lazy_gettext("Mapping doesn't validate subschema: {0}"),
  37.         cerrors.SEQUENCE_SCHEMA.code: lazy_gettext("One or more sequence-items don't validate: {0}"),
  38.         cerrors.KEYSCHEMA.code: lazy_gettext("One or more properties of a mapping  don't validate: {0}"),
  39.         cerrors.VALUESCHEMA.code: lazy_gettext("One or more values in a mapping don't validate: {0}"),
  40.  
  41.         cerrors.NONEOF.code: lazy_gettext("One or more definitions validate"),
  42.         cerrors.ONEOF.code: lazy_gettext("None or more than one rule validate"),
  43.         cerrors.ANYOF.code: lazy_gettext("No definitions validate"),
  44.         cerrors.ALLOF.code: lazy_gettext("One or more definitions don't validate"),
  45.     })
  46.  
  47.     def __init__(self, tree=None, custom_messages=None):
  48.         super().__init__(tree)
  49.         self.custom_messages = custom_messages or {}
  50.  
  51.     def format_message(self, field, error):
  52.         tmp = self.custom_messages
  53.         for i, x in enumerate(error.schema_path):
  54.             try:
  55.                 tmp = tmp[x]
  56.             except KeyError:
  57.                 if i == len(error.schema_path) - 1 and 'any' in tmp:
  58.                     return tmp['any']
  59.                 return super().format_message(field, error)
  60.         if isinstance(tmp, dict):
  61.             return super().format_message(field, error)
  62.         else:
  63.             return tmp
  64.  
  65.  
  66. class Validator(cerberus.Validator):
  67.     """Usage:
  68.    schema = {"name": {"minlength": 2, "error_messages": {"minlength": "Custom too few"}}}
  69.    v = Validator(schema)
  70.    v.validate({"q": "0"})  # => False
  71.    v.errors  # => {'q': ['Custom too few']}
  72.    """
  73.  
  74.     def __init__(self, *args, **kwargs):
  75.         if args:
  76.             if 'schema' in kwargs:
  77.                 raise TypeError("got multiple values for argument 'schema'")
  78.             schema = args[0]
  79.         else:
  80.             schema = kwargs.pop('schema')
  81.  
  82.         if isinstance(schema, dict):
  83.             schema = copy.deepcopy(schema)
  84.             self.populate_custom_messages(schema)
  85.             args = [schema] + list(args[1:])
  86.  
  87.         kwargs['error_handler'] = CustomErrorHandler(custom_messages=self.custom_messages)
  88.         if 'purge_unknown' not in kwargs:
  89.             kwargs['purge_unknown'] = True
  90.         super().__init__(*args, **kwargs)
  91.         self.custom_messages = {}
  92.         self._allowed_func_caches = {}
  93.  
  94.     def populate_custom_messages(self, schema):
  95.         self.custom_messages = {}
  96.         queue = [(schema, self.custom_messages)]
  97.         while queue:
  98.             item, msgs = queue.pop()
  99.             if 'error_messages' in item:
  100.                 assert isinstance(item['error_messages'], dict)
  101.                 msgs.update(item.pop('error_messages'))
  102.             for k, v in item.items():
  103.                 if isinstance(v, dict):
  104.                     msgs[k] = {}
  105.                     queue.append((v, msgs[k]))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement