GitHub - bayinfosys/json-logic-path: json-logic extended with json-ng paths

3 min read Original article ↗

A Python implementation of JsonLogic extended with JSONPath-backed multi-value resolution via the vars operator.

Forked from the original json-logic-py and updated for Python 3.11+. Developed and maintained by Bay Information Systems.

Operators

var -- scalar dot-path resolution

Resolves a single value from the data context using dot notation. List indices are supported as integer path segments. Returns None (or a supplied default) if the path does not exist.

jsonLogic({"var": "user.name"}, {"user": {"name": "Alice"}})
# "Alice"

jsonLogic({"var": "items.0"}, {"items": ["a", "b"]})
# "a"

jsonLogic({"var": ["missing", "default"]}, {})
# "default"

vars -- JSONPath multi-value resolution

Resolves multiple values from the data context using a JSONPath expression (via jsonpath-ng). Always returns a list.

An empty list indicates no matches. An empty list is falsey in Python, so a failed match behaves correctly in boolean branch conditions without any special-casing.

var and vars are distinct operator keys and do not interact.

data = {"tags": ["a", "b", "c"]}
jsonLogic({"vars": "tags[*]"}, data)
# ["a", "b", "c"]

jsonLogic({"vars": "steps[?type='image-eval'].output.score"}, state)
# [0.9, 0.4]

jsonLogic({"vars": "nothing[*]"}, {})
# []  -- falsey

Branch conditions in workflow definitions

var resolves scalar values for threshold comparisons:

rule = {">=": [{"var": "steps.safety_check.output.scores.unsafe"}, 0.7]}
jsonLogic(rule, workflow_state)
# False -- score is 0.1, do not halt

vars collects values across parallel step outputs for fan-in gates:

rule = {"==": [
    {"count": [{"vars": "steps[?type='image-embed'].output.vector"}]},
    2
]}
jsonLogic(rule, workflow_state)
# True -- both embed steps have produced output

Composite conditions combining both:

rule = {
    "and": [
        {"<":  [{"var": "steps.safety_check.output.scores.unsafe"}, 0.3]},
        {">=": [{"var": "steps.aesthetic.output.scores.aesthetic"}, 0.7]},
    ]
}

List operations

map, filter, and reduce work against lists produced by vars:

# filter scores above threshold
jsonLogic(
    {"filter": [{"vars": "scores[*]"}, {">=": [{"var": ""}, 0.7]}]},
    {"scores": [0.9, 0.2, 0.75, 0.4]}
)
# [0.9, 0.75]

# sum all scores
jsonLogic(
    {"reduce": [
        {"vars": "scores[*]"},
        {"+": [{"var": "accumulator"}, {"var": "current"}]},
        0
    ]},
    {"scores": [0.9, 0.2, 0.75]}
)
# 1.85

Input wiring in workflow definitions

var for direct scalar input references (common case):

input:
  text: {"var": "steps.caption.output.text"}

vars for fan-out input references (all items at a path):

input:
  embeddings: {"vars": "steps[?type='image-embed'].output.vector"}

The executor sees a list at an input field and expands it into one dispatch per item. vars is the declaration; the executor is the implementation of the expansion.

Installation

pip install json-logic-path

For development:

pip install -e ".[dev]"
pytest

Compatibility

  • Python 3.11+
  • jsonpath-ng is required for the vars operator and is installed automatically. All other operators work without it.

Licence

MIT. See LICENSE for details.

This package is derived from json-logic-py by Nadir Izr, which is itself a Python port of json-logic-js by Jeremy Wadhams. Both are published under the MIT licence.

Developed and maintained by Bay Information Systems.