Skip to content

Commit 7b3c51e

Browse files
authored
fix: required fields in nested pydantic models need to follow parent nullability (#2199)
* fix: required fields in nested pydantic models need to follow parent nullability * test: add inverse test
1 parent 1ee7d1e commit 7b3c51e

File tree

2 files changed

+16
-0
lines changed

2 files changed

+16
-0
lines changed

dlt/common/libs/pydantic.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ def pydantic_to_table_schema_columns(
164164
result[schema_key] = {
165165
**hints,
166166
"name": snake_case_naming_convention.make_path(name, hints["name"]),
167+
# if the outer field containing the nested mode is optional,
168+
# then each field in the model itself has to be nullable as well,
169+
# as otherwise we end up with flattened non-nullable optional nested fields
170+
"nullable": hints["nullable"] or nullable,
167171
}
168172
elif data_type == "json" and skip_nested_types:
169173
continue

tests/libs/test_pydantic.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,3 +743,15 @@ class MyModel(BaseModel):
743743

744744
with pytest.raises(ValidationError):
745745
m = MyModel(column_type={"data_type": "invalid_type"}) # type: ignore[typeddict-item]
746+
747+
748+
def test_parent_nullable_means_children_nullable():
749+
class MyParent(BaseModel):
750+
optional_child: Optional[ChildModel]
751+
non_optional_child: ChildModel
752+
dlt_config: ClassVar[DltConfig] = {"skip_nested_types": True}
753+
754+
schema = pydantic_to_table_schema_columns(MyParent)
755+
756+
assert schema["optional_child__child_attribute"]["nullable"]
757+
assert schema["non_optional_child__child_attribute"]["nullable"] is False

0 commit comments

Comments
 (0)