Closed jeancochrane closed 2 years ago
Just did a little bit of messing about to figure out a workaround. I tried adding a field validator with @validates
, but it seems like the object is initialized before the field validator runs, so we still get a TypeError
:
Incorrect validation error:
TypeError: __init__() missing 1 required positional argument: 'url'
@validates_schema
seems to work, however:
@dataclass
class IncorrectValidationError:
url: str = field(metadata={"required": True, "marshmallow_field": Url()})
@validates_schema
def validate_schema(self, data: Dict, **kwargs: Any) -> None:
if "url" not in data:
raise ValidationError({"url": ["Missing data for required field."]})
Incorrect validation error:
ValidationError: {'url': ['Missing data for required field.']}
Only downside is that it seems like validates_schema
runs after all other required
checks have been completed, so if the caller is missing other required fields, they won't see the field validated by the schema in the output unless all other fields are provided:
from dataclasses import field
from typing import Any, Dict
from marshmallow import validates_schema, ValidationError
from marshmallow.fields import Url
from marshmallow_dataclass import dataclass
@dataclass
class IncorrectValidationError:
foo: str = field(metadata={"required": True})
url: str = field(metadata={"required": True, "marshmallow_field": Url()})
@validates_schema
def validate_schema(self, data: Dict, **kwargs: Any) -> None:
if "url" not in data:
raise ValidationError({"url": ["Missing data for required field."]})
if __name__ == "__main__":
print("Incorrect validation error, missing both arguments:")
try:
IncorrectValidationError.Schema().load({})
except ValidationError as e:
print("ValidationError:", e.messages)
print("Incorrect validation error, missing only url:")
try:
IncorrectValidationError.Schema().load({"foo": "bar"})
except ValidationError as e:
print("ValidationError:", e.messages)
Incorrect validation error, missing both arguments:
ValidationError: {'foo': ['Missing data for required field.']}
Incorrect validation error, missing only url:
ValidationError: {'url': ['Missing data for required field.']}
This is an improvement over getting a TypeError
for my purposes, at least!
On further reflection, I don't actually think this is a bug -- I think the object instantiated in marshmallow_field
just needs to have the same value of required
as the field()
kwarg does, e.g.:
from dataclasses import field
from marshmallow import ValidationError
from marshmallow.fields import Url
from marshmallow_dataclass import dataclass
@dataclass
class RaiseValidationError:
"""dataclass *with* marshmallow_field; validation raises ValidationError"""
url: str = field(metadata={"required": True, "marshmallow_field": Url(required=True)})
if __name__ == "__main__":
print("Correct validation error:")
try:
RaiseValidationError.Schema().load({})
except ValidationError as e:
print("ValidationError:", e.messages)
Correct validation error:
ValidationError: {'url': ['Missing data for required field.']}
When
required=True
is set in on a field in itsdataclasses.field.metadata
dictionary, I would expect the package to raiseValidationError
when validating the schema when the field is missing. Instead, the package seems to raise aTypeError
.Here's a reproducible example of the issue:
Output:
I'd be happy to put up a PR to fix this if it would be helpful!