1use std::panic::AssertUnwindSafe;
2
3use polars::frame::DataFrame;
4use polars::series::IntoSeries;
5use polars_error::PolarsResult;
6use polars_error::signals::{KeyboardInterrupt, catch_keyboard_interrupt};
7use pyo3::exceptions::PyKeyboardInterrupt;
8use pyo3::marker::Ungil;
9use pyo3::{PyErr, PyResult, Python};
10
11use crate::dataframe::PyDataFrame;
12use crate::error::PyPolarsErr;
13use crate::series::PySeries;
14use crate::timeout::{cancel_polars_timeout, schedule_polars_timeout};
15
16#[macro_export]
18macro_rules! apply_method_all_arrow_series2 {
19 ($self:expr, $method:ident, $($args:expr),*) => {
20 match $self.dtype() {
21 DataType::Boolean => $self.bool().unwrap().$method($($args),*),
22 DataType::String => $self.str().unwrap().$method($($args),*),
23 DataType::UInt8 => $self.u8().unwrap().$method($($args),*),
24 DataType::UInt16 => $self.u16().unwrap().$method($($args),*),
25 DataType::UInt32 => $self.u32().unwrap().$method($($args),*),
26 DataType::UInt64 => $self.u64().unwrap().$method($($args),*),
27 DataType::Int8 => $self.i8().unwrap().$method($($args),*),
28 DataType::Int16 => $self.i16().unwrap().$method($($args),*),
29 DataType::Int32 => $self.i32().unwrap().$method($($args),*),
30 DataType::Int64 => $self.i64().unwrap().$method($($args),*),
31 DataType::Int128 => $self.i128().unwrap().$method($($args),*),
32 DataType::Float32 => $self.f32().unwrap().$method($($args),*),
33 DataType::Float64 => $self.f64().unwrap().$method($($args),*),
34 DataType::Date => $self.date().unwrap().$method($($args),*),
35 DataType::Datetime(_, _) => $self.datetime().unwrap().$method($($args),*),
36 DataType::List(_) => $self.list().unwrap().$method($($args),*),
37 DataType::Struct(_) => $self.struct_().unwrap().$method($($args),*),
38 dt => panic!("dtype {:?} not supported", dt)
39 }
40 }
41}
42
43#[allow(unused)]
45pub(crate) fn to_py_err<E: Into<PyPolarsErr>>(e: E) -> PyErr {
46 e.into().into()
47}
48
49pub trait EnterPolarsExt {
50 fn enter_polars<T, E, F>(self, f: F) -> PyResult<T>
57 where
58 F: Ungil + Send + FnOnce() -> Result<T, E>,
59 T: Ungil + Send,
60 E: Ungil + Send + Into<PyPolarsErr>;
61
62 #[inline(always)]
65 fn enter_polars_ok<T, F>(self, f: F) -> PyResult<T>
66 where
67 Self: Sized,
68 F: Ungil + Send + FnOnce() -> T,
69 T: Ungil + Send,
70 {
71 self.enter_polars(move || PyResult::Ok(f()))
72 }
73
74 #[inline(always)]
77 fn enter_polars_df<F>(self, f: F) -> PyResult<PyDataFrame>
78 where
79 Self: Sized,
80 F: Ungil + Send + FnOnce() -> PolarsResult<DataFrame>,
81 {
82 self.enter_polars(f).map(PyDataFrame::new)
83 }
84
85 #[inline(always)]
88 fn enter_polars_series<T, F>(self, f: F) -> PyResult<PySeries>
89 where
90 Self: Sized,
91 T: Ungil + Send + IntoSeries,
92 F: Ungil + Send + FnOnce() -> PolarsResult<T>,
93 {
94 self.enter_polars(f).map(|s| PySeries::new(s.into_series()))
95 }
96}
97
98impl EnterPolarsExt for Python<'_> {
99 fn enter_polars<T, E, F>(self, f: F) -> PyResult<T>
100 where
101 F: Ungil + Send + FnOnce() -> Result<T, E>,
102 T: Ungil + Send,
103 E: Ungil + Send + Into<PyPolarsErr>,
104 {
105 let timeout = schedule_polars_timeout();
106 let ret = self.allow_threads(|| catch_keyboard_interrupt(AssertUnwindSafe(f)));
107 cancel_polars_timeout(timeout);
108 match ret {
109 Ok(Ok(ret)) => Ok(ret),
110 Ok(Err(err)) => Err(PyErr::from(err.into())),
111 Err(KeyboardInterrupt) => Err(PyKeyboardInterrupt::new_err("")),
112 }
113 }
114}