2323
2424from datamodel_code_generator import (
2525 DEFAULT_SHARED_MODULE_NAME ,
26+ AllOfMergeMode ,
2627 DataclassArguments ,
2728 InvalidClassNameError ,
2829 ReadOnlyWriteOnlyModelType ,
@@ -562,6 +563,7 @@ def __init__( # noqa: PLR0913
562563 use_title_as_name : bool = False ,
563564 use_operation_id_as_name : bool = False ,
564565 use_unique_items_as_set : bool = False ,
566+ allof_merge_mode : AllOfMergeMode = AllOfMergeMode .Constraints ,
565567 http_headers : Sequence [tuple [str , str ]] | None = None ,
566568 http_ignore_tls : bool = False ,
567569 use_annotated : bool = False ,
@@ -655,6 +657,7 @@ def __init__( # noqa: PLR0913
655657 use_title_as_name = use_title_as_name ,
656658 use_operation_id_as_name = use_operation_id_as_name ,
657659 use_unique_items_as_set = use_unique_items_as_set ,
660+ allof_merge_mode = allof_merge_mode ,
658661 http_headers = http_headers ,
659662 http_ignore_tls = http_ignore_tls ,
660663 use_annotated = use_annotated ,
@@ -1365,6 +1368,68 @@ def _is_list_with_any_item_type(self, data_type: DataType | None) -> bool: # no
13651368 break
13661369 return item_type .type == ANY
13671370
1371+ def _merge_property_schemas (self , parent_dict : dict [str , Any ], child_dict : dict [str , Any ]) -> dict [str , Any ]:
1372+ """Merge parent and child property schemas for allOf."""
1373+ if self .allof_merge_mode == AllOfMergeMode .NoMerge :
1374+ return child_dict .copy ()
1375+
1376+ non_merged_fields : set [str ] = set ()
1377+ if self .allof_merge_mode == AllOfMergeMode .Constraints :
1378+ non_merged_fields = {"default" , "examples" , "example" }
1379+
1380+ result = {key : value for key , value in parent_dict .items () if key not in non_merged_fields }
1381+
1382+ for key , value in child_dict .items ():
1383+ if key in result and isinstance (result [key ], dict ) and isinstance (value , dict ):
1384+ result [key ] = self ._merge_property_schemas (result [key ], value )
1385+ else :
1386+ result [key ] = value
1387+ return result
1388+
1389+ def _merge_properties_with_parent_constraints (
1390+ self , child_obj : JsonSchemaObject , parent_refs : list [str ]
1391+ ) -> JsonSchemaObject :
1392+ """Merge child properties with parent property constraints for allOf inheritance."""
1393+ if not child_obj .properties :
1394+ return child_obj
1395+
1396+ parent_properties : dict [str , JsonSchemaObject ] = {}
1397+ for ref in parent_refs :
1398+ try :
1399+ parent_schema = self ._load_ref_schema_object (ref )
1400+ except Exception : # pragma: no cover # noqa: BLE001, S112
1401+ continue
1402+ if parent_schema .properties :
1403+ for prop_name , prop_schema in parent_schema .properties .items ():
1404+ if isinstance (prop_schema , JsonSchemaObject ) and prop_name not in parent_properties :
1405+ parent_properties [prop_name ] = prop_schema
1406+
1407+ if not parent_properties :
1408+ return child_obj
1409+
1410+ merged_properties : dict [str , JsonSchemaObject | bool ] = {}
1411+ for prop_name , child_prop in child_obj .properties .items ():
1412+ if not isinstance (child_prop , JsonSchemaObject ):
1413+ merged_properties [prop_name ] = child_prop
1414+ continue
1415+
1416+ parent_prop = parent_properties .get (prop_name )
1417+ if parent_prop is None :
1418+ merged_properties [prop_name ] = child_prop
1419+ continue
1420+
1421+ parent_dict = parent_prop .dict (exclude_unset = True , by_alias = True )
1422+ child_dict = child_prop .dict (exclude_unset = True , by_alias = True )
1423+ merged_dict = self ._merge_property_schemas (parent_dict , child_dict )
1424+ merged_properties [prop_name ] = self .SCHEMA_OBJECT_TYPE .parse_obj (merged_dict )
1425+
1426+ merged_obj_dict = child_obj .dict (exclude_unset = True , by_alias = True )
1427+ merged_obj_dict ["properties" ] = {
1428+ k : v .dict (exclude_unset = True , by_alias = True ) if isinstance (v , JsonSchemaObject ) else v
1429+ for k , v in merged_properties .items ()
1430+ }
1431+ return self .SCHEMA_OBJECT_TYPE .parse_obj (merged_obj_dict )
1432+
13681433 def _get_inherited_field_type (self , prop_name : str , base_classes : list [Reference ]) -> DataType | None :
13691434 """Get the data type for an inherited property from parent schemas."""
13701435 for base in base_classes :
@@ -1662,6 +1727,8 @@ def _parse_all_of_item( # noqa: PLR0912, PLR0913, PLR0917
16621727 required : list [str ],
16631728 union_models : list [Reference ],
16641729 ) -> None :
1730+ parent_refs = [item .ref for item in obj .allOf if item .ref ]
1731+
16651732 for all_of_item in obj .allOf : # noqa: PLR1702
16661733 if all_of_item .ref : # $ref
16671734 ref_schema = self ._load_ref_schema_object (all_of_item .ref )
@@ -1681,9 +1748,11 @@ def _parse_all_of_item( # noqa: PLR0912, PLR0913, PLR0917
16811748 if ref .path not in {b .path for b in base_classes }:
16821749 base_classes .append (ref )
16831750 else :
1751+ # Merge child properties with parent constraints before processing
1752+ merged_item = self ._merge_properties_with_parent_constraints (all_of_item , parent_refs )
16841753 module_name = get_module_name (name , None , treat_dot_as_module = self .treat_dot_as_module )
16851754 object_fields = self .parse_object_fields (
1686- all_of_item ,
1755+ merged_item ,
16871756 path ,
16881757 module_name ,
16891758 class_name = name ,
0 commit comments