reame get_validators > __get_validators__ (#338)

* reame get_validators > __get_validators__

* update docs
This commit is contained in:
Samuel Colvin
2018-12-27 20:30:41 +00:00
committed by GitHub
parent e28d689f8c
commit 9ad1a0ad24
8 changed files with 78 additions and 49 deletions
+1
View File
@@ -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)
....................
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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