From 9587da0de6a692273e8483fc117f9883e2226dce Mon Sep 17 00:00:00 2001 From: Snarr Date: Tue, 26 Nov 2024 17:01:16 -0500 Subject: [PATCH 01/19] Catch null default type and refactor error messages --- .../sdk/wfsdk/internal/WfRunVariableImpl.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java index 48f6bd5ec..eff5ff320 100644 --- a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java +++ b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java @@ -37,9 +37,13 @@ class WfRunVariableImpl implements WfRunVariable { public WfRunVariableImpl(String name, Object typeOrDefaultVal, WorkflowThreadImpl parent) { this.name = name; - this.typeOrDefaultVal = typeOrDefaultVal; this.parent = parent; + if (typeOrDefaultVal == null) { + throw new IllegalArgumentException("The 'typeOrDefaultVal' argument must be either a VariableType or a default value, but a null value was provided."); + } + this.typeOrDefaultVal = typeOrDefaultVal; + // As per GH Issue #582, the default is now PRIVATE_VAR. this.accessLevel = WfRunVariableAccessLevel.PRIVATE_VAR; initializeType(); @@ -49,13 +53,8 @@ private void initializeType() { if (typeOrDefaultVal instanceof VariableType) { this.type = (VariableType) typeOrDefaultVal; } else { - try { - this.defaultValue = LHLibUtil.objToVarVal(typeOrDefaultVal); - this.type = LHLibUtil.fromValueCase(defaultValue.getValueCase()); - } catch (LHSerdeError e) { - throw new IllegalArgumentException( - "Was unable to convert provided default value to LH Variable Type", e); - } + setDefaultValue(typeOrDefaultVal); + this.type = LHLibUtil.fromValueCase(defaultValue.getValueCase()); } } @@ -98,15 +97,21 @@ public WfRunVariable required() { @Override public WfRunVariable withDefault(Object defaultVal) { + setDefaultValue(defaultVal); + + if (!LHLibUtil.fromValueCase(defaultValue.getValueCase()).equals(type)) { + throw new IllegalArgumentException("Default value type does not match LH variable type " + type); + } + + return this; + } + + private void setDefaultValue(Object defaultVal) { try { - VariableValue attempt = LHLibUtil.objToVarVal(defaultVal); - if (!LHLibUtil.fromValueCase(attempt.getValueCase()).equals(type)) { - throw new IllegalArgumentException("Default value type does not match variable type"); - } + this.defaultValue = LHLibUtil.objToVarVal(defaultVal); } catch (LHSerdeError e) { throw new IllegalArgumentException("Was unable to convert provided default value to LH Variable Type", e); } - return this; } @Override From 3c5fe820c2b342840949a73da54368b2b63a00fc Mon Sep 17 00:00:00 2001 From: Snarr Date: Tue, 26 Nov 2024 17:01:24 -0500 Subject: [PATCH 02/19] Port LHExpression SDK changes to Python --- sdk-python/littlehorse/workflow.py | 199 +++++++++++++++++++++++++++-- 1 file changed, 186 insertions(+), 13 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index 13b54058a..a697fcd9d 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -136,6 +136,41 @@ def to_variable_assignment(value: Any) -> VariableAssignment: ) +class LHExpression: + def __init__(self, lhs: Any, operation: VariableMutationType, rhs: Any) -> None: + self._lhs = lhs + self._operation = operation + self._rhs = rhs + pass + + def add(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.ADD, other) + + def subtract(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.SUBTRACT, other) + + def multiply(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.MULTIPLY, other) + + def divide(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.DIVIDE, other) + + def extend(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.EXTEND, other) + + def remove_if_present(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_IF_PRESENT, other) + + def remove_index(self, other: int) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) + + def remove_index(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) + + def remove_key(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_KEY, other) + + class WorkflowCondition: def __init__(self, left_hand: Any, comparator: Comparator, right_hand: Any) -> None: """Returns a WorkflowCondition that can be used in @@ -246,7 +281,7 @@ def __init__(self, format: str, *args: Any) -> None: self._args = args -class NodeOutput: +class NodeOutput(LHExpression): def __init__(self, node_name: str) -> None: self.node_name = node_name self._json_path: Optional[str] = None @@ -284,6 +319,33 @@ def with_json_path(self, json_path: str) -> "NodeOutput": out = NodeOutput(self.node_name) out.json_path = json_path return out + + def add(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.ADD, other) + + def subtract(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.SUBTRACT, other) + + def multiply(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.MULTIPLY, other) + + def divide(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.DIVIDE, other) + + def extend(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.EXTEND, other) + + def remove_if_present(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_IF_PRESENT, other) + + def remove_index(self, other: int) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) + + def remove_index(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) + + def remove_key(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_KEY, other) class WfRunVariable: @@ -291,10 +353,11 @@ def __init__( self, variable_name: str, variable_type: VariableType, + parent: WorkflowThread, default_value: Any = None, access_level: Optional[ Union[WfRunVariableAccessLevel, str] - ] = WfRunVariableAccessLevel.PUBLIC_VAR, + ] = WfRunVariableAccessLevel.PRIVATE_VAR, ) -> None: """Defines a Variable in the ThreadSpec and returns a handle to it. @@ -312,6 +375,7 @@ def __init__( """ self.name = variable_name self.type = variable_type + self.parent = parent self.default_value: Optional[VariableValue] = None self._json_path: Optional[str] = None self._required = False @@ -321,14 +385,7 @@ def __init__( self._access_level = access_level if default_value is not None: - self.default_value = to_variable_value(default_value) - if ( - self.default_value.WhichOneof("value") - != str(VariableType.Name(self.type)).lower() - ): - raise TypeError( - f"Default value is not a {VariableType.Name(variable_type)}" - ) + self.__set_default(default_value) @property def json_path(self) -> Optional[str]: @@ -368,7 +425,7 @@ def with_json_path(self, json_path: str) -> "WfRunVariable": f"JsonPath not allowed in a {VariableType.Name(self.type)} variable" ) - out = WfRunVariable(self.name, self.type, self.default_value) + out = WfRunVariable(self.name, self.type, self.parent, self.default_value) out.json_path = json_path return out @@ -445,6 +502,21 @@ def searchable_on( def required(self) -> "WfRunVariable": self._required = True return self + + def with_default(self, default_value: Any) -> WfRunVariable: + self.__set_default(default_value) + + return self + + def __set_default(self, default_value: Any): + self.default_value = to_variable_value(default_value) + if ( + self.default_value.WhichOneof("value") + != str(VariableType.Name(self.type)).lower() + ): + raise TypeError( + f"Default value type does not match LH variable type {VariableType.Name(self.default_value.variable_type)}" + ) def masked(self) -> "WfRunVariable": self._masked = True @@ -469,6 +541,66 @@ def compile(self) -> ThreadVarDef: access_level=self._access_level, ) + def is_equal_to(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.EQUALS, rhs) + + def is_not_equal_to(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.NOT_EQUALS, rhs) + + def is_greater_than(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.GREATER_THAN, rhs) + + def is_greater_than_eq(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.GREATER_THAN_EQ, rhs) + + def is_less_than_eq(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.LESS_THAN_EQ, rhs) + + def is_less_than(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.LESS_THAN, rhs) + + def does_contain(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.IN, rhs) + + def does_not_contain(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.NOT_IN, rhs) + + def is_in(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.IN, rhs) + + def is_not_in(self, rhs: Any) -> WorkflowCondition: + return self.parent.condition(self, Comparator.NOT_IN, rhs) + + def assign_to(self, rhs: Any): + self.parent.mutate(self, VariableMutationType.ASSIGN, rhs) + + def add(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.ADD, other) + + def subtract(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.SUBTRACT, other) + + def multiply(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.MULTIPLY, other) + + def divide(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.DIVIDE, other) + + def extend(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.EXTEND, other) + + def remove_if_present(self, other: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_IF_PRESENT, other) + + def remove_index(self, index: int) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) + + def remove_index(self, index: LHExpression) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) + + def remove_key(self, key: Any) -> LHExpression: + return LHExpression(self, VariableMutationType.REMOVE_KEY, key) + def __str__(self) -> str: return to_json(self.compile()) @@ -1129,6 +1261,48 @@ def execute( node_name = self.add_node(readable_name, task_node) return NodeOutput(node_name) + def multiply(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.MULTIPLY, rhs) + + def add(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.ADD, rhs) + + def divide(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.DIVIDE, rhs) + + def subtract(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.SUBTRACT, rhs) + + def extend(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.EXTEND, rhs) + + def remove_if_present(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.REMOVE_IF_PRESENT, rhs) + + def remove_index(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.REMOVE_INDEX, rhs) + + def remove_key(lhs: any, rhs: any) -> LHExpression: + return LHExpression(lhs, VariableMutationType.REMOVE_KEY, rhs) + + def declare_bool(self, name: str) -> WfRunVariable: + return self.add_variable(name, VariableType.BOOL) + + def declare_int(self, name: str) -> WfRunVariable: + return self.add_variable(name, VariableType.INT) + + def declare_double(self, name: str) -> WfRunVariable: + return self.add_variable(name, VariableType.DOUBLE) + + def declare_bytes(self, name: str) -> WfRunVariable: + return self.add_variable(name, VariableType.BYTES) + + def declare_json_arr(self, name: str) -> WfRunVariable: + return self.add_variable(name, VariableType.JSON_ARR) + + def declare_json_obj(self, name: str) -> WfRunVariable: + return self.add_variable(name, VariableType.JSON_OBJ) + def handle_any_failure( self, node: NodeOutput, initializer: "ThreadInitializer" ) -> None: @@ -1524,7 +1698,7 @@ def add_variable( raise ValueError(f"Variable {variable_name} already added") new_var = WfRunVariable( - variable_name, variable_type, default_value, access_level + variable_name, variable_type, self, default_value, access_level ) self._wf_run_variables.append(new_var) return new_var @@ -1934,7 +2108,6 @@ def with_task_timeout_seconds( self._default_timeout_seconds = timeout_seconds return self - def create_workflow_spec( workflow: Workflow, config: LHConfig, timeout: Optional[int] = None ) -> None: From b1eebae147b6717bc0eae0d3b74324e8f0182e7b Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 14:16:50 -0500 Subject: [PATCH 03/19] Update tests for new SDK changes --- sdk-python/littlehorse/workflow.py | 17 +----- sdk-python/tests/test_utils.py | 2 +- sdk-python/tests/test_workflow.py | 98 +++++++++++++++--------------- 3 files changed, 52 insertions(+), 65 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index a697fcd9d..a495f2bac 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -515,7 +515,7 @@ def __set_default(self, default_value: Any): != str(VariableType.Name(self.type)).lower() ): raise TypeError( - f"Default value type does not match LH variable type {VariableType.Name(self.default_value.variable_type)}" + f"Default value type does not match LH variable type {VariableType.Name(self.type)}" ) def masked(self) -> "WfRunVariable": @@ -1632,22 +1632,9 @@ def mutate( use the output of a Node Run to mutate variables). """ self._check_if_active() - last_node = self._last_node() - node_output: Optional[VariableMutation.NodeOutputSource] = None - rhs_assignment: Optional[VariableAssignment] = None literal_value: Optional[VariableValue] = None - - if isinstance(right_hand, NodeOutput): - if last_node.name != right_hand.node_name: - raise ReferenceError("NodeOutput does not match with last node") - node_output = VariableMutation.NodeOutputSource( - jsonpath=right_hand.json_path - ) - elif isinstance(right_hand, WfRunVariable): - rhs_assignment = to_variable_assignment(right_hand) - else: - literal_value = to_variable_value(right_hand) + rhs_assignment = to_variable_assignment(right_hand) mutation = VariableMutation( lhs_name=left_hand.name, diff --git a/sdk-python/tests/test_utils.py b/sdk-python/tests/test_utils.py index 49d7aa511..9953eca08 100644 --- a/sdk-python/tests/test_utils.py +++ b/sdk-python/tests/test_utils.py @@ -228,7 +228,7 @@ def test_parse_assignment_variable(self): # a WfRunVariable wf_run_variable = WfRunVariable( - variable_name="my-var-name", variable_type=VariableType.STR + variable_name="my-var-name", variable_type=VariableType.STR, parent=None ) wf_run_variable.json_path = "$.myPath" variable = to_variable_assignment(wf_run_variable) diff --git a/sdk-python/tests/test_workflow.py b/sdk-python/tests/test_workflow.py index 6f3c1c59c..35e8a72cd 100644 --- a/sdk-python/tests/test_workflow.py +++ b/sdk-python/tests/test_workflow.py @@ -74,23 +74,23 @@ def test_validate_json_path_format(self): class TestWfRunVariable(unittest.TestCase): def test_value_is_not_none(self): - variable = WfRunVariable("my-var", VariableType.STR, default_value="my-str") + variable = WfRunVariable("my-var", VariableType.STR, None, default_value="my-str") self.assertEqual(variable.default_value.WhichOneof("value"), "str") self.assertEqual(variable.default_value.str, "my-str") - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) self.assertEqual(variable.default_value, None) def test_validate_are_same_type(self): with self.assertRaises(TypeError) as exception_context: - WfRunVariable("my-var", VariableType.STR, 10) + WfRunVariable("my-var", VariableType.STR, None, 10) self.assertEqual( - "Default value is not a STR", + "Default value type does not match LH variable type STR", str(exception_context.exception), ) def test_validate_with_json_path_already_set(self): - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) variable.json_path = "$.myPath" with self.assertRaises(ValueError) as exception_context: variable.with_json_path("$.myNewOne") @@ -100,7 +100,7 @@ def test_validate_with_json_path_already_set(self): ) def test_validate_json_path_already_set(self): - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) variable.json_path = "$.myPath" with self.assertRaises(ValueError) as exception_context: variable.json_path = "$.myNewOne" @@ -110,7 +110,7 @@ def test_validate_json_path_already_set(self): ) def test_validate_json_path_format(self): - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) with self.assertRaises(ValueError) as exception_context: variable.json_path = "$myNewOne" self.assertEqual( @@ -119,7 +119,7 @@ def test_validate_json_path_format(self): ) def test_validate_is_json_obj_when_using_json_index(self): - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) with self.assertRaises(ValueError) as exception_context: variable.searchable_on("$.myPath", VariableType.STR) self.assertEqual( @@ -128,11 +128,11 @@ def test_validate_is_json_obj_when_using_json_index(self): ) def test_persistent(self): - variable = WfRunVariable("my-var", VariableType.STR).searchable() + variable = WfRunVariable("my-var", VariableType.STR, None).searchable() self.assertEqual(variable.compile().searchable, True) def test_validate_is_json_obj_when_using_json_pth(self): - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) with self.assertRaises(ValueError) as exception_context: variable.with_json_path("$.myPath") self.assertEqual( @@ -140,29 +140,29 @@ def test_validate_is_json_obj_when_using_json_pth(self): str(exception_context.exception), ) - variable = WfRunVariable("my-var", VariableType.JSON_OBJ) + variable = WfRunVariable("my-var", VariableType.JSON_OBJ, None) variable.with_json_path("$.myPath") - variable = WfRunVariable("my-var", VariableType.JSON_ARR) + variable = WfRunVariable("my-var", VariableType.JSON_ARR, None) variable.with_json_path("$.myPath") def test_json_path_creates_new(self): - variable = WfRunVariable("my-var", VariableType.JSON_ARR) + variable = WfRunVariable("my-var", VariableType.JSON_ARR, None) with_json = variable.with_json_path("$.myPath") self.assertIsNot(variable, with_json) def test_compile_variable(self): - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) self.assertEqual( variable.compile(), - ThreadVarDef(var_def=VariableDef(name="my-var", type=VariableType.STR)), + ThreadVarDef(var_def=VariableDef(name="my-var", type=VariableType.STR), access_level=WfRunVariableAccessLevel.PRIVATE_VAR), ) - variable = WfRunVariable("my-var", VariableType.JSON_OBJ) + variable = WfRunVariable("my-var", VariableType.JSON_OBJ, None) variable.searchable_on("$.myPath", VariableType.STR) expected_output = ThreadVarDef( var_def=VariableDef(name="my-var", type=VariableType.JSON_OBJ), - access_level="PUBLIC_VAR", + access_level="PRIVATE_VAR", ) expected_output.json_indexes.append( JsonIndex(field_path="$.myPath", field_type=VariableType.STR) @@ -170,7 +170,7 @@ def test_compile_variable(self): self.assertEqual(variable.compile(), expected_output) def test_compile_private_variable(self): - variable = WfRunVariable("my-var", VariableType.STR, access_level="PRIVATE_VAR") + variable = WfRunVariable("my-var", VariableType.STR, None, access_level="PRIVATE_VAR") expected_output = ThreadVarDef( var_def=VariableDef(name="my-var", type=VariableType.STR), access_level="PRIVATE_VAR", @@ -178,7 +178,7 @@ def test_compile_private_variable(self): self.assertEqual(variable.compile(), expected_output) def test_compile_inherited_variable(self): - variable = WfRunVariable("my-var", VariableType.STR) + variable = WfRunVariable("my-var", VariableType.STR, None) variable.with_access_level(WfRunVariableAccessLevel.INHERITED_VAR) expected_output = ThreadVarDef( var_def=VariableDef(name="my-var", type=VariableType.STR), @@ -286,7 +286,7 @@ class MyClass: def if_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT + variable_name="variable-1", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 1, @@ -294,7 +294,7 @@ def if_condition(self, thread: WorkflowThread) -> None: thread.execute("task-a") thread.mutate( WfRunVariable( - variable_name="variable-3", variable_type=VariableType.INT + variable_name="variable-3", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 3, @@ -304,7 +304,7 @@ def if_condition(self, thread: WorkflowThread) -> None: def else_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT + variable_name="variable-2", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 2, @@ -313,7 +313,7 @@ def else_condition(self, thread: WorkflowThread) -> None: thread.execute("task-d") thread.mutate( WfRunVariable( - variable_name="variable-4", variable_type=VariableType.INT + variable_name="variable-4", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 4, @@ -359,7 +359,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-1", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=1), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=1)), ) ], ), @@ -378,7 +378,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-2", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=2), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=2)), ) ], ), @@ -393,7 +393,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-3", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=3), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=3)), ) ], ) @@ -416,7 +416,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-4", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=4), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=4)), ) ], ) @@ -436,7 +436,7 @@ class MyClass: def if_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT + variable_name="variable-1", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 1, @@ -445,7 +445,7 @@ def if_condition(self, thread: WorkflowThread) -> None: def else_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT + variable_name="variable-2", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 2, @@ -491,7 +491,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-2", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=2), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=2)), ) ], ), @@ -510,7 +510,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-1", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=1), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=1)), ) ], ), @@ -530,7 +530,7 @@ class MyClass: def if_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT + variable_name="variable-2", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 2, @@ -539,7 +539,7 @@ def if_condition(self, thread: WorkflowThread) -> None: def my_entrypoint(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT + variable_name="variable-1", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 1, @@ -549,7 +549,7 @@ def my_entrypoint(self, thread: WorkflowThread) -> None: ) thread.mutate( WfRunVariable( - variable_name="variable-3", variable_type=VariableType.INT + variable_name="variable-3", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 3, @@ -575,7 +575,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-1", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=1), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=1)), ) ], ) @@ -599,7 +599,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-2", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=2), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=2)), ) ], ), @@ -626,7 +626,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-3", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=3), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=3)), ) ], ) @@ -642,7 +642,7 @@ class MyClass: def my_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT + variable_name="variable-1", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 1, @@ -650,7 +650,7 @@ def my_condition(self, thread: WorkflowThread) -> None: thread.execute("my-task") thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT + variable_name="variable-2", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 2, @@ -694,7 +694,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-1", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=1), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=1)), ) ], ), @@ -721,7 +721,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-2", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=2), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=2)), ) ], ) @@ -741,7 +741,7 @@ class MyClass: def my_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT + variable_name="variable-1", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 1, @@ -749,7 +749,7 @@ def my_condition(self, thread: WorkflowThread) -> None: thread.execute("my-task") thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT + variable_name="variable-2", variable_type=VariableType.INT, parent=None ), VariableMutationType.ASSIGN, 2, @@ -793,7 +793,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-1", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=1), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=1)), ) ], ), @@ -820,7 +820,7 @@ def to_thread(self): VariableMutation( lhs_name="variable-2", operation=VariableMutationType.ASSIGN, - literal_value=VariableValue(int=2), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=2)), ) ], ) @@ -1061,7 +1061,7 @@ def my_entrypoint(thread: WorkflowThread) -> None: VariableMutation( lhs_name="value", operation=VariableMutationType.MULTIPLY, - literal_value=VariableValue(int=2), + rhs_assignment=VariableAssignment(literal_value=VariableValue(int=2)), ) ], ) @@ -2006,7 +2006,7 @@ def wf_func(thread: WorkflowThread) -> None: mutation = mutations[0] self.assertEqual("my-var", mutation.lhs_name) self.assertEqual(VariableMutationType.ASSIGN, mutation.operation) - self.assertTrue(mutation.HasField("node_output")) + self.assertTrue(mutation.HasField("rhs_assignment")) def test_assign_to_variable_user_id(self): def wf_func(thread: WorkflowThread) -> None: @@ -2171,7 +2171,7 @@ def wf_func(thread: WorkflowThread) -> None: def test_reassign_to_user_var(self): def wf_func(thread: WorkflowThread) -> None: - user_var = WfRunVariable("my-var", VariableType.STR) + user_var = WfRunVariable("my-var", VariableType.STR, None) uto = thread.assign_user_task( "my-user-task", user_id="asdf", @@ -2197,7 +2197,7 @@ def wf_func(thread: WorkflowThread) -> None: def test_reassign_to_group(self): def wf_func(thread: WorkflowThread) -> None: - user_var = WfRunVariable("my-var", VariableType.STR) + user_var = WfRunVariable("my-var", VariableType.STR, None) uto = thread.assign_user_task( "my-user-task", user_id="asdf", From 1e5d0afce32af17834b205f4f6595a51da772200 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 14:33:29 -0500 Subject: [PATCH 04/19] Update 'remove_index' argument to use Optional Union instead of trying to overload --- sdk-python/littlehorse/workflow.py | 31 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index a495f2bac..0487adff0 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -161,11 +161,10 @@ def extend(self, other: Any) -> LHExpression: def remove_if_present(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.REMOVE_IF_PRESENT, other) - def remove_index(self, other: int) -> LHExpression: - return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) - - def remove_index(self, other: Any) -> LHExpression: - return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) + def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: + if index is None: + raise ValueError("Expected 'index' to be set, but it was None.") + return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) def remove_key(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.REMOVE_KEY, other) @@ -338,11 +337,10 @@ def extend(self, other: Any) -> LHExpression: def remove_if_present(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.REMOVE_IF_PRESENT, other) - def remove_index(self, other: int) -> LHExpression: - return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) - - def remove_index(self, other: Any) -> LHExpression: - return LHExpression(self, VariableMutationType.REMOVE_INDEX, other) + def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: + if index is None: + raise ValueError("Expected 'index' to be set, but it was None.") + return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) def remove_key(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.REMOVE_KEY, other) @@ -592,10 +590,9 @@ def extend(self, other: Any) -> LHExpression: def remove_if_present(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.REMOVE_IF_PRESENT, other) - def remove_index(self, index: int) -> LHExpression: - return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) - - def remove_index(self, index: LHExpression) -> LHExpression: + def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: + if index is None: + raise ValueError("Expected 'index' to be set, but it was None.") return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) def remove_key(self, key: Any) -> LHExpression: @@ -1279,8 +1276,10 @@ def extend(lhs: any, rhs: any) -> LHExpression: def remove_if_present(lhs: any, rhs: any) -> LHExpression: return LHExpression(lhs, VariableMutationType.REMOVE_IF_PRESENT, rhs) - def remove_index(lhs: any, rhs: any) -> LHExpression: - return LHExpression(lhs, VariableMutationType.REMOVE_INDEX, rhs) + def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: + if index is None: + raise ValueError("Expected 'index' to be set, but it was None.") + return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) def remove_key(lhs: any, rhs: any) -> LHExpression: return LHExpression(lhs, VariableMutationType.REMOVE_KEY, rhs) From 3f567a03555d79c5e28fce4f505e41dcbf15905d Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 14:34:40 -0500 Subject: [PATCH 05/19] Spotless apply on SDK Java --- .../io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java index eff5ff320..25a198b68 100644 --- a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java +++ b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java @@ -40,7 +40,8 @@ public WfRunVariableImpl(String name, Object typeOrDefaultVal, WorkflowThreadImp this.parent = parent; if (typeOrDefaultVal == null) { - throw new IllegalArgumentException("The 'typeOrDefaultVal' argument must be either a VariableType or a default value, but a null value was provided."); + throw new IllegalArgumentException( + "The 'typeOrDefaultVal' argument must be either a VariableType or a default value, but a null value was provided."); } this.typeOrDefaultVal = typeOrDefaultVal; From ae549148fb51dae2c7047f0d7bc383b95e284a04 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 14:36:57 -0500 Subject: [PATCH 06/19] Fix typing "Any" and add return type annotations --- sdk-python/littlehorse/workflow.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index 0487adff0..7a948f286 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -506,7 +506,7 @@ def with_default(self, default_value: Any) -> WfRunVariable: return self - def __set_default(self, default_value: Any): + def __set_default(self, default_value: Any) -> None: self.default_value = to_variable_value(default_value) if ( self.default_value.WhichOneof("value") @@ -569,7 +569,7 @@ def is_in(self, rhs: Any) -> WorkflowCondition: def is_not_in(self, rhs: Any) -> WorkflowCondition: return self.parent.condition(self, Comparator.NOT_IN, rhs) - def assign_to(self, rhs: Any): + def assign_to(self, rhs: Any) -> None: self.parent.mutate(self, VariableMutationType.ASSIGN, rhs) def add(self, other: Any) -> LHExpression: @@ -1258,22 +1258,22 @@ def execute( node_name = self.add_node(readable_name, task_node) return NodeOutput(node_name) - def multiply(lhs: any, rhs: any) -> LHExpression: + def multiply(lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.MULTIPLY, rhs) - def add(lhs: any, rhs: any) -> LHExpression: + def add(lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.ADD, rhs) - def divide(lhs: any, rhs: any) -> LHExpression: + def divide(lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.DIVIDE, rhs) - def subtract(lhs: any, rhs: any) -> LHExpression: + def subtract(lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.SUBTRACT, rhs) - def extend(lhs: any, rhs: any) -> LHExpression: + def extend(lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.EXTEND, rhs) - def remove_if_present(lhs: any, rhs: any) -> LHExpression: + def remove_if_present(lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.REMOVE_IF_PRESENT, rhs) def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: @@ -1281,7 +1281,7 @@ def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: raise ValueError("Expected 'index' to be set, but it was None.") return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) - def remove_key(lhs: any, rhs: any) -> LHExpression: + def remove_key(lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.REMOVE_KEY, rhs) def declare_bool(self, name: str) -> WfRunVariable: From 42caf832746ebc7066722ce1667eb95873f93540 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 14:59:34 -0500 Subject: [PATCH 07/19] Improve WfRunVariable constructor comments --- sdk-python/littlehorse/workflow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index 7a948f286..ea372316c 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -362,8 +362,9 @@ def __init__( Args: variable_name (str): The name of the variable. variable_type (VariableType): The variable type. - access_level (WfRunVariableAccessLevel): Sets the access level of a WfRunVariable. + parent (WorkflowThread): The parent WorkflowThread of this variable default_value (Any, optional): A default value. Defaults to None. + access_level (WfRunVariableAccessLevel): Sets the access level of a WfRunVariable. Defaults to PRIVATE_VAR. Returns: WfRunVariable: A handle to the created WfRunVariable. From 1d8fd2592a09658a2ef6af104e4ce413060a6417 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 14:59:50 -0500 Subject: [PATCH 08/19] Add ParentThread to WfRunVariables in tests --- sdk-python/tests/test_workflow.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sdk-python/tests/test_workflow.py b/sdk-python/tests/test_workflow.py index 35e8a72cd..d1b65d467 100644 --- a/sdk-python/tests/test_workflow.py +++ b/sdk-python/tests/test_workflow.py @@ -286,7 +286,7 @@ class MyClass: def if_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT, parent=None + variable_name="variable-1", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 1, @@ -294,7 +294,7 @@ def if_condition(self, thread: WorkflowThread) -> None: thread.execute("task-a") thread.mutate( WfRunVariable( - variable_name="variable-3", variable_type=VariableType.INT, parent=None + variable_name="variable-3", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 3, @@ -304,7 +304,7 @@ def if_condition(self, thread: WorkflowThread) -> None: def else_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT, parent=None + variable_name="variable-2", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 2, @@ -313,7 +313,7 @@ def else_condition(self, thread: WorkflowThread) -> None: thread.execute("task-d") thread.mutate( WfRunVariable( - variable_name="variable-4", variable_type=VariableType.INT, parent=None + variable_name="variable-4", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 4, @@ -436,7 +436,7 @@ class MyClass: def if_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT, parent=None + variable_name="variable-1", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 1, @@ -445,7 +445,7 @@ def if_condition(self, thread: WorkflowThread) -> None: def else_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT, parent=None + variable_name="variable-2", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 2, @@ -530,7 +530,7 @@ class MyClass: def if_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT, parent=None + variable_name="variable-2", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 2, @@ -539,7 +539,7 @@ def if_condition(self, thread: WorkflowThread) -> None: def my_entrypoint(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT, parent=None + variable_name="variable-1", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 1, @@ -549,7 +549,7 @@ def my_entrypoint(self, thread: WorkflowThread) -> None: ) thread.mutate( WfRunVariable( - variable_name="variable-3", variable_type=VariableType.INT, parent=None + variable_name="variable-3", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 3, @@ -741,7 +741,7 @@ class MyClass: def my_condition(self, thread: WorkflowThread) -> None: thread.mutate( WfRunVariable( - variable_name="variable-1", variable_type=VariableType.INT, parent=None + variable_name="variable-1", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 1, @@ -749,7 +749,7 @@ def my_condition(self, thread: WorkflowThread) -> None: thread.execute("my-task") thread.mutate( WfRunVariable( - variable_name="variable-2", variable_type=VariableType.INT, parent=None + variable_name="variable-2", variable_type=VariableType.INT, parent=thread ), VariableMutationType.ASSIGN, 2, From af792686b353522f064053867161cd6365d43302 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 15:38:36 -0500 Subject: [PATCH 09/19] Use 1 underscore for private method --- sdk-python/littlehorse/workflow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index ea372316c..e985a0869 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -384,7 +384,7 @@ def __init__( self._access_level = access_level if default_value is not None: - self.__set_default(default_value) + self._set_default(default_value) @property def json_path(self) -> Optional[str]: @@ -503,11 +503,11 @@ def required(self) -> "WfRunVariable": return self def with_default(self, default_value: Any) -> WfRunVariable: - self.__set_default(default_value) + self._set_default(default_value) return self - def __set_default(self, default_value: Any) -> None: + def _set_default(self, default_value: Any) -> None: self.default_value = to_variable_value(default_value) if ( self.default_value.WhichOneof("value") From 78f817bc045dac5fac96b5b884c3c716e1711187 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 16:22:40 -0500 Subject: [PATCH 10/19] Check for instance of LHExpression --- sdk-python/littlehorse/workflow.py | 41 ++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index e985a0869..b5abe720e 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -130,6 +130,14 @@ def to_variable_assignment(value: Any) -> VariableAssignment: json_path=json_path, variable_name=variable_name, ) + + if isinstance(value, LHExpression): + expression: LHExpression = value + return VariableAssignment( + expression=LHExpression(lhs=to_variable_assignment(expression.getLhs()), + operation=expression.getOperation(), + rhs=to_variable_assignment(expression.getRhs())) + ) return VariableAssignment( literal_value=to_variable_value(value), @@ -169,6 +177,14 @@ def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: def remove_key(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.REMOVE_KEY, other) + def getLhs(self) -> Any: + return self._lhs + + def getRhs(self) -> Any: + return self._rhs + + def getOperation(self) -> Any: + return self._operation class WorkflowCondition: def __init__(self, left_hand: Any, comparator: Comparator, right_hand: Any) -> None: @@ -351,7 +367,6 @@ def __init__( self, variable_name: str, variable_type: VariableType, - parent: WorkflowThread, default_value: Any = None, access_level: Optional[ Union[WfRunVariableAccessLevel, str] @@ -362,7 +377,6 @@ def __init__( Args: variable_name (str): The name of the variable. variable_type (VariableType): The variable type. - parent (WorkflowThread): The parent WorkflowThread of this variable default_value (Any, optional): A default value. Defaults to None. access_level (WfRunVariableAccessLevel): Sets the access level of a WfRunVariable. Defaults to PRIVATE_VAR. @@ -373,8 +387,7 @@ def __init__( TypeError: If variable_type and type(default_value) are not compatible. """ self.name = variable_name - self.type = variable_type - self.parent = parent + self.type = variable_type self.default_value: Optional[VariableValue] = None self._json_path: Optional[str] = None self._required = False @@ -541,34 +554,34 @@ def compile(self) -> ThreadVarDef: ) def is_equal_to(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.EQUALS, rhs) + return WorkflowCondition(self, Comparator.EQUALS, rhs) def is_not_equal_to(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.NOT_EQUALS, rhs) + return WorkflowCondition(self, Comparator.NOT_EQUALS, rhs) def is_greater_than(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.GREATER_THAN, rhs) + return WorkflowCondition(self, Comparator.GREATER_THAN, rhs) def is_greater_than_eq(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.GREATER_THAN_EQ, rhs) + return WorkflowCondition(self, Comparator.GREATER_THAN_EQ, rhs) def is_less_than_eq(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.LESS_THAN_EQ, rhs) + return WorkflowCondition(self, Comparator.LESS_THAN_EQ, rhs) def is_less_than(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.LESS_THAN, rhs) + return WorkflowCondition(self, Comparator.LESS_THAN, rhs) def does_contain(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.IN, rhs) + return WorkflowCondition(self, Comparator.IN, rhs) def does_not_contain(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.NOT_IN, rhs) + return WorkflowCondition(self, Comparator.NOT_IN, rhs) def is_in(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.IN, rhs) + return WorkflowCondition(self, Comparator.IN, rhs) def is_not_in(self, rhs: Any) -> WorkflowCondition: - return self.parent.condition(self, Comparator.NOT_IN, rhs) + return WorkflowCondition(self, Comparator.NOT_IN, rhs) def assign_to(self, rhs: Any) -> None: self.parent.mutate(self, VariableMutationType.ASSIGN, rhs) From cdf2d4cb9a895c235b1b32c1db1c1c412d8e6da8 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 16:25:21 -0500 Subject: [PATCH 11/19] Add back parent to WfRunVariable --- sdk-python/examples/basic/example_basic.py | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sdk-python/examples/basic/example_basic.py b/sdk-python/examples/basic/example_basic.py index bed79022f..34bfeb82d 100644 --- a/sdk-python/examples/basic/example_basic.py +++ b/sdk-python/examples/basic/example_basic.py @@ -1,11 +1,10 @@ import asyncio import logging from pathlib import Path -import random import littlehorse from littlehorse.config import LHConfig -from littlehorse.model import VariableType +from littlehorse.model import VariableType, VariableMutationType from littlehorse.worker import LHTaskWorker, WorkerContext from littlehorse.workflow import WorkflowThread, Workflow @@ -19,30 +18,31 @@ def get_config() -> LHConfig: config.load(config_path) return config - -def get_workflow() -> Workflow: +def test_workflow() -> Workflow: def my_entrypoint(wf: WorkflowThread) -> None: - the_name = wf.add_variable("input-name", VariableType.STR) - wf.execute("greet", the_name) + user_id = wf.add_variable("user-id", VariableType.STR).required() + item = wf.add_variable("item", VariableType.STR).required() + quantity = wf.add_variable("quantity", VariableType.INT).required() - return Workflow("example-basic", my_entrypoint) + wf.execute("charge-credit-card", user_id, quantity.multiply(wf.execute("fetch-price"), item)) + return Workflow("example-basic", my_entrypoint) -async def greeting(name: str, ctx: WorkerContext) -> str: - msg = f"Hello {name}!. WfRun {ctx.wf_run_id.id}" - print(msg) - await asyncio.sleep(random.uniform(0.5, 1.5)) - return msg +async def fetch_price(item: str, ctx: WorkerContext) -> str: + return 5 +async def charge_credit_card(user_id: str, total_price: float, ctx: WorkerContext) -> str: + print(f"Charging {user_id} ${total_price}") async def main() -> None: config = get_config() - wf = get_workflow() + wf = test_workflow() - littlehorse.create_task_def(greeting, "greet", config) + littlehorse.create_task_def(fetch_price, "fetch-price", config) + littlehorse.create_task_def(charge_credit_card, "charge-credit-card", config) littlehorse.create_workflow_spec(wf, config) - await littlehorse.start(LHTaskWorker(greeting, "greet", config)) + await littlehorse.start(LHTaskWorker(fetch_price, "fetch-price", config), LHTaskWorker(charge_credit_card, "charge-credit-card", config)) if __name__ == "__main__": From 08e1e497102827f4b0e16470019dd8f3ed8dbc75 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 16:25:57 -0500 Subject: [PATCH 12/19] Add parent attribute to class --- sdk-python/littlehorse/workflow.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index b5abe720e..fb17786b8 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -367,6 +367,7 @@ def __init__( self, variable_name: str, variable_type: VariableType, + parent: WorkflowThread, default_value: Any = None, access_level: Optional[ Union[WfRunVariableAccessLevel, str] @@ -377,6 +378,7 @@ def __init__( Args: variable_name (str): The name of the variable. variable_type (VariableType): The variable type. + parent (WorkflowThread): The parent WorkflowThread of this WfRunVariable. default_value (Any, optional): A default value. Defaults to None. access_level (WfRunVariableAccessLevel): Sets the access level of a WfRunVariable. Defaults to PRIVATE_VAR. @@ -388,6 +390,7 @@ def __init__( """ self.name = variable_name self.type = variable_type + self.parent = parent self.default_value: Optional[VariableValue] = None self._json_path: Optional[str] = None self._required = False @@ -554,34 +557,34 @@ def compile(self) -> ThreadVarDef: ) def is_equal_to(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.EQUALS, rhs) + return self.parent.condition(self, Comparator.EQUALS, rhs) def is_not_equal_to(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.NOT_EQUALS, rhs) + return self.parent.condition(self, Comparator.NOT_EQUALS, rhs) def is_greater_than(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.GREATER_THAN, rhs) + return self.parent.condition(self, Comparator.GREATER_THAN, rhs) def is_greater_than_eq(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.GREATER_THAN_EQ, rhs) + return self.parent.condition(self, Comparator.GREATER_THAN_EQ, rhs) def is_less_than_eq(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.LESS_THAN_EQ, rhs) + return self.parent.condition(self, Comparator.LESS_THAN_EQ, rhs) def is_less_than(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.LESS_THAN, rhs) + return self.parent.condition(self, Comparator.LESS_THAN, rhs) def does_contain(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.IN, rhs) + return self.parent.condition(self, Comparator.IN, rhs) def does_not_contain(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.NOT_IN, rhs) + return self.parent.condition(self, Comparator.NOT_IN, rhs) def is_in(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.IN, rhs) + return self.parent.condition(self, Comparator.IN, rhs) def is_not_in(self, rhs: Any) -> WorkflowCondition: - return WorkflowCondition(self, Comparator.NOT_IN, rhs) + return self.parent.condition(self, Comparator.NOT_IN, rhs) def assign_to(self, rhs: Any) -> None: self.parent.mutate(self, VariableMutationType.ASSIGN, rhs) From 8e3cfbca3cbdc80f394cc056a27bfbc566f1c4df Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 16:26:27 -0500 Subject: [PATCH 13/19] Restore example basic --- sdk-python/examples/basic/example_basic.py | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sdk-python/examples/basic/example_basic.py b/sdk-python/examples/basic/example_basic.py index 34bfeb82d..fe349646c 100644 --- a/sdk-python/examples/basic/example_basic.py +++ b/sdk-python/examples/basic/example_basic.py @@ -1,10 +1,11 @@ import asyncio import logging from pathlib import Path +import random import littlehorse from littlehorse.config import LHConfig -from littlehorse.model import VariableType, VariableMutationType +from littlehorse.model import VariableType from littlehorse.worker import LHTaskWorker, WorkerContext from littlehorse.workflow import WorkflowThread, Workflow @@ -18,32 +19,31 @@ def get_config() -> LHConfig: config.load(config_path) return config -def test_workflow() -> Workflow: - def my_entrypoint(wf: WorkflowThread) -> None: - user_id = wf.add_variable("user-id", VariableType.STR).required() - item = wf.add_variable("item", VariableType.STR).required() - quantity = wf.add_variable("quantity", VariableType.INT).required() - wf.execute("charge-credit-card", user_id, quantity.multiply(wf.execute("fetch-price"), item)) +def get_workflow() -> Workflow: + def my_entrypoint(wf: WorkflowThread) -> None: + the_name = wf.add_variable("input-name", VariableType.STR) + wf.execute("greet", the_name) return Workflow("example-basic", my_entrypoint) -async def fetch_price(item: str, ctx: WorkerContext) -> str: - return 5 -async def charge_credit_card(user_id: str, total_price: float, ctx: WorkerContext) -> str: - print(f"Charging {user_id} ${total_price}") +async def greeting(name: str, ctx: WorkerContext) -> str: + msg = f"Hello {name}!. WfRun {ctx.wf_run_id.id}" + print(msg) + await asyncio.sleep(random.uniform(0.5, 1.5)) + return msg + async def main() -> None: config = get_config() - wf = test_workflow() + wf = get_workflow() - littlehorse.create_task_def(fetch_price, "fetch-price", config) - littlehorse.create_task_def(charge_credit_card, "charge-credit-card", config) + littlehorse.create_task_def(greeting, "greet", config) littlehorse.create_workflow_spec(wf, config) - await littlehorse.start(LHTaskWorker(fetch_price, "fetch-price", config), LHTaskWorker(charge_credit_card, "charge-credit-card", config)) + await littlehorse.start(LHTaskWorker(greeting, "greet", config)) if __name__ == "__main__": - asyncio.run(main()) + asyncio.run(main()) \ No newline at end of file From 4d524b7658741b422a33020a21b069aaa4403cc4 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 16:27:01 -0500 Subject: [PATCH 14/19] Remove pass --- sdk-python/littlehorse/workflow.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index fb17786b8..b12349381 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -149,7 +149,6 @@ def __init__(self, lhs: Any, operation: VariableMutationType, rhs: Any) -> None: self._lhs = lhs self._operation = operation self._rhs = rhs - pass def add(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.ADD, other) From 0e073347f38c5b8a90883bd0e4c6b9dfde61e89f Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 16:28:21 -0500 Subject: [PATCH 15/19] Use Proto Expression instead of LHExpression --- sdk-python/littlehorse/workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index b12349381..92da5dc46 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -134,7 +134,7 @@ def to_variable_assignment(value: Any) -> VariableAssignment: if isinstance(value, LHExpression): expression: LHExpression = value return VariableAssignment( - expression=LHExpression(lhs=to_variable_assignment(expression.getLhs()), + expression=VariableAssignment.Expression(lhs=to_variable_assignment(expression.getLhs()), operation=expression.getOperation(), rhs=to_variable_assignment(expression.getRhs())) ) From 39c45f8e77dd8c1dcd747e109aa13ee4d890291f Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 17:01:39 -0500 Subject: [PATCH 16/19] Add self to methods --- sdk-python/littlehorse/workflow.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index 92da5dc46..10d2297c5 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -134,9 +134,10 @@ def to_variable_assignment(value: Any) -> VariableAssignment: if isinstance(value, LHExpression): expression: LHExpression = value return VariableAssignment( - expression=VariableAssignment.Expression(lhs=to_variable_assignment(expression.getLhs()), - operation=expression.getOperation(), - rhs=to_variable_assignment(expression.getRhs())) + expression=VariableAssignment.Expression( + lhs=to_variable_assignment(expression.lhs()), + operation=expression.operation(), + rhs=to_variable_assignment(expression.rhs())) ) return VariableAssignment( @@ -176,13 +177,13 @@ def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: def remove_key(self, other: Any) -> LHExpression: return LHExpression(self, VariableMutationType.REMOVE_KEY, other) - def getLhs(self) -> Any: + def lhs(self) -> Any: return self._lhs - def getRhs(self) -> Any: + def rhs(self) -> Any: return self._rhs - def getOperation(self) -> Any: + def operation(self) -> Any: return self._operation class WorkflowCondition: @@ -1274,22 +1275,22 @@ def execute( node_name = self.add_node(readable_name, task_node) return NodeOutput(node_name) - def multiply(lhs: Any, rhs: Any) -> LHExpression: + def multiply(self, lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.MULTIPLY, rhs) - def add(lhs: Any, rhs: Any) -> LHExpression: + def add(self, lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.ADD, rhs) - def divide(lhs: Any, rhs: Any) -> LHExpression: + def divide(self, lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.DIVIDE, rhs) - def subtract(lhs: Any, rhs: Any) -> LHExpression: + def subtract(self, lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.SUBTRACT, rhs) - def extend(lhs: Any, rhs: Any) -> LHExpression: + def extend(self, lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.EXTEND, rhs) - def remove_if_present(lhs: Any, rhs: Any) -> LHExpression: + def remove_if_present(self, lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.REMOVE_IF_PRESENT, rhs) def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: @@ -1297,7 +1298,7 @@ def remove_index(self, index: Optional[Union[int, Any]] = None) -> LHExpression: raise ValueError("Expected 'index' to be set, but it was None.") return LHExpression(self, VariableMutationType.REMOVE_INDEX, index) - def remove_key(lhs: Any, rhs: Any) -> LHExpression: + def remove_key(self, lhs: Any, rhs: Any) -> LHExpression: return LHExpression(lhs, VariableMutationType.REMOVE_KEY, rhs) def declare_bool(self, name: str) -> WfRunVariable: From 18214253f36ad4648eb878c09918f6ae5e87d07d Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 27 Nov 2024 17:07:20 -0500 Subject: [PATCH 17/19] Add WorkflowThread where applicable --- sdk-python/tests/test_workflow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk-python/tests/test_workflow.py b/sdk-python/tests/test_workflow.py index d1b65d467..d6938b44c 100644 --- a/sdk-python/tests/test_workflow.py +++ b/sdk-python/tests/test_workflow.py @@ -2171,7 +2171,7 @@ def wf_func(thread: WorkflowThread) -> None: def test_reassign_to_user_var(self): def wf_func(thread: WorkflowThread) -> None: - user_var = WfRunVariable("my-var", VariableType.STR, None) + user_var = WfRunVariable("my-var", VariableType.STR, thread) uto = thread.assign_user_task( "my-user-task", user_id="asdf", @@ -2197,7 +2197,7 @@ def wf_func(thread: WorkflowThread) -> None: def test_reassign_to_group(self): def wf_func(thread: WorkflowThread) -> None: - user_var = WfRunVariable("my-var", VariableType.STR, None) + user_var = WfRunVariable("my-var", VariableType.STR, thread) uto = thread.assign_user_task( "my-user-task", user_id="asdf", From 17356afecf620a84ba5c8333e19bbc71e1981d83 Mon Sep 17 00:00:00 2001 From: Snarr Date: Thu, 28 Nov 2024 12:30:05 -0500 Subject: [PATCH 18/19] Port tests to Python --- sdk-python/tests/test_workflow.py | 70 +++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/sdk-python/tests/test_workflow.py b/sdk-python/tests/test_workflow.py index d6938b44c..9b5ea55af 100644 --- a/sdk-python/tests/test_workflow.py +++ b/sdk-python/tests/test_workflow.py @@ -1079,6 +1079,76 @@ def my_entrypoint(thread: WorkflowThread) -> None: ), ) + def test_mutations_should_use_variable_assignments(self): + def my_entrypoint(thread: WorkflowThread) -> None: + my_var = thread.add_variable("my-var", VariableType.STR) + my_var.assign_to("some-value") + + wf_spec = Workflow("obiwan", my_entrypoint).compile() + entrypoint = wf_spec.thread_specs[wf_spec.entrypoint_thread_name] + node = entrypoint.nodes["0-entrypoint-ENTRYPOINT"] + + edge = node.outgoing_edges[0] + + self.assertEqual(edge.variable_mutations[0].rhs_assignment.literal_value.str, "some-value") + + def test_node_output_mutations_should_also_use_variable_assignments(self): + def my_entrypoint(thread: WorkflowThread) -> None: + my_var = thread.add_variable("my-var", VariableType.STR) + my_var.assign_to(thread.execute("use-the-force")) + + wf_spec = Workflow("obiwan", my_entrypoint).compile() + entrypoint = wf_spec.thread_specs[wf_spec.entrypoint_thread_name] + node = entrypoint.nodes["1-use-the-force-TASK"] + + edge = node.outgoing_edges[0] + + self.assertEqual(edge.variable_mutations[0].rhs_assignment.node_output.node_name, "1-use-the-force-TASK") + + def test_node_output_mutations_should_carry_json_path(self): + def my_entrypoint(thread: WorkflowThread) -> None: + my_var = thread.add_variable("my-var", VariableType.STR) + my_var.assign_to(thread.execute("use-the-force").with_json_path("$.hello.there")) + + wfSpec = Workflow("obiwan", my_entrypoint).compile() + entrypoint = wfSpec.thread_specs[wfSpec.entrypoint_thread_name] + node = entrypoint.nodes["1-use-the-force-TASK"] + + edge = node.outgoing_edges[0] + + self.assertEqual(edge.variable_mutations[0].rhs_assignment.node_output.node_name, "1-use-the-force-TASK") + + self.assertEqual(edge.variable_mutations[0].rhs_assignment.json_path, "$.hello.there") + + def test_assigning_variables_to_other_variables_should_use_variable_assignment(self): + def my_entrypoint(thread: WorkflowThread) -> None: + my_var = thread.add_variable("my-var", VariableType.STR) + other_var = thread.add_variable("other-var", VariableType.STR) + my_var.assign_to(other_var) + + wfSpec = Workflow("obiwan", my_entrypoint).compile() + entrypoint = wfSpec.thread_specs[wfSpec.entrypoint_thread_name] + node = entrypoint.nodes["0-entrypoint-ENTRYPOINT"] + + edge = node.outgoing_edges[0] + self.assertEqual(edge.variable_mutations[0].rhs_assignment.variable_name, "other-var") + + def test_assigning_variables_to_other_variables_should_carry_json_path(self): + def my_entrypoint(thread: WorkflowThread) -> None: + my_var = thread.add_variable("my-var", VariableType.STR) + other_var = thread.add_variable("other-var", VariableType.JSON_OBJ) + my_var.assign_to(other_var.with_json_path("$.hello.there")) + + wfSpec = Workflow("obiwan", my_entrypoint).compile() + entrypoint = wfSpec.thread_specs[wfSpec.entrypoint_thread_name] + node = entrypoint.nodes["0-entrypoint-ENTRYPOINT"] + + edge = node.outgoing_edges[0] + self.assertEqual(edge.variable_mutations[0].rhs_assignment.variable_name, "other-var") + + self.assertEqual(edge.variable_mutations[0].rhs_assignment.json_path, "$.hello.there") + + class TestWorkflow(unittest.TestCase): def test_entrypoint_is_a_function(self): From a011a8d6074717f7c7681355c9b39d4e18985355 Mon Sep 17 00:00:00 2001 From: Snarr Date: Mon, 2 Dec 2024 17:57:59 -0500 Subject: [PATCH 19/19] Rename "assign_to" method to "assign" in Java and Python --- .../littlehorse/sdk/wfsdk/WfRunVariable.java | 2 +- .../sdk/wfsdk/internal/WfRunVariableImpl.java | 2 +- .../wfsdk/internal/WorkflowThreadImplTest.java | 10 +++++----- sdk-python/littlehorse/workflow.py | 2 +- sdk-python/tests/test_workflow.py | 10 +++++----- server/src/test/java/e2e/BasicTest.java | 2 +- server/src/test/java/e2e/ExpressionTest.java | 18 +++++++++--------- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/WfRunVariable.java b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/WfRunVariable.java index a5a1002a5..7f17f0ef3 100644 --- a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/WfRunVariable.java +++ b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/WfRunVariable.java @@ -214,5 +214,5 @@ public interface WfRunVariable extends LHExpression { * provided by the Json Path is mutated. * @param rhs is the value to set this WfRunVariable to. */ - void assignTo(Serializable rhs); + void assign(Serializable rhs); } diff --git a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java index 25a198b68..4f408af79 100644 --- a/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java +++ b/sdk-java/src/main/java/io/littlehorse/sdk/wfsdk/internal/WfRunVariableImpl.java @@ -181,7 +181,7 @@ public WorkflowConditionImpl isNotIn(Serializable rhs) { } @Override - public void assignTo(Serializable rhs) { + public void assign(Serializable rhs) { parent.mutate(this, VariableMutationType.ASSIGN, rhs); } diff --git a/sdk-java/src/test/java/io/littlehorse/sdk/wfsdk/internal/WorkflowThreadImplTest.java b/sdk-java/src/test/java/io/littlehorse/sdk/wfsdk/internal/WorkflowThreadImplTest.java index 681c6a666..2a8aa238e 100644 --- a/sdk-java/src/test/java/io/littlehorse/sdk/wfsdk/internal/WorkflowThreadImplTest.java +++ b/sdk-java/src/test/java/io/littlehorse/sdk/wfsdk/internal/WorkflowThreadImplTest.java @@ -550,7 +550,7 @@ void mutationsShouldUseVariableAssignment() { // Deprecated the literal_value and node_output approach Workflow workflow = new WorkflowImpl("obiwan", wf -> { WfRunVariable myVar = wf.addVariable("my-var", VariableType.STR); - myVar.assignTo("some-value"); + myVar.assign("some-value"); }); PutWfSpecRequest wfSpec = workflow.compileWorkflow(); @@ -570,7 +570,7 @@ void nodeOutputMutationsShouldAlsoUseVariableAssignments() { // Deprecated the literal_value and node_output approach Workflow workflow = new WorkflowImpl("obiwan", wf -> { WfRunVariable myVar = wf.addVariable("my-var", VariableType.STR); - myVar.assignTo(wf.execute("use-the-force")); + myVar.assign(wf.execute("use-the-force")); }); PutWfSpecRequest wfSpec = workflow.compileWorkflow(); @@ -590,7 +590,7 @@ void nodeOutputMutationsShouldCarryJsonPath() { // Deprecated the literal_value and node_output approach Workflow workflow = new WorkflowImpl("obiwan", wf -> { WfRunVariable myVar = wf.addVariable("my-var", VariableType.STR); - myVar.assignTo(wf.execute("use-the-force").jsonPath("$.hello.there")); + myVar.assign(wf.execute("use-the-force").jsonPath("$.hello.there")); }); PutWfSpecRequest wfSpec = workflow.compileWorkflow(); @@ -614,7 +614,7 @@ void assigningVariablesToOtherVariablesShouldUseVariableAssignment() { Workflow workflow = new WorkflowImpl("obiwan", wf -> { WfRunVariable myVar = wf.addVariable("my-var", VariableType.STR); WfRunVariable otherVar = wf.addVariable("other-var", VariableType.STR); - myVar.assignTo(otherVar); + myVar.assign(otherVar); }); PutWfSpecRequest wfSpec = workflow.compileWorkflow(); @@ -632,7 +632,7 @@ void assigningVariablesToOtherVariablesShouldCarryJsonPath() { Workflow workflow = new WorkflowImpl("obiwan", wf -> { WfRunVariable myVar = wf.addVariable("my-var", VariableType.STR); WfRunVariable otherVar = wf.addVariable("other-var", VariableType.JSON_OBJ); - myVar.assignTo(otherVar.jsonPath("$.hello.there")); + myVar.assign(otherVar.jsonPath("$.hello.there")); }); PutWfSpecRequest wfSpec = workflow.compileWorkflow(); diff --git a/sdk-python/littlehorse/workflow.py b/sdk-python/littlehorse/workflow.py index 10d2297c5..74d6e72d9 100644 --- a/sdk-python/littlehorse/workflow.py +++ b/sdk-python/littlehorse/workflow.py @@ -586,7 +586,7 @@ def is_in(self, rhs: Any) -> WorkflowCondition: def is_not_in(self, rhs: Any) -> WorkflowCondition: return self.parent.condition(self, Comparator.NOT_IN, rhs) - def assign_to(self, rhs: Any) -> None: + def assign(self, rhs: Any) -> None: self.parent.mutate(self, VariableMutationType.ASSIGN, rhs) def add(self, other: Any) -> LHExpression: diff --git a/sdk-python/tests/test_workflow.py b/sdk-python/tests/test_workflow.py index 9b5ea55af..1604efd22 100644 --- a/sdk-python/tests/test_workflow.py +++ b/sdk-python/tests/test_workflow.py @@ -1082,7 +1082,7 @@ def my_entrypoint(thread: WorkflowThread) -> None: def test_mutations_should_use_variable_assignments(self): def my_entrypoint(thread: WorkflowThread) -> None: my_var = thread.add_variable("my-var", VariableType.STR) - my_var.assign_to("some-value") + my_var.assign("some-value") wf_spec = Workflow("obiwan", my_entrypoint).compile() entrypoint = wf_spec.thread_specs[wf_spec.entrypoint_thread_name] @@ -1095,7 +1095,7 @@ def my_entrypoint(thread: WorkflowThread) -> None: def test_node_output_mutations_should_also_use_variable_assignments(self): def my_entrypoint(thread: WorkflowThread) -> None: my_var = thread.add_variable("my-var", VariableType.STR) - my_var.assign_to(thread.execute("use-the-force")) + my_var.assign(thread.execute("use-the-force")) wf_spec = Workflow("obiwan", my_entrypoint).compile() entrypoint = wf_spec.thread_specs[wf_spec.entrypoint_thread_name] @@ -1108,7 +1108,7 @@ def my_entrypoint(thread: WorkflowThread) -> None: def test_node_output_mutations_should_carry_json_path(self): def my_entrypoint(thread: WorkflowThread) -> None: my_var = thread.add_variable("my-var", VariableType.STR) - my_var.assign_to(thread.execute("use-the-force").with_json_path("$.hello.there")) + my_var.assign(thread.execute("use-the-force").with_json_path("$.hello.there")) wfSpec = Workflow("obiwan", my_entrypoint).compile() entrypoint = wfSpec.thread_specs[wfSpec.entrypoint_thread_name] @@ -1124,7 +1124,7 @@ def test_assigning_variables_to_other_variables_should_use_variable_assignment(s def my_entrypoint(thread: WorkflowThread) -> None: my_var = thread.add_variable("my-var", VariableType.STR) other_var = thread.add_variable("other-var", VariableType.STR) - my_var.assign_to(other_var) + my_var.assign(other_var) wfSpec = Workflow("obiwan", my_entrypoint).compile() entrypoint = wfSpec.thread_specs[wfSpec.entrypoint_thread_name] @@ -1137,7 +1137,7 @@ def test_assigning_variables_to_other_variables_should_carry_json_path(self): def my_entrypoint(thread: WorkflowThread) -> None: my_var = thread.add_variable("my-var", VariableType.STR) other_var = thread.add_variable("other-var", VariableType.JSON_OBJ) - my_var.assign_to(other_var.with_json_path("$.hello.there")) + my_var.assign(other_var.with_json_path("$.hello.there")) wfSpec = Workflow("obiwan", my_entrypoint).compile() entrypoint = wfSpec.thread_specs[wfSpec.entrypoint_thread_name] diff --git a/server/src/test/java/e2e/BasicTest.java b/server/src/test/java/e2e/BasicTest.java index 094d1ab96..6e55ff439 100644 --- a/server/src/test/java/e2e/BasicTest.java +++ b/server/src/test/java/e2e/BasicTest.java @@ -27,7 +27,7 @@ public void shouldDoBasic() { public Workflow getBasic() { return new WorkflowImpl("test-basic", thread -> { WfRunVariable asdf = thread.declareBool("asdf"); - asdf.assignTo(thread.execute("ag-one")); + asdf.assign(thread.execute("ag-one")); }); } diff --git a/server/src/test/java/e2e/ExpressionTest.java b/server/src/test/java/e2e/ExpressionTest.java index 13f5b5117..c9c4962a1 100644 --- a/server/src/test/java/e2e/ExpressionTest.java +++ b/server/src/test/java/e2e/ExpressionTest.java @@ -247,7 +247,7 @@ public Workflow getExpression() { // EXTEND a String test var myStr = wf.declareStr("my-str"); wf.doIf(myStr.isNotEqualTo(null), then -> { - myStr.assignTo(myStr.extend("-suffix")); + myStr.assign(myStr.extend("-suffix")); }); // Add an int and composite expressions @@ -255,14 +255,14 @@ public Workflow getExpression() { var intToAddResult = wf.declareInt("int-to-add-result"); wf.doIf(intToAdd.isNotEqualTo(null), then -> { // Tests compound expressions - intToAddResult.assignTo(wf.execute("expr-add-one", intToAdd.add(1))); + intToAddResult.assign(wf.execute("expr-add-one", intToAdd.add(1))); }); // Division By Zero test var thingToDivideByZero = wf.declareInt("thing-to-divide-by-zero"); var divideByZeroResult = wf.declareInt("divide-by-zero-result"); wf.doIf(thingToDivideByZero.isNotEqualTo(null), then -> { - divideByZeroResult.assignTo(thingToDivideByZero.divide(0)); + divideByZeroResult.assign(thingToDivideByZero.divide(0)); }); // Test precision of arithmetic. Make use of the fact that we don't have @@ -273,8 +273,8 @@ public Workflow getExpression() { var divisionResultInt = wf.declareInt("division-result-int"); wf.doIf(divisionTestJson.isNotEqualTo(null), then -> { LHExpression foobar = divisionTestJson.jsonPath("$.lhs").divide(divisionTestJson.jsonPath("$.rhs")); - divisionResult.assignTo(foobar); - divisionResultInt.assignTo(foobar); + divisionResult.assign(foobar); + divisionResultInt.assign(foobar); }); // This test uses a complex expression where the things we are computing over @@ -289,20 +289,20 @@ public Workflow getExpression() { // TotalPrice = Quantity * Price * (1 - DiscountPercentage / 100) LHExpression pedro = quantity.multiply(price).multiply(wf.subtract(1.0, discountPercentage.divide(100.0))); - totalPriceInt.assignTo(pedro); - totalPriceDouble.assignTo(pedro); + totalPriceInt.assign(pedro); + totalPriceDouble.assign(pedro); }); // Test mutating sub-fields of a json object var json = wf.declareJsonObj("json"); wf.doIf(json.isNotEqualTo(null), then -> { - json.jsonPath("$.foo").assignTo("bar"); + json.jsonPath("$.foo").assign("bar"); }); // Test mutating doubly-nested fields of a Json Object var nestedJson = wf.declareJsonObj("nested-json"); wf.doIf(nestedJson.isNotEqualTo(null), then -> { - nestedJson.jsonPath("$.foo.bar").assignTo("baz"); + nestedJson.jsonPath("$.foo.bar").assign("baz"); }); }); }