mirror of
https://github.com/gorules/zen.git
synced 2026-10-09 00:02:30 +00:00
feat: py bindings refactoring (#317)
* feat: py bindings refactoring * unset version in pyproject.toml
This commit is contained in:
@@ -1,22 +1,21 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::content::PyZenDecisionContentJson;
|
||||
use crate::custom_node::PyCustomNode;
|
||||
use crate::decision::PyZenDecision;
|
||||
use crate::loader::PyDecisionLoader;
|
||||
use crate::mt::{block_on, worker_pool};
|
||||
use crate::value::PyValue;
|
||||
use crate::variable::PyVariable;
|
||||
use anyhow::{anyhow, Context};
|
||||
use pyo3::prelude::PyDictMethods;
|
||||
use pyo3::types::PyDict;
|
||||
use pyo3::{pyclass, pymethods, Bound, IntoPyObjectExt, Py, PyAny, PyResult, Python};
|
||||
use pyo3::{pyclass, pymethods, Bound, FromPyObject, IntoPyObjectExt, Py, PyAny, PyResult, Python};
|
||||
use pyo3_async_runtimes::tokio::get_current_locals;
|
||||
use pyo3_async_runtimes::{tokio, TaskLocals};
|
||||
use pythonize::depythonize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use zen_engine::model::DecisionContent;
|
||||
use zen_engine::{DecisionEngine, EvaluationOptions};
|
||||
use zen_expression::Variable;
|
||||
|
||||
#[pyclass]
|
||||
#[pyo3(name = "ZenEngine")]
|
||||
@@ -24,7 +23,7 @@ pub struct PyZenEngine {
|
||||
engine: Arc<DecisionEngine<PyDecisionLoader, PyCustomNode>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, FromPyObject)]
|
||||
pub struct PyZenEvaluateOptions {
|
||||
pub trace: Option<bool>,
|
||||
pub max_depth: Option<u8>,
|
||||
@@ -60,24 +59,26 @@ impl PyZenEngine {
|
||||
};
|
||||
|
||||
let loader = match options.get_item("loader")? {
|
||||
Some(loader) => Some(Python::with_gil(|py| loader.into_py_any(py))?),
|
||||
Some(loader) => Some(loader.into_py_any(py)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let custom_node = match options.get_item("customHandler")? {
|
||||
Some(custom_node) => Some(Python::with_gil(|py| custom_node.into_py_any(py))?),
|
||||
Some(custom_node) => Some(custom_node.into_py_any(py)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let task_locals = TaskLocals::with_running_loop(py)
|
||||
.ok()
|
||||
.map(|s| s.copy_context(py).ok())
|
||||
.flatten();
|
||||
let make_locals = || {
|
||||
TaskLocals::with_running_loop(py)
|
||||
.ok()
|
||||
.map(|s| s.copy_context(py).ok())
|
||||
.flatten()
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
engine: Arc::new(DecisionEngine::new(
|
||||
Arc::new(PyDecisionLoader::from(loader)),
|
||||
Arc::new(PyCustomNode::new(custom_node, task_locals)),
|
||||
Arc::new(PyDecisionLoader::new(loader, make_locals())),
|
||||
Arc::new(PyCustomNode::new(custom_node, make_locals())),
|
||||
)),
|
||||
})
|
||||
}
|
||||
@@ -86,20 +87,14 @@ impl PyZenEngine {
|
||||
pub fn evaluate(
|
||||
&self,
|
||||
py: Python,
|
||||
key: String,
|
||||
ctx: &Bound<'_, PyDict>,
|
||||
opts: Option<&Bound<'_, PyDict>>,
|
||||
key: &str,
|
||||
ctx: PyVariable,
|
||||
opts: Option<PyZenEvaluateOptions>,
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
let context: Variable = depythonize(ctx).context("Failed to convert dict")?;
|
||||
let options: PyZenEvaluateOptions = if let Some(op) = opts {
|
||||
depythonize(op).context("Failed to convert dict")?
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let options = opts.unwrap_or_default();
|
||||
let result = block_on(self.engine.evaluate_with_opts(
|
||||
key,
|
||||
context,
|
||||
ctx.into_inner(),
|
||||
EvaluationOptions {
|
||||
max_depth: options.max_depth,
|
||||
trace: options.trace,
|
||||
@@ -118,15 +113,11 @@ impl PyZenEngine {
|
||||
&'py self,
|
||||
py: Python<'py>,
|
||||
key: String,
|
||||
ctx: &Bound<'_, PyDict>,
|
||||
opts: Option<&Bound<'_, PyDict>>,
|
||||
ctx: PyValue,
|
||||
opts: Option<PyZenEvaluateOptions>,
|
||||
) -> PyResult<Py<PyAny>> {
|
||||
let context: Value = depythonize(ctx).context("Failed to convert dict")?;
|
||||
let options: PyZenEvaluateOptions = if let Some(op) = opts {
|
||||
depythonize(op).context("Failed to convert dict")?
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let context: Value = ctx.0;
|
||||
let options: PyZenEvaluateOptions = opts.unwrap_or_default();
|
||||
|
||||
let engine = self.engine.clone();
|
||||
let result = tokio::future_into_py_with_locals(py, get_current_locals(py)?, async move {
|
||||
@@ -157,16 +148,13 @@ impl PyZenEngine {
|
||||
Ok(result.unbind())
|
||||
}
|
||||
|
||||
pub fn create_decision(&self, content: String) -> PyResult<PyZenDecision> {
|
||||
let decision_content: DecisionContent =
|
||||
serde_json::from_str(&content).context("Failed to serialize decision content")?;
|
||||
|
||||
let decision = self.engine.create_decision(decision_content.into());
|
||||
pub fn create_decision(&self, content: PyZenDecisionContentJson) -> PyResult<PyZenDecision> {
|
||||
let decision = self.engine.create_decision(content.0 .0);
|
||||
Ok(PyZenDecision::from(decision))
|
||||
}
|
||||
|
||||
pub fn get_decision<'py>(&'py self, _py: Python<'py>, key: String) -> PyResult<PyZenDecision> {
|
||||
let decision = block_on(self.engine.get_decision(&key))
|
||||
pub fn get_decision<'py>(&'py self, _py: Python<'py>, key: &str) -> PyResult<PyZenDecision> {
|
||||
let decision = block_on(self.engine.get_decision(key))
|
||||
.context("Failed to find decision with given key")?;
|
||||
|
||||
Ok(PyZenDecision::from(decision))
|
||||
|
||||
Reference in New Issue
Block a user