Skip to content

Commit

Permalink
Use core schema fns to initalize SchemaValidators in the test suite. (
Browse files Browse the repository at this point in the history
#1631)

Co-authored-by: JONEMI21 <michael.jones2@kingfisher.com>
  • Loading branch information
mikeedjones and JONEMI21 authored Feb 11, 2025
1 parent f1aaaaf commit 2e4134c
Show file tree
Hide file tree
Showing 51 changed files with 1,752 additions and 1,915 deletions.
289 changes: 145 additions & 144 deletions tests/benchmarks/test_micro_benchmarks.py

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion tests/serializers/test_any.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
from dirty_equals import HasRepr, IsList

import pydantic_core
from pydantic_core import PydanticSerializationError, SchemaSerializer, SchemaValidator, core_schema, to_json
from pydantic_core import (
PydanticSerializationError,
SchemaSerializer,
SchemaValidator,
core_schema,
to_json,
)

from ..conftest import plain_repr
from .test_dataclasses import IsStrictDict, on_pypy
Expand Down
8 changes: 7 additions & 1 deletion tests/serializers/test_list_tuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@

import pytest

from pydantic_core import PydanticSerializationError, SchemaError, SchemaSerializer, core_schema, validate_core_schema
from pydantic_core import (
PydanticSerializationError,
SchemaError,
SchemaSerializer,
core_schema,
validate_core_schema,
)


def test_list_any():
Expand Down
20 changes: 10 additions & 10 deletions tests/serializers/test_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pytest

from pydantic_core import SchemaSerializer, core_schema
from pydantic_core import CoreConfig, SchemaSerializer, core_schema

try:
import numpy
Expand Down Expand Up @@ -149,15 +149,15 @@ def test_numpy():
(float('-inf'), 'null', {}),
(float('nan'), 'null', {}),
# explicit values of ser_json_inf_nan
(float('inf'), 'null', {'ser_json_inf_nan': 'null'}),
(float('-inf'), 'null', {'ser_json_inf_nan': 'null'}),
(float('nan'), 'null', {'ser_json_inf_nan': 'null'}),
(float('inf'), 'Infinity', {'ser_json_inf_nan': 'constants'}),
(float('-inf'), '-Infinity', {'ser_json_inf_nan': 'constants'}),
(float('nan'), 'NaN', {'ser_json_inf_nan': 'constants'}),
(float('inf'), '"Infinity"', {'ser_json_inf_nan': 'strings'}),
(float('-inf'), '"-Infinity"', {'ser_json_inf_nan': 'strings'}),
(float('nan'), '"NaN"', {'ser_json_inf_nan': 'strings'}),
(float('inf'), 'null', CoreConfig(ser_json_inf_nan='null')),
(float('-inf'), 'null', CoreConfig(ser_json_inf_nan='null')),
(float('nan'), 'null', CoreConfig(ser_json_inf_nan='null')),
(float('inf'), 'Infinity', CoreConfig(ser_json_inf_nan='constants')),
(float('-inf'), '-Infinity', CoreConfig(ser_json_inf_nan='constants')),
(float('nan'), 'NaN', CoreConfig(ser_json_inf_nan='constants')),
(float('inf'), '"Infinity"', CoreConfig(ser_json_inf_nan='strings')),
(float('-inf'), '"-Infinity"', CoreConfig(ser_json_inf_nan='strings')),
(float('nan'), '"NaN"', CoreConfig(ser_json_inf_nan='strings')),
],
)
def test_float_inf_and_nan_serializers(value, expected_json, config):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_build_error_deep():


def test_schema_as_string():
v = SchemaValidator({'type': 'bool'})
v = SchemaValidator(cs.bool_schema())
assert v.validate_python('tRuE') is True


Expand All @@ -53,7 +53,7 @@ def test_schema_wrong_type(pydantic_version):

@pytest.mark.parametrize('pickle_protocol', range(1, pickle.HIGHEST_PROTOCOL + 1))
def test_pickle(pickle_protocol: int) -> None:
v1 = SchemaValidator({'type': 'bool'})
v1 = SchemaValidator(cs.bool_schema())
assert v1.validate_python('tRuE') is True
p = pickle.dumps(v1, protocol=pickle_protocol)
v2 = pickle.loads(p)
Expand Down Expand Up @@ -98,7 +98,7 @@ def test_function_no_mode():

def test_try_self_schema_discriminator():
"""Trying to use self-schema when it shouldn't be used"""
v = SchemaValidator({'type': 'tagged-union', 'choices': {'int': {'type': 'int'}}, 'discriminator': 'self-schema'})
v = SchemaValidator(cs.tagged_union_schema(choices={'int': cs.int_schema()}, discriminator='self-schema'))
assert 'discriminator: LookupKey' in repr(v)


Expand Down
90 changes: 44 additions & 46 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
from dirty_equals import FunctionCheck, HasAttributes, IsInstance

from pydantic_core import CoreConfig, SchemaValidator, ValidationError
from pydantic_core import core_schema as cs

from .conftest import Err, plain_repr


def test_on_field():
v = SchemaValidator({'type': 'str', 'min_length': 2, 'max_length': 5})
v = SchemaValidator(cs.str_schema(min_length=2, max_length=5))
r = plain_repr(v)
assert 'min_length:Some(2)' in r
assert 'max_length:Some(5)' in r
Expand All @@ -19,14 +20,14 @@ def test_on_field():


def test_on_config():
v = SchemaValidator({'type': 'str'}, {'str_max_length': 5})
v = SchemaValidator(cs.str_schema(), config=CoreConfig(str_max_length=5))
assert 'max_length:Some(5)' in plain_repr(v)
assert v.isinstance_python('test') is True
assert v.isinstance_python('test long') is False


def test_field_priority_arg():
v = SchemaValidator({'type': 'str', 'max_length': 5}, {'str_max_length': 10})
v = SchemaValidator(cs.str_schema(max_length=5), config=CoreConfig(str_max_length=10))
assert 'max_length:Some(5)' in plain_repr(v)
assert v.isinstance_python('test') is True
assert v.isinstance_python('test long') is False
Expand All @@ -39,12 +40,11 @@ class MyModel:

def test_on_model_class():
v = SchemaValidator(
{
'type': 'model',
'cls': MyModel,
'config': {'str_max_length': 5},
'schema': {'type': 'model-fields', 'fields': {'f': {'type': 'model-field', 'schema': {'type': 'str'}}}},
}
cs.model_schema(
cls=MyModel,
config=CoreConfig(str_max_length=5),
schema=cs.model_fields_schema(fields={'f': cs.model_field(schema=cs.str_schema())}),
)
)
assert 'max_length:Some(5)' in plain_repr(v)
assert v.isinstance_python({'f': 'test'}) is True
Expand All @@ -53,15 +53,11 @@ def test_on_model_class():

def test_field_priority_model():
v = SchemaValidator(
{
'type': 'model',
'cls': MyModel,
'config': {'str_max_length': 10},
'schema': {
'type': 'model-fields',
'fields': {'f': {'type': 'model-field', 'schema': {'type': 'str', 'max_length': 5}}},
},
}
cs.model_schema(
cls=MyModel,
config=CoreConfig(str_max_length=10),
schema=cs.model_fields_schema(fields={'f': cs.model_field(schema=cs.str_schema(max_length=5))}),
)
)
assert 'max_length:Some(5)' in plain_repr(v)
assert v.isinstance_python({'f': 'test'}) is True
Expand All @@ -71,29 +67,34 @@ def test_field_priority_model():
@pytest.mark.parametrize(
'config,float_field_schema,input_value,expected',
[
({}, {'type': 'float'}, {'x': 'nan'}, IsInstance(MyModel) & HasAttributes(x=FunctionCheck(math.isnan))),
(
{'allow_inf_nan': True},
{'type': 'float'},
CoreConfig(),
cs.float_schema(),
{'x': 'nan'},
IsInstance(MyModel) & HasAttributes(x=FunctionCheck(math.isnan)),
),
(
{'allow_inf_nan': False},
{'type': 'float'},
CoreConfig(allow_inf_nan=True),
cs.float_schema(),
{'x': 'nan'},
IsInstance(MyModel) & HasAttributes(x=FunctionCheck(math.isnan)),
),
(
CoreConfig(allow_inf_nan=False),
cs.float_schema(),
{'x': 'nan'},
Err('Input should be a finite number [type=finite_number,'),
),
# field `allow_inf_nan` (if set) should have priority over global config
(
{'allow_inf_nan': True},
{'type': 'float', 'allow_inf_nan': False},
CoreConfig(allow_inf_nan=True),
cs.float_schema(allow_inf_nan=False),
{'x': 'nan'},
Err('Input should be a finite number [type=finite_number,'),
),
(
{'allow_inf_nan': False},
{'type': 'float', 'allow_inf_nan': True},
CoreConfig(allow_inf_nan=False),
cs.float_schema(allow_inf_nan=True),
{'x': 'nan'},
IsInstance(MyModel) & HasAttributes(x=FunctionCheck(math.isnan)),
),
Expand All @@ -102,12 +103,11 @@ def test_field_priority_model():
)
def test_allow_inf_nan(config: CoreConfig, float_field_schema, input_value, expected):
v = SchemaValidator(
{
'type': 'model',
'cls': MyModel,
'schema': {'type': 'model-fields', 'fields': {'x': {'type': 'model-field', 'schema': float_field_schema}}},
'config': config,
}
cs.model_schema(
cls=MyModel,
schema=cs.model_fields_schema(fields={'x': cs.model_field(schema=float_field_schema)}),
config=config,
)
)
if isinstance(expected, Err):
with pytest.raises(ValidationError, match=re.escape(expected.message)):
Expand All @@ -120,34 +120,32 @@ def test_allow_inf_nan(config: CoreConfig, float_field_schema, input_value, expe
@pytest.mark.parametrize(
'config,input_str',
(
({}, 'type=string_type, input_value=123, input_type=int'),
({'hide_input_in_errors': False}, 'type=string_type, input_value=123, input_type=int'),
({'hide_input_in_errors': True}, 'type=string_type'),
(CoreConfig(), 'type=string_type, input_value=123, input_type=int'),
(CoreConfig(hide_input_in_errors=False), 'type=string_type, input_value=123, input_type=int'),
(CoreConfig(hide_input_in_errors=True), 'type=string_type'),
),
)
def test_hide_input_in_errors(config, input_str):
v = SchemaValidator(
{
'type': 'model',
'cls': MyModel,
'schema': {'type': 'model-fields', 'fields': {'f': {'type': 'model-field', 'schema': {'type': 'str'}}}},
},
config,
cs.model_schema(
cls=MyModel, schema=cs.model_fields_schema(fields={'f': cs.model_field(schema=cs.str_schema())})
),
config=config,
)

with pytest.raises(ValidationError, match=re.escape(f'Input should be a valid string [{input_str}]')):
assert v.validate_python({'f': 123})


def test_cache_strings():
v = SchemaValidator({'type': 'str'})
v = SchemaValidator(cs.str_schema())
assert 'cache_strings=True' in plain_repr(v)

v = SchemaValidator({'type': 'str'}, {'cache_strings': True})
v = SchemaValidator(cs.str_schema(), config=CoreConfig(cache_strings=True))
assert 'cache_strings=True' in plain_repr(v)

v = SchemaValidator({'type': 'str'}, {'cache_strings': False})
v = SchemaValidator(cs.str_schema(), config=CoreConfig(cache_strings=False))
assert 'cache_strings=False' in plain_repr(v)

v = SchemaValidator({'type': 'str'}, {'cache_strings': 'keys'})
v = SchemaValidator(cs.str_schema(), config=CoreConfig(cache_strings='keys'))
assert "cache_strings='keys'" in plain_repr(v)
28 changes: 14 additions & 14 deletions tests/test_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ def test_all_errors():

@pytest.mark.skipif(sys.version_info < (3, 11), reason='This is the modern version used post 3.10.')
def test_validation_error_cause_contents():
enabled_config: CoreConfig = {'validation_error_cause': True}
enabled_config: CoreConfig = CoreConfig(validation_error_cause=True)

def multi_raise_py_error(v: Any) -> Any:
try:
Expand Down Expand Up @@ -605,7 +605,7 @@ def outer_raise_py_error(v: Any) -> Any:
def test_validation_error_cause_contents_legacy():
from exceptiongroup import BaseExceptionGroup

enabled_config: CoreConfig = {'validation_error_cause': True}
enabled_config: CoreConfig = CoreConfig(validation_error_cause=True)

def multi_raise_py_error(v: Any) -> Any:
try:
Expand Down Expand Up @@ -683,10 +683,10 @@ class CauseResult(enum.Enum):
[ # Without the backport should still work after 3.10 as not needed:
(
'Enabled',
{'validation_error_cause': True},
CoreConfig(validation_error_cause=True),
CauseResult.CAUSE if sys.version_info >= (3, 11) else CauseResult.IMPORT_ERROR,
),
('Disabled specifically', {'validation_error_cause': False}, CauseResult.NO_CAUSE),
('Disabled specifically', CoreConfig(validation_error_cause=False), CauseResult.NO_CAUSE),
('Disabled implicitly', {}, CauseResult.NO_CAUSE),
],
)
Expand Down Expand Up @@ -721,7 +721,7 @@ def singular_raise_py_error(v: Any) -> Any:
def test_validation_error_cause_traceback_preserved():
"""Makes sure historic bug of traceback being lost is fixed."""

enabled_config: CoreConfig = {'validation_error_cause': True}
enabled_config: CoreConfig = CoreConfig(validation_error_cause=True)

def singular_raise_py_error(v: Any) -> Any:
raise ValueError('Oh no!')
Expand Down Expand Up @@ -749,7 +749,7 @@ def __repr__(self):


def test_error_on_repr(pydantic_version):
s = SchemaValidator({'type': 'int'})
s = SchemaValidator(core_schema.int_schema())
with pytest.raises(ValidationError) as exc_info:
s.validate_python(BadRepr())

Expand All @@ -775,7 +775,7 @@ def test_error_on_repr(pydantic_version):


def test_error_json(pydantic_version):
s = SchemaValidator({'type': 'str', 'min_length': 3})
s = SchemaValidator(core_schema.str_schema(min_length=3))
with pytest.raises(ValidationError) as exc_info:
s.validate_python('12')

Expand Down Expand Up @@ -853,7 +853,7 @@ def raise_py_error(v: Any) -> Any:


def test_error_json_cycle():
s = SchemaValidator({'type': 'str', 'min_length': 3})
s = SchemaValidator(core_schema.str_schema(min_length=3))
cycle = []
cycle.append(cycle)
msg = '[type=string_type, input_value=[[...]], input_type=list]'
Expand All @@ -875,7 +875,7 @@ def __str__(self):


def test_error_json_unknown():
s = SchemaValidator({'type': 'str'})
s = SchemaValidator(core_schema.str_schema())
with pytest.raises(ValidationError) as exc_info:
s.validate_python(Foobar())

Expand Down Expand Up @@ -1089,7 +1089,7 @@ def test_loc_with_dots(pydantic_version):


def test_hide_input_in_error() -> None:
s = SchemaValidator({'type': 'int'})
s = SchemaValidator(core_schema.int_schema())
with pytest.raises(ValidationError) as exc_info:
s.validate_python('definitely not an int')

Expand All @@ -1098,7 +1098,7 @@ def test_hide_input_in_error() -> None:


def test_hide_input_in_json() -> None:
s = SchemaValidator({'type': 'int'})
s = SchemaValidator(core_schema.int_schema())
with pytest.raises(ValidationError) as exc_info:
s.validate_python('definitely not an int')

Expand All @@ -1111,7 +1111,7 @@ def test_hide_input_in_json() -> None:
reason='PyPy before 3.9 cannot pickle this correctly',
)
def test_validation_error_pickle() -> None:
s = SchemaValidator({'type': 'int'})
s = SchemaValidator(core_schema.int_schema())
with pytest.raises(ValidationError) as exc_info:
s.validate_python('definitely not an int')

Expand All @@ -1122,7 +1122,7 @@ def test_validation_error_pickle() -> None:

@pytest.mark.skipif('PYDANTIC_ERRORS_INCLUDE_URL' in os.environ, reason="can't test when envvar is set")
def test_errors_include_url() -> None:
s = SchemaValidator({'type': 'int'})
s = SchemaValidator(core_schema.int_schema())
with pytest.raises(ValidationError) as exc_info:
s.validate_python('definitely not an int')
assert 'https://errors.pydantic.dev' in repr(exc_info.value)
Expand All @@ -1149,7 +1149,7 @@ def test_errors_include_url_envvar(env_var, env_var_value, expected_to_have_url)
Since it can only be set before `ValidationError.__repr__()` is first called,
we need to spawn a subprocess to test it.
"""
code = "import pydantic_core; pydantic_core.SchemaValidator({'type': 'int'}).validate_python('ooo')"
code = "import pydantic_core; from pydantic_core import core_schema; pydantic_core.SchemaValidator(core_schema.int_schema()).validate_python('ooo')"
env = os.environ.copy()
env.pop('PYDANTIC_ERRORS_OMIT_URL', None) # in case the ambient environment has it set
if env_var_value is not None:
Expand Down
Loading

0 comments on commit 2e4134c

Please sign in to comment.