pyo3 icon indicating copy to clipboard operation
pyo3 copied to clipboard

Crazy idea: serde support

Open birkenfeld opened this issue 6 years ago • 18 comments

A few times now, I had to take in complex-ish Python data and convert it into an equivalent in Rust. FromPyObject already does the basic types, but I'd also like to convert e.g. nested dicts with certain keys into structs.

Do you think it would make sense to let serde handle this? It already has all the options you'd like, e.g. flattening of sub-structure and renaming of things. For structs, it should support both dicts (taking keys) and other objects (taking attributes).

The "ser" direction could also be supported, although I don't need it, and it would probably only construct dicts for structs.

birkenfeld avatar Aug 06 '19 04:08 birkenfeld

The "ser" direction could also be supported, although I don't need it, and it would probably only construct dicts for structs.

We actually wanted something like this, mostly when you want to return something which is 'data', but don't want (or can't) create a dedicated python wrapper for each struct.

ohadravid avatar Aug 06 '19 08:08 ohadravid

@birkenfeld I think that this sort of thing is a good idea, but is it really something that belongs in PyO3?

I think it makes sense to leave the core C API wrappers in PyO3 and break out useful additional functionality into their own crates.

pganssle avatar Aug 09 '19 14:08 pganssle

I took a stab at something like this, by implementing the custom serde traits, but then ran into lifetime issues with all the python data since everything relies on the interpreter lifetime. Not that it probably isn't possible, but It'll take someone with more experience than me.

I ended up just dumping everything to a raw json string and passing it over, which is a trivial amount of code on both python and rust sides, but not an elegant solution.

jmrgibson avatar Sep 05 '19 15:09 jmrgibson

I've made a crate to help deal with this. It let's you derive the necessary traits for PyO3 to convert a dict into your struct, as long as it knows how to convert every field.

I plan on having serde-like field attributes in the future, but if you're not using them the base functionality should beat passing things around as json.

gperinazzo avatar Sep 11 '19 03:09 gperinazzo

I would encourage you all not to overthink this. So allow me to step back and do exactly that at a more abstract level I guess... :-/

Who is your audience? Is it people who are primarily writing in Rust or Python?

What are they struggling with? Are they struggling with learning one language or the other, or learning how to call something from Python using e.g. ctypes or have they stumbled on pyo3 and are they wondering how that works?

What are they trying to accomplish? Are they trying to translate from one language to the other? Do they feel the "need for speed" and contemplating trying something other than C? Are they primarily Rust programmers looking for a more transparent "glue" for some larger problem (see the popularity of embedded Lua for various tasks)?

I have a brick in the wall to offer as someone primarily writing in Python who had an optimization problem and stumbled across pyo3 and thought "well maybe I'll trying doing it in Rust rather than C": m3047/pyo3-deserializer

(A friend of mine who write primarily in Rust brought this issue to my attention.)

m3047 avatar Jul 30 '20 18:07 m3047

One for the folks watching this: I've made a WIP crate which targets a full serde implementation for PyO3. See https://github.com/davidhewitt/pythonize

The idea is that it should be pretty much equivalent to serde_json but generates Python objects instead of string data.

Note that unlike dict-derive this means that it doesn't integrate very nicely with types that already implement IntoPy / FromPyObject - it's got to be serde all the way down. Maybe there's a way to solve that.

At the moment only the to-Python direction is implemented, but I'd be interested in taking feedback / help finishing this off.

davidhewitt avatar Aug 12 '20 07:08 davidhewitt

I had a similar use-case, convert a PyObject into a serde_json::json::Value. It might be slightly off-topic here, but I thought it could be useful for someone looking for something similar and landing here :) https://github.com/mozilla-services/python-canonicaljson-rs/blob/62599b246055a1c8a78e5777acdfe0fd594be3d8/src/lib.rs#L87-L167 (it was mostly inspired by Matthias Endler's hyperjson)

leplatrem avatar Sep 05 '20 08:09 leplatrem

I had a similar use-case, convert a PyObject into a serde_json::json::Value. It might be slightly off-topic here, but I thought it could be useful for someone looking for something similar and landing here :) https://github.com/mozilla-services/python-canonicaljson-rs/blob/62599b246055a1c8a78e5777acdfe0fd594be3d8/src/lib.rs#L87-L167 (it was mostly inspired by Matthias Endler's hyperjson)

This is exactly what I needed.

kivo360 avatar Dec 03 '20 20:12 kivo360

@kivo360 @leplatrem pythonize can also do similar (and more) using the depythonize API. It can convert PyObject into any type which implements Deserialize.

An interesting question I was wondering this week is whether we should provide serde wrappers for types like Py<T>.

davidhewitt avatar Dec 12 '20 11:12 davidhewitt

Is there any chance pythonize would become a native part of PyO3?

McSpidey avatar Aug 09 '22 23:08 McSpidey

I haven't seen a need for it to become part of the main crate; what's the advantage that you see from doing so?

davidhewitt avatar Aug 10 '22 06:08 davidhewitt

I'm new to PyO3 but even from just porting one simple app it seemed logical a native serialiser/deserialiser would be a fundamental core feature for efficient workflows, and serde is seemingly the defacto rust standard for this.

McSpidey avatar Aug 10 '22 06:08 McSpidey

That's a reasonable opinion. There's no performance or API disadvantages by having pythonize separate, and it reduces compile time for those who don't need it. For now I'm inclined to keep them separate, if there's a strong motivation to merge it in we can revisit.

davidhewitt avatar Aug 10 '22 07:08 davidhewitt

Is there still a compile time disadvantage if it's implemented as a 'feature'?

McSpidey avatar Aug 10 '22 07:08 McSpidey

Probably not a huge difference for users, however the PyO3 CI already takes a long time, and I count that as a compile time disadvantage too!

Also worth bearing in mind that I hoped that anything which merged into PyO3 would have a solution for https://github.com/davidhewitt/pythonize/issues/1 so that there would only be one integrated way to convert Rust -> Python objects, rather than two different mechanisms in the same crate.

I really do hold the opinion that pythonize is solving a different enough problem from PyO3 core that there's no need to make it part of the main API right now.

davidhewitt avatar Aug 10 '22 20:08 davidhewitt