From 0af18c4172d5855547d54f2b09506a5cf8ac69ae Mon Sep 17 00:00:00 2001 From: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:30:57 -0400 Subject: [PATCH] Add `invalid` schema placeholder (#1469) --- python/pydantic_core/core_schema.py | 22 ++++++++++++++++++++++ src/validators/mod.rs | 1 + tests/test_schema_functions.py | 8 +++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/python/pydantic_core/core_schema.py b/python/pydantic_core/core_schema.py index 922900170..b1c4c13b5 100644 --- a/python/pydantic_core/core_schema.py +++ b/python/pydantic_core/core_schema.py @@ -435,6 +435,26 @@ def model_ser_schema(cls: Type[Any], schema: CoreSchema) -> ModelSerSchema: ] +class InvalidSchema(TypedDict, total=False): + type: Required[Literal['invalid']] + ref: str + metadata: Dict[str, Any] + + +def invalid_schema(ref: str | None = None, metadata: Dict[str, Any] | None = None) -> InvalidSchema: + """ + Returns an invalid schema, used to indicate that a schema is invalid. + + Returns a schema that matches any value, e.g.: + + Args: + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + """ + + return _dict_not_none(type='invalid', ref=ref, metadata=metadata) + + class ComputedField(TypedDict, total=False): type: Required[Literal['computed-field']] property_name: Required[str] @@ -3826,6 +3846,7 @@ def definition_reference_schema( # union which kills performance not just for pydantic, but even for code using pydantic if not MYPY: CoreSchema = Union[ + InvalidSchema, AnySchema, NoneSchema, BoolSchema, @@ -3882,6 +3903,7 @@ def definition_reference_schema( # to update this, call `pytest -k test_core_schema_type_literal` and copy the output CoreSchemaType = Literal[ + 'invalid', 'any', 'none', 'bool', diff --git a/src/validators/mod.rs b/src/validators/mod.rs index 5f88d5dc8..fcd64ebf2 100644 --- a/src/validators/mod.rs +++ b/src/validators/mod.rs @@ -479,6 +479,7 @@ macro_rules! validator_match { $( <$validator>::EXPECTED_TYPE => build_specific_validator::<$validator>($type, $dict, $config, $definitions), )+ + "invalid" => return py_schema_err!("Cannot construct schema with `InvalidSchema` member."), _ => return py_schema_err!(r#"Unknown schema type: "{}""#, $type), } }; diff --git a/tests/test_schema_functions.py b/tests/test_schema_functions.py index 6d96678c8..a15adfca5 100644 --- a/tests/test_schema_functions.py +++ b/tests/test_schema_functions.py @@ -291,6 +291,7 @@ def args(*args, **kwargs): (core_schema.decimal_schema, args(), {'type': 'decimal'}), (core_schema.decimal_schema, args(multiple_of=5, gt=1.2), {'type': 'decimal', 'multiple_of': 5, 'gt': 1.2}), (core_schema.complex_schema, args(), {'type': 'complex'}), + (core_schema.invalid_schema, args(), {'type': 'invalid'}), ] @@ -299,7 +300,7 @@ def test_schema_functions(function, args_kwargs, expected_schema): args, kwargs = args_kwargs schema = function(*args, **kwargs) assert schema == expected_schema - if schema.get('type') in {None, 'definition-ref', 'typed-dict-field', 'model-field'}: + if schema.get('type') in {None, 'definition-ref', 'typed-dict-field', 'model-field', 'invalid'}: return v = SchemaValidator(schema) @@ -354,3 +355,8 @@ def test_expected_serialization_types(return_schema): ) ) ) + + +def test_err_on_invalid() -> None: + with pytest.raises(SchemaError, match='Cannot construct schema with `InvalidSchema` member.'): + SchemaValidator(core_schema.invalid_schema())