Skip to main content

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