diff --git a/.github/actions/build-pgo-wheel/action.yml b/.github/actions/build-pgo-wheel/action.yml index 0e0ee4e99..ca910b298 100644 --- a/.github/actions/build-pgo-wheel/action.yml +++ b/.github/actions/build-pgo-wheel/action.yml @@ -14,11 +14,6 @@ outputs: runs: using: "composite" steps: - - name: prepare self schema - shell: bash - # generate up front so that we don't have to do this inside the docker container - run: uv run python generate_self_schema.py - - name: prepare profiling directory shell: bash # making this ahead of the compile ensures that the local user can write to this diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cbf627af..b91442d1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -478,9 +478,6 @@ jobs: - run: pip install -U twine 'ruff==0.5.0' typing_extensions - # generate self-schema now, so we don't have to do so inside docker in maturin build - - run: python generate_self_schema.py - - name: build wheels uses: PyO3/maturin-action@v1 with: diff --git a/.gitignore b/.gitignore index 103281879..03ef0dcba 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,6 @@ node_modules/ /*.profraw /foobar.py /python/pydantic_core/*.so -/src/self_schema.py # samply /profile.json diff --git a/Cargo.toml b/Cargo.toml index 57cc42d6b..908c7e6b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,10 +12,8 @@ include = [ "/LICENSE", "/Makefile", "/build.rs", - "/generate_self_schema.py", "/rust-toolchain", "/src", - "!/src/self_schema.py", "/python/pydantic_core", "/tests", "/.cargo", diff --git a/Makefile b/Makefile index b52e097d6..6ca8fc075 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ .DEFAULT_GOAL := all -sources = python/pydantic_core tests generate_self_schema.py wasm-preview/run_tests.py +sources = python/pydantic_core tests wasm-preview/run_tests.py mypy-stubtest = uv run python -m mypy.stubtest pydantic_core._pydantic_core --allowlist .mypy-stubtest-allowlist @@ -124,7 +124,6 @@ clean: rm -f `find . -type f -name '*.py[co]' ` rm -f `find . -type f -name '*~' ` rm -f `find . -type f -name '.*~' ` - rm -rf src/self_schema.py rm -rf .cache rm -rf htmlcov rm -rf .pytest_cache diff --git a/benches/main.rs b/benches/main.rs index c558ca3c6..84ff2e330 100644 --- a/benches/main.rs +++ b/benches/main.rs @@ -8,15 +8,14 @@ use test::{black_box, Bencher}; use pyo3::prelude::*; use pyo3::types::{PyDict, PyString}; -use _pydantic_core::{validate_core_schema, SchemaValidator}; +use _pydantic_core::SchemaValidator; fn build_schema_validator_with_globals( py: Python, code: &CStr, globals: Option<&Bound<'_, PyDict>>, ) -> SchemaValidator { - let mut schema = py.eval(code, globals, None).unwrap().extract().unwrap(); - schema = validate_core_schema(&schema, None).unwrap().extract().unwrap(); + let schema = py.eval(code, globals, None).unwrap().extract().unwrap(); SchemaValidator::py_new(py, &schema, None).unwrap() } @@ -510,8 +509,7 @@ fn complete_model(bench: &mut Bencher) { sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap(); let complete_schema = py.import("complete_schema").unwrap(); - let mut schema = complete_schema.call_method0("schema").unwrap(); - schema = validate_core_schema(&schema, None).unwrap().extract().unwrap(); + let schema = complete_schema.call_method0("schema").unwrap(); let validator = SchemaValidator::py_new(py, &schema, None).unwrap(); let input = complete_schema.call_method0("input_data_lax").unwrap(); @@ -534,8 +532,7 @@ fn nested_model_using_definitions(bench: &mut Bencher) { sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap(); let complete_schema = py.import("nested_schema").unwrap(); - let mut schema = complete_schema.call_method0("schema_using_defs").unwrap(); - schema = validate_core_schema(&schema, None).unwrap().extract().unwrap(); + let schema = complete_schema.call_method0("schema_using_defs").unwrap(); let validator = SchemaValidator::py_new(py, &schema, None).unwrap(); let input = complete_schema.call_method0("input_data_valid").unwrap(); @@ -562,8 +559,7 @@ fn nested_model_inlined(bench: &mut Bencher) { sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap(); let complete_schema = py.import("nested_schema").unwrap(); - let mut schema = complete_schema.call_method0("inlined_schema").unwrap(); - schema = validate_core_schema(&schema, None).unwrap().extract().unwrap(); + let schema = complete_schema.call_method0("inlined_schema").unwrap(); let validator = SchemaValidator::py_new(py, &schema, None).unwrap(); let input = complete_schema.call_method0("input_data_valid").unwrap(); diff --git a/build.rs b/build.rs index f8f66901a..41a831eca 100644 --- a/build.rs +++ b/build.rs @@ -1,35 +1,3 @@ -use std::env; -use std::path::Path; -use std::process::Command; -use std::str::from_utf8; - -fn generate_self_schema() { - println!("cargo:rerun-if-changed=python/pydantic_core/core_schema.py"); - println!("cargo:rerun-if-changed=generate_self_schema.py"); - if Path::new("./src/self_schema.py").exists() && option_env!("CI") == Some("true") { - // self_schema.py already exists and CI indicates we're running on a github actions build, - // don't bother generating again - return; - } - - let output = Command::new( - env::var("PYTHON") - .ok() - .or_else(|| pyo3_build_config::get().executable.clone()) - .unwrap_or_else(|| "python3".to_owned()), - ) - .arg("generate_self_schema.py") - .output() - .expect("failed to execute process"); - - if !output.status.success() { - let stdout = from_utf8(&output.stdout).unwrap(); - let stderr = from_utf8(&output.stderr).unwrap(); - eprint!("{stdout}{stderr}"); - panic!("generate_self_schema.py failed with {}", output.status); - } -} - fn main() { pyo3_build_config::use_pyo3_cfgs(); if let Some(true) = version_check::supports_feature("coverage_attribute") { @@ -44,7 +12,5 @@ fn main() { println!("cargo:rustc-cfg=specified_profile_use"); } println!("cargo:rustc-check-cfg=cfg(specified_profile_use)"); - - generate_self_schema(); println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); } diff --git a/generate_self_schema.py b/generate_self_schema.py deleted file mode 100644 index 623acba58..000000000 --- a/generate_self_schema.py +++ /dev/null @@ -1,245 +0,0 @@ -""" -This script generates the schema for the schema - e.g. -a definition of what inputs can be provided to `SchemaValidator()`. - -The schema is generated from `python/pydantic_core/core_schema.py`. -""" - -from __future__ import annotations as _annotations - -import decimal -import importlib.util -import re -import sys -from collections.abc import Callable -from datetime import date, datetime, time, timedelta -from pathlib import Path -from re import Pattern -from typing import TYPE_CHECKING, Any, ForwardRef, Union - -from typing_extensions import TypedDict, get_args, get_origin, is_typeddict - -TypingUnionType = type[Union[str, int]] - -try: - from types import UnionType as TypesUnionType - - UnionType = Union[TypingUnionType, TypesUnionType] - -except ImportError: - TypesUnionType = TypingUnionType - UnionType = TypingUnionType - - -THIS_DIR = Path(__file__).parent -SAVE_PATH = THIS_DIR / 'src' / 'self_schema.py' - -if TYPE_CHECKING: - from pydantic_core import core_schema -else: - # can't import core_schema.py directly as pydantic-core might not be installed - core_schema_spec = importlib.util.spec_from_file_location( - '_typing', str(THIS_DIR / 'python' / 'pydantic_core' / 'core_schema.py') - ) - core_schema = importlib.util.module_from_spec(core_schema_spec) - core_schema_spec.loader.exec_module(core_schema) - -# the validator for referencing schema (Schema is used recursively, so has to use a reference) -schema_ref_validator = {'type': 'definition-ref', 'schema_ref': 'root-schema'} - - -def get_schema(obj: Any, definitions: dict[str, core_schema.CoreSchema]) -> core_schema.CoreSchema: # noqa: C901 - if isinstance(obj, str): - return {'type': obj} - elif obj in (datetime, timedelta, date, time, bool, int, float, str, decimal.Decimal, complex): - return {'type': obj.__name__.lower()} - elif is_typeddict(obj): - return type_dict_schema(obj, definitions) - elif obj == Any or obj == type: - return {'type': 'any'} - if isinstance(obj, type) and issubclass(obj, core_schema.Protocol): - return {'type': 'callable'} - - origin = get_origin(obj) - assert origin is not None, f'origin cannot be None, obj={obj}, you probably need to fix generate_self_schema.py' - if origin is Union or origin is TypesUnionType: - return union_schema(obj, definitions) - elif obj is Callable or origin is Callable: - return {'type': 'callable'} - elif origin is core_schema.Literal: - expected = all_literal_values(obj) - assert expected, f'literal "expected" cannot be empty, obj={obj}' - return {'type': 'literal', 'expected': expected} - elif issubclass(origin, list): - return {'type': 'list', 'items_schema': get_schema(obj.__args__[0], definitions)} - elif issubclass(origin, set): - return {'type': 'set', 'items_schema': get_schema(obj.__args__[0], definitions)} - elif issubclass(origin, dict): - return { - 'type': 'dict', - 'keys_schema': get_schema(obj.__args__[0], definitions), - 'values_schema': get_schema(obj.__args__[1], definitions), - } - elif issubclass(origin, type): - # can't really use 'is-instance' since this is used for the class_ parameter of 'is-instance' validators - return {'type': 'any'} - elif origin in (Pattern, re.Pattern): - # can't really use 'is-instance' easily with Pattern, so we use `any` as a placeholder for now - return {'type': 'any'} - else: - # debug(obj) - raise TypeError(f'Unknown type: {obj!r}') - - -def tagged_union(std_union_schema: dict[str, Any], discriminator_key: str, ref: str | None = None) -> dict[str, Any]: - """ - Build a tagged union schema from a standard union schema. - """ - tagged_choices = {} - for choice in std_union_schema['choices']: - literal = choice['fields'][discriminator_key]['schema']['expected'] - assert isinstance(literal, list), 'literal expected must be a list' - assert all(isinstance(arg, str) for arg in literal), 'literal expected must be a list of strings' - first, *rest = literal - tagged_choices[first] = choice - for arg in rest: - tagged_choices[arg] = choice - s = {'type': 'tagged-union', 'discriminator': discriminator_key, 'choices': tagged_choices} - if ref is not None: - s['ref'] = ref - return s - - -defined_ser_schema = False - - -def type_dict_schema( # noqa: C901 - typed_dict: type[TypedDict], definitions: dict[str, core_schema.CoreSchema] -) -> dict[str, Any]: - global defined_ser_schema - - required_keys = getattr(typed_dict, '__required_keys__', set()) - fields = {} - - for field_name, field_type in typed_dict.__annotations__.items(): - required = field_name in required_keys - schema = None - fr_arg = None - if type(field_type) == ForwardRef: - fr_arg = field_type.__forward_arg__ - - fr_arg, matched = re.subn(r'Required\[(.+)]', r'\1', fr_arg) - if matched: - required = True - - if 'CoreSchema' == fr_arg or re.search('[^a-zA-Z]CoreSchema', fr_arg): - if fr_arg == 'CoreSchema': - schema = schema_ref_validator - elif fr_arg == 'list[CoreSchema]': - schema = {'type': 'list', 'items_schema': schema_ref_validator} - elif fr_arg == 'dict[str, CoreSchema]': - schema = {'type': 'dict', 'keys_schema': {'type': 'str'}, 'values_schema': schema_ref_validator} - elif fr_arg == 'dict[Hashable, CoreSchema]': - schema = {'type': 'dict', 'keys_schema': {'type': 'any'}, 'values_schema': schema_ref_validator} - elif fr_arg == 'list[Union[CoreSchema, tuple[CoreSchema, str]]]': - schema = { - 'type': 'list', - 'items_schema': { - 'type': 'union', - 'choices': [ - schema_ref_validator, - {'type': 'tuple', 'items_schema': [schema_ref_validator, {'type': 'str'}]}, - ], - }, - } - else: - raise ValueError(f'Unknown Schema forward ref: {fr_arg}') - else: - field_type = eval_forward_ref(field_type) - - if schema is None: - if get_origin(field_type) == core_schema.Required: - required = True - field_type = field_type.__args__[0] - - schema = get_schema(field_type, definitions) - if fr_arg == 'SerSchema': - if defined_ser_schema: - schema = {'type': 'definition-ref', 'schema_ref': 'ser-schema'} - else: - defined_ser_schema = True - definitions['ser-schema'] = tagged_union(schema, 'type', 'ser-schema') - schema = {'type': 'definition-ref', 'schema_ref': 'ser-schema'} - elif fr_arg.endswith('SerSchema'): - schema = tagged_union(schema, 'type') - - # now_utc_offset is an int that must be in the range -24 hours to +24 hours, we manually add a constraint here - if field_name == 'now_utc_offset': - schema.update(gt=-86_400, lt=86_400) - fields[field_name] = {'schema': schema, 'required': required} - - return {'type': 'typed-dict', 'fields': fields, 'extra_behavior': 'forbid'} - - -def union_schema(union_type: UnionType, definitions) -> core_schema.UnionSchema | core_schema.DefinitionReferenceSchema: - return {'type': 'union', 'choices': [get_schema(arg, definitions) for arg in union_type.__args__]} - - -def all_literal_values(type_: type[core_schema.Literal]) -> list[any]: - if get_origin(type_) is core_schema.Literal: - values = get_args(type_) - return [x for value in values for x in all_literal_values(value)] - else: - return [type_] - - -def eval_forward_ref(type_: Any) -> Any: - if sys.version_info < (3, 12, 4): - return type_._evaluate(core_schema.__dict__, None, recursive_guard=set()) - else: - return type_._evaluate(core_schema.__dict__, None, type_params=set(), recursive_guard=set()) - - -def main() -> None: - schema_union = core_schema.CoreSchema - assert get_origin(schema_union) is Union, 'expected core_schema.CoreSchema to be a Union' - - definitions: dict[str, core_schema.CoreSchema] = {} - - choices = {} - for s in schema_union.__args__: - type_ = s.__annotations__['type'] - m = re.search(r"Literal\['(.+?)']", type_.__forward_arg__) - assert m, f'Unknown schema type: {type_}' - key = m.group(1) - value = get_schema(s, definitions) - choices[key] = value - - schema = core_schema.definitions_schema( - schema=core_schema.definition_reference_schema(schema_ref='root-schema'), - definitions=[ - core_schema.tagged_union_schema(choices, discriminator='type', ref='root-schema'), - *definitions.values(), - ], - ) - python_code = ( - f'# this file is auto-generated by generate_self_schema.py, DO NOT edit manually\nself_schema = {schema}\n' - ) - try: - from black import Mode, TargetVersion, format_file_contents - except ImportError: - pass - else: - mode = Mode( - line_length=120, - string_normalization=False, - magic_trailing_comma=False, - target_versions={TargetVersion.PY37, TargetVersion.PY38, TargetVersion.PY39, TargetVersion.PY310}, - ) - python_code = format_file_contents(python_code, fast=False, mode=mode) - SAVE_PATH.write_text(python_code) - print(f'Self schema definition written to {SAVE_PATH}') - - -if __name__ == '__main__': - main() diff --git a/python/pydantic_core/__init__.py b/python/pydantic_core/__init__.py index 98b64b86e..a146499d0 100644 --- a/python/pydantic_core/__init__.py +++ b/python/pydantic_core/__init__.py @@ -25,7 +25,6 @@ from_json, to_json, to_jsonable_python, - validate_core_schema, ) from .core_schema import CoreConfig, CoreSchema, CoreSchemaType, ErrorType @@ -66,7 +65,6 @@ 'to_json', 'from_json', 'to_jsonable_python', - 'validate_core_schema', ] diff --git a/python/pydantic_core/_pydantic_core.pyi b/python/pydantic_core/_pydantic_core.pyi index 398020bb1..ea8ce5f01 100644 --- a/python/pydantic_core/_pydantic_core.pyi +++ b/python/pydantic_core/_pydantic_core.pyi @@ -34,7 +34,6 @@ __all__ = [ 'to_jsonable_python', 'list_all_errors', 'TzInfo', - 'validate_core_schema', ] __version__: str build_profile: str @@ -1010,12 +1009,3 @@ class TzInfo(datetime.tzinfo): More info can be found at [`tzinfo.fromutc`][datetime.tzinfo.fromutc].""" def __deepcopy__(self, _memo: dict[Any, Any]) -> TzInfo: ... - -def validate_core_schema(schema: CoreSchema, *, strict: bool | None = None) -> CoreSchema: - """Validate a core schema. - - This currently uses lax mode for validation (i.e. will coerce strings to dates and such) - but may use strict mode in the future. - We may also remove this function altogether, do not rely on it being present if you are - using pydantic-core directly. - """ diff --git a/python/pydantic_core/core_schema.py b/python/pydantic_core/core_schema.py index f03daac36..6f522bacc 100644 --- a/python/pydantic_core/core_schema.py +++ b/python/pydantic_core/core_schema.py @@ -953,7 +953,7 @@ class DateSchema(TypedDict, total=False): gt: date now_op: Literal['past', 'future'] # defaults to current local utc offset from `time.localtime().tm_gmtoff` - # value is restricted to -86_400 < offset < 86_400 by bounds in generate_self_schema.py + # value is restricted to -86_400 < offset < 86_400: now_utc_offset: int ref: str metadata: dict[str, Any] diff --git a/src/lib.rs b/src/lib.rs index 2404ebdfb..84bf95a22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,7 +39,7 @@ pub use serializers::{ to_json, to_jsonable_python, PydanticSerializationError, PydanticSerializationUnexpectedValue, SchemaSerializer, WarningsArg, }; -pub use validators::{validate_core_schema, PySome, SchemaValidator}; +pub use validators::{PySome, SchemaValidator}; use crate::input::Input; @@ -113,8 +113,8 @@ mod _pydantic_core { #[pymodule_export] use crate::{ - from_json, list_all_errors, to_json, to_jsonable_python, validate_core_schema, ArgsKwargs, PyMultiHostUrl, - PySome, PyUrl, PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticSerializationError, + from_json, list_all_errors, to_json, to_jsonable_python, ArgsKwargs, PyMultiHostUrl, PySome, PyUrl, + PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticSerializationError, PydanticSerializationUnexpectedValue, PydanticUndefinedType, PydanticUseDefault, SchemaError, SchemaSerializer, SchemaValidator, TzInfo, ValidationError, }; diff --git a/src/validators/mod.rs b/src/validators/mod.rs index 0e497f634..2fd79c495 100644 --- a/src/validators/mod.rs +++ b/src/validators/mod.rs @@ -4,13 +4,11 @@ use enum_dispatch::enum_dispatch; use jiter::{PartialMode, StringCacheMode}; use pyo3::exceptions::PyTypeError; -use pyo3::ffi::c_str; -use pyo3::sync::GILOnceCell; use pyo3::types::{PyAny, PyDict, PyString, PyTuple, PyType}; use pyo3::{intern, PyTraverseError, PyVisit}; use pyo3::{prelude::*, IntoPyObjectExt}; -use crate::build_tools::{py_schema_err, py_schema_error_type, SchemaError}; +use crate::build_tools::{py_schema_err, py_schema_error_type}; use crate::definitions::{Definitions, DefinitionsBuilder}; use crate::errors::{LocItem, ValError, ValResult, ValidationError}; use crate::input::{Input, InputType, StringMapping}; @@ -457,68 +455,6 @@ impl SchemaValidator { } } -static SCHEMA_DEFINITION: GILOnceCell = GILOnceCell::new(); - -#[derive(Debug, Clone)] -pub struct SelfValidator<'py> { - validator: &'py SchemaValidator, -} - -impl<'py> SelfValidator<'py> { - pub fn new(py: Python<'py>) -> PyResult { - let validator = SCHEMA_DEFINITION.get_or_init(py, || match Self::build(py) { - Ok(schema) => schema, - Err(e) => panic!("Error building schema validator:\n {e}"), - }); - Ok(Self { validator }) - } - - pub fn validate_schema(&self, schema: &Bound<'py, PyAny>, strict: Option) -> PyResult> { - let py = schema.py(); - let mut recursion_guard = RecursionState::default(); - let mut state = ValidationState::new( - Extra::new(strict, None, None, None, InputType::Python, true.into(), None, None), - &mut recursion_guard, - false.into(), - ); - match self.validator.validator.validate(py, schema, &mut state) { - Ok(schema_obj) => Ok(schema_obj.into_bound(py)), - Err(e) => Err(SchemaError::from_val_error(py, e)), - } - } - - fn build(py: Python) -> PyResult { - let code = c_str!(include_str!("../self_schema.py")); - let locals = PyDict::new(py); - py.run(code, None, Some(&locals))?; - let self_schema = locals.get_as_req(intern!(py, "self_schema"))?; - - let mut definitions_builder = DefinitionsBuilder::new(); - - let validator = match build_validator(&self_schema, None, &mut definitions_builder) { - Ok(v) => v, - Err(err) => return py_schema_err!("Error building self-schema:\n {}", err), - }; - let definitions = definitions_builder.finish()?; - Ok(SchemaValidator { - validator, - definitions, - py_schema: py.None(), - py_config: None, - title: "Self Schema".into_py_any(py)?, - hide_input_in_errors: false, - validation_error_cause: false, - cache_str: true.into(), - }) - } -} - -#[pyfunction(signature = (schema, *, strict = None))] -pub fn validate_core_schema<'py>(schema: &Bound<'py, PyAny>, strict: Option) -> PyResult> { - let self_validator = SelfValidator::new(schema.py())?; - self_validator.validate_schema(schema, strict) -} - pub trait BuildValidator: Sized { const EXPECTED_TYPE: &'static str; diff --git a/tests/benchmarks/complete_schema.py b/tests/benchmarks/complete_schema.py index e12cdb298..300c841fa 100644 --- a/tests/benchmarks/complete_schema.py +++ b/tests/benchmarks/complete_schema.py @@ -1,7 +1,13 @@ +from __future__ import annotations + from decimal import Decimal +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pydantic_core import CoreSchema -def schema(*, strict: bool = False) -> dict: +def schema(*, strict: bool = False) -> CoreSchema: class MyModel: # __slots__ is not required, but it avoids __pydantic_fields_set__ falling into __dict__ __slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__' @@ -12,7 +18,7 @@ def append_func(input_value, info): def wrap_function(input_value, validator, info): return f'Input {validator(input_value)} Changed' - return { + return { # type: ignore 'type': 'model', 'cls': MyModel, 'config': {'strict': strict}, @@ -342,7 +348,7 @@ def input_data_wrong(): } -def wrap_schema_in_root_model(schema: dict) -> dict: +def wrap_schema_in_root_model(schema: CoreSchema) -> CoreSchema: class MyRootModel: # __slots__ is not required, but it avoids __pydantic_fields_set__ falling into __dict__ __slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__' diff --git a/tests/benchmarks/test_complete_benchmark.py b/tests/benchmarks/test_complete_benchmark.py index 5552e43cc..6ef046529 100644 --- a/tests/benchmarks/test_complete_benchmark.py +++ b/tests/benchmarks/test_complete_benchmark.py @@ -9,7 +9,7 @@ import pytest -from pydantic_core import SchemaSerializer, SchemaValidator, ValidationError, validate_core_schema +from pydantic_core import SchemaSerializer, SchemaValidator, ValidationError from .complete_schema import input_data_lax, input_data_strict, input_data_wrong, schema, wrap_schema_in_root_model @@ -17,7 +17,7 @@ def test_complete_valid(): lax_schema = schema() cls = lax_schema['cls'] - lax_validator = SchemaValidator(validate_core_schema(lax_schema)) + lax_validator = SchemaValidator(lax_schema) output = lax_validator.validate_python(input_data_lax()) assert isinstance(output, cls) assert len(output.__pydantic_fields_set__) == 41 @@ -74,14 +74,14 @@ def test_complete_valid(): }, } - strict_validator = SchemaValidator(validate_core_schema(schema(strict=True))) + strict_validator = SchemaValidator(schema(strict=True)) output2 = strict_validator.validate_python(input_data_strict()) assert output_dict == output2.__dict__ def test_complete_invalid(): lax_schema = schema() - lax_validator = SchemaValidator(validate_core_schema(lax_schema)) + lax_validator = SchemaValidator(lax_schema) with pytest.raises(ValidationError) as exc_info: lax_validator.validate_python(input_data_wrong()) assert len(exc_info.value.errors(include_url=False)) == 739 @@ -89,25 +89,25 @@ def test_complete_invalid(): @pytest.mark.benchmark(group='complete') def test_complete_core_lax(benchmark): - v = SchemaValidator(validate_core_schema(schema())) + v = SchemaValidator(schema()) benchmark(v.validate_python, input_data_lax()) @pytest.mark.benchmark(group='complete') def test_complete_core_strict(benchmark): - v = SchemaValidator(validate_core_schema(schema(strict=True))) + v = SchemaValidator(schema(strict=True)) benchmark(v.validate_python, input_data_strict()) @pytest.mark.benchmark(group='complete') def test_complete_core_root(benchmark): - v = SchemaValidator(validate_core_schema(wrap_schema_in_root_model(schema()))) + v = SchemaValidator(wrap_schema_in_root_model(schema())) benchmark(v.validate_python, {'root': input_data_lax()}) @pytest.mark.benchmark(group='complete-to-python') def test_complete_core_serializer_to_python(benchmark): - core_schema = validate_core_schema(schema()) + core_schema = schema() v = SchemaValidator(core_schema) model = v.validate_python(input_data_lax()) serializer = SchemaSerializer(core_schema) @@ -117,7 +117,7 @@ def test_complete_core_serializer_to_python(benchmark): @pytest.mark.benchmark(group='complete-to-json') def test_complete_core_serializer_to_json(benchmark): - core_schema = validate_core_schema(schema()) + core_schema = schema() v = SchemaValidator(core_schema) model = v.validate_python(input_data_lax()) serializer = SchemaSerializer(core_schema) @@ -126,7 +126,7 @@ def test_complete_core_serializer_to_json(benchmark): @pytest.mark.benchmark(group='complete-wrong') def test_complete_core_error(benchmark): - v = SchemaValidator(validate_core_schema(schema())) + v = SchemaValidator(schema()) data = input_data_wrong() @benchmark @@ -141,7 +141,7 @@ def f(): @pytest.mark.benchmark(group='complete-wrong') def test_complete_core_isinstance(benchmark): - v = SchemaValidator(validate_core_schema(schema())) + v = SchemaValidator(schema()) data = input_data_wrong() assert v.isinstance_python(data) is False @@ -161,14 +161,14 @@ def default_json_encoder(obj): @pytest.mark.benchmark(group='complete-json') def test_complete_core_json(benchmark): - v = SchemaValidator(validate_core_schema(schema())) + v = SchemaValidator(schema()) json_data = json.dumps(input_data_lax(), default=default_json_encoder) benchmark(v.validate_json, json_data) @pytest.mark.benchmark(group='complete-json') def test_complete_core_root_json(benchmark): - v = SchemaValidator(validate_core_schema(wrap_schema_in_root_model(schema()))) + v = SchemaValidator(wrap_schema_in_root_model(schema())) json_data = json.dumps({'root': input_data_lax()}, default=default_json_encoder) benchmark(v.validate_json, json_data) @@ -176,4 +176,4 @@ def test_complete_core_root_json(benchmark): @pytest.mark.benchmark(group='build') def test_build_schema(benchmark): lax_schema = schema() - benchmark(lambda s: SchemaValidator(validate_core_schema(s)), lax_schema) + benchmark(SchemaValidator, lax_schema) diff --git a/tests/conftest.py b/tests/conftest.py index e9079c8ba..b1c1e8fb0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,7 +15,7 @@ import hypothesis import pytest -from pydantic_core import ArgsKwargs, CoreSchema, SchemaValidator, ValidationError, validate_core_schema +from pydantic_core import ArgsKwargs, CoreSchema, SchemaValidator, ValidationError from pydantic_core.core_schema import CoreConfig __all__ = 'Err', 'PyAndJson', 'assert_gc', 'is_free_threaded', 'plain_repr', 'infinite_generator' @@ -64,7 +64,7 @@ def __init__( *, validator_type: Literal['json', 'python'] | None = None, ): - self.validator = SchemaValidator(validate_core_schema(schema), config) + self.validator = SchemaValidator(schema, config) self.validator_type = validator_type def validate_python(self, py_input, strict: bool | None = None, context: Any = None): diff --git a/tests/serializers/test_definitions.py b/tests/serializers/test_definitions.py index d45398097..456b0ab1d 100644 --- a/tests/serializers/test_definitions.py +++ b/tests/serializers/test_definitions.py @@ -1,6 +1,6 @@ import pytest -from pydantic_core import SchemaError, SchemaSerializer, core_schema, validate_core_schema +from pydantic_core import SchemaError, SchemaSerializer, core_schema def test_custom_ser(): @@ -23,20 +23,6 @@ def test_ignored_def(): assert s.to_python([1, 2, 3]) == [1, 2, 3] -def test_def_error(): - with pytest.raises(SchemaError) as exc_info: - validate_core_schema( - core_schema.definitions_schema( - core_schema.list_schema(core_schema.definition_reference_schema('foobar')), - [core_schema.int_schema(ref='foobar'), {'type': 'wrong'}], - ) - ) - - assert str(exc_info.value).startswith( - "Invalid Schema:\ndefinitions.definitions.1\n Input tag 'wrong' found using 'type'" - ) - - def test_repeated_ref(): with pytest.raises(SchemaError, match='SchemaError: Duplicate ref: `foobar`'): SchemaSerializer( diff --git a/tests/serializers/test_dict.py b/tests/serializers/test_dict.py index cc1b56091..dcd7f6acc 100644 --- a/tests/serializers/test_dict.py +++ b/tests/serializers/test_dict.py @@ -3,7 +3,7 @@ import pytest from dirty_equals import IsStrictDict -from pydantic_core import SchemaError, SchemaSerializer, core_schema, validate_core_schema +from pydantic_core import SchemaSerializer, core_schema def test_dict_str_int(): @@ -143,18 +143,3 @@ def test_filter_runtime_int(): core_schema.dict_schema(core_schema.any_schema(), serialization=core_schema.filter_dict_schema(exclude={0, 1})) ) assert s.to_python({0: 0, 1: 1, 2: 2, 3: 3}, include={1, 2}) == {1: 1, 2: 2} - - -@pytest.mark.parametrize( - 'include_value,error_msg', - [ - ('foobar', 'Input should be a valid set'), - ({'a': 'dict'}, 'Input should be a valid set'), - ({4.2}, 'Input should be a valid integer, got a number with a fractional part'), - ], -) -def test_include_error(include_value, error_msg): - with pytest.raises(SchemaError, match=error_msg): - validate_core_schema( - core_schema.dict_schema(serialization=core_schema.filter_dict_schema(include=include_value)) - ) diff --git a/tests/serializers/test_list_tuple.py b/tests/serializers/test_list_tuple.py index 7473ee261..ec475be24 100644 --- a/tests/serializers/test_list_tuple.py +++ b/tests/serializers/test_list_tuple.py @@ -5,10 +5,8 @@ from pydantic_core import ( PydanticSerializationError, - SchemaError, SchemaSerializer, core_schema, - validate_core_schema, ) @@ -162,13 +160,10 @@ def test_exclude(schema_func, seq_f): assert v.to_json(seq_f('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'), exclude={-1, -2}) == b'["a","c","e"]' -@pytest.mark.parametrize('include,exclude', [({1, 3, 5}, {5, 6}), ([1, 3, 5], [5, 6])]) -def test_filter(include, exclude): +def test_filter(): v = SchemaSerializer( - validate_core_schema( - core_schema.list_schema( - core_schema.any_schema(), serialization=core_schema.filter_seq_schema(include=include, exclude=exclude) - ) + core_schema.list_schema( + core_schema.any_schema(), serialization=core_schema.filter_seq_schema(include={1, 3, 5}, exclude={5, 6}) ) ) assert v.to_python([0, 1, 2, 3, 4, 5, 6, 7]) == [1, 3] @@ -197,23 +192,6 @@ class RemovedContains(ImplicitContains): __contains__ = None # This might be done to explicitly force the `x in RemovedContains()` check to not be allowed -@pytest.mark.parametrize( - 'include_value,error_msg', - [ - ('foobar', 'Input should be a valid set'), - ({'a': 'dict'}, 'Input should be a valid set'), - ({4.2}, 'Input should be a valid integer, got a number with a fractional part'), - ({'a'}, 'Input should be a valid integer, unable to parse string as an integer'), - ], -) -@pytest.mark.parametrize('schema_func', [core_schema.list_schema, core_schema.tuple_variable_schema]) -def test_include_error(schema_func, include_value, error_msg): - with pytest.raises(SchemaError, match=error_msg): - validate_core_schema( - schema_func(core_schema.any_schema(), serialization=core_schema.filter_seq_schema(include=include_value)) - ) - - @pytest.mark.parametrize( 'include,exclude,expected', [ diff --git a/tests/serializers/test_misc.py b/tests/serializers/test_misc.py deleted file mode 100644 index 7753f1948..000000000 --- a/tests/serializers/test_misc.py +++ /dev/null @@ -1,15 +0,0 @@ -import pytest - -from pydantic_core import SchemaError, core_schema, validate_core_schema - - -@pytest.mark.parametrize( - 'ser_schema,msg', - [ - ({'invalid': 'schema'}, "Unable to extract tag using discriminator 'type'"), - ({'type': 'unknown'}, "Input tag 'unknown' found using 'type' does not match any of the expected tags:"), - ], -) -def test_invalid_ser_schema(ser_schema, msg): - with pytest.raises(SchemaError, match=msg): - validate_core_schema(core_schema.any_schema(serialization=ser_schema)) diff --git a/tests/test_build.py b/tests/test_build.py index b20a58530..c0579f934 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -2,55 +2,15 @@ import pytest -from pydantic_core import SchemaError, SchemaValidator, validate_core_schema +from pydantic_core import SchemaValidator from pydantic_core import core_schema as cs -def test_build_error_type(): - with pytest.raises(SchemaError, match="Input tag 'foobar' found using 'type' does not match any of the"): - validate_core_schema({'type': 'foobar', 'title': 'TestModel'}) - - -def test_build_error_internal(): - with pytest.raises(SchemaError, match='Input should be a valid integer, unable to parse string as an integer'): - validate_core_schema({'type': 'str', 'min_length': 'xxx', 'title': 'TestModel'}) - - -def test_build_error_deep(): - with pytest.raises(SchemaError, match='Input should be a valid integer, unable to parse string as an integer'): - validate_core_schema( - { - 'title': 'MyTestModel', - 'type': 'typed-dict', - 'fields': {'age': {'schema': {'type': 'int', 'ge': 'not-int'}}}, - } - ) - - def test_schema_as_string(): v = SchemaValidator(cs.bool_schema()) assert v.validate_python('tRuE') is True -def test_schema_wrong_type(pydantic_version): - with pytest.raises(SchemaError) as exc_info: - validate_core_schema(1) - assert str(exc_info.value) == ( - 'Invalid Schema:\n Input should be a valid dictionary or object to' - ' extract fields from [type=model_attributes_type, input_value=1, input_type=int]\n' - f' For further information visit https://errors.pydantic.dev/{pydantic_version}/v/model_attributes_type' - ) - assert exc_info.value.errors() == [ - { - 'input': 1, - 'loc': (), - 'msg': 'Input should be a valid dictionary or object to extract fields from', - 'type': 'model_attributes_type', - } - ] - assert exc_info.value.error_count() == 1 - - @pytest.mark.parametrize('pickle_protocol', range(1, pickle.HIGHEST_PROTOCOL + 1)) def test_pickle(pickle_protocol: int) -> None: v1 = SchemaValidator(cs.bool_schema()) @@ -61,14 +21,6 @@ def test_pickle(pickle_protocol: int) -> None: assert repr(v1) == repr(v2) -@pytest.mark.skip -def test_schema_definition_error(): - schema = {'type': 'union', 'choices': []} - schema['choices'].append({'type': 'nullable', 'schema': schema}) - with pytest.raises(SchemaError, match='Recursion error - cyclic reference detected'): - validate_core_schema(schema) - - def test_not_schema_definition_error(): schema = { 'type': 'typed-dict', @@ -81,21 +33,6 @@ def test_not_schema_definition_error(): assert repr(v).count('TypedDictField') == 101 -def test_no_type(): - with pytest.raises(SchemaError, match="Unable to extract tag using discriminator 'type'"): - validate_core_schema({}) - - -def test_wrong_type(): - with pytest.raises(SchemaError, match="Input tag 'unknown' found using 'type' does not match any of the"): - validate_core_schema({'type': 'unknown'}) - - -def test_function_no_mode(): - with pytest.raises(SchemaError, match="Input tag 'function' found using 'type' does not match any of the"): - validate_core_schema({'type': 'function'}) - - def test_try_self_schema_discriminator(): """Trying to use self-schema when it shouldn't be used""" v = SchemaValidator(cs.tagged_union_schema(choices={'int': cs.int_schema()}, discriminator='self-schema')) diff --git a/tests/validators/test_custom_error.py b/tests/validators/test_custom_error.py index ada4aef47..3839b5313 100644 --- a/tests/validators/test_custom_error.py +++ b/tests/validators/test_custom_error.py @@ -1,6 +1,6 @@ import pytest -from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema from ..conftest import PyAndJson @@ -31,11 +31,6 @@ def test_custom_error_type(py_and_json: PyAndJson): ] -def test_custom_error_error(): - with pytest.raises(SchemaError, match=r'custom_error_type\s+Field required \[type=missing'): - validate_core_schema({'type': 'custom-error', 'schema': {'type': 'int'}}) - - def test_custom_error_invalid(): msg = "custom_error_message should not be provided if 'custom_error_type' matches a known error" with pytest.raises(SchemaError, match=msg): diff --git a/tests/validators/test_date.py b/tests/validators/test_date.py index 161f115d9..8300a15ad 100644 --- a/tests/validators/test_date.py +++ b/tests/validators/test_date.py @@ -7,7 +7,7 @@ import pytest -from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema from pydantic_core import core_schema as cs from ..conftest import Err, PyAndJson @@ -229,11 +229,6 @@ def test_date_kwargs(kwargs: dict[str, Any], input_value: date, expected: Err | assert output == expected -def test_invalid_constraint(): - with pytest.raises(SchemaError, match=r'date\.gt\n Input should be a valid date or datetime'): - validate_core_schema({'type': 'date', 'gt': 'foobar'}) - - def test_dict_py(): v = SchemaValidator(cs.dict_schema(keys_schema=cs.date_schema(), values_schema=cs.int_schema())) assert v.validate_python({date(2000, 1, 1): 2, date(2000, 1, 2): 4}) == {date(2000, 1, 1): 2, date(2000, 1, 2): 4} @@ -308,8 +303,3 @@ def test_date_past_future_today(): assert v.isinstance_python(today) is False assert v.isinstance_python(today - timedelta(days=1)) is False assert v.isinstance_python(today + timedelta(days=1)) is True - - -def test_offset_too_large(): - with pytest.raises(SchemaError, match=r'Input should be less than 86400 \[type=less_than,'): - validate_core_schema(core_schema.date_schema(now_op='past', now_utc_offset=24 * 3600)) diff --git a/tests/validators/test_datetime.py b/tests/validators/test_datetime.py index 21b0db61e..b56a77e54 100644 --- a/tests/validators/test_datetime.py +++ b/tests/validators/test_datetime.py @@ -8,7 +8,7 @@ import pytest -from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema from pydantic_core import core_schema as cs from ..conftest import Err, PyAndJson @@ -318,11 +318,6 @@ def test_union(): assert v.validate_python(datetime(2022, 1, 2)) == datetime(2022, 1, 2) -def test_invalid_constraint(): - with pytest.raises(SchemaError, match=r'datetime\.gt\n Input should be a valid datetime'): - validate_core_schema({'type': 'datetime', 'gt': 'foobar'}) - - @pytest.mark.parametrize( 'input_value,expected', [ @@ -421,19 +416,6 @@ def test_mock_utc_offset_8_hours(mocker): assert not v.isinstance_python(future) -def test_offset_too_large(): - with pytest.raises(SchemaError, match=r'Input should be greater than -86400 \[type=greater_than,'): - validate_core_schema(core_schema.datetime_schema(now_op='past', now_utc_offset=-24 * 3600)) - - -def test_raises_schema_error_for_unknown_constraint_kind(): - with pytest.raises( - SchemaError, - match=(r'Input should be \'aware\' or \'naive\' \[type=literal_error, input_value=\'foo\', input_type=str\]'), - ): - validate_core_schema({'type': 'datetime', 'tz_constraint': 'foo'}) - - def test_aware(): v = SchemaValidator(core_schema.datetime_schema(tz_constraint='aware')) value = datetime.now(tz=timezone.utc) @@ -511,11 +493,6 @@ def test_tz_constraint_too_high(): SchemaValidator(core_schema.datetime_schema(tz_constraint=2**64)) -def test_tz_constraint_wrong(): - with pytest.raises(SchemaError, match="Input should be 'aware' or 'naive"): - validate_core_schema(core_schema.datetime_schema(tz_constraint='wrong')) - - def test_tz_hash() -> None: v = SchemaValidator(core_schema.datetime_schema()) lookup: dict[datetime, str] = {} diff --git a/tests/validators/test_definitions.py b/tests/validators/test_definitions.py index 1c730ee6f..967eeae2d 100644 --- a/tests/validators/test_definitions.py +++ b/tests/validators/test_definitions.py @@ -1,6 +1,6 @@ import pytest -from pydantic_core import SchemaError, SchemaValidator, core_schema, validate_core_schema +from pydantic_core import SchemaError, SchemaValidator, core_schema from ..conftest import plain_repr @@ -45,20 +45,6 @@ def test_check_ref_used_ignores_metadata(): # assert plain_repr(v).endswith('definitions=[])') -def test_def_error(): - with pytest.raises(SchemaError) as exc_info: - validate_core_schema( - core_schema.definitions_schema( - core_schema.list_schema(core_schema.definition_reference_schema('foobar')), - [core_schema.int_schema(ref='foobar'), {'type': 'wrong'}], - ) - ) - assert str(exc_info.value).startswith( - "Invalid Schema:\ndefinitions.definitions.1\n Input tag 'wrong' found using 'type'" - ) - assert exc_info.value.error_count() == 1 - - def test_dict_repeat(): v = SchemaValidator( core_schema.definitions_schema( diff --git a/tests/validators/test_function.py b/tests/validators/test_function.py index 09ef7c74f..8d138d16c 100644 --- a/tests/validators/test_function.py +++ b/tests/validators/test_function.py @@ -8,7 +8,7 @@ import pytest from dirty_equals import HasRepr -from pydantic_core import CoreConfig, SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import CoreConfig, SchemaValidator, ValidationError, core_schema from pydantic_core import core_schema as cs from ..conftest import plain_repr @@ -210,14 +210,6 @@ def f(input_value, validator, info): ) -def test_function_wrap_not_callable(): - with pytest.raises(SchemaError, match='function-wrap.function.typed-dict.function\n Input should be callable'): - validate_core_schema(core_schema.with_info_wrap_validator_function([], core_schema.str_schema())) - - with pytest.raises(SchemaError, match='function-wrap.function\n Field required'): - validate_core_schema({'type': 'function-wrap', 'schema': {'type': 'str'}}) - - def test_wrap_error(): def f(input_value, validator, info): try: @@ -426,17 +418,6 @@ def f(input_value): assert v.validate_python('x') == 'xx' -def test_plain_with_schema(): - with pytest.raises(SchemaError, match='function-plain.schema\n Extra inputs are not permitted'): - validate_core_schema( - { - 'type': 'function-plain', - 'function': {'type': 'with-info', 'function': lambda x: x}, - 'schema': {'type': 'str'}, - } - ) - - def test_validate_assignment(): def f(input_value): input_value.more = 'foobar' diff --git a/tests/validators/test_model_fields.py b/tests/validators/test_model_fields.py index cc04f07c1..e288f2fd8 100644 --- a/tests/validators/test_model_fields.py +++ b/tests/validators/test_model_fields.py @@ -9,7 +9,7 @@ import pytest from dirty_equals import FunctionCheck, HasRepr, IsStr -from pydantic_core import CoreConfig, SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import CoreConfig, SchemaError, SchemaValidator, ValidationError, core_schema from ..conftest import Err, PyAndJson @@ -430,11 +430,6 @@ def test_json_error(): ] -def test_missing_schema_key(): - with pytest.raises(SchemaError, match='model-fields.fields.x.schema\n Field required'): - validate_core_schema({'type': 'model-fields', 'fields': {'x': {'type': 'str'}}}) - - def test_fields_required_by_default(): """By default all fields should be required""" v = SchemaValidator( @@ -739,11 +734,9 @@ def test_paths_allow_by_name(py_and_json: PyAndJson, input_value): @pytest.mark.parametrize( 'alias_schema,error', [ - ({'validation_alias': ['foo', ['bar']]}, 'Input should be a valid string'), ({'validation_alias': []}, 'Lookup paths should have at least one element'), ({'validation_alias': [[]]}, 'Each alias path should have at least one element'), ({'validation_alias': [123]}, "TypeError: 'int' object cannot be converted to 'PyList'"), - ({'validation_alias': [[[]]]}, 'Input should be a valid string'), ({'validation_alias': [[1, 'foo']]}, 'TypeError: The first item in an alias path should be a string'), ], ids=repr, @@ -751,12 +744,10 @@ def test_paths_allow_by_name(py_and_json: PyAndJson, input_value): def test_alias_build_error(alias_schema, error): with pytest.raises(SchemaError, match=error): SchemaValidator( - schema=validate_core_schema( - { - 'type': 'model-fields', - 'fields': {'field_a': {'type': 'model-field', 'schema': {'type': 'int'}, **alias_schema}}, - } - ) + schema={ + 'type': 'model-fields', + 'fields': {'field_a': {'type': 'model-field', 'schema': {'type': 'int'}, **alias_schema}}, + } ) @@ -1478,20 +1469,6 @@ def test_bad_default_factory(default_factory, error_message): class TestOnError: - def test_on_error_bad_name(self): - with pytest.raises(SchemaError, match="Input should be 'raise', 'omit' or 'default'"): - validate_core_schema( - { - 'type': 'model-fields', - 'fields': { - 'x': { - 'type': 'model-field', - 'schema': {'type': 'default', 'schema': {'type': 'str'}, 'on_error': 'rais'}, - } - }, - } - ) - def test_on_error_bad_default(self): with pytest.raises(SchemaError, match="'on_error = default' requires a `default` or `default_factory`"): SchemaValidator( diff --git a/tests/validators/test_pickling.py b/tests/validators/test_pickling.py index b46c57029..0ddaf5991 100644 --- a/tests/validators/test_pickling.py +++ b/tests/validators/test_pickling.py @@ -4,15 +4,13 @@ import pytest -from pydantic_core import core_schema, validate_core_schema +from pydantic_core import core_schema from pydantic_core._pydantic_core import SchemaValidator, ValidationError def test_basic_schema_validator(): v = SchemaValidator( - validate_core_schema( - {'type': 'dict', 'strict': True, 'keys_schema': {'type': 'int'}, 'values_schema': {'type': 'int'}} - ) + {'type': 'dict', 'strict': True, 'keys_schema': {'type': 'int'}, 'values_schema': {'type': 'int'}} ) v = pickle.loads(pickle.dumps(v)) assert v.validate_python({'1': 2, '3': 4}) == {1: 2, 3: 4} diff --git a/tests/validators/test_time.py b/tests/validators/test_time.py index c5f5e3c39..9a643acfb 100644 --- a/tests/validators/test_time.py +++ b/tests/validators/test_time.py @@ -5,7 +5,7 @@ import pytest -from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema from ..conftest import Err, PyAndJson @@ -198,11 +198,6 @@ def test_time_bound_ctx(): ] -def test_invalid_constraint(): - with pytest.raises(SchemaError, match='Input should be in a valid time format'): - validate_core_schema({'type': 'time', 'gt': 'foobar'}) - - def test_dict_py(): v = SchemaValidator( core_schema.dict_schema(keys_schema=core_schema.time_schema(), values_schema=core_schema.int_schema()) @@ -300,8 +295,3 @@ def test_neg_7200(): def test_tz_constraint_too_high(): with pytest.raises(SchemaError, match='OverflowError: Python int too large to convert to C long'): SchemaValidator(core_schema.time_schema(tz_constraint=2**64)) - - -def test_tz_constraint_wrong(): - with pytest.raises(SchemaError, match="Input should be 'aware' or 'naive"): - validate_core_schema(core_schema.time_schema(tz_constraint='wrong')) diff --git a/tests/validators/test_timedelta.py b/tests/validators/test_timedelta.py index c10a2d592..243fbfb95 100644 --- a/tests/validators/test_timedelta.py +++ b/tests/validators/test_timedelta.py @@ -5,7 +5,7 @@ import pytest -from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import SchemaError, SchemaValidator, ValidationError, core_schema from ..conftest import Err, PyAndJson @@ -209,20 +209,6 @@ def test_timedelta_kwargs_strict(): assert output == timedelta(days=2, hours=1) -def test_invalid_constraint(): - with pytest.raises( - SchemaError, - match='Invalid Schema:\ntimedelta.gt\n Input should be a valid timedelta, invalid character in hour', - ): - validate_core_schema({'type': 'timedelta', 'gt': 'foobar'}) - - with pytest.raises( - SchemaError, - match='Invalid Schema:\ntimedelta.le\n Input should be a valid timedelta, invalid character in hour', - ): - validate_core_schema({'type': 'timedelta', 'le': 'foobar'}) - - def test_dict_py(): v = SchemaValidator( core_schema.dict_schema(keys_schema=core_schema.timedelta_schema(), values_schema=core_schema.int_schema()) diff --git a/tests/validators/test_typed_dict.py b/tests/validators/test_typed_dict.py index b224b65ea..3d96d40e0 100644 --- a/tests/validators/test_typed_dict.py +++ b/tests/validators/test_typed_dict.py @@ -8,7 +8,7 @@ import pytest from dirty_equals import FunctionCheck -from pydantic_core import CoreConfig, SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import CoreConfig, SchemaError, SchemaValidator, ValidationError, core_schema from ..conftest import Err, PyAndJson, assert_gc @@ -190,11 +190,6 @@ def test_allow_extra_invalid(): ) -def test_allow_extra_wrong(): - with pytest.raises(SchemaError, match="Input should be 'allow', 'forbid' or 'ignore'"): - validate_core_schema({'type': 'typed-dict', 'fields': {}, 'config': {'extra_fields_behavior': 'wrong'}}) - - def test_str_config(): v = SchemaValidator( core_schema.typed_dict_schema( @@ -231,11 +226,6 @@ def test_json_error(): ] -def test_missing_schema_key(): - with pytest.raises(SchemaError, match='typed-dict.fields.x.schema\n Field required'): - validate_core_schema({'type': 'typed-dict', 'fields': {'x': {'type': 'str'}}}) - - def test_fields_required_by_default(): """By default all fields should be required""" v = SchemaValidator( @@ -629,11 +619,9 @@ def test_paths_allow_by_name(py_and_json: PyAndJson, input_value): @pytest.mark.parametrize( 'alias_schema,error', [ - ({'validation_alias': ['foo', ['bar']]}, 'Input should be a valid string'), ({'validation_alias': []}, 'Lookup paths should have at least one element'), ({'validation_alias': [[]]}, 'Each alias path should have at least one element'), ({'validation_alias': [123]}, "TypeError: 'int' object cannot be converted to 'PyList'"), - ({'validation_alias': [[[]]]}, 'Input should be a valid string'), ({'validation_alias': [[1, 'foo']]}, 'TypeError: The first item in an alias path should be a string'), ], ids=repr, @@ -641,12 +629,10 @@ def test_paths_allow_by_name(py_and_json: PyAndJson, input_value): def test_alias_build_error(alias_schema, error): with pytest.raises(SchemaError, match=error): SchemaValidator( - schema=validate_core_schema( - { - 'type': 'typed-dict', - 'fields': {'field_a': {'type': 'typed-dict-field', 'schema': {'type': 'int'}, **alias_schema}}, - } - ) + schema={ + 'type': 'typed-dict', + 'fields': {'field_a': {'type': 'typed-dict-field', 'schema': {'type': 'int'}, **alias_schema}}, + } ) @@ -906,20 +892,6 @@ def test_bad_default_factory(default_factory, error_message): class TestOnError: - def test_on_error_bad_name(self): - with pytest.raises(SchemaError, match="Input should be 'raise', 'omit' or 'default'"): - validate_core_schema( - { - 'type': 'typed-dict', - 'fields': { - 'x': { - 'type': 'typed-dict-field', - 'schema': {'type': 'default', 'schema': {'type': 'str'}, 'on_error': 'rais'}, - } - }, - } - ) - def test_on_error_bad_omit(self): with pytest.raises(SchemaError, match="Field 'x': 'on_error = omit' cannot be set for required fields"): SchemaValidator( diff --git a/tests/validators/test_union.py b/tests/validators/test_union.py index 7e0daacec..8f54d00e8 100644 --- a/tests/validators/test_union.py +++ b/tests/validators/test_union.py @@ -8,7 +8,7 @@ import pytest from dirty_equals import IsFloat, IsInt -from pydantic_core import CoreConfig, SchemaError, SchemaValidator, ValidationError, core_schema, validate_core_schema +from pydantic_core import CoreConfig, SchemaError, SchemaValidator, ValidationError, core_schema from ..conftest import plain_repr @@ -231,22 +231,6 @@ def test_union_list_bool_int(): ] -def test_no_choices(pydantic_version): - with pytest.raises(SchemaError) as exc_info: - validate_core_schema({'type': 'union'}) - - assert str(exc_info.value) == ( - 'Invalid Schema:\n' - 'union.choices\n' - " Field required [type=missing, input_value={'type': 'union'}, input_type=dict]\n" - f' For further information visit https://errors.pydantic.dev/{pydantic_version}/v/missing' - ) - assert exc_info.value.error_count() == 1 - assert exc_info.value.errors() == [ - {'input': {'type': 'union'}, 'loc': ('union', 'choices'), 'msg': 'Field required', 'type': 'missing'} - ] - - def test_empty_choices(): msg = r'Error building "union" validator:\s+SchemaError: One or more union choices required' with pytest.raises(SchemaError, match=msg):