Skip to content

Commit c607fd8

Browse files
authored
Add coerce_numbers_to_str option in str_schema (#1249)
1 parent 0830d0d commit c607fd8

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

python/pydantic_core/core_schema.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ def str_schema(
764764
to_upper: bool | None = None,
765765
regex_engine: Literal['rust-regex', 'python-re'] | None = None,
766766
strict: bool | None = None,
767+
coerce_numbers_to_str: bool | None = None,
767768
ref: str | None = None,
768769
metadata: Any = None,
769770
serialization: SerSchema | None = None,
@@ -793,6 +794,7 @@ def str_schema(
793794
- `python-re` use the [`re`](https://docs.python.org/3/library/re.html) module,
794795
which supports all regex features, but may be slower.
795796
strict: Whether the value should be a string or a value that can be converted to a string
797+
coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode).
796798
ref: optional unique identifier of the schema, used to reference the schema in other places
797799
metadata: Any other information you want to include with the schema, not used by pydantic-core
798800
serialization: Custom serialization schema
@@ -807,6 +809,7 @@ def str_schema(
807809
to_upper=to_upper,
808810
regex_engine=regex_engine,
809811
strict=strict,
812+
coerce_numbers_to_str=coerce_numbers_to_str,
810813
ref=ref,
811814
metadata=metadata,
812815
serialization=serialization,

src/validators/string.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use pyo3::prelude::*;
33
use pyo3::types::{PyDict, PyString};
44
use regex::Regex;
55

6-
use crate::build_tools::{is_strict, py_schema_error_type, schema_or_config};
6+
use crate::build_tools::{is_strict, py_schema_error_type, schema_or_config, schema_or_config_same};
77
use crate::errors::{ErrorType, ValError, ValResult};
88
use crate::input::Input;
99
use crate::tools::SchemaDict;
@@ -184,12 +184,8 @@ impl StrConstrainedValidator {
184184
let to_upper: bool =
185185
schema_or_config(schema, config, intern!(py, "to_upper"), intern!(py, "str_to_upper"))?.unwrap_or(false);
186186

187-
let coerce_numbers_to_str = match config {
188-
Some(c) => c
189-
.get_item("coerce_numbers_to_str")?
190-
.map_or(Ok(false), |any| any.is_truthy())?,
191-
None => false,
192-
};
187+
let coerce_numbers_to_str: bool =
188+
schema_or_config_same(schema, config, intern!(py, "coerce_numbers_to_str"))?.unwrap_or(false);
193189

194190
Ok(Self {
195191
strict: is_strict(schema, config)?,

tests/validators/test_string.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,34 @@ def test_backtracking_regex_python(mode) -> None:
367367
with pytest.raises(ValidationError):
368368
# not a valid match for the pattern
369369
v.validate_python('r#"#')
370+
371+
372+
@pytest.mark.parametrize('number', (42, 443, 10242))
373+
def test_coerce_numbers_to_str_schema(number: int):
374+
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=True))
375+
assert v.validate_python(number) == str(number)
376+
assert v.validate_json(str(number)) == str(number)
377+
378+
379+
@pytest.mark.parametrize('number', (42, 443, 10242))
380+
def test_coerce_numbers_to_str_schema_precedence(number: int):
381+
config = core_schema.CoreConfig(coerce_numbers_to_str=False)
382+
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=True), config=config)
383+
assert v.validate_python(number) == str(number)
384+
assert v.validate_json(str(number)) == str(number)
385+
386+
config = core_schema.CoreConfig(coerce_numbers_to_str=True)
387+
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=False), config=config)
388+
with pytest.raises(ValidationError):
389+
v.validate_python(number)
390+
with pytest.raises(ValidationError):
391+
v.validate_json(str(number))
392+
393+
394+
@pytest.mark.parametrize('number', (42, 443, 10242))
395+
def test_coerce_numbers_to_str_schema_with_strict_mode(number: int):
396+
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=True, strict=True))
397+
with pytest.raises(ValidationError):
398+
v.validate_python(number)
399+
with pytest.raises(ValidationError):
400+
v.validate_json(str(number))

0 commit comments

Comments
 (0)