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
4 changes: 2 additions & 2 deletions py/.github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ jobs:
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi

- name: Lint with flake8
- name: Lint with ruff
run: |
flake8 src/jsonlogic --count --show-source --statistics --max-line-length=120
ruff check src/jsonlogic --output-format=concise --statistics --line-length=120


- name: MyPy
Expand Down
5 changes: 4 additions & 1 deletion py/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "jsonlogic-py"
version = "0.2"
version = "0.2.1"
authors = [
{ name="Peter Pirkelbauer"}, { name="Seth Bromberger"}
]
Expand All @@ -24,7 +24,10 @@ classifiers = [
dependencies = {file = ["requirements.txt"]}
optional-dependencies = {dev = {file = ["requirements-dev.txt"] }}

[tool.setuptools.package-data]
jsonlogic = ["py.typed"]

[project.urls]
Homepage = "https://github.com/MetallData/jsonlogic"
Issues = "https://github.com/MetallData/jsonlogic/issues"

2 changes: 1 addition & 1 deletion py/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pytest
coverage
json-logic-qubit
flake8
ruff
mypy
27 changes: 15 additions & 12 deletions py/src/jsonlogic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ def __new__(cls, *_, **__):
setattr(cls, dunder, lambda self, *x, o=op: Expression(o, self, *x))
return super().__new__(cls)

def prepare(self) -> Any:
def _prepare(self) -> Any:
"""prepares the structure for json by converting it into something that can be dumped"""
raise NotImplementedError()

def to_json(self) -> str:
def _to_json(self) -> str:
"""represents the object as JSON"""
return json.dumps(self.prepare())
return json.dumps(self._prepare())

def __str__(self):
return self.to_json()
return self._to_json()


class Literal(Operand):
Expand All @@ -46,21 +46,21 @@ def __repr__(self):
def __str__(self):
return str(self.type)

def prepare(self) -> PyJsonType:
return self.type.prepare()
def _prepare(self) -> PyJsonType:
return self.type._prepare()


class Variable(Operand):
"""A JSONLogic variable"""

def __init__(self, var: str, docstr: str | None = None):
super().__init__()
self.var = var
self._var = var
if docstr is not None:
self.__doc__ = docstr

def prepare(self):
return {"var": self.var}
def _prepare(self):
return {"var": self._var}


class Expression(Operand):
Expand All @@ -83,10 +83,10 @@ def __init__(
# add the remaining variables, casting them to Literals if they're not Variables, Expressions, or Literals.
self.on = tuple(Literal(o) if not isinstance(o, Operand) else o for o in on)

def prepare(self):
def _prepare(self):
return {
str(self.op): [self.o1.prepare()]
+ list(x.prepare() if isinstance(x, Operand) else x for x in self.on)
str(self.op): [self.o1._prepare()]
+ list(x._prepare() if isinstance(x, Operand) else x for x in self.on)
}


Expand Down Expand Up @@ -126,3 +126,6 @@ def prepare(self):

# class _Any(Type, Any):
# """Type representing any JSONLogic type"""


__all__ = ["Operation", "Operand", "Literal", "Variable", "Expression"]
12 changes: 6 additions & 6 deletions py/src/jsonlogic/jsontypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def __init__(self, val):
def __str__(self):
return f"[{self.typename}]{self.val}"

def prepare(self) -> PyJsonType:
def _prepare(self) -> PyJsonType:
"""Prepares the type for JSON serialization"""
raise NotImplementedError("class has not defined prepare()")

Expand All @@ -32,7 +32,7 @@ class JsonNumber(JsonType):

typename = "Number"

def prepare(self):
def _prepare(self):
return int(self.val) if isinstance(self.val, int) else float(self.val)


Expand All @@ -41,7 +41,7 @@ class JsonBool(JsonType):

typename = "Boolean"

def prepare(self) -> bool:
def _prepare(self) -> bool:
return bool(self.val)


Expand All @@ -50,7 +50,7 @@ class JsonStr(JsonType):

typename = "String"

def prepare(self) -> str:
def _prepare(self) -> str:
return str(self.val)


Expand All @@ -59,7 +59,7 @@ class JsonArray(JsonType):

typename = "Array"

def prepare(self) -> list:
def _prepare(self) -> list:
return list(self.val)


Expand All @@ -68,7 +68,7 @@ class JsonObj(JsonType):

typename = "Object"

def prepare(self) -> dict:
def _prepare(self) -> dict:
return dict(self.val)


Expand Down
2 changes: 1 addition & 1 deletion py/src/jsonlogic/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def __str__(self):
# string and array concatenation
_jl_cat = Operation("cat", None)

jl_operations: dict[str, Operation | Callable[..., Operation]] = {
jl_operations: dict[str, Operation] = {
"__lt__": _jl_lt,
"__le__": _jl_le,
"__eq__": _jl_eq,
Expand Down
Empty file added py/src/jsonlogic/py.typed
Empty file.
10 changes: 4 additions & 6 deletions py/test/test_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
sys.path.append("src")

from jsonlogic import Expression, Variable, Literal, Operand, Operation
from jsonlogic.classes import Entity
from dataclasses import dataclass


@pytest.fixture
Expand Down Expand Up @@ -40,13 +38,13 @@ def l2():

def test_expression(op1, op2, v1, v2, l1, l2):
e = Expression(op1, v1)
assert e.to_json() == str(e) == '{"op1": [{"var": "var1"}]}'
assert e._to_json() == str(e) == '{"op1": [{"var": "var1"}]}'

e = Expression(op2, v1, v2)
assert e.to_json() == str(e) == '{"op2": [{"var": "var1"}, {"var": "var2"}]}'
assert e._to_json() == str(e) == '{"op2": [{"var": "var1"}, {"var": "var2"}]}'

e = Expression(op2, v1, l1)
assert e.to_json() == str(e) == '{"op2": [{"var": "var1"}, 5]}'
assert e._to_json() == str(e) == '{"op2": [{"var": "var1"}, 5]}'


def test_operations():
Expand All @@ -63,4 +61,4 @@ def test_literals(l1, l2):
def test_operand():
o = Operand()
with pytest.raises(NotImplementedError):
o.prepare()
o._prepare()
2 changes: 1 addition & 1 deletion py/test/test_jsonlogic.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _s():


def assert_op(e: jl.Expression, d):
assert jsonLogic(e.prepare(), d)
assert jsonLogic(e._prepare(), d)


def test_lt_gt_ne(_s, _i, _f):
Expand Down
14 changes: 7 additions & 7 deletions py/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_bool():
assert b.val is True
assert isinstance(b.val, bool)
assert str(b) == "[Boolean]True"
assert b.prepare() is True
assert b._prepare() is True


def test_int():
Expand All @@ -21,7 +21,7 @@ def test_int():
assert b.val == 10
assert isinstance(b.val, int)
assert str(b) == "[Number]10"
assert b.prepare() == 10
assert b._prepare() == 10


def test_float():
Expand All @@ -30,7 +30,7 @@ def test_float():
assert b.val == 10.1
assert isinstance(b.val, float)
assert str(b) == "[Number]10.1"
assert b.prepare() == 10.1
assert b._prepare() == 10.1


def test_dict():
Expand All @@ -40,7 +40,7 @@ def test_dict():
assert b.val == d
assert isinstance(b.val, dict)
assert str(b).startswith("[Object]")
assert b.prepare() == d
assert b._prepare() == d


def test_str():
Expand All @@ -49,7 +49,7 @@ def test_str():
assert b.val == "hello"
assert isinstance(b.val, str)
assert str(b).startswith("[String]")
assert b.prepare() == "hello"
assert b._prepare() == "hello"


def test_list():
Expand All @@ -59,7 +59,7 @@ def test_list():
assert b.val == d
assert isinstance(b.val, list)
assert str(b).startswith("[Array]")
assert b.prepare() == d
assert b._prepare() == d


def test_deduce():
Expand All @@ -82,4 +82,4 @@ class TestType(JsonType):
assert tt.typename == "UNDEFINED"
assert str(tt) == "[UNDEFINED]10"
with pytest.raises(NotImplementedError):
tt.prepare()
tt._prepare()