Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-python/src/expr/serde.rs
7889 views
1
use std::io::{BufReader, BufWriter};
2
3
use polars::lazy::prelude::Expr;
4
use polars_utils::pl_serialize;
5
use pyo3::prelude::*;
6
use pyo3::pybacked::PyBackedBytes;
7
use pyo3::types::PyBytes;
8
9
use crate::PyExpr;
10
use crate::error::PyPolarsErr;
11
use crate::exceptions::ComputeError;
12
use crate::file::get_file_like;
13
14
#[pymethods]
15
impl PyExpr {
16
// Pickle we set FC is false, as that is used for caching (compact is faster) and is not intended to be used
17
// across different versions.
18
fn __getstate__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
19
// Used in pickle/pickling
20
let mut writer: Vec<u8> = vec![];
21
pl_serialize::SerializeOptions::default()
22
.serialize_into_writer::<_, _, false>(&mut writer, &self.inner)
23
.map_err(|e| PyPolarsErr::Other(format!("{e}")))?;
24
25
Ok(PyBytes::new(py, &writer))
26
}
27
28
fn __setstate__(&mut self, state: &Bound<PyAny>) -> PyResult<()> {
29
// Used in pickle/pickling
30
let bytes = state.extract::<PyBackedBytes>()?;
31
self.inner = pl_serialize::SerializeOptions::default()
32
.deserialize_from_reader::<_, _, false>(&*bytes)
33
.map_err(|e| PyPolarsErr::Other(format!("{e}")))?;
34
Ok(())
35
}
36
37
/// Serialize into binary data.
38
fn serialize_binary(&self, py_f: Py<PyAny>) -> PyResult<()> {
39
let file = get_file_like(py_f, true)?;
40
let writer = BufWriter::new(file);
41
pl_serialize::SerializeOptions::default()
42
.serialize_into_writer::<_, _, true>(writer, &self.inner)
43
.map_err(|err| ComputeError::new_err(err.to_string()))
44
}
45
46
/// Serialize into a JSON string.
47
#[cfg(feature = "json")]
48
fn serialize_json(&self, py_f: Py<PyAny>) -> PyResult<()> {
49
let file = get_file_like(py_f, true)?;
50
let writer = BufWriter::new(file);
51
serde_json::to_writer(writer, &self.inner)
52
.map_err(|err| ComputeError::new_err(err.to_string()))
53
}
54
55
/// Deserialize a file-like object containing binary data into an Expr.
56
#[staticmethod]
57
fn deserialize_binary(py_f: Py<PyAny>) -> PyResult<PyExpr> {
58
let file = get_file_like(py_f, false)?;
59
let reader = BufReader::new(file);
60
let expr: Expr = pl_serialize::SerializeOptions::default()
61
.deserialize_from_reader::<_, _, true>(reader)
62
.map_err(|err| ComputeError::new_err(err.to_string()))?;
63
Ok(expr.into())
64
}
65
66
/// Deserialize a file-like object containing JSON string data into an Expr.
67
#[staticmethod]
68
#[cfg(feature = "json")]
69
fn deserialize_json(py_f: Py<PyAny>) -> PyResult<PyExpr> {
70
// it is faster to first read to memory and then parse: https://github.com/serde-rs/json/issues/160
71
// so don't bother with files.
72
let mut json = String::new();
73
let _ = get_file_like(py_f, false)?
74
.read_to_string(&mut json)
75
.unwrap();
76
77
// SAFETY:
78
// We skipped the serializing/deserializing of the static in lifetime in `DataType`
79
// so we actually don't have a lifetime at all when serializing.
80
81
// &str still has a lifetime. But it's ok, because we drop it immediately
82
// in this scope.
83
let json = unsafe { std::mem::transmute::<&'_ str, &'static str>(json.as_str()) };
84
85
let inner: Expr = serde_json::from_str(json).map_err(|_| {
86
let msg = "could not deserialize input into an expression";
87
ComputeError::new_err(msg)
88
})?;
89
Ok(inner.into())
90
}
91
}
92
93