polars_python/series/
export.rs

1use polars_core::prelude::*;
2use polars_ffi::version_0::SeriesExport;
3use pyo3::IntoPyObjectExt;
4use pyo3::prelude::*;
5use pyo3::types::{PyCapsule, PyList};
6
7use super::PySeries;
8use crate::error::PyPolarsErr;
9use crate::interop;
10use crate::interop::arrow::to_py::series_to_stream;
11use crate::prelude::*;
12
13#[pymethods]
14impl PySeries {
15    /// Convert this Series to a Python list.
16    /// This operation copies data.
17    pub fn to_list<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
18        let series = &self.series;
19
20        fn to_list_recursive<'py>(py: Python<'py>, series: &Series) -> PyResult<Bound<'py, PyAny>> {
21            let pylist = match series.dtype() {
22                DataType::Boolean => PyList::new(py, series.bool().map_err(PyPolarsErr::from)?)?,
23                DataType::UInt8 => PyList::new(py, series.u8().map_err(PyPolarsErr::from)?)?,
24                DataType::UInt16 => PyList::new(py, series.u16().map_err(PyPolarsErr::from)?)?,
25                DataType::UInt32 => PyList::new(py, series.u32().map_err(PyPolarsErr::from)?)?,
26                DataType::UInt64 => PyList::new(py, series.u64().map_err(PyPolarsErr::from)?)?,
27                DataType::Int8 => PyList::new(py, series.i8().map_err(PyPolarsErr::from)?)?,
28                DataType::Int16 => PyList::new(py, series.i16().map_err(PyPolarsErr::from)?)?,
29                DataType::Int32 => PyList::new(py, series.i32().map_err(PyPolarsErr::from)?)?,
30                DataType::Int64 => PyList::new(py, series.i64().map_err(PyPolarsErr::from)?)?,
31                DataType::Int128 => PyList::new(py, series.i128().map_err(PyPolarsErr::from)?)?,
32                DataType::Float32 => PyList::new(py, series.f32().map_err(PyPolarsErr::from)?)?,
33                DataType::Float64 => PyList::new(py, series.f64().map_err(PyPolarsErr::from)?)?,
34                DataType::Categorical(_, _) | DataType::Enum(_, _) => {
35                    with_match_categorical_physical_type!(series.dtype().cat_physical().unwrap(), |$C| {
36                        PyList::new(py, series.cat::<$C>().unwrap().iter_str())?
37                    })
38                },
39                #[cfg(feature = "object")]
40                DataType::Object(_) => {
41                    let v = PyList::empty(py);
42                    for i in 0..series.len() {
43                        let obj: Option<&ObjectValue> = series.get_object(i).map(|any| any.into());
44                        v.append(obj)?;
45                    }
46                    v
47                },
48                DataType::List(_) => {
49                    let v = PyList::empty(py);
50                    let ca = series.list().map_err(PyPolarsErr::from)?;
51                    for opt_s in ca.amortized_iter() {
52                        match opt_s {
53                            None => {
54                                v.append(py.None())?;
55                            },
56                            Some(s) => {
57                                let pylst = to_list_recursive(py, s.as_ref())?;
58                                v.append(pylst)?;
59                            },
60                        }
61                    }
62                    v
63                },
64                DataType::Array(_, _) => {
65                    let v = PyList::empty(py);
66                    let ca = series.array().map_err(PyPolarsErr::from)?;
67                    for opt_s in ca.amortized_iter() {
68                        match opt_s {
69                            None => {
70                                v.append(py.None())?;
71                            },
72                            Some(s) => {
73                                let pylst = to_list_recursive(py, s.as_ref())?;
74                                v.append(pylst)?;
75                            },
76                        }
77                    }
78                    v
79                },
80                DataType::Date => {
81                    let ca = series.date().map_err(PyPolarsErr::from)?;
82                    return Wrap(ca).into_bound_py_any(py);
83                },
84                DataType::Time => {
85                    let ca = series.time().map_err(PyPolarsErr::from)?;
86                    return Wrap(ca).into_bound_py_any(py);
87                },
88                DataType::Datetime(_, _) => {
89                    let ca = series.datetime().map_err(PyPolarsErr::from)?;
90                    return Wrap(ca).into_bound_py_any(py);
91                },
92                DataType::Decimal(_, _) => {
93                    let ca = series.decimal().map_err(PyPolarsErr::from)?;
94                    return Wrap(ca).into_bound_py_any(py);
95                },
96                DataType::String => {
97                    let ca = series.str().map_err(PyPolarsErr::from)?;
98                    return Wrap(ca).into_bound_py_any(py);
99                },
100                DataType::Struct(_) => {
101                    let ca = series.struct_().map_err(PyPolarsErr::from)?;
102                    return Wrap(ca).into_bound_py_any(py);
103                },
104                DataType::Duration(_) => {
105                    let ca = series.duration().map_err(PyPolarsErr::from)?;
106                    return Wrap(ca).into_bound_py_any(py);
107                },
108                DataType::Binary => {
109                    let ca = series.binary().map_err(PyPolarsErr::from)?;
110                    return Wrap(ca).into_bound_py_any(py);
111                },
112                DataType::Null => {
113                    let null: Option<u8> = None;
114                    let n = series.len();
115                    let iter = std::iter::repeat_n(null, n);
116                    use std::iter::RepeatN;
117                    struct NullIter {
118                        iter: RepeatN<Option<u8>>,
119                        n: usize,
120                    }
121                    impl Iterator for NullIter {
122                        type Item = Option<u8>;
123
124                        fn next(&mut self) -> Option<Self::Item> {
125                            self.iter.next()
126                        }
127                        fn size_hint(&self) -> (usize, Option<usize>) {
128                            (self.n, Some(self.n))
129                        }
130                    }
131                    impl ExactSizeIterator for NullIter {}
132
133                    PyList::new(py, NullIter { iter, n })?
134                },
135                DataType::Unknown(_) => {
136                    panic!("to_list not implemented for unknown")
137                },
138                DataType::BinaryOffset => {
139                    unreachable!()
140                },
141            };
142            Ok(pylist.into_any())
143        }
144
145        to_list_recursive(py, series)
146    }
147
148    /// Return the underlying Arrow array.
149    #[allow(clippy::wrong_self_convention)]
150    fn to_arrow(&mut self, py: Python<'_>, compat_level: PyCompatLevel) -> PyResult<PyObject> {
151        self.rechunk(py, true)?;
152        let pyarrow = py.import("pyarrow")?;
153
154        interop::arrow::to_py::to_py_array(
155            self.series.to_arrow(0, compat_level.0),
156            &self.series.field().to_arrow(compat_level.0),
157            &pyarrow,
158        )
159    }
160
161    #[allow(unused_variables)]
162    #[pyo3(signature = (requested_schema=None))]
163    fn __arrow_c_stream__<'py>(
164        &self,
165        py: Python<'py>,
166        requested_schema: Option<PyObject>,
167    ) -> PyResult<Bound<'py, PyCapsule>> {
168        series_to_stream(&self.series, py)
169    }
170
171    pub fn _export(&mut self, _py: Python<'_>, location: usize) {
172        let export = polars_ffi::version_0::export_series(&self.series);
173        unsafe {
174            (location as *mut SeriesExport).write(export);
175        }
176    }
177}