How do I return a custom rule-name/error-code usin

2019-07-23 12:48发布

问题:

Am validating .csv file and I want to give the results of the validation in a format the user is accustomed to. To make use of Cerberus, I've let the user to define the validation rules in a .yaml file.

schema.yaml

Rules:
 Rule1:
  maxlength: 10

 Rule2:
  allowed: ["MO", "TU", "WE", "TH", "FR", "SA", "SU"]

 Rule3:
  required: True

I have then mapped those rules to the columns in the CSV file where they apply.

csv_fields.yaml

Fields:
 1:
  rules:
   - Rule1
   - Rule2

 2:
  rules:
   - Rule2
   - Rule3

 3:
  rules:
   - Rule1
   - Rule3

sample_file.csv

Below is a sample file that has three columns: first_name, day_of_week and is_employed.

Peter, XX, True

To validate using Cerberus, am cross referencing the rules defined in the rules key of the csv_fields.yaml document with the Rules in the schema.yaml file. This is easy to do as .yaml files are read as dictionaries in python in a key-value format.

My Problem

In the above sample data, cerberus with throw the error 'day_of_week': ['unallowed value XX'] but a user won't know what rule triggered this error.

What am looking forward to tell the user is that the error unallowed value XX was triggered by Rule2 as the user knows Rule2 rather than the technical Cerberus specific definition.

Is there a way to achieve this even if it means defining the schema.yaml differently?

I've looked at the Cerberus Errors Section but can't seem to find a way to do this.

Update:

So I've tried adding a meta field to the rule definition in schema.yaml

Rules:
 Rule1:
  maxlength: 10
  meta: {'rule_name': "Rule1"}

But when I test, I can't seem to access this Meta Key from the Error raised as I can't find it in document_error_tree or even schema_error_tree.

回答1:

I was at the same space as you are, I'll tell you what I did.

Created a custom error_handler and prepend the error messages with human readable keys.

from cerberus.errors import BasicErrorHandler

class CustomErrorHandler(BasicErrorHandler):
        def __init__(self, schema):
            self.custom_defined_schema = schema

        def _format_message(self, field, error):
            return self.custom_defined_schema[field].get('meta', {}).get('rule_name', field) + ': ' + super(CustomErrorHandler, self)._format_message(field, error)

val = Validator(schema, error_handler=CustomErrorHandler(schema))

This is what I did, hopefully it can be of use to you.