Skip to main content

Tiny, safe boolean-expression language with dotted paths, functions, and rule books.

Project description

boolia

A tiny, safe boolean expression engine: like Jinja for logic.

  • Grammar: and, or, not, parentheses, comparisons (== != > >= <= <), in
  • Values: numbers, strings, booleans, null/None, identifiers, dotted paths (user.age, house.light.on)
  • Tags: bare identifiers evaluate True if present in a tags: set[str]
  • Functions: user-registered, safe callables (starts_with, matches, ...)
  • RuleBook: name your rules and evaluate them later
  • RuleGroup: compose rules with all/any semantics and nested groups
  • Missing policy: choose to raise or substitute None/False/custom default
from boolia import evaluate, RuleBook, DEFAULT_FUNCTIONS

expr = "(car and elephant) or house.light.on"
print(evaluate(expr, context={"house": {"light": {"on": True}}}, tags={"car"}))  # True

Install (local)

pip install -e .[dev]
pytest -q
ruff check .
mypy .

Tooling

The project ships with Ruff for linting and MyPy for type checking. After installing the development extras you can run the primary checks with:

ruff check .
mypy .

Quick start

from boolia import evaluate, DEFAULT_FUNCTIONS

ctx  = {"user": {"age": 21, "roles": ["admin", "ops"]}}
tags = {"beta"}
expr = "user.age >= 18 and 'admin' in user.roles"
print(evaluate(expr, context=ctx, tags=tags))  # True

Functions

from boolia import evaluate, DEFAULT_FUNCTIONS

DEFAULT_FUNCTIONS.register("starts_with", lambda s, p: str(s).startswith(str(p)))

expr = "starts_with(user.name, 'Sn')"
print(evaluate(expr, context={"user": {"name": "Snoopy"}}))  # True

RuleBook

from boolia import RuleBook, RuleGroup

rules = RuleBook()
rules.add("adult", "user.age >= 18")
rules.add("brazilian", "starts_with(user.country, 'Br')")
rules.add("vip", "contains(user.roles, 'vip')")
rules.add_group(
    "eligible",
    mode="all",
    members=[
        "adult",
        RuleGroup(mode="any", members=["brazilian", "vip"]),
    ],
)

ok = rules.evaluate(
    "eligible",
    context={"user": {"age": 22, "country": "Brazil", "roles": ["member"]}},
)
print(ok)  # True

print(rules.evaluate("eligible", context={"user": {"age": 22, "country": "Chile", "roles": ["vip"]}}))  # True
print(rules.evaluate("eligible", context={"user": {"age": 17, "country": "Chile", "roles": ["member"]}}))  # False

RuleGroup members can be rule names, already compiled Rule objects, or other RuleGroup instances. Nested groups short-circuit according to their mode (all/any), empty groups are vacuously True/False, and cycles raise a helpful error. Add groups with RuleBook.add_group or register existing ones with RuleBook.register.

Missing policy

from boolia import evaluate, MissingVariableError

try:
    evaluate("user.age >= 18 and house.light.on", context={"user": {"age": 20}}, on_missing="raise")
except MissingVariableError as e:
    print(e)  # Missing variable/path: house.light.on

print(evaluate("score >= 10", context={}, on_missing="default", default_value=0))  # False
print(evaluate("flag and beta", context={}, tags={"beta"}, on_missing="none"))     # False (flag is None)

Notes

  • Use on_missing="none" if you want tags to override missing bare identifiers.
  • For stricter semantics on dotted paths, keep on_missing="raise" and allow tags only for bare names.

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

boolia-0.1.1.tar.gz (28.7 kB view details)

Uploaded Source

Built Distribution

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

boolia-0.1.1-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file boolia-0.1.1.tar.gz.

File metadata

  • Download URL: boolia-0.1.1.tar.gz
  • Upload date:
  • Size: 28.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for boolia-0.1.1.tar.gz
Algorithm Hash digest
SHA256 4dbc730913e115dc9f219ce9119c0264d7574f487ae5719e622b0a1097bc94c4
MD5 321c57ed4f0d854d76819ec8091e140d
BLAKE2b-256 e78beb3ea3e9df8da7d7f337b15e147a3aab569f9f7a29b724eb36b7e9afe953

See more details on using hashes here.

File details

Details for the file boolia-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: boolia-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for boolia-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cf9c8e380b498490935f6e9b0d562c064759e3bb81a328381df1d083b1285814
MD5 563ac65e3e4dd5f702784627535acebb
BLAKE2b-256 623601cd7c1e6d0cfa23fb716747e070556faa7c517b24a822948183dbdd342d

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