@@ -2,13 +2,12 @@ use pyo3::prelude::*;
2
2
use pyo3:: types:: { PyDict , PyList , PyString } ;
3
3
use pyo3:: { intern, PyTraverseError , PyVisit } ;
4
4
use serde:: ser:: SerializeMap ;
5
- use serde:: Serialize ;
6
5
7
6
use crate :: build_tools:: py_schema_error_type;
8
7
use crate :: definitions:: DefinitionsBuilder ;
9
8
use crate :: py_gc:: PyGcTraverse ;
10
9
use crate :: serializers:: filter:: SchemaFilter ;
11
- use crate :: serializers:: shared:: { BuildSerializer , CombinedSerializer , PydanticSerializer , TypeSerializer } ;
10
+ use crate :: serializers:: shared:: { BuildSerializer , CombinedSerializer , PydanticSerializer } ;
12
11
use crate :: tools:: SchemaDict ;
13
12
14
13
use super :: errors:: py_err_se_err;
@@ -48,18 +47,31 @@ impl ComputedFields {
48
47
exclude : Option < & Bound < ' _ , PyAny > > ,
49
48
extra : & Extra ,
50
49
) -> PyResult < ( ) > {
51
- if extra. round_trip {
52
- // Do not serialize computed fields
53
- return Ok ( ( ) ) ;
54
- }
55
- for computed_field in & self . 0 {
56
- let field_extra = Extra {
57
- field_name : Some ( computed_field. property_name . as_str ( ) ) ,
58
- ..* extra
59
- } ;
60
- computed_field. to_python ( model, output_dict, filter, include, exclude, & field_extra) ?;
61
- }
62
- Ok ( ( ) )
50
+ self . serialize_fields (
51
+ model,
52
+ filter,
53
+ include,
54
+ exclude,
55
+ extra,
56
+ |e| e,
57
+ |ComputedFieldToSerialize {
58
+ computed_field,
59
+ value,
60
+ include,
61
+ exclude,
62
+ field_extra,
63
+ } | {
64
+ let key = match field_extra. serialize_by_alias_or ( computed_field. serialize_by_alias ) {
65
+ true => computed_field. alias_py . bind ( model. py ( ) ) ,
66
+ false => computed_field. property_name_py . bind ( model. py ( ) ) ,
67
+ } ;
68
+ let value =
69
+ computed_field
70
+ . serializer
71
+ . to_python ( & value, include. as_ref ( ) , exclude. as_ref ( ) , & field_extra) ?;
72
+ output_dict. set_item ( key, value)
73
+ } ,
74
+ )
63
75
}
64
76
65
77
pub fn serde_serialize < S : serde:: ser:: Serializer > (
@@ -71,44 +83,96 @@ impl ComputedFields {
71
83
exclude : Option < & Bound < ' _ , PyAny > > ,
72
84
extra : & Extra ,
73
85
) -> Result < ( ) , S :: Error > {
86
+ self . serialize_fields (
87
+ model,
88
+ filter,
89
+ include,
90
+ exclude,
91
+ extra,
92
+ py_err_se_err,
93
+ |ComputedFieldToSerialize {
94
+ computed_field,
95
+ value,
96
+ include,
97
+ exclude,
98
+ field_extra,
99
+ } | {
100
+ let key = match field_extra. serialize_by_alias_or ( computed_field. serialize_by_alias ) {
101
+ true => & computed_field. alias ,
102
+ false => & computed_field. property_name ,
103
+ } ;
104
+ let s = PydanticSerializer :: new (
105
+ & value,
106
+ & computed_field. serializer ,
107
+ include. as_ref ( ) ,
108
+ exclude. as_ref ( ) ,
109
+ & field_extra,
110
+ ) ;
111
+ map. serialize_entry ( key, & s)
112
+ } ,
113
+ )
114
+ }
115
+
116
+ /// Iterate each field for serialization, filtering on
117
+ /// `include` and `exclude` if provided.
118
+ #[ allow( clippy:: too_many_arguments) ]
119
+ fn serialize_fields < ' a , ' py , E > (
120
+ & ' a self ,
121
+ model : & ' a Bound < ' py , PyAny > ,
122
+ filter : & ' a SchemaFilter < isize > ,
123
+ include : Option < & ' a Bound < ' py , PyAny > > ,
124
+ exclude : Option < & ' a Bound < ' py , PyAny > > ,
125
+ extra : & ' a Extra ,
126
+ convert_error : impl FnOnce ( PyErr ) -> E ,
127
+ mut serialize : impl FnMut ( ComputedFieldToSerialize < ' a , ' py > ) -> Result < ( ) , E > ,
128
+ ) -> Result < ( ) , E > {
74
129
if extra. round_trip {
75
130
// Do not serialize computed fields
76
131
return Ok ( ( ) ) ;
77
132
}
78
133
79
134
for computed_field in & self . 0 {
80
135
let property_name_py = computed_field. property_name_py . bind ( model. py ( ) ) ;
136
+ let ( next_include, next_exclude) = match filter. key_filter ( property_name_py, include, exclude) {
137
+ Ok ( Some ( ( next_include, next_exclude) ) ) => ( next_include, next_exclude) ,
138
+ Ok ( None ) => continue ,
139
+ Err ( e) => return Err ( convert_error ( e) ) ,
140
+ } ;
81
141
82
- if let Some ( ( next_include, next_exclude) ) = filter
83
- . key_filter ( property_name_py, include, exclude)
84
- . map_err ( py_err_se_err) ?
85
- {
86
- let value = model. getattr ( property_name_py) . map_err ( py_err_se_err) ?;
87
- if extra. exclude_none && value. is_none ( ) {
88
- continue ;
142
+ let value = match model. getattr ( property_name_py) {
143
+ Ok ( field_value) => field_value,
144
+ Err ( e) => {
145
+ return Err ( convert_error ( e) ) ;
89
146
}
90
- let field_extra = Extra {
91
- field_name : Some ( computed_field. property_name . as_str ( ) ) ,
92
- ..* extra
93
- } ;
94
- let cfs = ComputedFieldSerializer {
95
- model,
96
- computed_field,
97
- include : next_include. as_ref ( ) ,
98
- exclude : next_exclude. as_ref ( ) ,
99
- extra : & field_extra,
100
- } ;
101
- let key = match extra. serialize_by_alias_or ( computed_field. serialize_by_alias ) {
102
- true => computed_field. alias . as_str ( ) ,
103
- false => computed_field. property_name . as_str ( ) ,
104
- } ;
105
- map. serialize_entry ( key, & cfs) ?;
147
+ } ;
148
+ if extra. exclude_none && value. is_none ( ) {
149
+ continue ;
106
150
}
151
+
152
+ let field_extra = Extra {
153
+ field_name : Some ( & computed_field. property_name ) ,
154
+ ..* extra
155
+ } ;
156
+ serialize ( ComputedFieldToSerialize {
157
+ computed_field,
158
+ value,
159
+ include : next_include,
160
+ exclude : next_exclude,
161
+ field_extra,
162
+ } ) ?;
107
163
}
108
164
Ok ( ( ) )
109
165
}
110
166
}
111
167
168
+ struct ComputedFieldToSerialize < ' a , ' py > {
169
+ computed_field : & ' a ComputedField ,
170
+ value : Bound < ' py , PyAny > ,
171
+ include : Option < Bound < ' py , PyAny > > ,
172
+ exclude : Option < Bound < ' py , PyAny > > ,
173
+ field_extra : Extra < ' a > ,
174
+ }
175
+
112
176
#[ derive( Debug ) ]
113
177
struct ComputedField {
114
178
property_name : String ,
@@ -143,44 +207,6 @@ impl ComputedField {
143
207
serialize_by_alias : config. get_as ( intern ! ( py, "serialize_by_alias" ) ) ?,
144
208
} )
145
209
}
146
-
147
- fn to_python (
148
- & self ,
149
- model : & Bound < ' _ , PyAny > ,
150
- output_dict : & Bound < ' _ , PyDict > ,
151
- filter : & SchemaFilter < isize > ,
152
- include : Option < & Bound < ' _ , PyAny > > ,
153
- exclude : Option < & Bound < ' _ , PyAny > > ,
154
- extra : & Extra ,
155
- ) -> PyResult < ( ) > {
156
- let py = model. py ( ) ;
157
- let property_name_py = self . property_name_py . bind ( py) ;
158
-
159
- if let Some ( ( next_include, next_exclude) ) = filter. key_filter ( property_name_py, include, exclude) ? {
160
- let next_value = model. getattr ( property_name_py) ?;
161
-
162
- let value = self
163
- . serializer
164
- . to_python ( & next_value, next_include. as_ref ( ) , next_exclude. as_ref ( ) , extra) ?;
165
- if extra. exclude_none && value. is_none ( py) {
166
- return Ok ( ( ) ) ;
167
- }
168
- let key = match extra. serialize_by_alias_or ( self . serialize_by_alias ) {
169
- true => self . alias_py . bind ( py) ,
170
- false => property_name_py,
171
- } ;
172
- output_dict. set_item ( key, value) ?;
173
- }
174
- Ok ( ( ) )
175
- }
176
- }
177
-
178
- pub ( crate ) struct ComputedFieldSerializer < ' py > {
179
- model : & ' py Bound < ' py , PyAny > ,
180
- computed_field : & ' py ComputedField ,
181
- include : Option < & ' py Bound < ' py , PyAny > > ,
182
- exclude : Option < & ' py Bound < ' py , PyAny > > ,
183
- extra : & ' py Extra < ' py > ,
184
210
}
185
211
186
212
impl_py_gc_traverse ! ( ComputedField { serializer } ) ;
@@ -190,21 +216,3 @@ impl PyGcTraverse for ComputedFields {
190
216
self . 0 . py_gc_traverse ( visit)
191
217
}
192
218
}
193
-
194
- impl_py_gc_traverse ! ( ComputedFieldSerializer <' _> { computed_field } ) ;
195
-
196
- impl Serialize for ComputedFieldSerializer < ' _ > {
197
- fn serialize < S : serde:: ser:: Serializer > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error > {
198
- let py = self . model . py ( ) ;
199
- let property_name_py = self . computed_field . property_name_py . bind ( py) ;
200
- let next_value = self . model . getattr ( property_name_py) . map_err ( py_err_se_err) ?;
201
- let s = PydanticSerializer :: new (
202
- & next_value,
203
- & self . computed_field . serializer ,
204
- self . include ,
205
- self . exclude ,
206
- self . extra ,
207
- ) ;
208
- s. serialize ( serializer)
209
- }
210
- }
0 commit comments