mirror of
https://git.freebsd.org/ports.git
synced 2025-07-03 02:20:33 -04:00
270 lines
12 KiB
Text
270 lines
12 KiB
Text
Obtained from: https://github.com/pydantic/pydantic/commit/2575e71894a32dc615f9fa7a94ff37bb604a48a8
|
|
https://github.com/pydantic/pydantic/commit/70d3c3e00f960191b4cc488ddb252f723fce8020
|
|
https://github.com/pydantic/pydantic/commit/e5323ffaba449940028a9e580da81bdd3d8bd0c9
|
|
|
|
--- pydantic/_internal/_config.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ pydantic/_internal/_config.py
|
|
@@ -65,6 +65,7 @@ class ConfigWrapper:
|
|
hide_input_in_errors: bool
|
|
defer_build: bool
|
|
schema_generator: type[GenerateSchema] | None
|
|
+ coerce_numbers_to_str: bool
|
|
|
|
def __init__(self, config: ConfigDict | dict[str, Any] | type[Any] | None, *, check: bool = True):
|
|
if check:
|
|
@@ -160,6 +161,7 @@ class ConfigWrapper:
|
|
str_max_length=self.config_dict.get('str_max_length'),
|
|
str_min_length=self.config_dict.get('str_min_length'),
|
|
hide_input_in_errors=self.config_dict.get('hide_input_in_errors'),
|
|
+ coerce_numbers_to_str=self.config_dict.get('coerce_numbers_to_str'),
|
|
)
|
|
)
|
|
return core_config
|
|
@@ -200,6 +202,7 @@ config_defaults = ConfigDict(
|
|
json_encoders=None,
|
|
defer_build=False,
|
|
schema_generator=None,
|
|
+ coerce_numbers_to_str=False,
|
|
)
|
|
|
|
|
|
--- pydantic/_internal/_core_utils.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ pydantic/_internal/_core_utils.py
|
|
@@ -262,9 +262,9 @@ class _WalkCoreSchema:
|
|
) -> core_schema.CoreSchema:
|
|
schema = cast(core_schema.TuplePositionalSchema, schema)
|
|
schema['items_schema'] = [self.walk(v, f) for v in schema['items_schema']]
|
|
- extra_schema = schema.get('extra_schema')
|
|
- if extra_schema is not None:
|
|
- schema['extra_schema'] = self.walk(extra_schema, f)
|
|
+ extras_schema = schema.get('extras_schema')
|
|
+ if extras_schema is not None:
|
|
+ schema['extras_schema'] = self.walk(extras_schema, f)
|
|
return schema
|
|
|
|
def handle_dict_schema(self, schema: core_schema.DictSchema, f: Walk) -> core_schema.CoreSchema:
|
|
@@ -314,9 +314,9 @@ class _WalkCoreSchema:
|
|
return schema
|
|
|
|
def handle_model_fields_schema(self, schema: core_schema.ModelFieldsSchema, f: Walk) -> core_schema.CoreSchema:
|
|
- extra_validator = schema.get('extra_validator')
|
|
- if extra_validator is not None:
|
|
- schema['extra_validator'] = self.walk(extra_validator, f)
|
|
+ extras_schema = schema.get('extras_schema')
|
|
+ if extras_schema is not None:
|
|
+ schema['extras_schema'] = self.walk(extras_schema, f)
|
|
replaced_fields: dict[str, core_schema.ModelField] = {}
|
|
replaced_computed_fields: list[core_schema.ComputedField] = []
|
|
for computed_field in schema.get('computed_fields', ()):
|
|
@@ -333,9 +333,9 @@ class _WalkCoreSchema:
|
|
return schema
|
|
|
|
def handle_typed_dict_schema(self, schema: core_schema.TypedDictSchema, f: Walk) -> core_schema.CoreSchema:
|
|
- extra_validator = schema.get('extra_validator')
|
|
- if extra_validator is not None:
|
|
- schema['extra_validator'] = self.walk(extra_validator, f)
|
|
+ extras_schema = schema.get('extras_schema')
|
|
+ if extras_schema is not None:
|
|
+ schema['extras_schema'] = self.walk(extras_schema, f)
|
|
replaced_computed_fields: list[core_schema.ComputedField] = []
|
|
for computed_field in schema.get('computed_fields', ()):
|
|
replaced_field = computed_field.copy()
|
|
--- pydantic/_internal/_generate_schema.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ pydantic/_internal/_generate_schema.py
|
|
@@ -480,7 +480,7 @@ class GenerateSchema:
|
|
|
|
model_validators = decorators.model_validators.values()
|
|
|
|
- extra_validator = None
|
|
+ extras_schema = None
|
|
if core_config.get('extra_fields_behavior') == 'allow':
|
|
for tp in (cls, *cls.__mro__):
|
|
extras_annotation = cls.__annotations__.get('__pydantic_extra__', None)
|
|
@@ -495,7 +495,7 @@ class GenerateSchema:
|
|
required=True,
|
|
)[1]
|
|
if extra_items_type is not Any:
|
|
- extra_validator = self.generate_schema(extra_items_type)
|
|
+ extras_schema = self.generate_schema(extra_items_type)
|
|
break
|
|
|
|
with self._config_wrapper_stack.push(config_wrapper):
|
|
@@ -521,7 +521,7 @@ class GenerateSchema:
|
|
self._computed_field_schema(d, decorators.field_serializers)
|
|
for d in computed_fields.values()
|
|
],
|
|
- extra_validator=extra_validator,
|
|
+ extras_schema=extras_schema,
|
|
model_name=cls.__name__,
|
|
)
|
|
inner_schema = apply_validators(fields_schema, decorators.root_validators.values(), None)
|
|
--- pydantic/config.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ pydantic/config.py
|
|
@@ -207,5 +207,11 @@ class ConfigDict(TypedDict, total=False):
|
|
Defaults to `None`.
|
|
"""
|
|
|
|
+ coerce_numbers_to_str: bool
|
|
+ """
|
|
+ If `True`, enables automatic coercion of any `Number` type to `str` in "lax" (non-strict) mode.
|
|
+ Defaults to `False`.
|
|
+ """
|
|
+
|
|
|
|
__getattr__ = getattr_migration(__name__)
|
|
--- pydantic/json_schema.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ pydantic/json_schema.py
|
|
@@ -795,8 +795,8 @@ class GenerateJsonSchema:
|
|
prefixItems = [self.generate_inner(item) for item in schema['items_schema']]
|
|
if prefixItems:
|
|
json_schema['prefixItems'] = prefixItems
|
|
- if 'extra_schema' in schema:
|
|
- json_schema['items'] = self.generate_inner(schema['extra_schema'])
|
|
+ if 'extras_schema' in schema:
|
|
+ json_schema['items'] = self.generate_inner(schema['extras_schema'])
|
|
else:
|
|
json_schema['maxItems'] = len(schema['items_schema'])
|
|
self.update_with_validations(json_schema, schema, self.ValidationsMapping.array)
|
|
@@ -1383,10 +1383,10 @@ class GenerateJsonSchema:
|
|
if self.mode == 'serialization':
|
|
named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', [])))
|
|
json_schema = self._named_required_fields_schema(named_required_fields)
|
|
- extra_validator = schema.get('extra_validator', None)
|
|
- if extra_validator is not None:
|
|
+ extras_schema = schema.get('extras_schema', None)
|
|
+ if extras_schema is not None:
|
|
schema_to_update = self.resolve_schema_to_update(json_schema)
|
|
- schema_to_update['additionalProperties'] = self.generate_inner(extra_validator)
|
|
+ schema_to_update['additionalProperties'] = self.generate_inner(extras_schema)
|
|
return json_schema
|
|
|
|
def field_is_present(self, field: CoreSchemaField) -> bool:
|
|
--- pydantic/v1/main.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ pydantic/v1/main.py
|
|
@@ -161,9 +161,9 @@ class ModelMetaclass(ABCMeta):
|
|
|
|
for f in fields.values():
|
|
f.set_config(config)
|
|
- extra_validators = vg.get_validators(f.name)
|
|
- if extra_validators:
|
|
- f.class_validators.update(extra_validators)
|
|
+ extras_schemas = vg.get_validators(f.name)
|
|
+ if extras_schemas:
|
|
+ f.class_validators.update(extras_schemas)
|
|
# re-run prepare to add extra validators
|
|
f.populate_validators()
|
|
|
|
--- pyproject.toml.orig 2020-02-02 00:00:00 UTC
|
|
+++ pyproject.toml
|
|
@@ -61,7 +61,7 @@ requires-python = '>=3.7'
|
|
dependencies = [
|
|
'typing-extensions>=4.6.1',
|
|
'annotated-types>=0.4.0',
|
|
- "pydantic-core==2.6.3",
|
|
+ "pydantic-core==2.9.0",
|
|
]
|
|
dynamic = ['version', 'readme']
|
|
|
|
--- tests/test_json_schema.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ tests/test_json_schema.py
|
|
@@ -2475,7 +2475,7 @@ def test_tuple_with_extra_schema():
|
|
@classmethod
|
|
def __get_pydantic_core_schema__(cls, _source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
|
|
return core_schema.tuple_positional_schema(
|
|
- [core_schema.int_schema(), core_schema.str_schema()], extra_schema=core_schema.int_schema()
|
|
+ [core_schema.int_schema(), core_schema.str_schema()], extras_schema=core_schema.int_schema()
|
|
)
|
|
|
|
class Model(BaseModel):
|
|
--- tests/test_types.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ tests/test_types.py
|
|
@@ -12,6 +12,7 @@ from dataclasses import dataclass
|
|
from datetime import date, datetime, time, timedelta, timezone
|
|
from decimal import Decimal
|
|
from enum import Enum, IntEnum
|
|
+from numbers import Number
|
|
from pathlib import Path
|
|
from typing import (
|
|
Any,
|
|
@@ -5690,3 +5691,46 @@ def test_decimal_float_precision() -> None:
|
|
assert ta.validate_python('1.1') == Decimal('1.1')
|
|
assert ta.validate_json('1') == Decimal('1')
|
|
assert ta.validate_python(1) == Decimal('1')
|
|
+
|
|
+
|
|
+def test_coerce_numbers_to_str_disabled_in_strict_mode() -> None:
|
|
+ class Model(BaseModel):
|
|
+ model_config = ConfigDict(strict=True, coerce_numbers_to_str=True)
|
|
+ value: str
|
|
+
|
|
+ with pytest.raises(ValidationError, match='value'):
|
|
+ Model.model_validate({'value': 42})
|
|
+ with pytest.raises(ValidationError, match='value'):
|
|
+ Model.model_validate_json('{"value": 42}')
|
|
+
|
|
+
|
|
+@pytest.mark.parametrize(
|
|
+ ('number', 'expected_str'),
|
|
+ [
|
|
+ pytest.param(42, '42', id='42'),
|
|
+ pytest.param(42.0, '42.0', id='42.0'),
|
|
+ pytest.param(Decimal('42.0'), '42.0', id="Decimal('42.0')"),
|
|
+ ],
|
|
+)
|
|
+def test_coerce_numbers_to_str(number: Number, expected_str: str) -> None:
|
|
+ class Model(BaseModel):
|
|
+ model_config = ConfigDict(coerce_numbers_to_str=True)
|
|
+ value: str
|
|
+
|
|
+ assert Model.model_validate({'value': number}).model_dump() == {'value': expected_str}
|
|
+
|
|
+
|
|
+@pytest.mark.parametrize(
|
|
+ ('number', 'expected_str'),
|
|
+ [
|
|
+ pytest.param('42', '42', id='42'),
|
|
+ pytest.param('42.0', '42', id='42.0'),
|
|
+ pytest.param('42.13', '42.13', id='42.13'),
|
|
+ ],
|
|
+)
|
|
+def test_coerce_numbers_to_str_from_json(number: str, expected_str: str) -> None:
|
|
+ class Model(BaseModel):
|
|
+ model_config = ConfigDict(coerce_numbers_to_str=True)
|
|
+ value: str
|
|
+
|
|
+ assert Model.model_validate_json(f'{{"value": {number}}}').model_dump() == {'value': expected_str}
|
|
--- tests/test_utils.py.orig 2020-02-02 00:00:00 UTC
|
|
+++ tests/test_utils.py
|
|
@@ -547,8 +547,8 @@ def test_camel2snake(value: str, result: str) -> None:
|
|
(
|
|
pytest.param({}, {}, id='Positional tuple without extra_schema'),
|
|
pytest.param(
|
|
- {'extra_schema': core_schema.float_schema()},
|
|
- {'extra_schema': {'type': 'str'}},
|
|
+ {'extras_schema': core_schema.float_schema()},
|
|
+ {'extras_schema': {'type': 'str'}},
|
|
id='Positional tuple with extra_schema',
|
|
),
|
|
),
|
|
@@ -575,8 +575,8 @@ def test_handle_tuple_positional_schema(params, expect
|
|
(
|
|
pytest.param({}, {}, id='Model fields without extra_validator'),
|
|
pytest.param(
|
|
- {'extra_validator': core_schema.float_schema()},
|
|
- {'extra_validator': {'type': 'str'}},
|
|
+ {'extras_schema': core_schema.float_schema()},
|
|
+ {'extras_schema': {'type': 'str'}},
|
|
id='Model fields with extra_validator',
|
|
),
|
|
),
|
|
@@ -608,8 +608,8 @@ def test_handle_model_fields_schema(params, expected_e
|
|
(
|
|
pytest.param({}, {}, id='Typeddict without extra_validator'),
|
|
pytest.param(
|
|
- {'extra_validator': core_schema.float_schema()},
|
|
- {'extra_validator': {'type': 'str'}},
|
|
+ {'extras_schema': core_schema.float_schema()},
|
|
+ {'extras_schema': {'type': 'str'}},
|
|
id='Typeddict with extra_validator',
|
|
),
|
|
),
|