Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use core schema fns to initalize SchemaValidators in the test suite. #1631

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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