Skip to content

Commit

Permalink
Fix serialization of models with computed fields (#550)
Browse files Browse the repository at this point in the history
* Fix serialization of models with computed fields

* Move the n_computed_fields method
  • Loading branch information
dmontagu authored Apr 24, 2023
1 parent 51f24f6 commit ae4cb28
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/serializers/computed_fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ impl ComputedFields {
}
}

pub fn len(&self) -> usize {
self.0.len()
}

pub fn to_python(
&self,
model: &PyAny,
Expand Down
9 changes: 8 additions & 1 deletion src/serializers/type_serializers/typed_dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ impl TypedDictSerializer {
}
}

pub fn n_computed_fields(&self) -> usize {
match self.computed_fields {
None => 0,
Some(ref computed_fields) => computed_fields.len(),
}
}

fn exclude_default(&self, value: &PyAny, extra: &Extra, field: &TypedDictField) -> PyResult<bool> {
if extra.exclude_defaults {
if let Some(default) = field.serializer.get_default(value.py())? {
Expand Down Expand Up @@ -262,7 +269,7 @@ impl TypeSerializer for TypedDictSerializer {
};
let expected_len = match self.include_extra {
true => py_dict.len(),
false => self.fields.len(),
false => self.fields.len() + self.n_computed_fields(),
};
// NOTE! As above, we maintain the order of the input dict assuming that's right
// we don't both with `used_fields` here because on unions, `to_python(..., mode='json')` is used
Expand Down
36 changes: 36 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,40 @@ mod tests {
SchemaSerializer::py_new(py, schema, None).unwrap();
})
}

#[test]
fn test_serialize_computed_fields() {
Python::with_gil(|py| {
let code = r#"
class A:
@property
def b(self) -> str:
return "b"
schema = {
"cls": A,
"config": {},
"schema": {
"computed_fields": [{"property_name": "b", "type": "computed-field"}],
"fields": {},
"return_fields_set": True,
"type": "typed-dict",
},
"type": "model",
}
a = A()
"#;
let locals = PyDict::new(py);
py.run(code, None, Some(locals)).unwrap();
let a: &PyAny = locals.get_item("a").unwrap().extract().unwrap();
let schema: &PyDict = locals.get_item("schema").unwrap().extract().unwrap();
let serialized: Vec<u8> = SchemaSerializer::py_new(py, schema, None)
.unwrap()
.to_json(py, a, None, None, None, true, false, false, false, false, true, None)
.unwrap()
.extract(py)
.unwrap();
assert_eq!(serialized, b"{\"b\":\"b\"}");
})
}
}

0 comments on commit ae4cb28

Please sign in to comment.