monarch_types/
pyobject.rs1use hyperactor::Named;
10use pyo3::prelude::*;
11use pyo3::types::PyBytes;
12use serde::Deserialize;
13use serde::Serialize;
14
15#[derive(Debug, Clone, Serialize, Deserialize, Named)]
16pub struct PickledPyObject {
17 #[serde(with = "serde_bytes")]
18 bytes: Vec<u8>,
19 cloudpickle: bool,
20}
21
22impl PickledPyObject {
23 pub fn pickle<'py>(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
24 Self::pickle_impl(obj, false)
25 }
26
27 pub fn cloudpickle<'py>(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
28 Self::pickle_impl(obj, true)
29 }
30
31 fn module(cloudpickle: bool) -> &'static str {
32 if cloudpickle { "cloudpickle" } else { "pickle" }
33 }
34
35 fn pickle_impl<'py>(obj: &Bound<'py, PyAny>, cloudpickle: bool) -> PyResult<Self> {
36 let module = Self::module(cloudpickle);
37 let bytes = obj
38 .py()
39 .import(module)?
40 .call_method1("dumps", (obj,))?
41 .downcast_into::<PyBytes>()?
42 .as_bytes()
43 .to_vec();
44 Ok(Self { bytes, cloudpickle })
45 }
46
47 pub fn unpickle<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
48 py.import(Self::module(self.cloudpickle))?
49 .call_method1("loads", (self.bytes.as_slice(),))
50 }
51}
52
53impl TryFrom<&Bound<'_, PyAny>> for PickledPyObject {
54 type Error = PyErr;
55 fn try_from(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
56 Self::pickle(obj)
57 }
58}
59
60impl TryFrom<Bound<'_, PyAny>> for PickledPyObject {
61 type Error = PyErr;
62 fn try_from(obj: Bound<'_, PyAny>) -> PyResult<Self> {
63 Self::pickle(&obj)
64 }
65}
66
67impl FromPyObject<'_> for PickledPyObject {
68 fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
69 PickledPyObject::pickle(obj)
70 }
71}
72
73impl<'py> IntoPyObject<'py> for &PickledPyObject {
74 type Target = PyAny;
75 type Output = Bound<'py, Self::Target>;
76 type Error = PyErr;
77
78 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
79 self.unpickle(py)
80 }
81}