polars_python/series/
export.rs

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