Skip to main content

Open-Source Business Rules Engine

Project description

License: MIT

Python ZEN Engine

ZEN Engine is business friendly Open-Source Business Rules Engine (BRE) to execute decision models according to the GoRules JSON Decision Model (JDM) standard. It is written in Rust and provides native bindings for NodeJS and Python. ZEN Engine allows to load and execute JSON Decision Model (JDM) from JSON files.

Usage

ZEN Engine is built as embeddable BRE for your Rust, NodeJS or Python applications. It parses JDM from JSON content. It is up to you to obtain the JSON content, e.g. from file system, database or service call.

If you are looking for a Decision-as-a-Service (DaaS) over REST, take a look at GoRules Cloud.

Installation

pip install zen-engine

Usage

To execute a simple decision you can use the code below.

import zen

# Example filesystem content, it is up to you how you obtain content
with open("./jdm_graph.json", "r") as f:
  content = f.read()

engine = zen.ZenEngine()

decision = engine.create_decision(content)
result = decision.evaluate({"input": 15})

Loaders

For more advanced use cases where you want to load multiple decisions and utilise graphs you can build loaders.

import zen

def loader(key):
    with open("./jdm_directory/" + key, "r") as f:
        return f.read()

engine = zen.ZenEngine({"loader": loader})
result = engine.evaluate("jdm_graph1.json", {"input": 5})

When engine.evaluate is invoked it will call loader and pass a key expecting a content of the JDM decision graph. In the case above we will assume file jdm_directory/jdm_graph1.json exists.

Similar to this example you can also utilise loader to load from different places, for example from REST API, from S3, Database, etc.

JSON Decision Model (JDM)

JDM is a modeling standard for business decisions and business rules and is stored in a JSON format. Decision models are represented by graphs. Graphs are built using nodes and edges. Edges are used to pass the data from one node to another (left-side to right-side).

You can try Free Online Editor with built in Simulator.

JSON Decision Model

JSON Example

Input node contains all data sent in the context, and Output node returns the data from the decision. Data flows from the Input Node towards Output Node evaluating all the Nodes in between and passing the data where nodes are connected.

Decision Tables

Decision table is a node which allows business users to easily modify and add new rules in an intuitive way using spreadsheet like interface. The structure of decision table is defined by its schema. Schema consists of inputs and outputs.

Decision tables are evaluated row by row from top to bottom, and depending on the hit policy a result is calculated.

Inputs

Input fields are commonly (qualified) names for example cart.total or customer.country.

{
  "cart": {
    "total": 1000
  },
  "customer": {
    "country": "US"
  }
}

Inputs are using business-friendly ZEN Expression Language. The language is designed to follow these principles:

  • Side-effect free
  • Dynamic types
  • Simple syntax for broad audiences

List shows basic example of the unary tests in the Input Fields:

Input entry Input Expression
"A" the field equals "A"
"A", "B" the field is either "A" or "B"
36 the numeric value equals 36
< 36 a value less than 36
> 36 a value greater than 36
[20..39] a value between 20 and 39 (inclusive)
20,39 a value either 20 or 39
<20, >39 a value either less than 20 or greater than 39
true the boolean value true
false the boolean value false
any value, even null/undefined
null the value null or undefined

Note: For the full list please visit ZEN Expression Language.

Outputs

The result of the decisionTableNode evaluation is:

  • an object if the hit policy of the decision table is FIRST and a rule matched. The structure is defined by the output fields. Qualified field names with a dot (.) inside lead to nested objects.
  • null/undefined if no rule matched in FIRST hit policy
  • an array of objects if the hit policy of the decision table is COLLECT (one array item for each matching rule) or empty array if no rules match

Example:

Screenshot 2023-03-10 at 22 57 04

And the result would be:

{
  "flatProperty": "A",
  "output": {
    "nested": {
      "property": "B"
    },
    "property": 36
  }
}

Functions

Function nodes are JavaScript lambdas that allow for quick and easy parsing, re-mapping or otherwise modifying the data. Inputs of the node are provided as function's arguments. Functions are executed on top of Google's V8 Engine that is built in into the ZEN Engine.

const handler = (input) => {
    return input;
};

Decision

Decision is a special node whose purpose is for decision model to have an ability to call other/re-usable decision models during an execution.

Support matrix

linux-x64-gnu linux-arm64-gnu darwin-x64 darwin-arm64 win32-x64-msvc
yes yes yes yes yes

We do not support linux-musl for now as we are relying on the GoogleV8 engine to run function blocks as isolates.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zen_engine-0.13.0.tar.gz (96.8 kB view hashes)

Uploaded Source

Built Distributions

zen_engine-0.13.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-cp311-none-win_amd64.whl (8.2 MB view hashes)

Uploaded CPython 3.11 Windows x86-64

zen_engine-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-cp311-cp311-macosx_11_0_arm64.whl (10.3 MB view hashes)

Uploaded CPython 3.11 macOS 11.0+ ARM64

zen_engine-0.13.0-cp311-cp311-macosx_10_7_x86_64.whl (10.9 MB view hashes)

Uploaded CPython 3.11 macOS 10.7+ x86-64

zen_engine-0.13.0-cp310-none-win_amd64.whl (8.2 MB view hashes)

Uploaded CPython 3.10 Windows x86-64

zen_engine-0.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-cp310-cp310-macosx_11_0_arm64.whl (10.3 MB view hashes)

Uploaded CPython 3.10 macOS 11.0+ ARM64

zen_engine-0.13.0-cp310-cp310-macosx_10_7_x86_64.whl (10.9 MB view hashes)

Uploaded CPython 3.10 macOS 10.7+ x86-64

zen_engine-0.13.0-cp39-none-win_amd64.whl (8.2 MB view hashes)

Uploaded CPython 3.9 Windows x86-64

zen_engine-0.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-cp38-none-win_amd64.whl (8.2 MB view hashes)

Uploaded CPython 3.8 Windows x86-64

zen_engine-0.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

zen_engine-0.13.0-cp37-none-win_amd64.whl (8.2 MB view hashes)

Uploaded CPython 3.7 Windows x86-64

zen_engine-0.13.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (15.5 MB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ x86-64

zen_engine-0.13.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (15.1 MB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ARM64

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page