dex-python-sdk 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dex/__init__.py +14 -0
- dex/client.py +568 -0
- dex/client_options.py +34 -0
- dex/command_request.py +130 -0
- dex/command_results.py +116 -0
- dex/communication.py +141 -0
- dex/communication_schema.py +68 -0
- dex/data_attributes.py +75 -0
- dex/dexpb/__init__.py +1 -0
- dex/dexpb/dex_pb2.py +305 -0
- dex/dexpb/dex_pb2.pyi +1273 -0
- dex/dexpb/dex_pb2_grpc.py +1126 -0
- dex/errors.py +132 -0
- dex/object_encoder.py +818 -0
- dex/persistence.py +94 -0
- dex/persistence_options.py +24 -0
- dex/persistence_schema.py +58 -0
- dex/py.typed +1 -0
- dex/registry.py +209 -0
- dex/reset_workflow_type_and_options.py +77 -0
- dex/rpc.py +100 -0
- dex/search_attributes.py +189 -0
- dex/state_decision.py +161 -0
- dex/state_execution_locals.py +71 -0
- dex/state_movement.py +123 -0
- dex/state_schema.py +54 -0
- dex/stop_workflow_options.py +23 -0
- dex/tests/__init__.py +84 -0
- dex/tests/dex-service-env/.env +7 -0
- dex/tests/dex-service-env/docker-compose-init.sh +44 -0
- dex/tests/dex-service-env/docker-compose.yml +87 -0
- dex/tests/dex-service-env/dynamicconfig/README.md +39 -0
- dex/tests/dex-service-env/dynamicconfig/development-sql.yaml +6 -0
- dex/tests/dex-service-env/dynamicconfig/docker.yaml +0 -0
- dex/tests/test_abnormal_exit_workflow.py +48 -0
- dex/tests/test_basic_workflow.py +75 -0
- dex/tests/test_conditional_complete.py +56 -0
- dex/tests/test_describe_workflow.py +45 -0
- dex/tests/test_empty_data_decodes_properly.py +79 -0
- dex/tests/test_internal_channel.py +33 -0
- dex/tests/test_internal_channel_with_no_prefix_channel.py +46 -0
- dex/tests/test_persistence_data_attributes.py +67 -0
- dex/tests/test_persistence_search_attributes.py +132 -0
- dex/tests/test_persistence_state_execution_locals.py +43 -0
- dex/tests/test_rpc.py +69 -0
- dex/tests/test_rpc_with_memo.py +200 -0
- dex/tests/test_rpc_with_memo_duplicate_java_tests.py +122 -0
- dex/tests/test_signal.py +56 -0
- dex/tests/test_skip_wait_until.py +85 -0
- dex/tests/test_state_failure_recovery.py +33 -0
- dex/tests/test_timer.py +40 -0
- dex/tests/test_wait_for_state_execution_completion.py +58 -0
- dex/tests/test_workflow_errors.py +92 -0
- dex/tests/test_workflow_state_options.py +123 -0
- dex/tests/test_workflow_state_options_override.py +49 -0
- dex/tests/worker_server.py +74 -0
- dex/tests/workflows/abnormal_exit_workflow.py +48 -0
- dex/tests/workflows/basic_workflow.py +69 -0
- dex/tests/workflows/conditional_complete_workflow.py +101 -0
- dex/tests/workflows/describe_workflow.py +52 -0
- dex/tests/workflows/empty_data_workflow.py +51 -0
- dex/tests/workflows/internal_channel_workflow.py +137 -0
- dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py +108 -0
- dex/tests/workflows/java_duplicate_rpc_memo_workflow.py +285 -0
- dex/tests/workflows/persistence_data_attributes_workflow.py +104 -0
- dex/tests/workflows/persistence_search_attributes_workflow.py +167 -0
- dex/tests/workflows/persistence_state_execution_local_workflow.py +69 -0
- dex/tests/workflows/recovery_workflow.py +90 -0
- dex/tests/workflows/rpc_memo_workflow.py +238 -0
- dex/tests/workflows/rpc_workflow.py +125 -0
- dex/tests/workflows/state_options_override_workflow.py +100 -0
- dex/tests/workflows/state_options_workflow.py +92 -0
- dex/tests/workflows/timer_workflow.py +52 -0
- dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py +77 -0
- dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py +78 -0
- dex/tests/workflows/wait_internal_channel_workflow.py +53 -0
- dex/tests/workflows/wait_signal_workflow.py +154 -0
- dex/type_store.py +105 -0
- dex/unregistered_client.py +595 -0
- dex/utils/__init__.py +14 -0
- dex/utils/dex_typing.py +31 -0
- dex/utils/persistence_utils.py +37 -0
- dex/worker_service.py +441 -0
- dex/workflow.py +86 -0
- dex/workflow_context.py +50 -0
- dex/workflow_info.py +21 -0
- dex/workflow_options.py +79 -0
- dex/workflow_state.py +134 -0
- dex/workflow_state_options.py +160 -0
- dex_python_sdk-0.0.1.dist-info/METADATA +140 -0
- dex_python_sdk-0.0.1.dist-info/RECORD +93 -0
- dex_python_sdk-0.0.1.dist-info/WHEEL +4 -0
- dex_python_sdk-0.0.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.command_request import CommandRequest, TimerCommand
|
|
16
|
+
from dex.command_results import CommandResults
|
|
17
|
+
from dex.communication import Communication
|
|
18
|
+
from dex.persistence import Persistence
|
|
19
|
+
from dex.state_decision import StateDecision
|
|
20
|
+
from dex.state_schema import StateSchema
|
|
21
|
+
from dex.workflow import ObjectWorkflow
|
|
22
|
+
from dex.workflow_context import WorkflowContext
|
|
23
|
+
from dex.workflow_state import T, WorkflowState
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WaitForStateWithStateExecutionIdState1(WorkflowState[None]):
|
|
27
|
+
def wait_until(
|
|
28
|
+
self,
|
|
29
|
+
ctx: WorkflowContext,
|
|
30
|
+
input: T,
|
|
31
|
+
persistence: Persistence,
|
|
32
|
+
communication: Communication,
|
|
33
|
+
) -> CommandRequest:
|
|
34
|
+
return CommandRequest.for_all_command_completed(
|
|
35
|
+
TimerCommand.by_seconds(2),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def execute(
|
|
39
|
+
self,
|
|
40
|
+
ctx: WorkflowContext,
|
|
41
|
+
input: T,
|
|
42
|
+
command_results: CommandResults,
|
|
43
|
+
persistence: Persistence,
|
|
44
|
+
communication: Communication,
|
|
45
|
+
) -> StateDecision:
|
|
46
|
+
return StateDecision.single_next_state(WaitForStateWithStateExecutionIdState2)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class WaitForStateWithStateExecutionIdState2(WorkflowState[None]):
|
|
50
|
+
def wait_until(
|
|
51
|
+
self,
|
|
52
|
+
ctx: WorkflowContext,
|
|
53
|
+
input: T,
|
|
54
|
+
persistence: Persistence,
|
|
55
|
+
communication: Communication,
|
|
56
|
+
) -> CommandRequest:
|
|
57
|
+
return CommandRequest.for_all_command_completed(
|
|
58
|
+
TimerCommand.by_seconds(2),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def execute(
|
|
62
|
+
self,
|
|
63
|
+
ctx: WorkflowContext,
|
|
64
|
+
input: T,
|
|
65
|
+
command_results: CommandResults,
|
|
66
|
+
persistence: Persistence,
|
|
67
|
+
communication: Communication,
|
|
68
|
+
) -> StateDecision:
|
|
69
|
+
return StateDecision.graceful_complete_workflow()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class WaitForStateWithStateExecutionIdWorkflow(ObjectWorkflow):
|
|
73
|
+
def get_workflow_states(self) -> StateSchema:
|
|
74
|
+
return StateSchema.with_starting_state(
|
|
75
|
+
WaitForStateWithStateExecutionIdState1(),
|
|
76
|
+
WaitForStateWithStateExecutionIdState2(),
|
|
77
|
+
)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.command_request import CommandRequest, TimerCommand
|
|
16
|
+
from dex.command_results import CommandResults
|
|
17
|
+
from dex.communication import Communication
|
|
18
|
+
from dex.persistence import Persistence
|
|
19
|
+
from dex.state_decision import StateDecision
|
|
20
|
+
from dex.state_schema import StateSchema
|
|
21
|
+
from dex.workflow import ObjectWorkflow
|
|
22
|
+
from dex.workflow_context import WorkflowContext
|
|
23
|
+
from dex.workflow_state import T, WorkflowState
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WaitForStateWithWaitForKeyState1(WorkflowState[None]):
|
|
27
|
+
def wait_until(
|
|
28
|
+
self,
|
|
29
|
+
ctx: WorkflowContext,
|
|
30
|
+
input: T,
|
|
31
|
+
persistence: Persistence,
|
|
32
|
+
communication: Communication,
|
|
33
|
+
) -> CommandRequest:
|
|
34
|
+
return CommandRequest.for_all_command_completed(
|
|
35
|
+
TimerCommand.by_seconds(2),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def execute(
|
|
39
|
+
self,
|
|
40
|
+
ctx: WorkflowContext,
|
|
41
|
+
input: T,
|
|
42
|
+
command_results: CommandResults,
|
|
43
|
+
persistence: Persistence,
|
|
44
|
+
communication: Communication,
|
|
45
|
+
) -> StateDecision:
|
|
46
|
+
return StateDecision.single_next_state(
|
|
47
|
+
WaitForStateWithWaitForKeyState2, None, None, "testKey"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class WaitForStateWithWaitForKeyState2(WorkflowState[None]):
|
|
52
|
+
def wait_until(
|
|
53
|
+
self,
|
|
54
|
+
ctx: WorkflowContext,
|
|
55
|
+
input: T,
|
|
56
|
+
persistence: Persistence,
|
|
57
|
+
communication: Communication,
|
|
58
|
+
) -> CommandRequest:
|
|
59
|
+
return CommandRequest.for_all_command_completed(
|
|
60
|
+
TimerCommand.by_seconds(2),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def execute(
|
|
64
|
+
self,
|
|
65
|
+
ctx: WorkflowContext,
|
|
66
|
+
input: T,
|
|
67
|
+
command_results: CommandResults,
|
|
68
|
+
persistence: Persistence,
|
|
69
|
+
communication: Communication,
|
|
70
|
+
) -> StateDecision:
|
|
71
|
+
return StateDecision.graceful_complete_workflow()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class WaitForStateWithWaitForKeyWorkflow(ObjectWorkflow):
|
|
75
|
+
def get_workflow_states(self) -> StateSchema:
|
|
76
|
+
return StateSchema.with_starting_state(
|
|
77
|
+
WaitForStateWithWaitForKeyState1(), WaitForStateWithWaitForKeyState2()
|
|
78
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.command_request import CommandRequest, InternalChannelCommand
|
|
16
|
+
from dex.command_results import CommandResults
|
|
17
|
+
from dex.communication import Communication
|
|
18
|
+
from dex.persistence import Persistence
|
|
19
|
+
from dex.state_decision import StateDecision
|
|
20
|
+
from dex.state_schema import StateSchema
|
|
21
|
+
from dex.workflow import ObjectWorkflow
|
|
22
|
+
from dex.workflow_context import WorkflowContext
|
|
23
|
+
from dex.workflow_state import T, WorkflowState
|
|
24
|
+
|
|
25
|
+
test_channel_name = "test-name"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class WaitState(WorkflowState[None]):
|
|
29
|
+
def wait_until(
|
|
30
|
+
self,
|
|
31
|
+
ctx: WorkflowContext,
|
|
32
|
+
input: T,
|
|
33
|
+
persistence: Persistence,
|
|
34
|
+
communication: Communication,
|
|
35
|
+
) -> CommandRequest:
|
|
36
|
+
return CommandRequest.for_all_command_completed(
|
|
37
|
+
InternalChannelCommand.by_name(test_channel_name)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def execute(
|
|
41
|
+
self,
|
|
42
|
+
ctx: WorkflowContext,
|
|
43
|
+
input: T,
|
|
44
|
+
command_results: CommandResults,
|
|
45
|
+
persistence: Persistence,
|
|
46
|
+
communication: Communication,
|
|
47
|
+
) -> StateDecision:
|
|
48
|
+
return StateDecision.graceful_complete_workflow()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class WaitInternalChannelWorkflow(ObjectWorkflow):
|
|
52
|
+
def get_workflow_states(self) -> StateSchema:
|
|
53
|
+
return StateSchema.with_starting_state(WaitState())
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from dex.dex_api.models.timer_result import TimerStatus
|
|
16
|
+
from dex.command_request import (
|
|
17
|
+
CommandRequest,
|
|
18
|
+
SignalChannelCommand,
|
|
19
|
+
TimerCommand,
|
|
20
|
+
)
|
|
21
|
+
from dex.command_results import (
|
|
22
|
+
CommandResults,
|
|
23
|
+
SignalChannelCommandResult,
|
|
24
|
+
TimerCommandResult,
|
|
25
|
+
)
|
|
26
|
+
from dex.communication import Communication
|
|
27
|
+
from dex.communication_schema import CommunicationMethod, CommunicationSchema
|
|
28
|
+
from dex.dex_api.models import ChannelRequestStatus
|
|
29
|
+
from dex.persistence import Persistence
|
|
30
|
+
from dex.rpc import rpc
|
|
31
|
+
from dex.state_decision import StateDecision
|
|
32
|
+
from dex.state_schema import StateSchema
|
|
33
|
+
from dex.workflow import ObjectWorkflow
|
|
34
|
+
from dex.workflow_context import WorkflowContext
|
|
35
|
+
from dex.workflow_state import T, WorkflowState
|
|
36
|
+
|
|
37
|
+
test_channel_int = "test-int"
|
|
38
|
+
test_channel_none = "test-none"
|
|
39
|
+
test_channel_str = "test-str"
|
|
40
|
+
test_idle_channel_none = "test-idle"
|
|
41
|
+
|
|
42
|
+
test_channel1 = "test-channel1"
|
|
43
|
+
test_channel1_id = "test-channel1-id"
|
|
44
|
+
test_channel2 = "test-channel2"
|
|
45
|
+
test_channel2_id = "test-channel2-id"
|
|
46
|
+
test_timer_id = "test-timer-id"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class WaitState1(WorkflowState[None]):
|
|
50
|
+
def wait_until(
|
|
51
|
+
self,
|
|
52
|
+
ctx: WorkflowContext,
|
|
53
|
+
input: T,
|
|
54
|
+
persistence: Persistence,
|
|
55
|
+
communication: Communication,
|
|
56
|
+
) -> CommandRequest:
|
|
57
|
+
return CommandRequest.for_all_command_completed(
|
|
58
|
+
SignalChannelCommand.by_name(test_channel_int),
|
|
59
|
+
SignalChannelCommand.by_name(test_channel_none),
|
|
60
|
+
SignalChannelCommand.by_name(test_channel_str),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def execute(
|
|
64
|
+
self,
|
|
65
|
+
ctx: WorkflowContext,
|
|
66
|
+
input: T,
|
|
67
|
+
command_results: CommandResults,
|
|
68
|
+
persistence: Persistence,
|
|
69
|
+
communication: Communication,
|
|
70
|
+
) -> StateDecision:
|
|
71
|
+
assert len(command_results.signal_channel_commands) == 3
|
|
72
|
+
sig1 = command_results.signal_channel_commands[0]
|
|
73
|
+
sig2 = command_results.signal_channel_commands[1]
|
|
74
|
+
sig3 = command_results.signal_channel_commands[2]
|
|
75
|
+
assert sig1 == SignalChannelCommandResult(
|
|
76
|
+
test_channel_int, 123, ChannelRequestStatus.RECEIVED, ""
|
|
77
|
+
)
|
|
78
|
+
assert sig2 == SignalChannelCommandResult(
|
|
79
|
+
test_channel_none, None, ChannelRequestStatus.RECEIVED, ""
|
|
80
|
+
)
|
|
81
|
+
assert sig3 == SignalChannelCommandResult(
|
|
82
|
+
test_channel_str, "abc", ChannelRequestStatus.RECEIVED, ""
|
|
83
|
+
)
|
|
84
|
+
return StateDecision.single_next_state(WaitState2, sig3.value)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class WaitState2(WorkflowState[str]):
|
|
88
|
+
def wait_until(
|
|
89
|
+
self,
|
|
90
|
+
ctx: WorkflowContext,
|
|
91
|
+
input: str,
|
|
92
|
+
persistence: Persistence,
|
|
93
|
+
communication: Communication,
|
|
94
|
+
) -> CommandRequest:
|
|
95
|
+
return CommandRequest.for_any_command_combination_completed(
|
|
96
|
+
[
|
|
97
|
+
[
|
|
98
|
+
test_channel1_id,
|
|
99
|
+
test_timer_id,
|
|
100
|
+
]
|
|
101
|
+
],
|
|
102
|
+
SignalChannelCommand.by_name(test_channel1, test_channel1_id),
|
|
103
|
+
SignalChannelCommand.by_name(test_channel2, test_channel2_id),
|
|
104
|
+
TimerCommand.by_seconds(1, test_timer_id),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def execute(
|
|
108
|
+
self,
|
|
109
|
+
ctx: WorkflowContext,
|
|
110
|
+
input: str,
|
|
111
|
+
command_results: CommandResults,
|
|
112
|
+
persistence: Persistence,
|
|
113
|
+
communication: Communication,
|
|
114
|
+
) -> StateDecision:
|
|
115
|
+
assert len(command_results.signal_channel_commands) == 2
|
|
116
|
+
assert (
|
|
117
|
+
len(
|
|
118
|
+
[
|
|
119
|
+
r
|
|
120
|
+
for r in command_results.signal_channel_commands
|
|
121
|
+
if r.status == ChannelRequestStatus.RECEIVED
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
== 1
|
|
125
|
+
)
|
|
126
|
+
sig1 = command_results.signal_channel_commands[0]
|
|
127
|
+
tim1 = command_results.timer_commands[0]
|
|
128
|
+
assert sig1 == SignalChannelCommandResult(
|
|
129
|
+
test_channel1, None, ChannelRequestStatus.RECEIVED, test_channel1_id
|
|
130
|
+
)
|
|
131
|
+
assert tim1 == TimerCommandResult(
|
|
132
|
+
TimerStatus.FIRED,
|
|
133
|
+
test_timer_id,
|
|
134
|
+
)
|
|
135
|
+
return StateDecision.graceful_complete_workflow(input)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class WaitSignalWorkflow(ObjectWorkflow):
|
|
139
|
+
def get_communication_schema(self) -> CommunicationSchema:
|
|
140
|
+
return CommunicationSchema.create(
|
|
141
|
+
CommunicationMethod.signal_channel_def(test_channel_int, int),
|
|
142
|
+
CommunicationMethod.signal_channel_def(test_channel_none, None),
|
|
143
|
+
CommunicationMethod.signal_channel_def(test_channel_str, str),
|
|
144
|
+
CommunicationMethod.signal_channel_def(test_idle_channel_none, None),
|
|
145
|
+
CommunicationMethod.signal_channel_def(test_channel1, None),
|
|
146
|
+
CommunicationMethod.signal_channel_def(test_channel2, None),
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def get_workflow_states(self) -> StateSchema:
|
|
150
|
+
return StateSchema.with_starting_state(WaitState1(), WaitState2())
|
|
151
|
+
|
|
152
|
+
@rpc()
|
|
153
|
+
def get_idle_signal_channel_size(self, com: Communication):
|
|
154
|
+
return com.get_signal_channel_size(test_idle_channel_none)
|
dex/type_store.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from typing import Optional
|
|
16
|
+
from enum import Enum
|
|
17
|
+
|
|
18
|
+
from dex.communication_schema import CommunicationMethod
|
|
19
|
+
from dex.errors import WorkflowDefinitionError, NotRegisteredError
|
|
20
|
+
from dex.persistence_schema import PersistenceField, PersistenceFieldType
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Type(Enum):
|
|
24
|
+
INTERNAL_CHANNEL = 1
|
|
25
|
+
DATA_ATTRIBUTE = 2
|
|
26
|
+
# TODO: extend to other types
|
|
27
|
+
# SIGNAL_CHANNEL = 3
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TypeStore:
|
|
31
|
+
_class_type: Type
|
|
32
|
+
_name_to_type_store: dict[str, Optional[type]]
|
|
33
|
+
_prefix_to_type_store: dict[str, Optional[type]]
|
|
34
|
+
|
|
35
|
+
def __init__(self, class_type: Type):
|
|
36
|
+
self._class_type = class_type
|
|
37
|
+
self._name_to_type_store = dict()
|
|
38
|
+
self._prefix_to_type_store = dict()
|
|
39
|
+
|
|
40
|
+
def is_valid_name_or_prefix(self, name: str) -> bool:
|
|
41
|
+
return self._validate_name(name)
|
|
42
|
+
|
|
43
|
+
def get_type(self, name: str) -> type:
|
|
44
|
+
is_registered = self._validate_name(name)
|
|
45
|
+
|
|
46
|
+
if not is_registered:
|
|
47
|
+
raise NotRegisteredError(f"{self._class_type} not registered: {name}")
|
|
48
|
+
|
|
49
|
+
t = self._do_get_type(name)
|
|
50
|
+
if t is None:
|
|
51
|
+
raise NotRegisteredError(f"{self._class_type} not registered: {name}")
|
|
52
|
+
|
|
53
|
+
return t
|
|
54
|
+
|
|
55
|
+
def add_internal_channel_def(self, obj: CommunicationMethod):
|
|
56
|
+
if self._class_type != Type.INTERNAL_CHANNEL:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
f"Cannot add internal channel definition to {self._class_type}"
|
|
59
|
+
)
|
|
60
|
+
self._do_add_to_store(obj.is_prefix, obj.name, obj.value_type)
|
|
61
|
+
|
|
62
|
+
def add_data_attribute_def(self, obj: PersistenceField):
|
|
63
|
+
if self._class_type != Type.DATA_ATTRIBUTE:
|
|
64
|
+
raise ValueError(
|
|
65
|
+
f"Cannot add internal channel definition to {self._class_type}"
|
|
66
|
+
)
|
|
67
|
+
self._do_add_to_store(
|
|
68
|
+
obj.field_type == PersistenceFieldType.DataAttributePrefix,
|
|
69
|
+
obj.key,
|
|
70
|
+
obj.value_type,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def _validate_name(self, name: str) -> bool:
|
|
74
|
+
if name in self._name_to_type_store:
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
for prefix in self._prefix_to_type_store.keys():
|
|
78
|
+
if name.startswith(prefix):
|
|
79
|
+
return True
|
|
80
|
+
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
def _do_get_type(self, name: str) -> Optional[type]:
|
|
84
|
+
if name in self._name_to_type_store:
|
|
85
|
+
t = self._name_to_type_store[name]
|
|
86
|
+
return t if t is not None else type(None)
|
|
87
|
+
|
|
88
|
+
for prefix, t in self._prefix_to_type_store.items():
|
|
89
|
+
if name.startswith(prefix):
|
|
90
|
+
return t if t is not None else type(None)
|
|
91
|
+
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
def _do_add_to_store(self, is_prefix: bool, name: str, t: Optional[type]):
|
|
95
|
+
if is_prefix:
|
|
96
|
+
store = self._prefix_to_type_store
|
|
97
|
+
else:
|
|
98
|
+
store = self._name_to_type_store
|
|
99
|
+
|
|
100
|
+
if name in store:
|
|
101
|
+
raise WorkflowDefinitionError(
|
|
102
|
+
f"{self._class_type} name/prefix {name} already exists"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
store[name] = t
|