fix(json_schema): keep min/maxLength when format falls back to str

_create_string_type returned early for any format, dropping minLength,
maxLength, and pattern even when the format resolves to a plain str
(custom formats / uri-reference).

Fixes #4404
This commit is contained in:
LHMQ878 2026-08-06 19:30:22 +08:00
commit 578bc73f12
2 changed files with 35 additions and 8 deletions

View file

@ -269,13 +269,6 @@ def _create_string_type(schema: Mapping[str, Any]) -> type | Annotated[Any, ...]
if "const" in schema:
return Literal[schema["const"]] # type: ignore
if fmt := schema.get("format"):
if fmt == "uri":
return AnyUrl
elif fmt == "uri-reference":
return str
return FORMAT_TYPES.get(fmt, str)
constraints = {
k: v
for k, v in {
@ -286,7 +279,22 @@ def _create_string_type(schema: Mapping[str, Any]) -> type | Annotated[Any, ...]
if v is not None
}
if not constraints:
# Resolve format first. Non-str formats (date-time, email, uri, json) do not
# take length/pattern constraints. Str-backed formats (unknown custom names
# and uri-reference) must still honor minLength/maxLength/pattern.
if fmt := schema.get("format"):
if fmt == "uri":
return AnyUrl
if fmt == "uri-reference":
base: type | Annotated[Any, ...] = str
else:
base = FORMAT_TYPES.get(fmt, str)
if base is not str:
return base
if not constraints:
return str
# Fall through to apply StringConstraints on the str-backed format.
elif not constraints:
return str
annotated: Any = Annotated[str, StringConstraints(**constraints)]

View file

@ -112,3 +112,22 @@ class TestFormatTypes:
)
assert isinstance(result.full_uri, AnyUrl)
assert isinstance(result.ref_uri, str)
def test_str_backed_format_keeps_max_length(self):
"""Unknown/custom formats fall back to str and must still enforce length."""
t = json_schema_to_type(
{"type": "string", "format": "phone", "maxLength": 3}
)
validator = TypeAdapter(t)
assert validator.validate_python("123") == "123"
with pytest.raises(ValidationError):
validator.validate_python("abcd")
def test_uri_reference_format_keeps_min_length(self):
t = json_schema_to_type(
{"type": "string", "format": "uri-reference", "minLength": 2}
)
validator = TypeAdapter(t)
assert validator.validate_python("/a") == "/a"
with pytest.raises(ValidationError):
validator.validate_python("")