Skip to content

Commit

Permalink
Support __get_validators__
Browse files Browse the repository at this point in the history
  • Loading branch information
hramezani committed Aug 21, 2023
1 parent 2835178 commit 285f7ae
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
19 changes: 12 additions & 7 deletions pydantic/_internal/_generate_schema.py
Expand Up @@ -587,16 +587,21 @@ def _generate_schema_from_property(self, obj: Any, source: Any) -> core_schema.C
else:
ref_mode = 'to-def'

schema: CoreSchema
get_schema = getattr(obj, '__get_pydantic_core_schema__', None)
if get_schema is None:
return None

schema: CoreSchema
if len(inspect.signature(get_schema).parameters) == 1:
# (source) -> CoreSchema
schema = get_schema(source)
validators = getattr(obj, '__get_validators__', None)
if validators is None:
return None
schema = core_schema.chain_schema([core_schema.general_plain_validator_function(v) for v in validators()])
else:
schema = get_schema(source, CallbackGetCoreSchemaHandler(self._generate_schema, self, ref_mode=ref_mode))
if len(inspect.signature(get_schema).parameters) == 1:
# (source) -> CoreSchema
schema = get_schema(source)
else:
schema = get_schema(
source, CallbackGetCoreSchemaHandler(self._generate_schema, self, ref_mode=ref_mode)
)

schema = self._unpack_refs_defs(schema)

Expand Down
48 changes: 47 additions & 1 deletion tests/test_deprecated.py
@@ -1,7 +1,7 @@
import platform
import re
import sys
from datetime import timedelta
from datetime import date, timedelta
from pathlib import Path
from types import SimpleNamespace
from typing import Any, Dict, Iterable, List, Type
Expand Down Expand Up @@ -523,6 +523,52 @@ def __get_validators__(cls) -> Iterable[Any]:
assert ta.json_schema() == {'anyOf': [{'type': 'string'}, {'type': 'number'}]}


def test_v1_get_validators():
class CustomDate(date):
@classmethod
def __get_validators__(cls):
yield cls.validate1
yield cls.validate2

@classmethod
def validate1(cls, v, i):
print(v)

if v.year < 2000:
raise ValueError('Invalid year')
return v

@classmethod
def validate2(cls, v, i):
return date.today().replace(month=1, day=1)

class Model(BaseModel):
x: CustomDate

with pytest.raises(ValidationError, match='Value error, Invalid year'):
Model(x=date(1999, 1, 1))

m = Model(x=date.today())
assert m.x.day == 1


def test_v1_get_validators_invalid_validator():
class InvalidValidator:
@classmethod
def __get_validators__(cls):
yield cls.has_wrong_arguments

@classmethod
def has_wrong_arguments(cls):
pass

class InvalidValidatorModel(BaseModel):
x: InvalidValidator

with pytest.raises(TypeError, match='takes 1 positional argument but 3 were given'):
InvalidValidatorModel(x=1)


def test_field_extra_arguments():
m = re.escape(
'Using extra keyword arguments on `Field` is deprecated and will be removed. Use `json_schema_extra` instead. '
Expand Down

0 comments on commit 285f7ae

Please sign in to comment.