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.0.tar.gz (28.6 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.0-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: boolia-0.1.0.tar.gz
  • Upload date:
  • Size: 28.6 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.0.tar.gz
Algorithm Hash digest
SHA256 8289226ec6bc80d52f9362847023e19c8b4de46bb86375538e63b52728d55462
MD5 8e242e3ce7953ae45fc2e08b6080b4fe
BLAKE2b-256 92c68c525d54d8da6c505c16ec8dc3070ca262a4746d14b599ff2ec2a6e013ec

See more details on using hashes here.

File details

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

File metadata

  • Download URL: boolia-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.7 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f3a68770c7798c1a47d54a48d30bbbc3f5600761187d06d0f9f3fda74be04fcd
MD5 7b85248e117309d515d606effdad501b
BLAKE2b-256 083f6e6eb64d7dd78d81bffbf397a251e030a6ef9197aa7c70dc817c56fb0e57

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