Skip to main content

checkngn (venmo-business-rules style)

A lightweight Python DSL for setting up business intelligence rules that can be configured without code.

(NOTE Disclaimer: Fork of Venmo-Business-Rules and CDICS-business-rules-enhanced, with simple updates like project setup and logging. But, not a drop-in replacement for the original)

CI

Overview

At its core any Rule Engine is "IF condition, THEN do action", but it is also MORE.. . As any system grows in complexity and usage, it can become burdensome if every change to the logic/behavior of the system also requires code change and deploy new code. checkngn provides a simple interface allowing anyone to capture new rules and logic defining the behavior of a system, and a way to then process those rules on the backend.

Use cases:

  • Marketing logic for customer/item discount eligibility
  • Automated emails based on user state or event sequences
  • Data validation rules for pandas DataFrames
  • Any condition-action workflow

Installation

# Using pip
pip install checkngn

# Using uv (faster)
uv pip install checkngn

Requirements: Python 3.13+

Quick Start

from checkngn import run_all
from checkngn.variables import BaseVariables, numeric_rule_variable, string_rule_variable
from checkngn.actions import BaseActions, rule_action
from checkngn.fields import FIELD_NUMERIC

# 1. Define variables
class ProductVariables(BaseVariables):
    def __init__(self, product):
        self.product = product

    @numeric_rule_variable()
    def current_inventory(self):
        return self.product['inventory']

    @string_rule_variable()
    def product_name(self):
        return self.product['name']

# 2. Define actions
class ProductActions(BaseActions):
    def __init__(self, product):
        self.product = product

    @rule_action(params={"sale_percentage": FIELD_NUMERIC})
    def put_on_sale(self, sale_percentage, results=None):
        self.product['price'] *= (1.0 - sale_percentage)

# 3. Define rules
rules = [
    {
        "conditions": {
            "all": [
                {"field": "current_inventory", "operator": "greater_than", "value": 20},
                {"field": "product_name", "operator": "contains", "value": "Widget"}
            ]
        },
        "actions": [
            {"action": "put_on_sale", "params": {"sale_percentage": 0.25}}
        ]
    }
]

# 4. Run rules
product = {'name': 'Super Widget', 'inventory': 50, 'price': 100.0}
run_all(rules, ProductVariables(product), ProductActions(product))
print(product['price'])  # 75.0

Debug Mode

Enable "check engine light" debug output to see rule evaluation:

run_all(rules, variables, actions, debug=True)

Output:

🔧 [checkngn] Evaluating rule 1/1
🔧 [checkngn] ✓ condition 'current_inventory greater_than 20' → True
🔧 [checkngn] ✓ condition 'product_name contains Widget' → True
🔧 [checkngn] ✓ 'all' block → True
🔧 [checkngn] Rule triggered ✓
🔧 [checkngn] Executing action 'put_on_sale' with {'sale_percentage': 0.25}

Or enable globally:

from checkngn import enable_debug
enable_debug(True)

Usage Guide

1. Define Variables

Variables represent values in your system. You define all available variables for a certain kind of object, then dynamically set conditions and thresholds for those.

from checkngn.variables import (
    BaseVariables,
    numeric_rule_variable,
    string_rule_variable,
    boolean_rule_variable,
    select_rule_variable,
    select_multiple_rule_variable,
    dataframe_rule_variable
)

class ProductVariables(BaseVariables):
    def __init__(self, product):
        self.product = product

    @numeric_rule_variable()
    def current_inventory(self):
        return self.product.current_inventory

    @numeric_rule_variable(label='Days until expiration')
    def expiration_days(self):
        return (self.product.expiration_date - datetime.date.today()).days

    @string_rule_variable()
    def current_month(self):
        return datetime.datetime.now().strftime("%B")

    @select_rule_variable(options=['Electronics', 'Clothing', 'Food'])
    def category(self):
        return self.product.category

OR with dataclasses(this applies to Actions Definitions as well):

...
@dataclass
class ProductVariables(BaseVariables):
    product: Product 

    @numeric_rule_variable
    def current_inventory(self):
        # This works because 'Product' has an .inventory attribute
        return self.product.inventory 

    @string_rule_variable
    def product_name(self):
        return self.product.name
    ....

2. Define Actions

Actions are executed when conditions are triggered.

from checkngn.actions import BaseActions, rule_action
from checkngn.fields import FIELD_NUMERIC, FIELD_TEXT, FIELD_SELECT

class ProductActions(BaseActions):
    def __init__(self, product):
        self.product = product

    @rule_action(params={"sale_percentage": FIELD_NUMERIC})
    def put_on_sale(self, sale_percentage, results=None):
        self.product.price *= (1.0 - sale_percentage)
        self.product.save()

    @rule_action(params={"number_to_order": FIELD_NUMERIC})
    def order_more(self, number_to_order, results=None):
        ProductOrder.objects.create(
            product_id=self.product.id,
            quantity=number_to_order
        )

3. Build Rules

Rules are JSON/dict structures with conditions and actions: NOTE: JSON structures uses different terminology from venmo's business-rules i.e. - generic "name" in conditions is replaced with "field". - generic "name" in actions is replace with "action" as it is self-documenting.

rules = [
    # expiration_days < 5 AND current_inventory > 20
    {
        "conditions": {
            "all": [
                {"field": "expiration_days", "operator": "less_than", "value": 5},
                {"field": "current_inventory", "operator": "greater_than", "value": 20}
            ]
        },
        "actions": [
            {"action": "put_on_sale", "params": {"sale_percentage": 0.25}}
        ]
    },
    # current_inventory < 5 OR current_month = "December"
    {
        "conditions": {
            "any": [
                {"field": "current_inventory", "operator": "less_than", "value": 5},
                {"field": "current_month", "operator": "equal_to", "value": "December"}
            ]
        },
        "actions": [
            {"action": "order_more", "params": {"number_to_order": 40}}
        ]
    },
    # NOT (current_inventory > 100)
    {
        "conditions": {
            "not": {
                "field": "current_inventory", "operator": "greater_than", "value": 100
            }
        },
        "actions": [
            {"action": "order_more", "params": {"number_to_order": 10}}
        ]
    }
]

Condition operators:

  • all - All conditions must be True (AND)
  • any - At least one condition must be True (OR)
  • not - Negates the condition

Action formats:

Actions support three formats using utility function "normalize_action": NOTE: dict is default, everything is normalized to "dict" use utility function "normalize_action"

from checkngn.utils import normalize_action
normalized_actions = normalize_action(actions)
run_all(rules, variables, normalized_actions, debug=True)
"actions": [
    {"action": "put_on_sale", "params": {"percent": 25}},   # dict - default
    ["order_more", {"quantity": 10}],                       # list, or tuple
    "notify_manager"                                        # string (no params)
]

4. Export Rule Schema

Export available variables, operators, and actions for UI generation:

from checkngn import export_rule_data

schema = export_rule_data(ProductVariables, ProductActions)

Returns:

{
    "variables": [
        {"field": "current_inventory", "label": "Current Inventory", "field_type": "numeric", "options": []},
        {"field": "expiration_days", "label": "Days until expiration", "field_type": "numeric", "options": []},
        ...
    ],
    "actions": [
        {"action": "put_on_sale", "label": "Put On Sale", "params": [{"name": "sale_percentage", "fieldType": "numeric", "label": "Sale Percentage"}]},
        ...
    ],
    "variable_type_operators": {
        "numeric": [
            {"operator": "equal_to", "label": "Equal To", "input_type": "numeric"},
            {"operator": "greater_than", "label": "Greater Than", "input_type": "numeric"},
            ...
        ],
        "string": [...],
        ...
    }
}

5. Run Rules

from checkngn import run_all

for product in products:
    run_all(
        rule_list=rules,
        defined_variables=ProductVariables(product),
        defined_actions=ProductActions(product),
        stop_on_first_trigger=True,  # Stop after first matching rule
        debug=False  # Set True for debug output
    )

Variable Types & Operators

Decorator Type Operators
@numeric_rule_variable() int, float equal_to, greater_than, less_than, greater_than_or_equal_to, less_than_or_equal_to
@string_rule_variable() str equal_to, equal_to_case_insensitive, starts_with, ends_with, contains, matches_regex, non_empty
@boolean_rule_variable() bool is_true, is_false
@select_rule_variable() list contains, does_not_contain
@select_multiple_rule_variable() list contains_all, is_contained_by, shares_at_least_one_element_with, shares_exactly_one_element_with, shares_no_elements_with
@dataframe_rule_variable() pd.DataFrame/Series exists, not_exists

Rules in YAML using utils

from checkngn.utils import yaml_to_dict, dict_to_yaml

yaml_rules = """
- conditions:
    all:
      - field: current_inventory
        operator: greater_than
        value: 20
  actions:
    - action: put_on_sale
      params:
        sale_percentage: 0.25
"""

rules = yaml_to_dict(yaml_rules)
run_all(rules, variables, actions)

# Convert results back to YAML if needed
yaml_result = dict_to_yaml(rules)

Alterntives

  • CDIS Business Rules -Fork Venmo original i.e. pre-cursor of this repo
  • Funnel Rules Engine : A code-driven engine designed for developers. Rules are defined as Python objects/functions. It is ideal for simple, maintainable logic within a codebase without the overhead of parsing JSON or managing external rule definitions. Choose funnel-rules-engine if you need to refactor complex conditional logic (spaghetti code) into a clean, testable structure within your application, and the rules are part of the application logic itself. Related Conference Talk by its creator: Rules Rule(Creating and Using a Rules Engine)

Documentation

See INTERNALS.md for detailed architecture documentation.

License

MIT

Metadata

Release files for checkngn 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for checkngn 0.1.4
File Size Uploaded
checkngn-0.1.4.tar.gz 36.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for checkngn 0.1.4
File Interpreter ABI Platform
checkngn-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 50.6 kB

Release files / checkngn-0.1.4.tar.gz

Download URL checkngn-0.1.4.tar.gz
Size 36.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7633a52c42eae83bd10eebafb3c812bb9f75f7db29979b1e262bb0dbb8677559
BLAKE2b-256 checksum
How to use checksums
20365eb08fe295d2efc0ce9f480fdf838fef8e4ba5b7f2ec43fa1eba653297a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.7

Release files / checkngn-0.1.4-py3-none-any.whl

Download URL checkngn-0.1.4-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cb134f248b61a02203de8e2f24bcec80e88ca85bfe1fa764810358993a6a2485
BLAKE2b-256 checksum
How to use checksums
c0ebd144948b43e0971cc482f9aef0f04fe1f249a64841747e46cea9fec883dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.7

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page