use std::sync::Arc; use crate::engine::PyZenEvaluateOptions; use crate::mt::worker_pool; use crate::value::PyValue; use crate::variable::PyVariable; use anyhow::{anyhow, Context}; use pyo3::{pyclass, pymethods, Py, PyAny, PyResult, Python}; use pyo3_async_runtimes::tokio; use pyo3_async_runtimes::tokio::get_current_locals; use pyo3_async_runtimes::tokio::re_exports::runtime::Runtime; use serde_json::Value; use zen_engine::Decision; #[pyclass] #[pyo3(name = "ZenDecision")] pub struct PyZenDecision(pub(crate) Arc); impl From for PyZenDecision { fn from(value: Decision) -> Self { Self(value.into()) } } #[pymethods] impl PyZenDecision { #[pyo3(signature = (ctx, opts=None))] pub fn evaluate( &self, py: Python, ctx: PyVariable, opts: Option, ) -> PyResult> { let options = opts.unwrap_or_default(); let decision = self.0.clone(); let rt = Runtime::new()?; let result = rt .block_on(decision.evaluate_with_opts(ctx.into_inner(), options.into())) .map_err(|e| { anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())) })?; crate::convert::response_to_py(py, result) } #[pyo3(signature = (ctx, opts=None))] pub fn async_evaluate<'py>( &'py self, py: Python<'py>, ctx: PyValue, opts: Option, ) -> PyResult> { let context: Value = ctx.0; let options = opts.unwrap_or_default(); let decision = self.0.clone(); let result = tokio::future_into_py_with_locals(py, get_current_locals(py)?, async move { let response = worker_pool() .spawn_pinned(move || async move { let context = zen_engine::Variable::try_from_value(context).map_err(|e| anyhow!(e))?; decision .evaluate_with_opts(context, options.into()) .await .map(crate::convert::PortableResponse::build) .map_err(|e| { anyhow!(serde_json::to_string(&e).unwrap_or_else(|_| e.to_string())) }) }) .await .context("Failed to join threads")??; Python::with_gil(|py| response.into_py(py)) })?; Ok(result.unbind()) } pub fn validate(&self) -> PyResult<()> { let decision = self.0.clone(); decision .validate() .map_err(|e| anyhow!(serde_json::to_string(&e).unwrap_or_else(|_| e.to_string())))?; Ok(()) } }