Conditions/TransitionsΒΆ
Conditions represent choices to move between actions β these are read by the application builder when executing the graph.
Note that these will always be specified in order β the first condition that evaluates to True will be the selected action.
- class burr.core.action.Condition(
- keys: List[str],
- resolver: Callable[[State], bool],
- name: str = None,
- optional_keys: List[str] = None,
- __init__(
- keys: List[str],
- resolver: Callable[[State], bool],
- name: str = None,
- optional_keys: List[str] = None,
Base condition class. Chooses keys to read from the state and a resolver function. If you want a condition that defaults to true, use Condition.default or just default.
Note that you can use a few fundamental operators to build more complex conditions:
~operator allows you to automatically invert the condition.|operator allows you to OR two conditions together.&operator allows you to AND two conditions together.
- Parameters:
keys β Keys to read from the state
resolver β Function to resolve the condition to True or False
name β Name of the condition
- __and__(other: Condition) ConditionΒΆ
Combines two conditions with an AND operator. This will return a new condition that is the AND of the two conditions.
To check if both foo is bar and baz is qux:
condition = Condition.when(foo="bar") & Condition.when(baz="qux") # equivalent to condition = Condition.when(foo="bar", baz="qux")
- Parameters:
other β Other condition to AND with
- Returns:
A new condition that is the AND of the two conditions
- __or__(other: Condition) ConditionΒΆ
Combines two conditions with an OR operator. This will return a new condition that is the OR of the two conditions.
To check if either foo is bar or baz is qux:
condition = Condition.when(foo="bar") | Condition.when(baz="qux")
- Parameters:
other β Other condition to OR with
- Returns:
A new condition that is the OR of the two conditions
- static expr(expr: str) ConditionΒΆ
Returns a condition that evaluates the given expression against state.
Do not accept expressions generated from user-inputted text, this has the potential to be unsafe. Internally this uses
eval(), so the expression can execute arbitrary Python and should only be used with developer-authored strings. If you need to accept expressions from less-trusted sources (dashboards, YAML, user input), useCondition.safe_expr()which restricts evaluation to a small allowlisted AST grammar interpreted directly (noeval()).You can also refer to this as
from burr.core import exprin the API.Warning
Condition.exprruns the supplied string under a full Pythoneval. Passing user-supplied or otherwise attacker-controllable strings to this function is equivalent to arbitrary code execution inside the application process. For example, an attacker who controls the expression string can execute__import__("os").system("...")or__import__("subprocess").check_output([...])and reach anything the host process can reach.The
globals=Noneargument toevalbelow is not a sandbox: CPython auto-injects__builtins__when globals is empty orNone, which is in fact relied upon here so that expressions likelen(x)work. No part of this function attempts to sandbox the evaluation.If you need to accept untrusted expressions, do not use
expr. Trackapache/burr#817for the opt-in safe-AST evaluator intended for that use case.- Parameters:
expr β Expression to evaluate. Must be a developer-authored Python expression over state variables and standard operators/builtins.
- Returns:
A condition that evaluates the given expression
- static lmda(
- resolver: Callable[[State], bool],
- state_keys: List[str],
Returns a condition that evaluates the given function of State. Note that this is just a simple wrapper over the Condition object.
This does not (yet) support optional (default) arguments.
- Parameters:
fn
state_keys
- Returns:
- property reads: list[str]ΒΆ
Returns the keys from the state that this function reads
- Returns:
A list of keys
- run(state: State, **run_kwargs) dictΒΆ
Runs the function on the given state and returns the result. The result is just a key/value dictionary.
- Parameters:
state β State to run the function on
run_kwargs β Additional arguments to the function passed at runtime.
- Returns:
Result of the function
- static safe_expr(expr: str) ConditionΒΆ
Returns a condition that evaluates
exprunder a restricted, allowlisted AST grammar.This is the opt-in safe sibling of
Condition.expr(). Whereasexpr()useseval()and therefore accepts the full Python expression grammar (and is unsafe for untrusted input),safe_expr()parses the expression, validates every node against an allowlist at call time, and then interprets the validated tree directly.eval()is never invoked on the parsed tree.Use
safe_exprwhen the expression string comes from a less-trusted source β for example a dashboard rule editor, a YAML-driven graph definition, or any user input. Useexprwhen the expression is authored by a developer and checked in.The allowed grammar is intentionally small:
Constants:
int,float,str,bool,None.Namelookups, resolved against the state viaState.get_all().Attributeaccess on names / other attributes. Any attribute whose name starts with__(dunder) is rejected β this closes the standard().__class__.__bases__[0].__subclasses__()sandbox-escape pattern.Subscript(state["foo"],items[0], slices).Compare:==,!=,<,>,<=,>=,in,not in,is,is not.BoolOp:and,or.UnaryOp:not, unary-, unary+.BinOparithmetic:+,-,*,/,//,%,**.Literal containers: tuple, list, set, dict.
Callonly to a tight allowlist of safe builtins by name:len,abs,min,max,sum,all,any,str,int,float,bool. All other calls are rejected.
Everything else is rejected at
safe_expr()call time (not at run time), including: lambdas, conditional expressions (a if b else c), comprehensions and generator expressions, the walrus operator,await,yield, imports, and anyCallnot on the builtin allowlist.- Parameters:
expr β Expression to evaluate
- Returns:
A condition that evaluates the given expression
- Raises:
ValueError β if the expression contains any disallowed construct (raised at call time β the condition is rejected before it ever runs).
SyntaxError β if the expression is not syntactically valid Python.
- classmethod when(**kwargs)ΒΆ
Returns a condition that checks state values using optional operators.
You can also refer to this as
from burr.core import whenin the API.Basic equality (unchanged from original):
when(foo="bar") # state["foo"] == "bar" when(foo="bar", baz="qux") # state["foo"] == "bar" AND state["baz"] == "qux"
Comparison operators via
__suffix:when(age__gt=18) # state["age"] > 18 when(age__gte=18) # state["age"] >= 18 when(age__lt=18) # state["age"] < 18 when(age__lte=18) # state["age"] <= 18 when(age__ne=0) # state["age"] != 0 when(age__eq=18) # state["age"] == 18 (explicit)
Membership operators:
when(status__in=["a", "b"]) # state["status"] in ["a", "b"] 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"
- Parameters:
kwargs β Keyword arguments with optional
__operatorsuffixes- Returns:
A condition that checks all specified constraints (AND)