feat: expose expressions through bindings; (#86)

* feat: expose expressions through bindings;

* fix fmt
This commit is contained in:
stefan-gorules
2023-09-14 16:07:55 +02:00
committed by GitHub
parent 1cef5bb263
commit 1b0ff9f6f1
14 changed files with 241 additions and 44 deletions
+4 -3
View File
@@ -12,9 +12,10 @@ crate-type = ["cdylib"]
[dependencies]
async-trait = "0.1.68"
anyhow = "1.0.71"
pyo3 = { version = "0.18.3", features = ["anyhow", "serde"] }
pythonize = "0.18.0"
pyo3 = { version = "0.19.2", features = ["anyhow", "serde"] }
pythonize = "0.19.0"
serde = "1.0.163"
serde_json = "1.0.96"
futures = "0.3.28"
zen-engine = { path = "../../core/engine" }
zen-engine = { path = "../../core/engine" }
zen-expression = { path = "../../core/expression" }
+8 -1
View File
@@ -28,7 +28,6 @@ class ZenEngine(unittest.TestCase):
r2 = tableDecision.evaluate({"input": 5})
r3 = tableDecision.evaluate({"input": 12})
print(r1)
self.assertEqual(r1["result"]["output"], 20)
self.assertEqual(r2["result"]["output"], 0)
self.assertEqual(r3["result"]["output"], 10)
@@ -42,5 +41,13 @@ class ZenEngine(unittest.TestCase):
r = functionDecision.evaluate({"input": 15})
self.assertEqual(r["result"]["output"], 30)
def test_evaluate_expression(self):
result = zen.evaluate_expression("sum(a)", { "a": [1, 2, 3, 4] })
self.assertEqual(result, 10)
def test_evaluate_unary_expression(self):
result = zen.evaluate_unary_expression("'FR', 'ES', 'GB'", { "$": "GB" })
self.assertEqual(result, True)
# run the test
unittest.main()
+58
View File
@@ -0,0 +1,58 @@
use anyhow::{anyhow, Context};
use pyo3::types::PyDict;
use pyo3::{pyfunction, PyObject, PyResult, Python, ToPyObject};
use pythonize::depythonize;
use serde_json::Value;
use zen_expression::isolate::Isolate;
use crate::value::PyValue;
#[pyfunction]
pub fn evaluate_expression(
py: Python,
expression: String,
ctx: Option<&PyDict>,
) -> PyResult<PyObject> {
let isolate = Isolate::default();
let ctx = ctx
.map(|ctx| depythonize(ctx))
.transpose()
.context("Failed to convert context")?;
if let Some(env_value) = ctx {
isolate.inject_env(&env_value);
}
let result = isolate
.run_standard(expression.as_str())
.map_err(|e| anyhow!(serde_json::to_string(&e).unwrap_or_else(|_| e.to_string())))?;
Ok(PyValue(result).to_object(py))
}
#[pyfunction]
pub fn evaluate_unary_expression(
py: Python,
expression: String,
ctx: &PyDict,
) -> PyResult<PyObject> {
let env_value: Value = depythonize(ctx).context("Failed to convert context")?;
let Some(env_object) = env_value.as_object() else {
return Err(anyhow!("Context must be an object").into());
};
if !env_object.contains_key("$") {
return Err(anyhow!("Context must contain '$' reference.").into());
}
let isolate = Isolate::default();
isolate.inject_env(&env_value);
let result = isolate
.run_unary(expression.as_str())
.map_err(|e| anyhow!(serde_json::to_string(&e).unwrap_or_else(|_| e.to_string())))?;
Ok(PyValue(result).to_object(py))
}
+6 -1
View File
@@ -1,10 +1,12 @@
use crate::decision::PyZenDecision;
use crate::engine::PyZenEngine;
use crate::expression::{evaluate_expression, evaluate_unary_expression};
use pyo3::types::PyModule;
use pyo3::{pymodule, PyResult, Python};
use pyo3::{pymodule, wrap_pyfunction, PyResult, Python};
mod decision;
mod engine;
mod expression;
mod loader;
mod value;
@@ -12,5 +14,8 @@ mod value;
fn zen(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PyZenEngine>()?;
m.add_class::<PyZenDecision>()?;
m.add_function(wrap_pyfunction!(evaluate_expression, m)?)?;
m.add_function(wrap_pyfunction!(evaluate_unary_expression, m)?)?;
Ok(())
}