Skip to content

Commit 0f1bc0f

Browse files
authored
Fix patternProperties/propertyNames key constraints lost with field_constraints (#2994)
1 parent 24b576e commit 0f1bc0f

5 files changed

Lines changed: 58 additions & 4 deletions

File tree

src/datamodel_code_generator/parser/jsonschema.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,7 +2912,7 @@ def parse_pattern_properties(
29122912
is_dict=True,
29132913
dict_key=self.data_type_manager.get_data_type(
29142914
Types.string,
2915-
pattern=merged_pattern if not self.field_constraints else None,
2915+
pattern=merged_pattern,
29162916
),
29172917
)
29182918
)
@@ -2975,7 +2975,7 @@ def parse_property_names( # noqa: PLR0912
29752975
or property_names.maxLength is not None
29762976
):
29772977
kwargs: dict[str, Any] = {}
2978-
if property_names.pattern and not self.field_constraints:
2978+
if property_names.pattern:
29792979
kwargs["pattern"] = property_names.pattern
29802980
if property_names.minLength is not None:
29812981
kwargs["minLength"] = property_names.minLength

tests/data/expected/main/jsonschema/pattern_properties_field_constraints.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
from __future__ import annotations
66

7-
from pydantic import BaseModel
7+
from pydantic import BaseModel, constr
88

99

1010
class Bar(BaseModel):
1111
name: str | None = None
1212

1313

1414
class Foo(BaseModel):
15-
bar: dict[str, Bar]
15+
bar: dict[constr(regex=r'^([a-zA-Z_][a-zA-Z0-9_]*)$'), Bar]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# generated by datamodel-codegen:
2+
# filename: pattern_properties.json
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from pydantic import BaseModel, constr
8+
9+
10+
class Bar(BaseModel):
11+
name: str | None = None
12+
13+
14+
class Foo(BaseModel):
15+
bar: dict[constr(pattern=r'^([a-zA-Z_][a-zA-Z0-9_]*)$'), Bar]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# generated by datamodel-codegen:
2+
# filename: property_names_pattern.json
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from pydantic import Field, RootModel, constr
8+
9+
10+
class PatternKeys(RootModel[dict[constr(pattern=r'^[a-z]+$'), str]]):
11+
root: dict[constr(pattern=r'^[a-z]+$'), str] = Field(..., title='PatternKeys')

tests/main/jsonschema/test_main_jsonschema.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3083,6 +3083,18 @@ def test_jsonschema_pattern_properties_field_constraints(output_file: Path) -> N
30833083
)
30843084

30853085

3086+
def test_jsonschema_pattern_properties_use_annotated(output_file: Path) -> None:
3087+
"""Test pattern properties with --use-annotated preserves pattern constraint on dict keys."""
3088+
run_main_and_assert(
3089+
input_path=JSON_SCHEMA_DATA_PATH / "pattern_properties.json",
3090+
output_path=output_file,
3091+
input_file_type="jsonschema",
3092+
assert_func=assert_file_content,
3093+
expected_file="pattern_properties_use_annotated.py",
3094+
extra_args=["--output-model-type", "pydantic_v2.BaseModel", "--use-annotated"],
3095+
)
3096+
3097+
30863098
@LEGACY_BLACK_SKIP
30873099
def test_jsonschema_titles(output_file: Path) -> None:
30883100
"""Test JSON Schema title handling."""
@@ -3892,6 +3904,22 @@ def test_main_jsonschema_property_names_pattern(output_file: Path) -> None:
38923904
)
38933905

38943906

3907+
def test_main_jsonschema_property_names_pattern_field_constraints(output_file: Path) -> None:
3908+
"""Test propertyNames pattern with field_constraints preserves constr key."""
3909+
run_main_and_assert(
3910+
input_path=JSON_SCHEMA_DATA_PATH / "property_names_pattern.json",
3911+
output_path=output_file,
3912+
input_file_type="jsonschema",
3913+
assert_func=assert_file_content,
3914+
expected_file="property_names_pattern_field_constraints.py",
3915+
extra_args=[
3916+
"--output-model-type",
3917+
"pydantic_v2.BaseModel",
3918+
"--field-constraints",
3919+
],
3920+
)
3921+
3922+
38953923
def test_main_jsonschema_property_names_enum(output_file: Path) -> None:
38963924
"""Test propertyNames with enum constraint generates dict with Literal key."""
38973925
run_main_and_assert(

0 commit comments

Comments
 (0)