Skip to main content

A rules engine to clarify your pipelines development

Project description

rulesengine

Is there any developer liking to work with hundreds of chained if/else? If you're one of those this package isn't for you.

A rules engine is a way to structure your code as pipelines. The objective is to create chained modular and reusable rules with a simple structure structure :

  • A filter: can I do some stuff?
  • An action: I know I can do some stuff so I do it

With a rules engine you have to think your pipeline has stackable modules to generate easily readable pipelines.

Example with some potatoes

Here is an example on how to (try to) eat smashed potatoes:

# How to eat smashed potatoes
rules = RulesEngine()
rules.add(GetPotatoes)
rules.add(CookPotatoes)
rules.add(EatPotatoes)
rules.add(SmashPotatoes)
rules.add(EatSmashedPotatoes)
rules_output = rules.run()

rules_ouput.get("Eaten smashed potatoes portions")  # Sorry there is nothing

With a pipeline like this one, you won't eat any smashed potatoes but you'll still have eaten some potatoes (if GetPotatoes got you at least one potato). Let's see the SmashPotatoes rule to understand:

class SmashPotatoes(Rule):
    RULE_NAME = "Smash potatoes"

    def filter(self, input_data):
        """
        Can I really smash potatoes?
        """
        # Get my smashable potatoes
        smashable_potatoes = input_data.get("cooked potatoes")
        # Have I any smashable potatoes ?
        if smashable_potatoes is None or smashable_potatoes < 1:
            # There isn't any potato to smash. We won't do any thing...
            return False
        # YES! We can smash potatoes!!!
        return True

    def action(self, input_data):
        """
        Let's smash potatoes because we can
        """
        # Get you potatoes
        smashable_potatoes = input_data.get("cooked potatoes")
        # Do your job (an other RulesEngine?)
        smashed_potatoes_portions = ...

        input_data.set("smashed potatoes portions", smashed_potatoes_portions)
        input_data.set("cooked potatoes", 0)

In this rule if the filter isn't applied, we won't apply the action :

  • No cooked potatoes no action and finally no smashed potatoes portions
  • At least 1 cooked potatoes, the action is performed and we have at least 1 smashed potatoes portions

Installation

pip install rulesengine

Documentation & Help

Create a rule

from rulesengine import Rule

class MyRule(Rule):
    RULE_NAME = "A minimal rule"

    # An execution order (positive or -1). Rules of same level are executed in their
    # declaration order. -1 are executed lastly and minimal values are executed firstly
    RULE_ORDER = -1

    def filter(self, input_data):
        """
        Test if you can apply your rule, are all variables initialized?
        """
        return True

    def action(self, input_data):
        """
        Do some stuff
        """

Access data

An object is passed between rules and returned by the RulesEngine.run() method : RulesData

# Get an element (return None if not initialized)
my_data.get('my element key')

# Set or update an element
my_data.set('my element key', something)

# Delete an element (let's free some memory!)
my_data.delete('my element key')

# Get previously executed rule
my_data.get_previous()

# Set expected next rule
my_data.set_expected_next(MyNextRule.RULE_NAME)

Create pipeline

from rulesengine import RulesEngine

# Initialize the pipeline
rules = RulesEngine()
rules.add(MyRule, forced_order=0)  # Will be executed first
rules.add(MyRule)  # The same rule again
rules.add(AnOtherRule, previous_rule=MyNextRule.RULE_NAME)  # Won't match the previous rule condition
rules.add(AnOtherRule, converter=a_funtion) # Sometime, to reuse rules we need to do extra stuff before the rule
rules_output = rules.run()

Pipelines doesn't have to be run to the end

from rulesengine import RulesCourse

# Run every runnable rules (default)
rules = RulesEngine(rules_course=RulesCourse.non_blocking)

# Stop on the first rules's filter returning False
rules = RulesEngine(rules_course=RulesCourse.block_on_false)

# Stop on the first rules's filter returning True
rules = RulesEngine(rules_course=RulesCourse.block_on_true)

# Raise an error on the first rules's filter returning False
rules = RulesEngine(rules_course=RulesCourse.error_on_false)

Populate the pipeline before execution

# At creation
rules = RulesEngine({
        "data_1": 1,
        "data_2": list(),
    })

# afterward
rules.set(key, value)

Manage errors

There is only one rulesengine error : rulesengine.RulesEngineException

Contributing

As an open source project, rulesengine welcomes contributions of all forms (especially culinary but please don't send any potato, the smashing potato workflow will fail).

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

rulesengine-1.0.0.tar.gz (8.9 kB view details)

Uploaded Source

Built Distribution

rulesengine-1.0.0-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

Details for the file rulesengine-1.0.0.tar.gz.

File metadata

  • Download URL: rulesengine-1.0.0.tar.gz
  • Upload date:
  • Size: 8.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.10

File hashes

Hashes for rulesengine-1.0.0.tar.gz
Algorithm Hash digest
SHA256 8eb7b3ebb5c20a337978f401fe0c8cbb94825203e28edabe8989d5d6f231f6c5
MD5 1de9589cc22f937a3d58e949e316cf12
BLAKE2b-256 cefdbe9135be5e2b995b5cf3f75dca2209c004bb96c7dd382f1d160f51df832a

See more details on using hashes here.

File details

Details for the file rulesengine-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: rulesengine-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.10

File hashes

Hashes for rulesengine-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 52c19e97c20b96dec081d3491029a3c6ef2486a04274852ae3abb5c45dd3e455
MD5 ec238c9c47baab4a208fa2909dee6898
BLAKE2b-256 0a0938cea9bae2fa33c4601b8eb6df7526cf3956ce8a938687b81bd2bd786901

See more details on using hashes here.

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