Skip to content

Commit ae4cb28

Browse files
authored
Fix serialization of models with computed fields (#550)
* Fix serialization of models with computed fields * Move the n_computed_fields method
1 parent 51f24f6 commit ae4cb28

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

src/serializers/computed_fields.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ impl ComputedFields {
3232
}
3333
}
3434

35+
pub fn len(&self) -> usize {
36+
self.0.len()
37+
}
38+
3539
pub fn to_python(
3640
&self,
3741
model: &PyAny,

src/serializers/type_serializers/typed_dict.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ impl TypedDictSerializer {
144144
}
145145
}
146146

147+
pub fn n_computed_fields(&self) -> usize {
148+
match self.computed_fields {
149+
None => 0,
150+
Some(ref computed_fields) => computed_fields.len(),
151+
}
152+
}
153+
147154
fn exclude_default(&self, value: &PyAny, extra: &Extra, field: &TypedDictField) -> PyResult<bool> {
148155
if extra.exclude_defaults {
149156
if let Some(default) = field.serializer.get_default(value.py())? {
@@ -262,7 +269,7 @@ impl TypeSerializer for TypedDictSerializer {
262269
};
263270
let expected_len = match self.include_extra {
264271
true => py_dict.len(),
265-
false => self.fields.len(),
272+
false => self.fields.len() + self.n_computed_fields(),
266273
};
267274
// NOTE! As above, we maintain the order of the input dict assuming that's right
268275
// we don't both with `used_fields` here because on unions, `to_python(..., mode='json')` is used

tests/test.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,40 @@ mod tests {
2828
SchemaSerializer::py_new(py, schema, None).unwrap();
2929
})
3030
}
31+
32+
#[test]
33+
fn test_serialize_computed_fields() {
34+
Python::with_gil(|py| {
35+
let code = r#"
36+
class A:
37+
@property
38+
def b(self) -> str:
39+
return "b"
40+
41+
schema = {
42+
"cls": A,
43+
"config": {},
44+
"schema": {
45+
"computed_fields": [{"property_name": "b", "type": "computed-field"}],
46+
"fields": {},
47+
"return_fields_set": True,
48+
"type": "typed-dict",
49+
},
50+
"type": "model",
51+
}
52+
a = A()
53+
"#;
54+
let locals = PyDict::new(py);
55+
py.run(code, None, Some(locals)).unwrap();
56+
let a: &PyAny = locals.get_item("a").unwrap().extract().unwrap();
57+
let schema: &PyDict = locals.get_item("schema").unwrap().extract().unwrap();
58+
let serialized: Vec<u8> = SchemaSerializer::py_new(py, schema, None)
59+
.unwrap()
60+
.to_json(py, a, None, None, None, true, false, false, false, false, true, None)
61+
.unwrap()
62+
.extract(py)
63+
.unwrap();
64+
assert_eq!(serialized, b"{\"b\":\"b\"}");
65+
})
66+
}
3167
}

0 commit comments

Comments
 (0)