Currently because of configs it is not possible to map a type to a SchemaValidator or CoreSchema. Consider:
class Inner(BaseModel):
x: dict[str, list[float]]
model_config = ConfigDict(allow_inf_nan=False)
class Outer(BaseModel):
inner: Inner
x: dict[str, list[float]]
model_config = ConfigDict(allow_inf_nan=True)
Edit by @Viicos: allow_inf_nan actually doesn't seem to alter the core schema of x. One example that does however is use_enum_values.
Because of this we can’t just have a type_cache: dict[type, CoreSchema] when we build a schema from types in Pydantic: although dict[str, list[float]] shows up in two places the actual schema differs because of the model config.
To get around this I propose that we establish a rule: “every validator must be derivable from the type and only the type”. That means that all of the things coming from configs have to live elsewhere. For this I propose we (1) move all config things to ValidationState and (2) introduce a validator that mutates ValidationState to set the current config.
For example, we’d have {‘type’: ‘config’, ‘config’: {‘allow_inf_nan’: True}, ‘schema’: {…}}. At runtime this would mutate the validation context. And FloatValidator would pull that configuration from the context instead of storing it on the struct. Now both CoreSchema::Float and FloatValidator are immutable respect to the type and thus we can map from a type to a CoreSchema or SchemaValidator.
I expect this will slightly simplify some code (it essentially merges runtime parameters and compile time parameters into one code path where compile time just means a compile time defined mutation of runtime parameters) and have a minimal performance impact (we can still convert all configs to rust structs ahead of time, it’s just a struct being passed in through context vs hardcoded on the validator).
I think we might as well also establish or consider current behavior wrt rules for config merging and interaction with runtime parameters.
@davidhewitt @sydney-runkle wdyt?
Currently because of configs it is not possible to map a type to a SchemaValidator or CoreSchema. Consider:
Because of this we can’t just have a
type_cache: dict[type, CoreSchema]when we build a schema from types in Pydantic: althoughdict[str, list[float]]shows up in two places the actual schema differs because of the model config.To get around this I propose that we establish a rule: “every validator must be derivable from the type and only the type”. That means that all of the things coming from configs have to live elsewhere. For this I propose we (1) move all config things to ValidationState and (2) introduce a validator that mutates ValidationState to set the current config.
For example, we’d have
{‘type’: ‘config’, ‘config’: {‘allow_inf_nan’: True}, ‘schema’: {…}}. At runtime this would mutate the validation context. And FloatValidator would pull that configuration from the context instead of storing it on the struct. Now both CoreSchema::Float and FloatValidator are immutable respect to the type and thus we can map from a type to a CoreSchema or SchemaValidator.I expect this will slightly simplify some code (it essentially merges runtime parameters and compile time parameters into one code path where compile time just means a compile time defined mutation of runtime parameters) and have a minimal performance impact (we can still convert all configs to rust structs ahead of time, it’s just a struct being passed in through context vs hardcoded on the validator).
I think we might as well also establish or consider current behavior wrt rules for config merging and interaction with runtime parameters.
@davidhewitt @sydney-runkle wdyt?