Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/jsonata/jsonata.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import sys
import threading
from dataclasses import dataclass
from typing import Any, Callable, Mapping, MutableSequence, Optional, Sequence, Type, MutableMapping
from typing import Any, Callable, Mapping, MutableSequence, Optional, Sequence, Type, MutableMapping, Union

from jsonata import functions, jexception, parser, signature as sig, timebox, utils

Expand Down Expand Up @@ -1976,7 +1976,7 @@ def is_output_convert_nulls(self) -> bool:
def set_output_convert_nulls(self, output_convert_nulls: bool) -> None:
self.output_convert_nulls = output_convert_nulls

def evaluate(self, input: Optional[Any], bindings: Optional[Frame] = None) -> Optional[Any]:
def evaluate(self, input: Optional[Any], bindings: Optional[Union[Frame, Mapping[str, Any]]] = None) -> Optional[Any]:
# throw if the expression compiled with syntax errors
if self.errors is not None:
raise jexception.JException("S0500", 0)
Expand All @@ -1986,7 +1986,9 @@ def evaluate(self, input: Optional[Any], bindings: Optional[Frame] = None) -> Op
# var exec_env
# the variable bindings have been passed in - create a frame to hold these
exec_env = self.create_frame(self.environment)
for k, v in bindings.bindings.items():
# accept either a Frame or a plain mapping (e.g. dict) of variable bindings
items = bindings.bindings if isinstance(bindings, Jsonata.Frame) else bindings
for k, v in items.items():
exec_env.bind(k, v)
else:
exec_env = self.environment
Expand Down
23 changes: 23 additions & 0 deletions tests/jsonata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,29 @@ def test_path(self):
print(str(data))
self.eval_expr("foo.bar", data, None, 42, None)

def test_dict_bindings(self):
data = {
"products": [
{"name": "Apple", "price": 1.20},
{"name": "Banana", "price": 0.50},
{"name": "Cherry", "price": 2.50},
]
}
expr = jsonata.Jsonata(
"products[price <= $maxPrice]"
".(name & ' costs ' & $currencySymbol & $string(price))"
)
expected = ["Apple costs $1.2", "Banana costs $0.5"]

# A plain dict can be passed directly as the bindings.
assert expr.evaluate(data, bindings={"maxPrice": 1.50, "currencySymbol": "$"}) == expected

# A Frame is still accepted for backward compatibility.
binding_frame = jsonata.Jsonata.Frame(None)
binding_frame.bind("maxPrice", 1.50)
binding_frame.bind("currencySymbol", "$")
assert expr.evaluate(data, bindings=binding_frame) == expected

def run_case(self, name):
if not self.run_test_suite(name):
raise Exception()
Expand Down
Loading