@@ -156,59 +156,28 @@ impl GeneralFieldsSerializer {
156156 let output_dict = PyDict :: new ( py) ;
157157 let mut used_req_fields: usize = 0 ;
158158
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 {
170166 used_req_fields += 1 ;
171167 }
172168 }
173- continue ;
174169 }
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 ( ) ) ;
193173
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 {
195179 used_req_fields += 1 ;
196180 }
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 ( ) ) ;
212181 }
213182 }
214183 }
@@ -232,6 +201,73 @@ impl GeneralFieldsSerializer {
232201 }
233202 }
234203
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+
235271 pub ( crate ) fn main_serde_serialize < ' py , S : serde:: ser:: Serializer > (
236272 & self ,
237273 main_iter : impl Iterator < Item = PyResult < ( Bound < ' py , PyAny > , Bound < ' py , PyAny > ) > > ,
@@ -245,45 +281,63 @@ impl GeneralFieldsSerializer {
245281 // we don't both with `used_fields` here because on unions, `to_python(..., mode='json')` is used
246282 let mut map = serializer. serialize_map ( Some ( expected_len) ) ?;
247283
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) ?;
250291 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) ?;
255294 }
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+ }
261298
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) ?;
277331 }
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) ?;
282332 }
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) ?;
284337 }
338+ // no error case here since unions (which need the error case) use `to_python(..., mode='json')`
285339 }
286- Ok ( map )
340+ Ok ( ( ) )
287341 }
288342
289343 pub ( crate ) fn add_computed_fields_python (
0 commit comments