Skip to content

Commit

Permalink
Add coerce_numbers_to_str option in str_schema
Browse files Browse the repository at this point in the history
  • Loading branch information
NeevCohen committed Mar 26, 2024
1 parent 0830d0d commit 6cc9989
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 6 deletions.
3 changes: 3 additions & 0 deletions python/pydantic_core/core_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@ def str_schema(
to_upper: bool | None = None,
regex_engine: Literal['rust-regex', 'python-re'] | None = None,
strict: bool | None = None,
coerce_numbers_to_str: bool | None = None,
ref: str | None = None,
metadata: Any = None,
serialization: SerSchema | None = None,
Expand Down Expand Up @@ -793,6 +794,7 @@ def str_schema(
- `python-re` use the [`re`](https://docs.python.org/3/library/re.html) module,
which supports all regex features, but may be slower.
strict: Whether the value should be a string or a value that can be converted to a string
coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode).
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
serialization: Custom serialization schema
Expand All @@ -807,6 +809,7 @@ def str_schema(
to_upper=to_upper,
regex_engine=regex_engine,
strict=strict,
coerce_numbers_to_str=coerce_numbers_to_str,
ref=ref,
metadata=metadata,
serialization=serialization,
Expand Down
9 changes: 3 additions & 6 deletions src/validators/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use pyo3::prelude::*;
use pyo3::types::{PyDict, PyString};
use regex::Regex;

use crate::build_tools::schema_or_config_same;
use crate::build_tools::{is_strict, py_schema_error_type, schema_or_config};
use crate::errors::{ErrorType, ValError, ValResult};
use crate::input::Input;
Expand Down Expand Up @@ -184,12 +185,8 @@ impl StrConstrainedValidator {
let to_upper: bool =
schema_or_config(schema, config, intern!(py, "to_upper"), intern!(py, "str_to_upper"))?.unwrap_or(false);

let coerce_numbers_to_str = match config {
Some(c) => c
.get_item("coerce_numbers_to_str")?
.map_or(Ok(false), |any| any.is_truthy())?,
None => false,
};
let coerce_numbers_to_str: bool =
schema_or_config_same(schema, config, intern!(py, "coerce_numbers_to_str"))?.unwrap_or(false);

Ok(Self {
strict: is_strict(schema, config)?,
Expand Down
31 changes: 31 additions & 0 deletions tests/validators/test_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,34 @@ def test_backtracking_regex_python(mode) -> None:
with pytest.raises(ValidationError):
# not a valid match for the pattern
v.validate_python('r#"#')


@pytest.mark.parametrize('number', (42, 443, 10242))
def test_coerce_numbers_to_str_schema(number: int):
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=True))
assert v.validate_python(number) == str(number)
assert v.validate_json(str(number)) == str(number)


@pytest.mark.parametrize('number', (42, 443, 10242))
def test_coerce_numbers_to_str_schema_precedence(number: int):
config = core_schema.CoreConfig(coerce_numbers_to_str=False)
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=True), config=config)
assert v.validate_python(number) == str(number)
assert v.validate_json(str(number)) == str(number)

config = core_schema.CoreConfig(coerce_numbers_to_str=True)
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=False), config=config)
with pytest.raises(ValidationError):
v.validate_python(number)
with pytest.raises(ValidationError):
v.validate_json(str(number))


@pytest.mark.parametrize('number', (42, 443, 10242))
def test_coerce_numbers_to_str_schema_with_strict_mode(number: int):
v = SchemaValidator(core_schema.str_schema(coerce_numbers_to_str=True, strict=True))
with pytest.raises(ValidationError):
v.validate_python(number)
with pytest.raises(ValidationError):
v.validate_json(str(number))

0 comments on commit 6cc9989

Please sign in to comment.