mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
reame get_validators > __get_validators__ (#338)
* reame get_validators > __get_validators__ * update docs
This commit is contained in:
@@ -16,6 +16,7 @@ v0.17.0 (unreleased)
|
||||
(**breaking change**: this supersedes the ``validate_assignment`` argument with ``config``)
|
||||
* support for nested dataclasses, #334 by @samuelcolvin
|
||||
* better errors when getting an ``ImportError`` with ``PyObject``, #309 by @samuelcolvin
|
||||
* rename ``get_validators`` to ``__get_validators__``, deprecation warning on use of old name, #338 by @samuelcolvin
|
||||
|
||||
v0.16.1 (2018-12-10)
|
||||
....................
|
||||
|
||||
@@ -3,7 +3,7 @@ from pydantic import BaseModel, ValidationError
|
||||
|
||||
class StrictStr(str):
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
|
||||
+7
-2
@@ -391,8 +391,13 @@ against defined Json structure if it's provided.
|
||||
Custom Data Types
|
||||
.................
|
||||
|
||||
You can also define your own data types. Class method ``get_validators`` will be called to get validators to parse and
|
||||
validate the input data.
|
||||
You can also define your own data types. The class method ``__get_validators__`` will be called
|
||||
to get validators to parse and validate the input data.
|
||||
|
||||
.. note::
|
||||
|
||||
The name of ``__get_validators__`` was changed from ``get_validators`` in ``v0.17``,
|
||||
the old name is currently still supported but deprecated and will be removed in future.
|
||||
|
||||
.. literalinclude:: examples/custom_data_types.py
|
||||
|
||||
|
||||
+8
-2
@@ -1,4 +1,5 @@
|
||||
import inspect
|
||||
import warnings
|
||||
from enum import IntEnum
|
||||
from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Pattern, Set, Tuple, Type, Union
|
||||
|
||||
@@ -201,8 +202,13 @@ class Field:
|
||||
def _populate_validators(self):
|
||||
class_validators_ = self.class_validators.values()
|
||||
if not self.sub_fields:
|
||||
get_validators = getattr(self.type_, 'get_validators', None)
|
||||
get_validators = get_validators or getattr(self.type_, '__get_validators__', None)
|
||||
get_validators = getattr(self.type_, '__get_validators__', None)
|
||||
if not get_validators:
|
||||
get_validators = getattr(self.type_, 'get_validators', None)
|
||||
if get_validators:
|
||||
warnings.warn(
|
||||
f'get_validators has been replaced by __get_validators__ (on {self.name})', DeprecationWarning
|
||||
)
|
||||
v_funcs = (
|
||||
*tuple(v.func for v in class_validators_ if not v.whole and v.pre),
|
||||
*(
|
||||
|
||||
+1
-1
@@ -345,7 +345,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
return json.dumps(cls.schema(by_alias=by_alias), default=pydantic_encoder, **dumps_kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield dict_validator
|
||||
yield cls.validate
|
||||
|
||||
|
||||
+13
-13
@@ -67,7 +67,7 @@ NoneStrBytes = Optional[StrBytes]
|
||||
|
||||
class StrictStr(str):
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
@@ -85,7 +85,7 @@ class ConstrainedStr(str):
|
||||
regex: Optional[Pattern] = None
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield not_none_validator
|
||||
yield str_validator
|
||||
yield anystr_strip_whitespace
|
||||
@@ -118,7 +118,7 @@ def constr(*, strip_whitespace=False, min_length=None, max_length=None, curtail_
|
||||
|
||||
class EmailStr(str):
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
# included here and below so the error happens straight away
|
||||
if email_validator is None:
|
||||
raise ImportError('email-validator is not installed, run `pip install pydantic[email]`')
|
||||
@@ -140,7 +140,7 @@ class UrlStr(str):
|
||||
require_tld = True # whether to reject non-FQDN hostnames
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield not_none_validator
|
||||
yield str_validator
|
||||
yield anystr_strip_whitespace
|
||||
@@ -192,7 +192,7 @@ class NameEmail:
|
||||
self.email = email
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
if email_validator is None:
|
||||
raise ImportError('email-validator is not installed, run `pip install pydantic[email]`')
|
||||
|
||||
@@ -214,7 +214,7 @@ class PyObject:
|
||||
validate_always = True
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield str_validator
|
||||
yield cls.validate
|
||||
|
||||
@@ -233,7 +233,7 @@ class DSN(str):
|
||||
validate_always = True
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield str_validator
|
||||
yield cls.validate
|
||||
|
||||
@@ -268,7 +268,7 @@ class ConstrainedInt(int, metaclass=ConstrainedNumberMeta):
|
||||
le: Optional[int] = None
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield int_validator
|
||||
yield number_size_validator
|
||||
|
||||
@@ -294,7 +294,7 @@ class ConstrainedFloat(float, metaclass=ConstrainedNumberMeta):
|
||||
le: Union[None, int, float] = None
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield float_validator
|
||||
yield number_size_validator
|
||||
|
||||
@@ -322,7 +322,7 @@ class ConstrainedDecimal(Decimal, metaclass=ConstrainedNumberMeta):
|
||||
decimal_places: Optional[int] = None
|
||||
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield not_none_validator
|
||||
yield decimal_validator
|
||||
yield number_size_validator
|
||||
@@ -389,7 +389,7 @@ class UUID5(UUID):
|
||||
|
||||
class FilePath(Path):
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield path_validator
|
||||
yield path_exists_validator
|
||||
yield cls.validate
|
||||
@@ -404,7 +404,7 @@ class FilePath(Path):
|
||||
|
||||
class DirectoryPath(Path):
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield path_validator
|
||||
yield path_exists_validator
|
||||
yield cls.validate
|
||||
@@ -428,7 +428,7 @@ class JsonMeta(type):
|
||||
|
||||
class Json(metaclass=JsonMeta):
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
def __get_validators__(cls):
|
||||
yield str_validator
|
||||
yield cls.validate
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
||||
|
||||
import pytest
|
||||
|
||||
from pydantic import BaseConfig, BaseModel, NoneStrBytes, StrBytes, ValidationError, constr, validate_model
|
||||
from pydantic import BaseConfig, BaseModel, NoneStrBytes, StrBytes, ValidationError, constr, errors, validate_model
|
||||
|
||||
|
||||
def test_str_bytes():
|
||||
@@ -546,3 +546,48 @@ def test_optional_required():
|
||||
assert Model(bar=123).dict() == {'bar': 123}
|
||||
assert Model().dict() == {'bar': None}
|
||||
assert Model(bar=None).dict() == {'bar': None}
|
||||
|
||||
|
||||
def test_invalid_validator():
|
||||
class InvalidValidator:
|
||||
@classmethod
|
||||
def __get_validators__(cls):
|
||||
yield cls.has_wrong_arguments
|
||||
|
||||
@classmethod
|
||||
def has_wrong_arguments(cls, value, bar):
|
||||
pass
|
||||
|
||||
with pytest.raises(errors.ConfigError) as exc_info:
|
||||
|
||||
class InvalidValidatorModel(BaseModel):
|
||||
x: InvalidValidator = ...
|
||||
|
||||
assert exc_info.value.args[0].startswith('Invalid signature for validator')
|
||||
|
||||
|
||||
def test_unable_to_infer():
|
||||
with pytest.raises(errors.ConfigError) as exc_info:
|
||||
|
||||
class InvalidDefinitionModel(BaseModel):
|
||||
x = None
|
||||
|
||||
assert exc_info.value.args[0] == 'unable to infer type for attribute "x"'
|
||||
|
||||
|
||||
def test_get_validator():
|
||||
class CustomClass:
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
return v * 2
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
|
||||
class Model(BaseModel):
|
||||
x: CustomClass
|
||||
|
||||
assert Model(x=42).x == 84
|
||||
+1
-29
@@ -3,7 +3,7 @@ from typing import Any, List
|
||||
|
||||
import pytest
|
||||
|
||||
from pydantic import BaseModel, NoneBytes, NoneStr, Required, ValidationError, constr, errors
|
||||
from pydantic import BaseModel, NoneBytes, NoneStr, Required, ValidationError, constr
|
||||
|
||||
|
||||
def test_success():
|
||||
@@ -159,34 +159,6 @@ def test_prevent_extra_fails():
|
||||
]
|
||||
|
||||
|
||||
class InvalidValidator:
|
||||
@classmethod
|
||||
def get_validators(cls):
|
||||
yield cls.has_wrong_arguments
|
||||
|
||||
@classmethod
|
||||
def has_wrong_arguments(cls, value, bar):
|
||||
pass
|
||||
|
||||
|
||||
def test_invalid_validator():
|
||||
with pytest.raises(errors.ConfigError) as exc_info:
|
||||
|
||||
class InvalidValidatorModel(BaseModel):
|
||||
x: InvalidValidator = ...
|
||||
|
||||
assert exc_info.value.args[0].startswith('Invalid signature for validator')
|
||||
|
||||
|
||||
def test_unable_to_infer():
|
||||
with pytest.raises(errors.ConfigError) as exc_info:
|
||||
|
||||
class InvalidDefinitionModel(BaseModel):
|
||||
x = None
|
||||
|
||||
assert exc_info.value.args[0] == 'unable to infer type for attribute "x"'
|
||||
|
||||
|
||||
def test_not_required():
|
||||
class Model(BaseModel):
|
||||
a: float = None
|
||||
|
||||
Reference in New Issue
Block a user