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