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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Final
from typing import Final, Optional

from localstack.services.stepfunctions.asl.component.common.jsonata.jsonata_template_value import (
JSONataTemplateValue,
Expand All @@ -17,6 +17,9 @@ def __init__(self, identifier: str, value: JSONataTemplateValue):
self.identifier = identifier
self.value = value

def _field_name(self) -> Optional[str]:
return self.identifier

def _eval_body(self, env: Environment) -> None:
binding_container: dict = env.stack.pop()
self.value.eval(env=env)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
from typing import Final, Optional

from localstack.aws.api.stepfunctions import HistoryEventType, TaskFailedEventDetails
from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import (
FailureEvent,
FailureEventException,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name import (
StatesErrorName,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name_type import (
StatesErrorNameType,
)
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
StringJsonPath,
StringSampler,
)
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
from localstack.services.stepfunctions.asl.eval.environment import Environment
from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails
from localstack.services.stepfunctions.asl.utils.json_path import NoSuchJsonPathError


class InputPath(EvalComponent):
Expand All @@ -21,4 +34,20 @@ def _eval_body(self, env: Environment) -> None:
if isinstance(self.string_sampler, StringJsonPath):
# JsonPaths are sampled from a given state, hence pass the state's input.
env.stack.append(env.states.get_input())
self.string_sampler.eval(env=env)
try:
self.string_sampler.eval(env=env)
except NoSuchJsonPathError as no_such_json_path_error:
json_path = no_such_json_path_error.json_path
cause = f"Invalid path '{json_path}' : No results for path: $['{json_path[2:]}']"
raise FailureEventException(
failure_event=FailureEvent(
env=env,
error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime),
event_type=HistoryEventType.TaskFailed,
event_details=EventDetails(
taskFailedEventDetails=TaskFailedEventDetails(
error=StatesErrorNameType.StatesRuntime.to_name(), cause=cause
)
),
)
)
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
from typing import Final, Optional

from localstack.aws.api.stepfunctions import HistoryEventType, TaskFailedEventDetails
from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import (
FailureEvent,
FailureEventException,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name import (
StatesErrorName,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name_type import (
StatesErrorNameType,
)
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
StringSampler,
)
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
from localstack.services.stepfunctions.asl.eval.environment import Environment
from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails
from localstack.services.stepfunctions.asl.utils.json_path import NoSuchJsonPathError


class OutputPath(EvalComponent):
Expand All @@ -17,6 +30,22 @@ def _eval_body(self, env: Environment) -> None:
if self.string_sampler is None:
env.states.reset(input_value=dict())
return
self.string_sampler.eval(env=env)
try:
self.string_sampler.eval(env=env)
except NoSuchJsonPathError as no_such_json_path_error:
json_path = no_such_json_path_error.json_path
cause = f"Invalid path '{json_path}' : No results for path: $['{json_path[2:]}']"
raise FailureEventException(
failure_event=FailureEvent(
env=env,
error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime),
event_type=HistoryEventType.TaskFailed,
event_details=EventDetails(
taskFailedEventDetails=TaskFailedEventDetails(
error=StatesErrorNameType.StatesRuntime.to_name(), cause=cause
)
),
)
)
output_value = env.stack.pop()
env.states.reset(output_value)
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
import abc
from typing import Any, Final
from typing import Any, Final, Optional

from localstack.aws.api.stepfunctions import HistoryEventType, TaskFailedEventDetails
from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import (
FailureEvent,
FailureEventException,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name import (
StatesErrorName,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name_type import (
StatesErrorNameType,
)
from localstack.services.stepfunctions.asl.component.common.payload.payloadvalue.payload_value import (
PayloadValue,
)
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
StringExpressionSimple,
StringJsonPath,
)
from localstack.services.stepfunctions.asl.eval.environment import Environment
from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails
from localstack.services.stepfunctions.asl.utils.encoding import to_json_str


class PayloadBinding(PayloadValue, abc.ABC):
Expand All @@ -30,6 +16,9 @@ class PayloadBinding(PayloadValue, abc.ABC):
def __init__(self, field: str):
self.field = field

def _field_name(self) -> Optional[str]:
return self.field

@abc.abstractmethod
def _eval_val(self, env: Environment) -> Any: ...

Expand All @@ -47,29 +36,11 @@ def __init__(self, field: str, string_expression_simple: StringExpressionSimple)
super().__init__(field=field)
self.string_expression_simple = string_expression_simple

def _eval_val(self, env: Environment) -> Any:
try:
self.string_expression_simple.eval(env=env)
except RuntimeError as runtime_error:
if isinstance(self.string_expression_simple, StringJsonPath):
input_value_str = (
to_json_str(env.stack[1]) if env.stack else "<no input value found>"
)
failure_event = FailureEvent(
env=env,
error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime),
event_type=HistoryEventType.TaskFailed,
event_details=EventDetails(
taskFailedEventDetails=TaskFailedEventDetails(
error=StatesErrorNameType.StatesRuntime.to_name(),
cause=f"The JSONPath {self.string_expression_simple.literal_value} specified for the field {self.field}.$ could not be found in the input {input_value_str}",
)
),
)
raise FailureEventException(failure_event=failure_event)
else:
raise runtime_error
def _field_name(self) -> Optional[str]:
return f"{self.field}.$"

def _eval_val(self, env: Environment) -> Any:
self.string_expression_simple.eval(env=env)
value = env.stack.pop()
return value

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import abc
import copy
from typing import Any, Final
from typing import Any, Final, Optional

from localstack.aws.api.stepfunctions import HistoryEventType, TaskFailedEventDetails
from localstack.services.events.utils import to_json_str
from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import (
FailureEvent,
FailureEventException,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name import (
StatesErrorName,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name_type import (
StatesErrorNameType,
)
from localstack.services.stepfunctions.asl.component.common.query_language import QueryLanguageMode
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
from localstack.services.stepfunctions.asl.component.intrinsic.jsonata import (
get_intrinsic_functions_declarations,
)
from localstack.services.stepfunctions.asl.eval.environment import Environment
from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails
from localstack.services.stepfunctions.asl.jsonata.jsonata import (
JSONataExpression,
VariableDeclarations,
Expand All @@ -19,7 +32,10 @@
from localstack.services.stepfunctions.asl.jsonata.validations import (
validate_jsonata_expression_output,
)
from localstack.services.stepfunctions.asl.utils.json_path import extract_json
from localstack.services.stepfunctions.asl.utils.json_path import (
NoSuchJsonPathError,
extract_json,
)

JSONPATH_ROOT_PATH: Final[str] = "$"

Expand All @@ -30,6 +46,9 @@ class StringExpression(EvalComponent, abc.ABC):
def __init__(self, literal_value: str):
self.literal_value = literal_value

def _field_name(self) -> Optional[str]:
return None


class StringExpressionSimple(StringExpression, abc.ABC): ...

Expand Down Expand Up @@ -60,16 +79,38 @@ def _eval_body(self, env: Environment) -> None:


class StringContextPath(StringJsonPath):
context_object_path: Final[str]

def __init__(self, context_object_path: str):
json_path = context_object_path[1:]
super().__init__(json_path=json_path)
self.context_object_path = context_object_path

def _eval_body(self, env: Environment) -> None:
input_value = env.states.context_object.context_object_data
if self.json_path == JSONPATH_ROOT_PATH:
output_value = input_value
else:
output_value = extract_json(self.json_path, input_value)
try:
output_value = extract_json(self.json_path, input_value)
except NoSuchJsonPathError:
input_value_json_str = to_json_str(input_value)
cause = (
f"The JSONPath '${self.json_path}' specified for the field '{env.next_field_name}' "
f"could not be found in the input '{input_value_json_str}'"
)
raise FailureEventException(
failure_event=FailureEvent(
env=env,
error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime),
event_type=HistoryEventType.TaskFailed,
event_details=EventDetails(
taskFailedEventDetails=TaskFailedEventDetails(
error=StatesErrorNameType.StatesRuntime.to_name(), cause=cause
)
),
)
)
# TODO: introduce copy on write approach
env.stack.append(copy.deepcopy(output_value))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import abc
from typing import Final

from localstack.aws.api.stepfunctions import ExecutionFailedEventDetails, HistoryEventType
from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import (
FailureEvent,
FailureEventException,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name import (
StatesErrorName,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name_type import (
StatesErrorNameType,
)
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
StringJSONata,
StringSampler,
)
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
from localstack.services.stepfunctions.asl.eval.environment import Environment
from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails
from localstack.services.stepfunctions.asl.utils.json_path import NoSuchJsonPathError


class Heartbeat(EvalComponent, abc.ABC):
Expand Down Expand Up @@ -51,7 +64,23 @@ def __init__(self, string_sampler: StringSampler):
self.string_sampler = string_sampler

def _eval_seconds(self, env: Environment) -> int:
self.string_sampler.eval(env=env)
try:
self.string_sampler.eval(env=env)
except NoSuchJsonPathError as no_such_json_path_error:
json_path = no_such_json_path_error.json_path
cause = f"Invalid path '{json_path}' : No results for path: $['{json_path[2:]}']"
raise FailureEventException(
failure_event=FailureEvent(
env=env,
error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime),
event_type=HistoryEventType.ExecutionFailed,
event_details=EventDetails(
executionFailedEventDetails=ExecutionFailedEventDetails(
error=StatesErrorNameType.StatesRuntime.to_name(), cause=cause
)
),
)
)
seconds = env.stack.pop()
if not isinstance(seconds, int) and seconds <= 0:
raise ValueError(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import abc
from typing import Final, Optional

from localstack.aws.api.stepfunctions import (
ExecutionFailedEventDetails,
HistoryEventType,
)
from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import (
FailureEvent,
FailureEventException,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name import (
StatesErrorName,
)
from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name_type import (
StatesErrorNameType,
)
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
StringJSONata,
StringSampler,
)
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
from localstack.services.stepfunctions.asl.eval.environment import Environment
from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails
from localstack.services.stepfunctions.asl.utils.json_path import NoSuchJsonPathError


class EvalTimeoutError(TimeoutError):
Expand Down Expand Up @@ -72,7 +88,23 @@ def is_default_value(self) -> bool:
return False

def _eval_seconds(self, env: Environment) -> int:
self.string_sampler.eval(env=env)
try:
self.string_sampler.eval(env=env)
except NoSuchJsonPathError as no_such_json_path_error:
json_path = no_such_json_path_error.json_path
cause = f"Invalid path '{json_path}' : No results for path: $['{json_path[2:]}']"
raise FailureEventException(
failure_event=FailureEvent(
env=env,
error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime),
event_type=HistoryEventType.ExecutionFailed,
event_details=EventDetails(
executionFailedEventDetails=ExecutionFailedEventDetails(
error=StatesErrorNameType.StatesRuntime.to_name(), cause=cause
)
),
)
)
seconds = env.stack.pop()
if not isinstance(seconds, int) and seconds <= 0:
raise ValueError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ def eval(self, env: Environment) -> None:
if env.is_running():
self._log_evaluation_step("Computing")
try:
field_name = self._field_name()
if field_name is not None:
env.next_field_name = field_name
self._eval_body(env)
except FailureEventException as failure_event_exception:
self._log_failure_event_exception(failure_event_exception=failure_event_exception)
Expand All @@ -78,3 +81,6 @@ def eval(self, env: Environment) -> None:
@abc.abstractmethod
def _eval_body(self, env: Environment) -> None:
raise NotImplementedError()

def _field_name(self) -> Optional[str]:
return self.__class__.__name__
Loading
Loading