Conversation
This allows a user to pass a custom function that can do extra handling whenever an error happens in deserialization. Inspired by the `default` parameter to Python's `json.dump`. https://docs.python.org/3/library/json.html#json.dump
| } else if obj.is_instance_of::<PyByteArray>()? || obj.is_instance_of::<PyBytes>()? { | ||
| self.deserialize_bytes(visitor) |
There was a problem hiding this comment.
I removed this because it was the quickest and easiest way to use the on_error callback when handling a bytes object. Obviously this breaks other use cases of this library, so a different solution will be needed here.
| Some(on_error) => { | ||
| // Do we recurse infinitely if on_error returns something we can't | ||
| // deserialize? | ||
| self.input = on_error(self.input); |
There was a problem hiding this comment.
I'm not certain that reassigning to self.input here is appropriate. Maybe that could break serializing some nested data?
| // Do we recurse infinitely if on_error returns something we can't | ||
| // deserialize? | ||
| self.input = on_error(self.input); |
There was a problem hiding this comment.
I'm not sure how best to avoid this infinite recursion.
| /// Attempt to convert a Python object to an instance of `T` | ||
| pub fn depythonize_on_error<'de, T>( | ||
| obj: &'de PyAny, | ||
| on_error: &'de Option<fn(&PyAny) -> &PyAny>, |
There was a problem hiding this comment.
I haven't thought deeply about whether a different lifetime might be appropriate for on_error.
| let key = match key { | ||
| key if key.is_instance_of::<PyUnicode>()? => key, | ||
| key if key.is_none() => intern!(py, "null"), | ||
| key if key.is_instance_of::<PyBool>()? => match key.is_true()? { | ||
| true => intern!(py, "true"), | ||
| false => intern!(py, "false"), | ||
| }, | ||
| key => key.str()?, |
There was a problem hiding this comment.
Here I'm (mostly) matching the behaviour of json.dumps that converts "dict keys of a basic type" (str, int, float, bool, None) to strings.
Again, this probably shouldn't live here, but I'm not clear what the right approach is.
|
Sorry for having just seen this, been a long week for me. Thanks for opening the PR! The idea is the I wonder if we should call this I'll need to have a play with the implementation to understand if it's the right approach. Will try to do this in the next few days. |
No worries!
Pretty much - in my use case I use the
I considered that. I'm not sure if that's going to be helpful or confusing, since serde has its own concept of "default", which is different. (https://serde.rs/container-attrs.html#default)
Awesome! |
I'm opening this PR more as a place to start a discussion for my use-case and the changes I needed to make to support it. I'm hoping it's possible to turn this into a feature that's more broadly useful to other users.
My use case is I'm building a profiler/debugger called Kolo (https://kolo.app/). As part of this we have a Python library which inspects Python frame objects and serializes information about them (such as local variables) as json. In this I make use of a custom
JSONEncoderto serialize otherwise unserializable data (as theirrepr).I have been reimplementing this library in Rust for performance, and json encoding is a measurable slowdown in my profiling, so I'm trying to use
pythonizeandserde_jsonto avoid calling Python'sjson.dumps.With the changes in this branch, and the following implementation of a
dump_jsonfunction my tests all pass:Is a feature allowing some fallback behaviour on errors desirable for this library? Or is there a better way to achieve what I'm trying to do?