@@ -1054,87 +1054,102 @@ def render_union_to_json(out, union, union_name, discriminant_name, render_impor
10541054 end
10551055 out . puts "def from_json_dict(cls, json_value: #{ union_json_type } ) -> #{ union_name } :"
10561056 out . indent ( 2 ) do
1057- # String input handling: only valid for void arms
1058- out . puts "if isinstance(json_value, str):"
1059- out . indent ( 2 ) do
1060- if has_void_default
1061- # Void default arm: string input is valid for void arms and default,
1062- # but must reject non-void arm keys (they require dict form with a value)
1063- if non_void_keys . any?
1064- nv_keys_str = non_void_keys . map { |k | "\" #{ k } \" " } . join ( ", " )
1065- out . puts "if json_value in (#{ nv_keys_str } ,):"
1066- out . indent ( 2 ) do
1067- out . puts "raise ValueError(f\" '{json_value}' requires a value for #{ union_name } , use dict form instead\" )"
1068- end
1069- end
1070- if disc_enum
1071- disc_type_name = name ( disc_enum )
1072- out . puts "#{ discriminant_name } = #{ disc_type_name } .from_json_dict(json_value)"
1073- else
1074- out . puts "#{ discriminant_name } = #{ non_enum_disc_parse_expr ( disc_type_str , 'json_value' ) } "
1075- end
1076- out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } )"
1077- elsif void_keys . any?
1078- # Only specific void arms are valid as string input
1079- keys_str = void_keys . map { |k | "\" #{ k } \" " } . join ( ", " )
1080- out . puts "if json_value not in (#{ keys_str } ,):"
1057+ if has_void
1058+ if has_non_void
1059+ # Mixed mode: check for string input first (void arms)
1060+ out . puts "if isinstance(json_value, str):"
10811061 out . indent ( 2 ) do
1082- out . puts "raise ValueError(f \" Unexpected string '{json_value}' for #{ union_name } , must be one of: #{ void_keys . join ( ', ' ) } \" )"
1062+ render_union_void_from_json ( out , union_name , discriminant_name , disc_enum , disc_type_str , void_keys , non_void_keys , has_void_default )
10831063 end
1084- if disc_enum
1085- disc_type_name = name ( disc_enum )
1086- out . puts "#{ discriminant_name } = #{ disc_type_name } .from_json_dict(json_value)"
1087- else
1088- out . puts "#{ discriminant_name } = #{ non_enum_disc_parse_expr ( disc_type_str , 'json_value' ) } "
1089- end
1090- out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } )"
10911064 else
1092- # No void arms at all: string input is never valid
1093- out . puts "raise ValueError(f \" Unexpected string input for #{ union_name } : {json_value} \" )"
1065+ # Only void arms: json_value is always str, handle directly
1066+ render_union_void_from_json ( out , union_name , discriminant_name , disc_enum , disc_type_str , void_keys , non_void_keys , has_void_default )
10941067 end
10951068 end
10961069
1097- # Dict input handling: validate single key
1098- out . puts "if not isinstance(json_value, dict) or len(json_value) != 1:"
1099- out . indent ( 2 ) do
1100- out . puts "raise ValueError(f\" Expected a single-key object for #{ union_name } , got: {json_value}\" )"
1101- end
1070+ if has_non_void
1071+ # Dict input validation
1072+ if has_void
1073+ out . puts "if not isinstance(json_value, dict) or len(json_value) != 1:"
1074+ else
1075+ # Only non-void arms: json_value is always dict, skip isinstance check
1076+ out . puts "if len(json_value) != 1:"
1077+ end
1078+ out . indent ( 2 ) do
1079+ out . puts "raise ValueError(f\" Expected a single-key object for #{ union_name } , got: {json_value}\" )"
1080+ end
11021081
1103- out . puts "key = next(iter(json_value))"
1104- if disc_enum
1105- disc_type_name = name ( disc_enum )
1106- out . puts "#{ discriminant_name } = #{ disc_type_name } .from_json_dict(key)"
1107- else
1108- out . puts "#{ discriminant_name } = #{ non_enum_disc_parse_expr ( disc_type_str , 'key' ) } "
1109- end
1082+ out . puts "key = next(iter(json_value))"
1083+ if disc_enum
1084+ disc_type_name = name ( disc_enum )
1085+ out . puts "#{ discriminant_name } = #{ disc_type_name } .from_json_dict(key)"
1086+ else
1087+ out . puts "#{ discriminant_name } = #{ non_enum_disc_parse_expr ( disc_type_str , 'key' ) } "
1088+ end
11101089
1111- union . normal_arms . each do |arm |
1112- next if arm . void?
1113- arm . cases . each do |union_case |
1114- json_key = json_key_for_case ( union_case , disc_enum )
1115- arm_name = safe_identifier ( arm . name . underscore )
1116- local_var = safe_local_var ( arm_name )
1090+ union . normal_arms . each do |arm |
1091+ next if arm . void?
1092+ arm . cases . each do |union_case |
1093+ json_key = json_key_for_case ( union_case , disc_enum )
1094+ arm_name = safe_identifier ( arm . name . underscore )
1095+ local_var = safe_local_var ( arm_name )
11171096
1118- out . puts "if key == \" #{ json_key } \" :"
1119- out . indent ( 2 ) do
1120- render_import ( out , arm . declaration , union_name , track : false ) if render_import_in_func
1121- decode_expr = decode_union_arm_value ( arm , "json_value[\" #{ json_key } \" ]" )
1122- out . puts "#{ local_var } = #{ decode_expr } "
1123- out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } , #{ arm_name } =#{ local_var } )"
1097+ out . puts "if key == \" #{ json_key } \" :"
1098+ out . indent ( 2 ) do
1099+ render_import ( out , arm . declaration , union_name , track : false ) if render_import_in_func
1100+ decode_expr = decode_union_arm_value ( arm , "json_value[\" #{ json_key } \" ]" )
1101+ out . puts "#{ local_var } = #{ decode_expr } "
1102+ out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } , #{ arm_name } =#{ local_var } )"
1103+ end
11241104 end
11251105 end
1106+
1107+ if union . default_arm . present? && !union . default_arm . void?
1108+ arm_name = safe_identifier ( union . default_arm . name . underscore )
1109+ local_var = safe_local_var ( arm_name )
1110+ render_import ( out , union . default_arm . declaration , union_name , track : false ) if render_import_in_func
1111+ decode_expr = decode_union_arm_value ( union . default_arm , "json_value[key]" )
1112+ out . puts "#{ local_var } = #{ decode_expr } "
1113+ out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } , #{ arm_name } =#{ local_var } )"
1114+ else
1115+ out . puts "raise ValueError(f\" Unknown key '{key}' for #{ union_name } \" )"
1116+ end
11261117 end
1118+ end
1119+ end
11271120
1128- if union . default_arm . present? && !union . default_arm . void?
1129- arm_name = safe_identifier ( union . default_arm . name . underscore )
1130- local_var = safe_local_var ( arm_name )
1131- render_import ( out , union . default_arm . declaration , union_name , track : false ) if render_import_in_func
1132- decode_expr = decode_union_arm_value ( union . default_arm , "json_value[key]" )
1133- out . puts "#{ local_var } = #{ decode_expr } "
1134- out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } , #{ arm_name } =#{ local_var } )"
1121+ def render_union_void_from_json ( out , union_name , discriminant_name , disc_enum , disc_type_str , void_keys , non_void_keys , has_void_default )
1122+ if has_void_default
1123+ # Void default arm: string input is valid for void arms and default,
1124+ # but must reject non-void arm keys (they require dict form with a value)
1125+ if non_void_keys . any?
1126+ nv_keys_str = non_void_keys . map { |k | "\" #{ k } \" " } . join ( ", " )
1127+ out . puts "if json_value in (#{ nv_keys_str } ,):"
1128+ out . indent ( 2 ) do
1129+ out . puts "raise ValueError(f\" '{json_value}' requires a value for #{ union_name } , use dict form instead\" )"
1130+ end
1131+ end
1132+ if disc_enum
1133+ disc_type_name = name ( disc_enum )
1134+ out . puts "#{ discriminant_name } = #{ disc_type_name } .from_json_dict(json_value)"
1135+ else
1136+ out . puts "#{ discriminant_name } = #{ non_enum_disc_parse_expr ( disc_type_str , 'json_value' ) } "
1137+ end
1138+ out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } )"
1139+ elsif void_keys . any?
1140+ # Only specific void arms are valid as string input
1141+ keys_str = void_keys . map { |k | "\" #{ k } \" " } . join ( ", " )
1142+ out . puts "if json_value not in (#{ keys_str } ,):"
1143+ out . indent ( 2 ) do
1144+ out . puts "raise ValueError(f\" Unexpected string '{json_value}' for #{ union_name } , must be one of: #{ void_keys . join ( ', ' ) } \" )"
1145+ end
1146+ if disc_enum
1147+ disc_type_name = name ( disc_enum )
1148+ out . puts "#{ discriminant_name } = #{ disc_type_name } .from_json_dict(json_value)"
11351149 else
1136- out . puts "raise ValueError(f \" Unknown key '{key}' for #{ union_name } \" ) "
1150+ out . puts "#{ discriminant_name } = #{ non_enum_disc_parse_expr ( disc_type_str , 'json_value' ) } "
11371151 end
1152+ out . puts "return cls(#{ discriminant_name } =#{ discriminant_name } )"
11381153 end
11391154 end
11401155
0 commit comments