@@ -979,6 +979,106 @@ def _should_generate_base_model(self, *, generates_separate_models: bool = False
979979 return True
980980 return not generates_separate_models
981981
982+ def _ref_schema_generates_variant (self , ref_path : str , suffix : str ) -> bool :
983+ """Check if a referenced schema will generate a specific variant (Request or Response).
984+
985+ For Request variant: schema must have readOnly fields AND at least one non-readOnly field.
986+ For Response variant: schema must have writeOnly fields AND at least one non-writeOnly field.
987+ """
988+ try :
989+ ref_schema = self ._load_ref_schema_object (ref_path )
990+ except Exception : # noqa: BLE001 # pragma: no cover
991+ return False
992+
993+ has_read_only = False
994+ has_write_only = False
995+ has_non_read_only = False
996+ has_non_write_only = False
997+
998+ for prop in (ref_schema .properties or {}).values ():
999+ if not isinstance (prop , JsonSchemaObject ):
1000+ continue
1001+ is_read_only = self ._resolve_field_flag (prop , "readOnly" )
1002+ is_write_only = self ._resolve_field_flag (prop , "writeOnly" )
1003+ if is_read_only :
1004+ has_read_only = True
1005+ else :
1006+ has_non_read_only = True
1007+ if is_write_only :
1008+ has_write_only = True
1009+ else :
1010+ has_non_write_only = True
1011+
1012+ if suffix == "Request" :
1013+ return has_read_only and has_non_read_only
1014+ if suffix == "Response" :
1015+ return has_write_only and has_non_write_only
1016+ return False # pragma: no cover
1017+
1018+ def _ref_schema_has_model (self , ref_path : str ) -> bool :
1019+ """Check if a referenced schema will have a model (base or variant) generated.
1020+
1021+ Returns False if the schema has only readOnly or only writeOnly fields in request-response mode,
1022+ which would result in no model being generated at all.
1023+ """
1024+ try :
1025+ ref_schema = self ._load_ref_schema_object (ref_path )
1026+ except Exception : # noqa: BLE001 # pragma: no cover
1027+ return True
1028+
1029+ has_read_only = False
1030+ has_write_only = False
1031+
1032+ for prop in (ref_schema .properties or {}).values ():
1033+ if not isinstance (prop , JsonSchemaObject ):
1034+ continue
1035+ is_read_only = self ._resolve_field_flag (prop , "readOnly" )
1036+ is_write_only = self ._resolve_field_flag (prop , "writeOnly" )
1037+ if is_read_only :
1038+ has_read_only = True
1039+ elif is_write_only :
1040+ has_write_only = True
1041+ else : # pragma: no cover
1042+ return True
1043+
1044+ if has_read_only and not has_write_only :
1045+ return False
1046+ return not (has_write_only and not has_read_only )
1047+
1048+ def _update_data_type_ref_for_variant (self , data_type : DataType , suffix : str ) -> None :
1049+ """Recursively update data type references to point to variant models."""
1050+ if data_type .reference :
1051+ ref_path = data_type .reference .path
1052+ if self ._ref_schema_generates_variant (ref_path , suffix ):
1053+ path_parts = ref_path .split ("/" )
1054+ base_name = path_parts [- 1 ]
1055+ variant_name = f"{ base_name } { suffix } "
1056+ unique_name = self .model_resolver .get_class_name (variant_name , unique = False ).name
1057+ path_parts [- 1 ] = unique_name
1058+ variant_ref = self .model_resolver .add (path_parts , unique_name , class_name = True , unique = False )
1059+ data_type .reference = variant_ref
1060+ elif not self ._ref_schema_has_model (ref_path ):
1061+ if not hasattr (self , "_force_base_model_refs" ):
1062+ self ._force_base_model_refs : set [str ] = set ()
1063+ self ._force_base_model_refs .add (ref_path )
1064+ for nested_dt in data_type .data_types :
1065+ self ._update_data_type_ref_for_variant (nested_dt , suffix )
1066+
1067+ def _update_field_refs_for_variant (
1068+ self , model_fields : list [DataModelFieldBase ], suffix : str
1069+ ) -> list [DataModelFieldBase ]:
1070+ """Update field references in model_fields to point to variant models.
1071+
1072+ For Request models, refs should point to Request variants.
1073+ For Response models, refs should point to Response variants.
1074+ """
1075+ if self .read_only_write_only_model_type != ReadOnlyWriteOnlyModelType .RequestResponse :
1076+ return model_fields
1077+ for field in model_fields :
1078+ if field .data_type :
1079+ self ._update_data_type_ref_for_variant (field .data_type , suffix )
1080+ return model_fields
1081+
9821082 def _create_variant_model ( # noqa: PLR0913, PLR0917
9831083 self ,
9841084 path : list [str ],
@@ -991,6 +1091,8 @@ def _create_variant_model( # noqa: PLR0913, PLR0917
9911091 """Create a Request or Response model variant."""
9921092 if not model_fields :
9931093 return
1094+ # Update field refs to point to variant models when in request-response mode
1095+ self ._update_field_refs_for_variant (model_fields , suffix )
9941096 variant_name = f"{ base_name } { suffix } "
9951097 unique_name = self .model_resolver .get_class_name (variant_name , unique = True ).name
9961098 model_path = [* path [:- 1 ], unique_name ]
0 commit comments