mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
Merge pull request #676 from dmontagu/type-in-validation-error
Add type name to ValidationError error message
This commit is contained in:
@@ -3,6 +3,11 @@
|
||||
History
|
||||
-------
|
||||
|
||||
|
||||
v0.32 (unreleased)
|
||||
..................
|
||||
* add model name to ``ValidationError`` error message, #676 by @dmontagu
|
||||
|
||||
v0.31.1 (2019-07-31)
|
||||
....................
|
||||
* fix json generation for ``EnumError``, #697 by @dmontagu
|
||||
@@ -20,6 +25,7 @@ v0.31 (2019-07-24)
|
||||
* add ``Config.keep_untouched`` for custom descriptors support, #679 by @MrMrRobat
|
||||
* use ``inspect.cleandoc`` internally to get model description, #657 by @tiangolo
|
||||
* add ``Color`` to schema generation, by @euri10
|
||||
* add documentation for Literal type, #651 by @dmontagu
|
||||
|
||||
v0.30.1 (2019-07-15)
|
||||
....................
|
||||
|
||||
@@ -44,7 +44,7 @@ def setattr_validate_assignment(self: 'DataclassType', name: str, value: Any) ->
|
||||
d.pop(name)
|
||||
value, error_ = self.__pydantic_model__.__fields__[name].validate(value, d, loc=name, cls=self.__class__)
|
||||
if error_:
|
||||
raise ValidationError([error_])
|
||||
raise ValidationError([error_], type(self))
|
||||
|
||||
object.__setattr__(self, name, value)
|
||||
|
||||
|
||||
@@ -49,10 +49,11 @@ ErrorList = Union[Sequence[Any], ErrorWrapper]
|
||||
|
||||
|
||||
class ValidationError(ValueError):
|
||||
__slots__ = ('raw_errors',)
|
||||
__slots__ = ('raw_errors', 'model')
|
||||
|
||||
def __init__(self, errors: Sequence[ErrorList]) -> None:
|
||||
def __init__(self, errors: Sequence[ErrorList], model: Type[Any]) -> None:
|
||||
self.raw_errors = errors
|
||||
self.model = model
|
||||
|
||||
@lru_cache()
|
||||
def errors(self) -> List[Dict[str, Any]]:
|
||||
@@ -64,7 +65,10 @@ class ValidationError(ValueError):
|
||||
def __str__(self) -> str:
|
||||
errors = self.errors()
|
||||
no_errors = len(errors)
|
||||
return f'{no_errors} validation error{"" if no_errors == 1 else "s"}\n{display_errors(errors)}'
|
||||
return (
|
||||
f'{no_errors} validation error{"" if no_errors == 1 else "s"} for {self.model.__name__}\n'
|
||||
f'{display_errors(errors)}'
|
||||
)
|
||||
|
||||
|
||||
def display_errors(errors: List[Dict[str, Any]]) -> str:
|
||||
|
||||
+13
-7
@@ -293,7 +293,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
elif self.__config__.validate_assignment:
|
||||
value_, error_ = self.fields[name].validate(value, self.dict(exclude={name}), loc=name)
|
||||
if error_:
|
||||
raise ValidationError([error_])
|
||||
raise ValidationError([error_], type(self))
|
||||
else:
|
||||
self.__values__[name] = value_
|
||||
self.__fields_set__.add(name)
|
||||
@@ -372,7 +372,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
obj = dict(obj)
|
||||
except (TypeError, ValueError) as e:
|
||||
exc = TypeError(f'{cls.__name__} expected dict not {type(obj).__name__}')
|
||||
raise ValidationError([ErrorWrapper(exc, loc='__obj__')]) from e
|
||||
raise ValidationError([ErrorWrapper(exc, loc='__obj__')], cls) from e
|
||||
return cls(**obj)
|
||||
|
||||
@classmethod
|
||||
@@ -390,7 +390,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
b, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle
|
||||
)
|
||||
except (ValueError, TypeError, UnicodeDecodeError) as e:
|
||||
raise ValidationError([ErrorWrapper(e, loc='__obj__')])
|
||||
raise ValidationError([ErrorWrapper(e, loc='__obj__')], cls)
|
||||
return cls.parse_obj(obj)
|
||||
|
||||
@classmethod
|
||||
@@ -783,9 +783,15 @@ def validate_model( # noqa: C901 (ignore complexity)
|
||||
for f in sorted(extra):
|
||||
errors.append(ErrorWrapper(ExtraError(), loc=f, config=config))
|
||||
|
||||
if not raise_exc:
|
||||
return values, fields_set, ValidationError(errors) if errors else None
|
||||
|
||||
err = None
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
model_type = model if isinstance(model, type) else type(model)
|
||||
err = ValidationError(errors, model_type)
|
||||
|
||||
if not raise_exc:
|
||||
return values, fields_set, err
|
||||
|
||||
if err:
|
||||
raise err
|
||||
|
||||
return values, fields_set, None
|
||||
|
||||
@@ -135,7 +135,7 @@ from pydantic.error_wrappers import ValidationError, flatten_errors, get_exc_typ
|
||||
(
|
||||
'__str__',
|
||||
"""\
|
||||
11 validation errors
|
||||
11 validation errors for Model
|
||||
a
|
||||
value is not a valid integer (type=type_error.integer)
|
||||
b -> x
|
||||
@@ -227,7 +227,7 @@ def test_single_error():
|
||||
Model(x='x')
|
||||
|
||||
expected = """\
|
||||
1 validation error
|
||||
1 validation error for Model
|
||||
x
|
||||
value is not a valid integer (type=type_error.integer)"""
|
||||
assert str(exc_info.value) == expected
|
||||
@@ -239,7 +239,7 @@ x
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== """\
|
||||
1 validation error
|
||||
1 validation error for Model
|
||||
x
|
||||
field required (type=value_error.missing)"""
|
||||
)
|
||||
@@ -261,3 +261,19 @@ def test_nested_error():
|
||||
expected = [{'loc': ('data1', 0, 'data2', 0, 'x'), 'msg': 'field required', 'type': 'value_error.missing'}]
|
||||
|
||||
assert exc_info.value.errors() == expected
|
||||
|
||||
|
||||
def test_validate_assignment_error():
|
||||
class Model(BaseModel):
|
||||
x: int
|
||||
|
||||
class Config:
|
||||
validate_assignment = True
|
||||
|
||||
model = Model(x=1)
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
model.x = 'a'
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== '1 validation error for Model\nx\n value is not a valid integer (type=type_error.integer)'
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user