marshmallow-code / marshmallow-code/marshmallow
Passing extra kwargs with ValidationError
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 7.2k
- Forks
- 738
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 7
Description
Hi!
I'm trying to pass some extra data (e.g. error code) with (or inside) a ValidationError. My end goal is to have machine readable string constant (error code and error description) alongside marshmallow error message. For instance:
class Error(Enum):
"""Error codes."""
MISSING_DATA = 'Missing data'
FORBIDDEN_ENTITY = 'Forbidden data'
class MySchema(Schema):
name = fields.Str()
@validates_schema
def validate_string(self, value):
if value == 'forbidden_string':
# raise error with specific code
raise ValidationError('String is not allowed', error_code=Error.FORBIDDEN_ENTITY)
Later on, the error is to be serialized like this:
{
'code': 'FORBIDDEN_ENTITY', # Error.FORBIDDEN_ENTITY.name
'title': 'Forbidden data', # Error.FORBIDDEN_ENTITY.value
'detail': 'String is not allowed', # error message
'source': { # irrelevant here
'pointer': '/data/attribures/name',
},
However, there are quite a few issues I run into:
- Some conditions are checked before custom validation take place. For example, when field is marked with
required=True, orallow_none=False. Fortunately, in that casefail(self, key, **kwargs)is called, so it can be reimplemented to add custom code to the exception:
class BaseField(marshmallow.fields.Field):
def fail(self, key, **kwargs):
"""Raises `marshmallow.ValidationError` with error code appended."""
try:
super().fail(key, **kwargs)
except ValidationError as exc:
error_code = get_error_code(key) # get error code somehow
exc.kwargs[f'error_code_{self.name}'] = key
raise
self.name is used here to match error codes with field names when serializing the error.
-
However, as far as I understand, there is no way to do the same trick in field validators since they have no information about a field they validate (slightly related to https://github.com/marshmallow-code/marshmallow/pull/709). Thus, an exception with custom error code can be raised but the information about the field it corresponds with is lost.
-
Unmarshallercollectskwargsfrom allValidationErrors raised, but only in schema- and field-level validators.kwargsin exceptions raised inpre_loadandpost_loadfunctions are not propagated. Is this intended behavior? -
ValidationErrorraised in nested schemas are being caught and then reraised withoutkwargs. I believe https://github.com/marshmallow-code/marshmallow/blob/dev/marshmallow/fields.py#L474 is to blame. Is it intended? Although even if nested schemas do propagatekwargs, matching error codes with fields would be a huge pain...
Is there an easier way to achieve it?
My last resort would be to pick out an error code based on error message, but it will require a lot of fragile hardcoding.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading ValidationError, field validators, and Unmarshaller handling, then inspect marshmallow/fields.py around line 474. Trace how kwargs move through pre_load, post_load, schema-level, field-level, and nested validation errors. Done requires an agreed design and tests covering field association and kwargs propagation across these paths.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100