Skip to main content

A lightweight library for building, evaluating, and translating JSON-based rules

Project description

JSON Rule Engine

Python Version License: MIT PyPI version

A powerful and lightweight Python library for building, evaluating, and translating JSON-based business rules. Perfect for creating dynamic filtering systems, decision engines, and converting rules to Django ORM queries.

Features

  • Pythonic Rule Builder: Build JSON rules using fluent API
  • Nested Rule Support: Build complex nested AND/OR/NOT structures
  • JSON to Q Conversion: Convert JSON rules directly to Django Q objects
  • Rule Evaluator: Evaluate rules against any data object
  • Dependency Extraction: Extract field dependencies for CDC/caching
  • Frontend Parser: Parse UI rule builder format
  • Extensible: Add custom operators easily
  • Zero Dependencies: Core library has no external dependencies

Installation

# Basic installation
pip install json-rule-engine

# With Django support
pip install json-rule-engine[django]

# Development installation
pip install json-rule-engine[dev]

Quick Start

1. Build Rules (Pythonic)

from json_rule_engine import Field, Q

# Fluent builder
rule = Field('city').equals('NYC')
rule = Field('age').greater_than(18)
rule = Field('tags').has_any(['vip', 'premium'])

# Django-style Q
rule = Q(city='NYC')
rule = Q(age__gt=18)
rule = Q(tags__has_any=['vip'])

# Combine with & | ~
rule = (
    Field('city').equals('NYC') &
    Field('age').gt(18) |
    ~Field('status').equals('blocked')
)

# Get JSON
json_rule = rule.to_json()
# {"and": [{"==": [{"var": "city"}, "NYC"]}, {">": [{"var": "age"}, 18]}]}

2. Nested Rule Building

from json_rule_engine import RuleBuilder, JsonRule

# Complex nested structures
rule = RuleBuilder.and_(
    RuleBuilder.field('city').equals('NYC'),
    RuleBuilder.or_(
        RuleBuilder.field('state').equals('NY'),
        RuleBuilder.field('state').equals('CA'),
    ),
    RuleBuilder.field('tags').has_any(['vip']),
)

# Wrap existing JSON and combine with builder
existing_json = {"==": [{"var": "status"}, "active"]}
combined = JsonRule(existing_json) & Field('age').gt(18)

3. Rule Engine - Evaluate Rules

from json_rule_engine import RuleEngine

engine = RuleEngine()

# Evaluate against dict
data = {'city': 'NYC', 'age': 25, 'tags': ['vip']}
result = engine.evaluate(rule, data)  # Any (result)
result = engine.matches(rule, data)   # bool (True/False)

# Evaluate raw JSON
json_rule = {"==": [{"var": "city"}, "NYC"]}
result = engine.evaluate(json_rule, data)  # True

4. Evaluate Against Objects

from json_rule_engine import Evaluatable, RuleEngine

class Contact(Evaluatable):
    def __init__(self, name, city, age):
        self.name = name
        self.city = city
        self.age = age
    
    def to_eval_dict(self):
        return {
            'name': self.name,
            'city': self.city,
            'age': self.age,
        }

engine = RuleEngine()
contact = Contact('John', 'NYC', 25)

# Single evaluation with timing
result = engine.test(rule, contact)
# EvalResult(matches=True, eval_time_ms=0.01)

# Batch evaluation
contacts = [Contact(...), Contact(...), ...]
results = engine.batch(rule, contacts)
# {'matches': [...], 'non_matches': [...]}

# Filter matching
matches = engine.filter(rule, contacts)
# [Contact(...), Contact(...)]

5. JSON to Django Q (Direct Conversion)

from json_rule_engine import json_to_q, to_q, JsonToQ

# Direct JSON to Q conversion
json_rules = {
    "and": [
        {"==": [{"var": "city"}, "NYC"]},
        {"or": [
            {"==": [{"var": "state"}, "NY"]},
            {"==": [{"var": "state"}, "CA"]}
        ]}
    ]
}

q = json_to_q(json_rules)
# Result: Q(city='NYC') & (Q(state='NY') | Q(state='CA'))

# From Rule builder
rule = Field('city').equals('NYC') & Field('tags').has_any(['vip'])
q = to_q(rule)

# Using JsonToQ class with validation
converter = JsonToQ()
is_valid, errors = converter.validate(json_rules)
q, explanation = converter.convert_with_explanation(json_rules)

# Use with Django ORM
contacts = Contact.objects.filter(q)

API Reference

Rule Builder

Method JSON Output
Field('x').equals(v) {"==": [{"var": "x"}, v]}
Field('x').not_equals(v) {"!=": [{"var": "x"}, v]}
Field('x').gt(v) {">": [{"var": "x"}, v]}
Field('x').gte(v) {">=": [{"var": "x"}, v]}
Field('x').lt(v) {"<": [{"var": "x"}, v]}
Field('x').lte(v) {"<=": [{"var": "x"}, v]}
Field('x').contains(v) {"in": [v, {"var": "x"}]}
Field('x').startswith(v) {"_startswith": [...]}
Field('x').endswith(v) {"_endswith": [...]}
Field('x').is_empty() {"or": [{"==": [...]}, ...]}
Field('x').has_any([...]) {"some": [{"var": "x"}, ...]}
Field('x').has_all([...]) {"and": [...]}
Field('x').has_none([...]) {"none": [{"var": "x"}, ...]}

Nested Building

RuleBuilder.and_(rule1, rule2, ...)    # Nested AND
RuleBuilder.or_(rule1, rule2, ...)     # Nested OR  
RuleBuilder.not_(rule)                  # Nested NOT
RuleBuilder.field('name')               # Create Field
RuleBuilder.from_json(dict)             # Wrap existing JSON
RuleBuilder.from_frontend(dict)         # Parse frontend format

JsonRule(dict)                          # JSON wrapper
JsonRule(dict) & Field('x').eq(y)       # Combine JSON with builder

Q Style Builder

Q(field='value')           # equals
Q(field__eq='value')       # equals
Q(field__ne='value')       # not equals
Q(field__gt=10)            # greater than
Q(field__gte=10)           # greater or equal
Q(field__lt=10)            # less than
Q(field__lte=10)           # less or equal
Q(field__contains='x')     # contains
Q(field__startswith='x')   # starts with
Q(field__endswith='x')     # ends with
Q(field__in=[1,2,3])       # in list
Q(field__has_any=[...])    # has any (M2M)
Q(field__has_all=[...])    # has all (M2M)
Q(field__has_none=[...])   # has none (M2M)

Combining Rules

rule1 & rule2    # AND
rule1 | rule2    # OR
~rule            # NOT

# Or use functions
from json_rule_engine import AND, OR, NOT
AND(rule1, rule2, rule3)
OR(rule1, rule2)
NOT(rule)

JSON to Q Conversion

from json_rule_engine import json_to_q, to_q, JsonToQ

# Direct conversion
q = json_to_q(json_dict)              # JSON dict → Q
q = to_q(rule)                         # Rule builder → Q
q = to_q(json_dict)                    # Also accepts JSON

# Class-based with validation
converter = JsonToQ(field_map={'tags': 'profile__tags__id'})
q = converter.convert(json_dict)
q, explanation = converter.convert_with_explanation(json_dict)
is_valid, errors = converter.validate(json_dict)

RuleEngine

from json_rule_engine import RuleEngine

engine = RuleEngine()

# Evaluation
result = engine.evaluate(rule, data)       # Any (raw result)
result = engine.matches(rule, data)        # bool (True/False)

# Object evaluation
result = engine.test(rule, obj)            # EvalResult (with timing)
results = engine.batch(rule, [objs])       # {'matches': [], 'non_matches': []}
matches = engine.filter(rule, [objs])      # [matching objects]

# Custom operators
engine.register_operator('between', lambda vals, data: ...)

Dependencies (for CDC)

rule = Field('city').eq('NYC') & Field('tags').has_any(['101'])
deps = rule.get_dependencies()

deps.fields           # {'city'}
deps.tag_ids          # {101}
deps.phonebook_ids    # set()
deps.custom_field_ids # set()

# From JSON
json_rule = JsonRule(json_dict)
deps = json_rule.get_dependencies()

Supported JsonLogic Operators

Comparison

==, !=, ===, !==, >, >=, <, <=

Logic

and, or, !, !!, if, ?:

Array

in, some, all, none, merge

String

in (substring), cat

Arithmetic

+, -, *, /, %, min, max

Data

var, missing

Custom (Extended)

_contains, _startswith, _endswith, _is_empty, _is_not_empty

License

MIT

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

json_rule_engine-1.0.0.tar.gz (27.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

json_rule_engine-1.0.0-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: json_rule_engine-1.0.0.tar.gz
  • Upload date:
  • Size: 27.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for json_rule_engine-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f46b7cf6e18f96b86121035e0a4c104e367ccc776484a248ec9469a58ec2d130
MD5 358a2876ab2699b263b5cc70cbe16a70
BLAKE2b-256 a83da5ebec3350ebc2952dcef4aaed55c79ab90d6076cf5db2518177090d1279

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for json_rule_engine-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ae63108aca663c30f9cc68813b752f86d4a05bf13e923d10c04c4ef639bbc005
MD5 0e3be8b361acdb7d90494061bd2c90f9
BLAKE2b-256 ac4badf8968da44888eaf049fdf67ec3170d39cb7eace19c051464ba0f418321

See more details on using hashes here.

Supported by

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