polars_utils/
python_convert_registry.rs

1use std::any::Any;
2use std::ops::Deref;
3use std::sync::{Arc, LazyLock, RwLock};
4
5use pyo3::types::PyAnyMethods;
6use pyo3::{Py, PyAny, PyResult, Python};
7
8pub type FromPython = Arc<dyn Fn(Py<PyAny>) -> PyResult<Box<dyn Any>> + Send + Sync>;
9pub type ToPython = Arc<dyn for<'a> Fn(&'a dyn Any) -> PyResult<Py<PyAny>> + Send + Sync>;
10
11#[derive(Clone)]
12pub struct FromPythonConvertRegistry {
13    pub file_provider_result: FromPython,
14    pub series: FromPython,
15    pub df: FromPython,
16    pub dsl_plan: FromPython,
17    pub schema: FromPython,
18}
19
20#[derive(Clone)]
21pub struct ToPythonConvertRegistry {
22    pub df: ToPython,
23    pub series: ToPython,
24    pub dsl_plan: ToPython,
25    pub schema: ToPython,
26}
27
28impl ToPythonConvertRegistry {
29    /// Convert a Rust `DataFrame` to a Python `pl.DataFrame` object.
30    pub fn df_to_wrapped_pydf(&self, df: &dyn Any) -> PyResult<Py<PyAny>> {
31        static WRAP_DF: LazyLock<Py<PyAny>> = LazyLock::new(|| {
32            Python::attach(|py| {
33                py.import("polars._utils.wrap")
34                    .unwrap()
35                    .getattr("wrap_df")
36                    .unwrap()
37                    .unbind()
38            })
39        });
40
41        let pydf = (self.df)(df)?;
42
43        Python::attach(|py| WRAP_DF.call1(py, (pydf,)))
44    }
45}
46
47#[derive(Clone)]
48pub struct PythonConvertRegistry {
49    pub from_py: FromPythonConvertRegistry,
50    pub to_py: ToPythonConvertRegistry,
51}
52
53impl PythonConvertRegistry {
54    pub fn py_file_provider_args_dataclass(&self) -> &'static Py<PyAny> {
55        static CLS: LazyLock<Py<PyAny>> = LazyLock::new(|| {
56            Python::attach(|py| {
57                py.import("polars.io.partition")
58                    .unwrap()
59                    .getattr("FileProviderArgs")
60                    .unwrap()
61                    .unbind()
62            })
63        });
64
65        &CLS
66    }
67}
68
69static PYTHON_CONVERT_REGISTRY: LazyLock<RwLock<Option<PythonConvertRegistry>>> =
70    LazyLock::new(Default::default);
71
72pub fn get_python_convert_registry() -> PythonConvertRegistry {
73    PYTHON_CONVERT_REGISTRY
74        .deref()
75        .read()
76        .unwrap()
77        .as_ref()
78        .unwrap()
79        .clone()
80}
81
82pub fn register_converters(registry: PythonConvertRegistry) {
83    *PYTHON_CONVERT_REGISTRY.deref().write().unwrap() = Some(registry);
84}