This is an automated email from the ASF dual-hosted git repository. skrawcz pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/burr.git
commit 241d6ee0c7467841ab27f905dc26d93f2b9976c2 Author: Stefan Krawczyk <[email protected]> AuthorDate: Sun Mar 15 22:10:39 2026 -0700 Add is/isnot identity operators to when() conditions Adds __is and __isnot operators for identity checks, useful for None/True/False comparisons (e.g. when(value__is=None)). --- burr/core/action.py | 7 +++++++ docs/concepts/transitions.rst | 4 ++++ tests/core/test_action.py | 18 +++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/burr/core/action.py b/burr/core/action.py index cd98558c..df15b7f0 100644 --- a/burr/core/action.py +++ b/burr/core/action.py @@ -433,6 +433,8 @@ class Condition(Function): "in": ("in", lambda a, b: a in b), "notin": ("not in", lambda a, b: a not in b), "contains": ("contains", lambda a, b: b in a), + "is": ("is", lambda a, b: a is b), + "isnot": ("is not", lambda a, b: a is not b), } @classmethod @@ -482,6 +484,11 @@ class Condition(Function): when(status__notin=["x", "y"]) # state["status"] not in ["x", "y"] when(tags__contains="python") # "python" in state["tags"] + Identity operators:: + + when(value__is=None) # state["value"] is None + when(value__isnot=None) # state["value"] is not None + Multiple conditions are ANDed together:: when(age__gte=18, status="active") # age >= 18 AND status == "active" diff --git a/docs/concepts/transitions.rst b/docs/concepts/transitions.rst index 3ade8ef0..479ee881 100644 --- a/docs/concepts/transitions.rst +++ b/docs/concepts/transitions.rst @@ -67,6 +67,8 @@ Conditions have a few APIs, but the most common are the three convenience functi ("check", "tagged", when(tags__contains="python")), # collection contains value ("check", "clean", when(status__notin=["banned", "suspended"])), # not in ("check", "changed", when(status__ne="initial")), # not equal + ("check", "missing", when(value__is=None)), # identity check + ("check", "present", when(value__isnot=None)), # not-identity check ) Available operators: @@ -81,6 +83,8 @@ Available operators: - ``key__in=[values]`` — value is in the given collection - ``key__notin=[values]`` — value is not in the given collection - ``key__contains=value`` — collection/string in state contains the value +- ``key__is=value`` — identity check (``is``), useful for ``None``/``True``/``False`` +- ``key__isnot=value`` — negated identity check (``is not``) Multiple keyword arguments are ANDed together. For more complex expressions, use ``expr()``. diff --git a/tests/core/test_action.py b/tests/core/test_action.py index 381bb6ff..f65a0683 100644 --- a/tests/core/test_action.py +++ b/tests/core/test_action.py @@ -166,6 +166,14 @@ def test_condition_when_complex(): ({"tags__contains": "go"}, {"tags": ["python", "java"]}, False), ({"text__contains": "hello"}, {"text": "say hello world"}, True), ({"text__contains": "goodbye"}, {"text": "say hello world"}, False), + # __is (identity) + ({"value__is": None}, {"value": None}, True), + ({"value__is": None}, {"value": 0}, False), + ({"value__is": True}, {"value": True}, True), + ({"value__is": True}, {"value": 1}, False), + # __isnot (not identity) + ({"value__isnot": None}, {"value": "hello"}, True), + ({"value__isnot": None}, {"value": None}, False), ], ids=[ "eq-match", @@ -193,6 +201,12 @@ def test_condition_when_complex(): "contains-list-no-match", "contains-str-match", "contains-str-no-match", + "is-none-match", + "is-none-no-match", + "is-true-match", + "is-true-not-identical", + "isnot-not-none", + "isnot-is-none", ], ) def test_condition_when_operators(kwargs, state_dict, expected): @@ -226,11 +240,13 @@ def test_condition_when_operators_reads(kwargs, expected_reads): ({"status__in": ["a", "b"]}, "status in ['a', 'b']"), ({"status__notin": ["x"]}, "status not in ['x']"), ({"tags__contains": "py"}, "tags contains 'py'"), + ({"value__is": None}, "value is None"), + ({"value__isnot": None}, "value is not None"), # plain equality still uses old format ({"foo": "bar"}, "foo=bar"), ({"foo": "bar", "baz": "qux"}, "baz=qux, foo=bar"), ], - ids=["gte", "lt", "ne", "in", "notin", "contains", "plain-eq", "plain-multi"], + ids=["gte", "lt", "ne", "in", "notin", "contains", "is", "isnot", "plain-eq", "plain-multi"], ) def test_condition_when_operators_name(kwargs, expected_name): cond = Condition.when(**kwargs)
