Skip to main content

Simple Rule Engine in Pure Python

License: MIT Build codecov PyPI - Python Version PyPI - Version

The Simple Rule Engine is a lightweight library for creating, combining, and evaluating (nested) rules. Inspired by Django's Q object, it allows you to construct complex logical conditions and evaluate them against dictionaries of data.

Quickstart

pip install light-rule-engine
from rule_engine import Rule, evaluate

# Rule: (foo == "bar" OR foo == "baz") AND (name == "John" AND age >= 21)
rule = Rule(
    Rule(foo="bar") | Rule(foo="baz"),
    name="John", age__gte=21
)

example_true = {"foo": "bar", "name": "John", "age": 22}
example_false = {"foo": "qux", "name": "Jane", "age": 19}

assert evaluate(rule, example_true)
assert not evaluate(rule, example_false)

Features

  • Create rules with simple conditions or nested logic.
  • Combine rules using logical operators:
    • & (AND)
    • | (OR)
    • ~ (NOT)
  • Evaluate rules against dictionaries of values.
  • Supports a wide range of operators (listed below).
  • Extensible: Add your own custom operators if needed.

Installation

pip install light-rule-engine
poetry add light-rule-engine
uv add light-rule-engine

Supported Operators

Operator Description
gte Greater than or equal to
gt Greater than
lte Less than or equal to
lt Less than
in Value is in a list/collection
iin Value is in a list/collection or string (case insensitive)
nin Value is not in a list/collection
inin Value is not in a list/collection or string (case insensitive)
startswith String starts with a specific value
istartswith String starts with a specific value (case-insensitive)
endswith String ends with a specific value
iendswith String ends with a specific value (case-insensitive)
contains Collection or string contains a specific value
icontains String contains a specific value (case-insensitive)
exact Value matches exactly
iexact Value matches exactly (case-insensitive)
ne Not equal
eq Equal to
regex Matches a regular expression pattern
is Identity comparison (evaluates with is)
notset Value is not set

Basic Usage

Creating Rules

Rules can be created using the Rule object. You can pass positional arguments (*args) for nested rules and keyword arguments (**kwargs) for conditions.

from rule_engine import Rule

# Simple rule with conditions
rule = Rule(name="John", age__gte=21)

# Nested rules with logical operators
complex_rule = Rule(
    Rule(name="John") & Rule(age__gte=21),
    Rule(name="Jane") | Rule(age__lt=20)
)

Logical Operators

  • & (AND): Combines rules that must all be satisfied.
  • | (OR): Combines rules where at least one must be satisfied.
  • ~ (NOT): Negates a rule.

Example:

from rule_engine import Rule

# Rule: (name == "John" AND age >= 21) OR (name == "Jane" AND age < 20)
rule = Rule(
    Rule(name="John") & Rule(age__gte=21) |
    Rule(name="Jane") & Rule(age__lt=20)
)

Alternatively, you can also express this in the following fashion:

from rule_engine import Rule

rule = Rule(name="John", age__gte=21) | Rule(name="Jane", age__lt=20)

Evaluating Rules

To evaluate a rule, use the evaluate function or the evaluate method of the rule. Provide a dictionary of data to check the rule against.

from rule_engine import Rule, evaluate

# Rule: (foo == "bar" OR foo == "baz") AND (name == "John" AND age >= 21)
rule = Rule(
    Rule(foo="bar") | Rule(foo="baz"),
    name="John", age__gte=21
)

example_true = {"foo": "bar", "name": "John", "age": 22}
example_false = {"foo": "qux", "name": "Jane", "age": 19}

assert evaluate(rule, example_true)
assert not evaluate(rule, example_false)

Advanced Usage

Custom Operators

You can extend the rule engine by adding new operators. Use the func operator for custom logic, or modify the OPERATOR_FUNCTIONS dictionary for persistent custom operators.

You can set a Rule's id in two ways:

from rule_engine import Rule

rule = Rule(name="John")
rule.id = "my-rule"

or

from rule_engine import Rule

rule = Rule(name="John", __id="my-rule")

Raise on Missing Fields

from rule_engine import Rule

rule = Rule(name="John", age__gte=21, __raise_on_notset=True)

rule.evaluate({"name": "John"})
# >>> ValueError(f"Field 'age' is not set in the example data")

Full example

from rule_engine import Rule, evaluate

# Complex rule example
rule = Rule(
    Rule(credit_rating__gte=50, flood_risk__lt=10) |
    Rule(revenue__gt=1_000_000)
)

data = {"credit_rating": 55, "flood_risk": 5}
assert evaluate(rule, data)

data = {"revenue": 1_500_000}
assert evaluate(rule, data)

data = {"credit_rating": 40, "flood_risk": 15, "revenue": 500_000}
assert not evaluate(rule, data)

The EvaluationResult object

The evaluate function returns an EvaluationResult object that contains the result of the evaluation and the rule that was evaluated.

It contains a granular representation of the evaluation process, including the result of each condition and the final result.

from rule_engine import Rule, evaluate

rule = Rule(name="John") & Rule(age__gte=21) | Rule(name="Jane")
example = {"name": "John", "age": 22}
res = evaluate(rule, example)

print(bool(res))  # True
print(res.to_json(indent=2))  # to_dict() also available

"""
{
  "field": "name",
  "value": "John",
  "operator": "eq",
  "condition_value": "John",
  "result": true,
  "negated": false,
  "children": [
    [
      "AND",
      {
        "field": "age",
        "value": 22,
        "operator": "gte",
        "condition_value": 21,
        "result": true,
        "negated": false,
        "children": []
      }
    ],
    [
      "OR",
      {
        "field": "name",
        "value": "John",
        "operator": "eq",
        "condition_value": "Jane",
        "result": false,
        "negated": false,
        "children": []
      }
    ]
  ]
}
"""

Contributing

Contributions are welcome! For feature requests, bug reports, or questions, please open an issue on GitHub.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Acknowledgements

This project was inspired by Django's awesome Q object and the need for a simple rule engine in Python.

Metadata

Release files for light-rule-engine 1.2.0

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

Source distribution (sdist)

Source distribution for light-rule-engine 1.2.0
File Size Uploaded Provenance Actions
light_rule_engine-1.2.0.tar.gz 20.7 kB With provenance Details for light_rule_engine-1.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for light-rule-engine 1.2.0
File Interpreter ABI Platform Actions
light_rule_engine-1.2.0-py3-none-any.whl Python 3 none any Details for light_rule_engine-1.2.0-py3-none-any.whl

Total release size: 41.3 kB

Release files / light_rule_engine-1.2.0.tar.gz

Download URL light_rule_engine-1.2.0.tar.gz
Size 20.7 kB
Tags Source
SHA-256 checksum
How to use checksums
98963ac09d69417aa4df8202a38b4c9a44e9e4c7bb63cd9b9eff862e92bf5836
BLAKE2b-256 checksum
How to use checksums
bedc039230d1549105c8ada12b6ce58eb64cff83bf1c577b42be18b5b846f7c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 22, 2025.

Transparency log

Release files / light_rule_engine-1.2.0-py3-none-any.whl

Download URL light_rule_engine-1.2.0-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4e9e03042f1d42432310682f84ee3d6f7a31ef1671f648c44175b6a824d6bc60
BLAKE2b-256 checksum
How to use checksums
566d3f36fc7dcfcfea504ad06fd2d5ae8d1889701153c79b16dc0585ed381488
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 22, 2025.

Transparency log

Security for light-rule-engine 1.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for light_rule_engine-1.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 22, 2025.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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