From 7642acc048c74c0897a68a1559e6ab47034d9bb6 Mon Sep 17 00:00:00 2001 From: Yurii Karabas <1998uriyyo@gmail.com> Date: Thu, 26 Dec 2024 09:33:33 +0100 Subject: [PATCH] Revert changes to model-fields and dataclass --- python/pydantic_core/core_schema.py | 10 +---- src/validators/dataclass.rs | 11 ----- src/validators/model_fields.rs | 7 ---- tests/validators/test_dataclasses.py | 60 --------------------------- tests/validators/test_model_fields.py | 53 ----------------------- 5 files changed, 1 insertion(+), 140 deletions(-) diff --git a/python/pydantic_core/core_schema.py b/python/pydantic_core/core_schema.py index c968ab8f6..b5bc8e960 100644 --- a/python/pydantic_core/core_schema.py +++ b/python/pydantic_core/core_schema.py @@ -96,7 +96,7 @@ class CoreConfig(TypedDict, total=False): validate_default: bool # used on typed-dicts and arguments populate_by_name: bool # replaces `allow_population_by_field_name` in pydantic v1 - # stop validation on a first error, used with typed-dict, model-fields, and dataclass fields + # stop validation on a first error, used with typed-dict fail_fast: bool # fields related to string fields only str_max_length: int @@ -3004,7 +3004,6 @@ class ModelFieldsSchema(TypedDict, total=False): # all these values can be set via config, equivalent fields have `typed_dict_` prefix extra_behavior: ExtraBehavior populate_by_name: bool # replaces `allow_population_by_field_name` in pydantic v1 - fail_fast: bool # default: False from_attributes: bool ref: str metadata: Dict[str, Any] @@ -3021,7 +3020,6 @@ def model_fields_schema( extra_behavior: ExtraBehavior | None = None, populate_by_name: bool | None = None, from_attributes: bool | None = None, - fail_fast: bool | None = None, ref: str | None = None, metadata: Dict[str, Any] | None = None, serialization: SerSchema | None = None, @@ -3051,7 +3049,6 @@ def model_fields_schema( extra_behavior: The extra behavior to use for the typed dict populate_by_name: Whether the typed dict should populate by name from_attributes: Whether the typed dict should be populated from attributes - fail_fast: Stop validation on the first error serialization: Custom serialization schema """ return _dict_not_none( @@ -3064,7 +3061,6 @@ def model_fields_schema( extra_behavior=extra_behavior, populate_by_name=populate_by_name, from_attributes=from_attributes, - fail_fast=fail_fast, ref=ref, metadata=metadata, serialization=serialization, @@ -3248,7 +3244,6 @@ class DataclassArgsSchema(TypedDict, total=False): fields: Required[List[DataclassField]] computed_fields: List[ComputedField] populate_by_name: bool # default: False - fail_fast: bool # default: False collect_init_only: bool # default: False ref: str metadata: Dict[str, Any] @@ -3262,7 +3257,6 @@ def dataclass_args_schema( *, computed_fields: List[ComputedField] | None = None, populate_by_name: bool | None = None, - fail_fast: bool | None = None, collect_init_only: bool | None = None, ref: str | None = None, metadata: Dict[str, Any] | None = None, @@ -3291,7 +3285,6 @@ def dataclass_args_schema( fields: The fields to use for the dataclass computed_fields: Computed fields to use when serializing the dataclass populate_by_name: Whether to populate by name - fail_fast: Stop validation on the first error collect_init_only: Whether to collect init only fields into a dict to pass to `__post_init__` 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 @@ -3304,7 +3297,6 @@ def dataclass_args_schema( fields=fields, computed_fields=computed_fields, populate_by_name=populate_by_name, - fail_fast=fail_fast, collect_init_only=collect_init_only, ref=ref, metadata=metadata, diff --git a/src/validators/dataclass.rs b/src/validators/dataclass.rs index 1b63ad95c..53be75e88 100644 --- a/src/validators/dataclass.rs +++ b/src/validators/dataclass.rs @@ -40,7 +40,6 @@ pub struct DataclassArgsValidator { validator_name: String, extra_behavior: ExtraBehavior, extras_validator: Option>, - fail_fast: bool, loc_by_alias: bool, } @@ -55,7 +54,6 @@ impl BuildValidator for DataclassArgsValidator { let py = schema.py(); let populate_by_name = schema_or_config_same(schema, config, intern!(py, "populate_by_name"))?.unwrap_or(false); - let fail_fast = schema_or_config_same(schema, config, intern!(py, "fail_fast"))?.unwrap_or(false); let extra_behavior = ExtraBehavior::from_schema_or_config(py, schema, config, ExtraBehavior::Ignore)?; @@ -130,7 +128,6 @@ impl BuildValidator for DataclassArgsValidator { validator_name, extra_behavior, extras_validator, - fail_fast, loc_by_alias: config.get_as(intern!(py, "loc_by_alias"))?.unwrap_or(true), } .into()) @@ -177,10 +174,6 @@ impl Validator for DataclassArgsValidator { // go through fields getting the value from args or kwargs and validating it for (index, field) in self.fields.iter().enumerate() { - if self.fail_fast && !errors.is_empty() { - break; - } - if !field.init { match field.validator.default_value(py, Some(field.name.as_str()), state) { Ok(Some(value)) => { @@ -298,10 +291,6 @@ impl Validator for DataclassArgsValidator { if let Some(kwargs) = args.kwargs() { if kwargs.len() != used_keys.len() { for result in kwargs.iter() { - if self.fail_fast && !errors.is_empty() { - break; - } - let (raw_key, value) = result?; match raw_key .borrow_input() diff --git a/src/validators/model_fields.rs b/src/validators/model_fields.rs index bf296cfc1..7aba7c8e3 100644 --- a/src/validators/model_fields.rs +++ b/src/validators/model_fields.rs @@ -36,7 +36,6 @@ pub struct ModelFieldsValidator { strict: bool, from_attributes: bool, loc_by_alias: bool, - fail_fast: bool, } impl BuildValidator for ModelFieldsValidator { @@ -52,7 +51,6 @@ impl BuildValidator for ModelFieldsValidator { let from_attributes = schema_or_config_same(schema, config, intern!(py, "from_attributes"))?.unwrap_or(false); let populate_by_name = schema_or_config_same(schema, config, intern!(py, "populate_by_name"))?.unwrap_or(false); - let fail_fast = schema_or_config_same(schema, config, intern!(py, "fail_fast"))?.unwrap_or(false); let extra_behavior = ExtraBehavior::from_schema_or_config(py, schema, config, ExtraBehavior::Ignore)?; @@ -104,7 +102,6 @@ impl BuildValidator for ModelFieldsValidator { extras_validator, strict, from_attributes, - fail_fast, loc_by_alias: config.get_as(intern!(py, "loc_by_alias"))?.unwrap_or(true), } .into()) @@ -171,10 +168,6 @@ impl Validator for ModelFieldsValidator { let state = &mut state.rebind_extra(|extra| extra.data = Some(model_dict.clone())); for field in &self.fields { - if self.fail_fast && !errors.is_empty() { - break; - } - let op_key_value = match dict.get_item(&field.lookup_key) { Ok(v) => v, Err(ValError::LineErrors(line_errors)) => { diff --git a/tests/validators/test_dataclasses.py b/tests/validators/test_dataclasses.py index 9edff579c..a9b367008 100644 --- a/tests/validators/test_dataclasses.py +++ b/tests/validators/test_dataclasses.py @@ -1713,63 +1713,3 @@ class Foo: assert exc_info.value.errors(include_url=False) == expected.errors else: assert dataclasses.asdict(v.validate_python(input_value)) == expected - - -@pytest.mark.parametrize( - ('fail_fast', 'expected'), - [ - pytest.param( - True, - [ - { - 'type': 'string_type', - 'loc': ('a',), - 'msg': 'Input should be a valid string', - 'input': 10, - }, - ], - id='fail_fast', - ), - pytest.param( - False, - [ - { - 'type': 'string_type', - 'loc': ('a',), - 'msg': 'Input should be a valid string', - 'input': 10, - }, - { - 'type': 'string_type', - 'loc': ('b',), - 'msg': 'Input should be a valid string', - 'input': 20, - }, - ], - id='not_fail_fast', - ), - ], -) -def test_dataclass_fail_fast(fail_fast, expected): - @dataclasses.dataclass - class Foo: - a: str - b: str - - schema = core_schema.dataclass_schema( - Foo, - core_schema.dataclass_args_schema( - 'Foo', - [ - core_schema.dataclass_field(name='a', schema=core_schema.str_schema()), - core_schema.dataclass_field(name='b', schema=core_schema.str_schema()), - ], - fail_fast=fail_fast, - ), - ['a', 'b'], - ) - - with pytest.raises(ValidationError) as exc_info: - SchemaValidator(schema).validate_python({'a': 10, 'b': 20}) - - assert exc_info.value.errors(include_url=False) == expected diff --git a/tests/validators/test_model_fields.py b/tests/validators/test_model_fields.py index 2c971ac5b..8a22d96c3 100644 --- a/tests/validators/test_model_fields.py +++ b/tests/validators/test_model_fields.py @@ -1781,56 +1781,3 @@ def test_extra_behavior_ignore(config: Union[core_schema.CoreConfig, None], sche } ] assert 'not_f' not in m - - -@pytest.mark.parametrize( - ('fail_fast', 'expected'), - [ - pytest.param( - True, - [ - { - 'input': 'x', - 'loc': ('a',), - 'msg': 'Input should be a valid integer, unable to parse string as an integer', - 'type': 'int_parsing', - }, - ], - id='fail_fast', - ), - pytest.param( - False, - [ - { - 'input': 'x', - 'loc': ('a',), - 'msg': 'Input should be a valid integer, unable to parse string as an integer', - 'type': 'int_parsing', - }, - { - 'input': 'y', - 'loc': ('b',), - 'msg': 'Input should be a valid integer, unable to parse string as an integer', - 'type': 'int_parsing', - }, - ], - id='not_fail_fast', - ), - ], -) -def test_model_fields_fail_fast(fail_fast, expected): - v = SchemaValidator( - { - 'type': 'model-fields', - 'fields': { - 'a': {'type': 'model-field', 'schema': {'type': 'int'}}, - 'b': {'type': 'model-field', 'schema': {'type': 'int'}}, - }, - 'fail_fast': fail_fast, - }, - ) - - with pytest.raises(ValidationError) as exc_info: - v.validate_python({'a': 'x', 'b': 'y'}) - - assert exc_info.value.errors(include_url=False) == expected