23andMe / Yamale

A schema and validator for YAML.
MIT License
679 stars 88 forks source link

Custom error messages? #158

Closed SuperSajuuk closed 3 years ago

SuperSajuuk commented 3 years ago

Hi there!

I'm just wondering: is there a quick and simple way to override just error messages in validators? I'm finding that a lot of people complain about the error message responses from the validation failing because they aren't sure what the error means, but I don't want to override all validators "simply" to have a different error string. I was able to do this for a custom Timezone validator (comparing strings against pytz.all_timezones) but doing that method for every validator is not very feasible.

If there is a way to have custom error messages while preserving base Yamale validation, please let me know. Thanks!

mildebrandt commented 3 years ago

Hi, thanks for using Yamale!

The Validator class has a fail() method:

    def fail(self, value):
        """Override to define a custom fail message"""
        return '\'%s\' is not a %s.' % (value, self.get_name())

I think you may be able to override/patch this in your code for any of the existing validators. I haven't tried this and look forward to see what you find.

Also, please feel free to open up issues on any specific error messages that are unclear.

SuperSajuuk commented 3 years ago

Hi, thanks for using Yamale!

The Validator class has a fail() method:

    def fail(self, value):
        """Override to define a custom fail message"""
        return '\'%s\' is not a %s.' % (value, self.get_name())

I think you may be able to override/patch this in your code for any of the existing validators. I haven't tried this and look forward to see what you find.

Also, please feel free to open up issues on any specific error messages that are unclear.

Hi.

In a normal use case of Yamale, I think the error messages are generally fine. For me though, since my use targets people who are generally unfamiliar with YAML and aren't technically "savvy" as it were, being able to override just the error messages would help a lot so that I can write more clearer error messages that explains the problem [as well as linking documentation pages] but from what I read in the code, you have to override the _is_valid() method which would mean having to copypaste the original validators' code to keep the functionality in place.

It would be great if it were possible to override "just" the error portion only without having to override _is_valid(): or is it possible to get the original validators' code by calling super()? I'll also have a look and see what I'm able to do on my own though.

Thanks for you help so far!

mildebrandt commented 3 years ago

Right, you wouldn't want to override the _is_valid() method. Instead, you want to override the fail() method. Here's something that will work to override the message from "String":

#!/usr/bin/env python3
import yamale

def string_fail(self, value):
    return f'The attribute {self.get_name()} is not a string. You entered the following: {value}'

yamale.validators.validators.String.fail = string_fail

schema = yamale.make_schema('./schema.yaml')
data = yamale.make_data('./data.yaml')

try:
    yamale.validate(schema, data)
except yamale.yamale_error.YamaleError as e:
    print(e.results[0].errors[0])
MichaelPereira commented 3 years ago

@mildebrandt Thanks a lot for this tip, I was able to use it to customize the error message for each class, which is a lot better than the default of showing the Validator name/tag.

I was even able to go a step farther by making it dynamic based on specific conditions as I'm validating parts of the input string differently for ease of use for users:

class CustomValidator(Validator)

    tag = "CustomValidator"
    _error_msg = ""

    def fail(self, value):
        return self._error_msg

    def _is_valid(self, value):
        if some_condition:
            self._error_msg = f"{value} needs to start with X"
            return False

        if some_other_condition:
            self._error_msg = f"{value} needs to end with Y"
            return False

    return True
mildebrandt commented 3 years ago

@SuperSajuuk I'm going to close this. If you have other questions on this topic, please reopen. Thanks!