schema
schema copied to clipboard
General changes to error handling in schema
Problem
In my opinion, the way SchemaErrors are produced can be improved. There are a few problems with the current implementation:
- Error string formatting logic is duplicated throughout the code, does not exist in all needed cases (e.g. callable validators).
SchemaErrorobjects do not contain a reference to the data that validation failed on, which could be useful to users catching the exception.- Many functions throw
SchemaErrors in a context in which aSchemaErroris handled, which causes a long traceback containingwhile handling this exception, another exception has occured: .... This stack trace doesn't contain any useful information because we collect theautosanderrorsfrom the handledSchemaErrorexceptions anyway. SchemaError's interface is hard to understand at first (mainly because ofautosanderrors) for anyone wanting to implement a custom validator that can throw aSchemaError'.
Possible solution
I would like to offer a new implementation of SchemaError that will hopefully solve all of the above. Pseudocode:
# The new SchemaError class
class SchemaError(Exception):
def __init__(self, generated_error_msg, user_error_msg, invalid_data):
super(Schema, self).__init__()
self.generated_error_msg = generated_error_msg
self.user_error_msg = user_error_msg
self.invalid_data = invalid_data
def __str__(self):
return '{}: {}'.format(self.generated_error_msg, self.user_error_msg.format(self.invalid_data))
# Usage example
try:
s.validate(data)
except SchemaError as e:
six.raise_from(SchemaError(auto, user_msg, data), e)
This solves the problems above:
- Formatting is handled in one place.
- The exception contains the data.
- We don't collect
autosanderrorsanymore, and let python's exception chaining do the job instead. - IMO the new interface is much simpler and more pythonic.
Drawbacks
Some users might have raise SchemaError(...) in their code. Such code will break if we change the interface of SchemaError.__init__. We could:
- Change the interface and break compatability (maybe bump a major version)
- Try to make the new interface backwards compatible - maybe keep the
autosanderrorsarguments and have theinvalid_dataargument default to None. - We can make a new class for the proposed exception, and have it inherit from
SchemaError. That way,SchemaErrorcould still be raised, and catchingSchemaErrors will catch the new exception type as well.
I quite like this proposal, thanks! I'm not very enthusiastic about breaking backwards compatibility, though. How much work do you think it would be to make the interface backwards-compatible? Would you be willing/available to give this a shot?
I guess its still a thing, sad to see we didnt get a proper errors handling yet. Wasted my time trying to get a useful error out the current implementation.
I wouldn't mind if the new error-class has different, but it might help avoid complex work on backwards compatiblity.