@@ -156,59 +156,28 @@ impl GeneralFieldsSerializer {
156
156
let output_dict = PyDict :: new ( py) ;
157
157
let mut used_req_fields: usize = 0 ;
158
158
159
- let mut items = main_iter. collect :: < PyResult < Vec < _ > > > ( ) ?;
160
- if extra. sort_keys {
161
- items. sort_by_cached_key ( |( key, _) | key_str ( key) . unwrap_or_default ( ) . to_string ( ) ) ;
162
- }
163
-
164
- for ( key, value) in items {
165
- let key_str = key_str ( & key) ?;
166
- let op_field = self . fields . get ( key_str) ;
167
- if extra. exclude_none && value. is_none ( ) {
168
- if let Some ( field) = op_field {
169
- if field. required {
159
+ if !extra. sort_keys {
160
+ for result in main_iter {
161
+ let ( key, value) = result?;
162
+ if let Some ( is_required) =
163
+ self . process_field_entry_python ( & key, & value, & output_dict, include, exclude, & extra) ?
164
+ {
165
+ if is_required {
170
166
used_req_fields += 1 ;
171
167
}
172
168
}
173
- continue ;
174
169
}
175
- let field_extra = Extra {
176
- field_name : Some ( key_str) ,
177
- ..extra
178
- } ;
179
- if let Some ( ( next_include, next_exclude) ) = self . filter . key_filter ( & key, include, exclude) ? {
180
- if let Some ( field) = op_field {
181
- if let Some ( ref serializer) = field. serializer {
182
- if !exclude_default ( & value, & field_extra, serializer) ? {
183
- let value = serializer. to_python (
184
- & value,
185
- next_include. as_ref ( ) ,
186
- next_exclude. as_ref ( ) ,
187
- & field_extra,
188
- ) ?;
189
- let output_key = field. get_key_py ( output_dict. py ( ) , & field_extra) ;
190
- output_dict. set_item ( output_key, value) ?;
191
- }
192
- }
170
+ } else {
171
+ let mut items = main_iter. collect :: < PyResult < Vec < _ > > > ( ) ?;
172
+ items. sort_by_cached_key ( |( key, _) | key_str ( key) . unwrap_or_default ( ) . to_string ( ) ) ;
193
173
194
- if field. required {
174
+ for ( key, value) in items {
175
+ if let Some ( is_required) =
176
+ self . process_field_entry_python ( & key, & value, & output_dict, include, exclude, & extra) ?
177
+ {
178
+ if is_required {
195
179
used_req_fields += 1 ;
196
180
}
197
- } else if self . mode == FieldsMode :: TypedDictAllow {
198
- let value = match & self . extra_serializer {
199
- Some ( serializer) => {
200
- serializer. to_python ( & value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , & field_extra) ?
201
- }
202
- None => infer_to_python ( & value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , & field_extra) ?,
203
- } ;
204
- output_dict. set_item ( key, value) ?;
205
- } else if field_extra. check == SerCheck :: Strict {
206
- return Err ( PydanticSerializationUnexpectedValue :: new (
207
- Some ( format ! ( "Unexpected field `{key}`" ) ) ,
208
- field_extra. model_type_name ( ) . map ( |bound| bound. to_string ( ) ) ,
209
- None ,
210
- )
211
- . to_py_err ( ) ) ;
212
181
}
213
182
}
214
183
}
@@ -232,6 +201,73 @@ impl GeneralFieldsSerializer {
232
201
}
233
202
}
234
203
204
+ fn process_field_entry_python < ' py > (
205
+ & self ,
206
+ key : & Bound < ' py , PyAny > ,
207
+ value : & Bound < ' py , PyAny > ,
208
+ output_dict : & Bound < ' py , PyDict > ,
209
+ include : Option < & Bound < ' py , PyAny > > ,
210
+ exclude : Option < & Bound < ' py , PyAny > > ,
211
+ extra : & Extra ,
212
+ ) -> PyResult < Option < bool > > {
213
+ // This function updates output_dict directly and returns:
214
+ // - Some(true) -> Field was required and processed
215
+ // - Some(false) -> Field was processed but not required
216
+ // - None -> Field was filtered out or skipped
217
+ let key_str = key_str ( key) ?;
218
+ let op_field = self . fields . get ( key_str) ;
219
+
220
+ if extra. exclude_none && value. is_none ( ) {
221
+ if let Some ( field) = op_field {
222
+ if field. required {
223
+ return Ok ( Some ( true ) ) ;
224
+ }
225
+ }
226
+ return Ok ( None ) ;
227
+ }
228
+
229
+ let field_extra = Extra {
230
+ field_name : Some ( key_str) ,
231
+ ..* extra
232
+ } ;
233
+
234
+ if let Some ( ( next_include, next_exclude) ) = self . filter . key_filter ( key, include, exclude) ? {
235
+ if let Some ( field) = op_field {
236
+ if let Some ( ref serializer) = field. serializer {
237
+ if !exclude_default ( value, & field_extra, serializer) ? {
238
+ let value =
239
+ serializer. to_python ( value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , & field_extra) ?;
240
+ let output_key = field. get_key_py ( output_dict. py ( ) , & field_extra) ;
241
+ output_dict. set_item ( output_key, value) ?;
242
+ }
243
+ }
244
+
245
+ if field. required {
246
+ return Ok ( Some ( true ) ) ;
247
+ }
248
+ return Ok ( Some ( false ) ) ;
249
+ } else if self . mode == FieldsMode :: TypedDictAllow {
250
+ let value = match & self . extra_serializer {
251
+ Some ( serializer) => {
252
+ serializer. to_python ( value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , & field_extra) ?
253
+ }
254
+ None => infer_to_python ( value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , & field_extra) ?,
255
+ } ;
256
+ output_dict. set_item ( key, value) ?;
257
+ return Ok ( None ) ;
258
+ } else if field_extra. check == SerCheck :: Strict {
259
+ return Err ( PydanticSerializationUnexpectedValue :: new (
260
+ Some ( format ! ( "Unexpected field `{key}`" ) ) ,
261
+ field_extra. model_type_name ( ) . map ( |bound| bound. to_string ( ) ) ,
262
+ None ,
263
+ )
264
+ . to_py_err ( ) ) ;
265
+ }
266
+ }
267
+
268
+ Ok ( None )
269
+ }
270
+
235
271
pub ( crate ) fn main_serde_serialize < ' py , S : serde:: ser:: Serializer > (
236
272
& self ,
237
273
main_iter : impl Iterator < Item = PyResult < ( Bound < ' py , PyAny > , Bound < ' py , PyAny > ) > > ,
@@ -245,45 +281,63 @@ impl GeneralFieldsSerializer {
245
281
// we don't both with `used_fields` here because on unions, `to_python(..., mode='json')` is used
246
282
let mut map = serializer. serialize_map ( Some ( expected_len) ) ?;
247
283
248
- let mut items = main_iter. collect :: < PyResult < Vec < _ > > > ( ) . map_err ( py_err_se_err) ?;
249
- if extra. sort_keys {
284
+ if !extra. sort_keys {
285
+ for result in main_iter {
286
+ let ( key, value) = result. map_err ( py_err_se_err) ?;
287
+ self . process_field_entry :: < S > ( & key, & value, & mut map, include, exclude, & extra) ?;
288
+ }
289
+ } else {
290
+ let mut items = main_iter. collect :: < PyResult < Vec < _ > > > ( ) . map_err ( py_err_se_err) ?;
250
291
items. sort_by_cached_key ( |( key, _) | key_str ( key) . unwrap_or_default ( ) . to_string ( ) ) ;
251
- }
252
- for ( key, value) in items {
253
- if extra. exclude_none && value. is_none ( ) {
254
- continue ;
292
+ for ( key, value) in items {
293
+ self . process_field_entry :: < S > ( & key, & value, & mut map, include, exclude, & extra) ?;
255
294
}
256
- let key_str = key_str ( & key) . map_err ( py_err_se_err) ?;
257
- let field_extra = Extra {
258
- field_name : Some ( key_str) ,
259
- ..extra
260
- } ;
295
+ }
296
+ Ok ( map)
297
+ }
261
298
262
- let filter = self . filter . key_filter ( & key, include, exclude) . map_err ( py_err_se_err) ?;
263
- if let Some ( ( next_include, next_exclude) ) = filter {
264
- if let Some ( field) = self . fields . get ( key_str) {
265
- if let Some ( ref serializer) = field. serializer {
266
- if !exclude_default ( & value, & field_extra, serializer) . map_err ( py_err_se_err) ? {
267
- let s = PydanticSerializer :: new (
268
- & value,
269
- serializer,
270
- next_include. as_ref ( ) ,
271
- next_exclude. as_ref ( ) ,
272
- & field_extra,
273
- ) ;
274
- let output_key = field. get_key_json ( key_str, & field_extra) ;
275
- map. serialize_entry ( & output_key, & s) ?;
276
- }
299
+ fn process_field_entry < ' py , S : serde:: ser:: Serializer > (
300
+ & self ,
301
+ key : & Bound < ' py , PyAny > ,
302
+ value : & Bound < ' py , PyAny > ,
303
+ map : & mut S :: SerializeMap ,
304
+ include : Option < & Bound < ' py , PyAny > > ,
305
+ exclude : Option < & Bound < ' py , PyAny > > ,
306
+ extra : & Extra ,
307
+ ) -> Result < ( ) , S :: Error > {
308
+ if extra. exclude_none && value. is_none ( ) {
309
+ return Ok ( ( ) ) ;
310
+ }
311
+ let key_str = key_str ( key) . map_err ( py_err_se_err) ?;
312
+ let field_extra = Extra {
313
+ field_name : Some ( key_str) ,
314
+ ..* extra
315
+ } ;
316
+
317
+ let filter = self . filter . key_filter ( key, include, exclude) . map_err ( py_err_se_err) ?;
318
+ if let Some ( ( next_include, next_exclude) ) = filter {
319
+ if let Some ( field) = self . fields . get ( key_str) {
320
+ if let Some ( ref serializer) = field. serializer {
321
+ if !exclude_default ( value, & field_extra, serializer) . map_err ( py_err_se_err) ? {
322
+ let s = PydanticSerializer :: new (
323
+ value,
324
+ serializer,
325
+ next_include. as_ref ( ) ,
326
+ next_exclude. as_ref ( ) ,
327
+ & field_extra,
328
+ ) ;
329
+ let output_key = field. get_key_json ( key_str, & field_extra) ;
330
+ map. serialize_entry ( & output_key, & s) ?;
277
331
}
278
- } else if self . mode == FieldsMode :: TypedDictAllow {
279
- let output_key = infer_json_key ( & key, & field_extra) . map_err ( py_err_se_err) ?;
280
- let s = SerializeInfer :: new ( & value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , & field_extra) ;
281
- map. serialize_entry ( & output_key, & s) ?;
282
332
}
283
- // no error case here since unions (which need the error case) use `to_python(..., mode='json')`
333
+ } else if self . mode == FieldsMode :: TypedDictAllow {
334
+ let output_key = infer_json_key ( key, & field_extra) . map_err ( py_err_se_err) ?;
335
+ let s = SerializeInfer :: new ( value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , & field_extra) ;
336
+ map. serialize_entry ( & output_key, & s) ?;
284
337
}
338
+ // no error case here since unions (which need the error case) use `to_python(..., mode='json')`
285
339
}
286
- Ok ( map )
340
+ Ok ( ( ) )
287
341
}
288
342
289
343
pub ( crate ) fn add_computed_fields_python (
0 commit comments