Skip to main content

A simple rule engine implemented in python

Project description

Sauron Rule engine - One engine to rule them all

Coverage Status GitHub Twitter: joaovoce

A simple rule engine to be used in python, it is based on simple rules and actions that can be chained with each other. The idea is to run the rule processor on events and have it mutate data or trigger actions

Heavily inspired on FastAPI. We use type annotations in our engine so that we can export data to other systems or frontends to convey what conditions and actions are possible using that engine

Install

pip install sauron-rule-engine

Concepts

Sauron rule engine is based on custom functions that can be called by a rule.

Condition

Condition to be satisfied in order for the actions to run, they can take some or no parameters at all Multiple conditions can be chained in order to create more complex ones, currently all chained conditions must be satisfied

Action

An Action is the intented result. Usually they are there to mutate state or trigger/schedule other kinds of actions in your system. Actions can also be chained and will run in order.

Rule

A Rule is a dict or json string containing the conditions and actions and the arguments they should be run with. Usually those rules will be built by a frontend to match complex and adaptable business rules from your customer

Use it

A simple example of the usage

from sauron_rule_engine.rule_engine import RuleEngine

engine = RuleEngine()


@engine.condition("First Condition")
def first_condition(lower_number: int = 10, greater_number: int = 20) -> bool:
    """
    Checks if first number is lower than the first
    - lower_number: Number expected to be low
    - higher_number: Number expected to be high
    """
    return lower_number < greater_number


@engine.condition()
def second_condition():
    """
    Takes no argument and always returns True
    """
    return True


@engine.action("The Action")
def print_the_equation(
    lower_number: int = 10, greater_number: int = 20
) -> None:
    """
    Prints a statement Asserting that the first number is lower than the second number
    - lower_number: Number expected to be low
    - higher_number: Number expected to be high
    """
    print(f"{lower_number} < {greater_number}")


rule = {
    "conditions": [
        {
            "name": "first_condition",
            "args": {"lower_number": 3, "greater_number": 10},
        }
    ],
    "actions": [
        {
            "name": "print_the_equation",
            "args": {"lower_number": 3, "greater_number": 10},
        }
    ],
}


engine.run(rule)

Choices Fields

Choices fields are supported through python's built-in Enum type. Example:

from sauron_rule_engine.rule_engine import RuleEngine
from enum import Enum

class Color(str, Enum):
    red = "R"
    green = "G"
    blue = "B"


@engine.condition("is it red?")
def is_red(color: Color) -> bool:
    """
    Checks if the color is red
    """
    return color == color.red

Export Conditions and Actions

You can use the function export_metadata to export your data in a dict or as a json string (just pass json=True). Here is an Example and the output:

from sauron_rule_engine.rule_engine import RuleEngine
from enum import Enum

engine = RuleEngine()


@engine.condition("First Condition")
def first_condition(lower_number: int = 10, greater_number: int = 20) -> bool:
    """
    Checks if first number is lower than the first
    - lower_number: Number expected to be low
    - higher_number: Number expected to be high
    """
    return lower_number < greater_number


@engine.condition()
def second_condition():
    """
    Takes no argument and always returns True
    """
    return True


@engine.action("The Action")
def print_the_equation(
    lower_number: int = 10, greater_number: int = 20
) -> None:
    """
    Prints a statement Asserting that the first number is lower than the second number
    - lower_number: Number expected to be low
    - higher_number: Number expected to be high
    """
    print(f"{lower_number} < {greater_number}")


class Color(str, Enum):
    red = "R"
    green = "G"
    blue = "B"


@engine.condition("is it red?")
def is_red(color: Color) -> bool:
    """
    Checks if the color is red
    """
    return color == color.red


metadata = engine.export_metadata(json=True)
print(metadata)

Results in the following json to be served to your frontend:

{
  "actions": {
    "print_the_equation": {
      "args": {
        "lower_number": { "default": 10, "type": "int", "choices": null },
        "greater_number": { "default": 20, "type": "int", "choices": null }
      },
      "doc": "Prints a statement Asserting that the first number is lower than the second number\n- lower_number: Number expected to be low\n- higher_number: Number expected to be high",
      "name": "The Action"
    }
  },
  "conditions": {
    "first_condition": {
      "args": {
        "lower_number": { "default": 10, "type": "int", "choices": null },
        "greater_number": { "default": 20, "type": "int", "choices": null }
      },
      "doc": "Checks if first number is lower than the first\n- lower_number: Number expected to be low\n- higher_number: Number expected to be high",
      "name": "First Condition"
    },
    "second_condition": {
      "args": {},
      "doc": "Takes no argument and always returns True",
      "name": "second_condition"
    },
    "is_red": {
      "args": {
        "color": {
          "default": null,
          "type": "Color",
          "choices": ["red", "green", "blue"]
        }
      },
      "doc": "Checks if the color is red",
      "name": "is it red?"
    }
  }
}

More Features coming to town

  • Support pydantic types
  • Support for complex types with hints to the frontend (like a range for an int type

Author

👤 João Ricardo Lhullier Lugão

Show your support

Give a ⭐️ if this project helped you!


This README was generated with ❤️ by readme-md-generator

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

sauron-rule-engine-0.1.6.tar.gz (6.4 kB view details)

Uploaded Source

Built Distribution

sauron_rule_engine-0.1.6-py3-none-any.whl (6.3 kB view details)

Uploaded Python 3

File details

Details for the file sauron-rule-engine-0.1.6.tar.gz.

File metadata

  • Download URL: sauron-rule-engine-0.1.6.tar.gz
  • Upload date:
  • Size: 6.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/0.12.16 CPython/3.7.3 Linux/5.0.0-15-generic

File hashes

Hashes for sauron-rule-engine-0.1.6.tar.gz
Algorithm Hash digest
SHA256 f3d7e13ec7adb96c712ca487a110d762c5577171ab66d912418b492f4c7528ea
MD5 dffa7a992e2f5cd7e1031d93459da18d
BLAKE2b-256 8b3ac9fc91af7114689a3904fac4b6723bd4f683d770bcbb7ca5a1186d0795ae

See more details on using hashes here.

File details

Details for the file sauron_rule_engine-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: sauron_rule_engine-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 6.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/0.12.16 CPython/3.7.3 Linux/5.0.0-15-generic

File hashes

Hashes for sauron_rule_engine-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 db3ea6c4e0e3fd72ceeebecbcc1b84b0cf6394927c6eedfe72ce4af43f920579
MD5 ebe1b14d89e6555ddac990aa72326958
BLAKE2b-256 a7c10c75eea2c8318e7d6c465ce36d3335c4aeec5a277867942c78c1daf64306

See more details on using hashes here.

Supported by

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