dex-python-sdk 0.0.2__cp311-abi3-win_amd64.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.
Files changed (121) hide show
  1. dex/__init__.py +146 -0
  2. dex/_grpc_errors.py +73 -0
  3. dex/_invocation_context.py +269 -0
  4. dex/_native.pyd +0 -0
  5. dex/_native.pyi +20 -0
  6. dex/_utils.py +18 -0
  7. dex/_value_hydrator.py +223 -0
  8. dex/_value_mapper.py +174 -0
  9. dex/_worker_dispatcher.py +451 -0
  10. dex/_worker_service.py +60 -0
  11. dex/attribute.py +87 -0
  12. dex/blob_cache.py +73 -0
  13. dex/channel.py +165 -0
  14. dex/client.py +715 -0
  15. dex/client_options.py +19 -0
  16. dex/codec.py +286 -0
  17. dex/command_request.py +120 -0
  18. dex/command_results.py +107 -0
  19. dex/communication.py +136 -0
  20. dex/communication_schema.py +54 -0
  21. dex/condition.py +74 -0
  22. dex/context.py +86 -0
  23. dex/data_attributes.py +70 -0
  24. dex/dexpb/__init__.py +1 -0
  25. dex/dexpb/dex_pb2.py +381 -0
  26. dex/dexpb/dex_pb2.pyi +1734 -0
  27. dex/dexpb/dex_pb2_grpc.py +1298 -0
  28. dex/errors.py +109 -0
  29. dex/flow.py +456 -0
  30. dex/flow_config.py +29 -0
  31. dex/flow_info.py +51 -0
  32. dex/flow_options.py +122 -0
  33. dex/object_encoder.py +799 -0
  34. dex/persistence.py +89 -0
  35. dex/persistence_options.py +12 -0
  36. dex/persistence_schema.py +51 -0
  37. dex/py.typed +1 -0
  38. dex/registry.py +204 -0
  39. dex/reset_workflow_type_and_options.py +67 -0
  40. dex/rpc.py +93 -0
  41. dex/runtime_errors.py +81 -0
  42. dex/search_attributes.py +184 -0
  43. dex/state_decision.py +153 -0
  44. dex/state_execution_locals.py +66 -0
  45. dex/state_movement.py +115 -0
  46. dex/state_schema.py +48 -0
  47. dex/step.py +194 -0
  48. dex/step_execution.py +42 -0
  49. dex/stop_workflow_options.py +18 -0
  50. dex/tests/__init__.py +80 -0
  51. dex/tests/dex-service-env/.env +7 -0
  52. dex/tests/dex-service-env/docker-compose-init.sh +44 -0
  53. dex/tests/dex-service-env/docker-compose.yml +97 -0
  54. dex/tests/dex-service-env/dynamicconfig/README.md +39 -0
  55. dex/tests/dex-service-env/dynamicconfig/development-sql.yaml +9 -0
  56. dex/tests/dex-service-env/dynamicconfig/docker.yaml +2 -0
  57. dex/tests/test_abnormal_exit_workflow.py +43 -0
  58. dex/tests/test_basic_workflow.py +70 -0
  59. dex/tests/test_conditional_complete.py +50 -0
  60. dex/tests/test_describe_workflow.py +40 -0
  61. dex/tests/test_empty_data_decodes_properly.py +74 -0
  62. dex/tests/test_internal_channel.py +28 -0
  63. dex/tests/test_internal_channel_with_no_prefix_channel.py +41 -0
  64. dex/tests/test_persistence_data_attributes.py +62 -0
  65. dex/tests/test_persistence_search_attributes.py +127 -0
  66. dex/tests/test_persistence_state_execution_locals.py +38 -0
  67. dex/tests/test_rpc.py +64 -0
  68. dex/tests/test_rpc_with_memo.py +195 -0
  69. dex/tests/test_rpc_with_memo_duplicate_java_tests.py +117 -0
  70. dex/tests/test_signal.py +51 -0
  71. dex/tests/test_skip_wait_until.py +76 -0
  72. dex/tests/test_state_failure_recovery.py +28 -0
  73. dex/tests/test_timer.py +35 -0
  74. dex/tests/test_wait_for_state_execution_completion.py +53 -0
  75. dex/tests/test_workflow_errors.py +87 -0
  76. dex/tests/test_workflow_state_options.py +118 -0
  77. dex/tests/test_workflow_state_options_override.py +44 -0
  78. dex/tests/worker_server.py +64 -0
  79. dex/tests/workflows/abnormal_exit_workflow.py +42 -0
  80. dex/tests/workflows/basic_workflow.py +62 -0
  81. dex/tests/workflows/conditional_complete_workflow.py +95 -0
  82. dex/tests/workflows/describe_workflow.py +46 -0
  83. dex/tests/workflows/empty_data_workflow.py +45 -0
  84. dex/tests/workflows/internal_channel_workflow.py +129 -0
  85. dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py +100 -0
  86. dex/tests/workflows/java_duplicate_rpc_memo_workflow.py +276 -0
  87. dex/tests/workflows/persistence_data_attributes_workflow.py +98 -0
  88. dex/tests/workflows/persistence_search_attributes_workflow.py +159 -0
  89. dex/tests/workflows/persistence_state_execution_local_workflow.py +63 -0
  90. dex/tests/workflows/recovery_workflow.py +82 -0
  91. dex/tests/workflows/rpc_memo_workflow.py +231 -0
  92. dex/tests/workflows/rpc_workflow.py +117 -0
  93. dex/tests/workflows/state_options_override_workflow.py +93 -0
  94. dex/tests/workflows/state_options_workflow.py +84 -0
  95. dex/tests/workflows/timer_workflow.py +46 -0
  96. dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py +70 -0
  97. dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py +71 -0
  98. dex/tests/workflows/wait_internal_channel_workflow.py +47 -0
  99. dex/tests/workflows/wait_signal_workflow.py +147 -0
  100. dex/timer.py +21 -0
  101. dex/type_store.py +99 -0
  102. dex/unregistered_client.py +585 -0
  103. dex/utils/__init__.py +3 -0
  104. dex/utils/dex_typing.py +25 -0
  105. dex/utils/persistence_utils.py +32 -0
  106. dex/wait.py +49 -0
  107. dex/worker.py +121 -0
  108. dex/worker_options.py +22 -0
  109. dex/worker_service.py +432 -0
  110. dex/workflow.py +79 -0
  111. dex/workflow_context.py +44 -0
  112. dex/workflow_info.py +16 -0
  113. dex/workflow_options.py +74 -0
  114. dex/workflow_state.py +123 -0
  115. dex/workflow_state_options.py +154 -0
  116. dex_python_sdk-0.0.2.dist-info/METADATA +202 -0
  117. dex_python_sdk-0.0.2.dist-info/RECORD +121 -0
  118. dex_python_sdk-0.0.2.dist-info/WHEEL +4 -0
  119. dex_python_sdk-0.0.2.dist-info/licenses/LEGACY_NOTICES.md +61 -0
  120. dex_python_sdk-0.0.2.dist-info/licenses/LICENSE +192 -0
  121. dex_python_sdk-0.0.2.dist-info/sboms/dex-blob-cache-python.cyclonedx.json +2406 -0
@@ -0,0 +1,70 @@
1
+ # Legacy Materials in this file remain under their original licenses.
2
+ # See LEGACY_NOTICES.md.
3
+
4
+ # Modifications Copyright (c) 2026 Super Durable, Inc.
5
+ #
6
+ # Modifications after the Legacy Cutoff are licensed under the
7
+ # Super Durable Source License 1.0.
8
+ # Legacy Materials remain under their original licenses.
9
+ # See LICENSE and LEGACY_NOTICES.md.
10
+
11
+ from dex.command_request import CommandRequest, TimerCommand
12
+ from dex.command_results import CommandResults
13
+ from dex.communication import Communication
14
+ from dex.persistence import Persistence
15
+ from dex.state_decision import StateDecision
16
+ from dex.state_schema import StateSchema
17
+ from dex.workflow import ObjectWorkflow
18
+ from dex.workflow_context import WorkflowContext
19
+ from dex.workflow_state import T, WorkflowState
20
+
21
+ class WaitForStateWithStateExecutionIdState1(WorkflowState[None]):
22
+ def wait_until(
23
+ self,
24
+ ctx: WorkflowContext,
25
+ input: T,
26
+ persistence: Persistence,
27
+ communication: Communication,
28
+ ) -> CommandRequest:
29
+ return CommandRequest.for_all_command_completed(
30
+ TimerCommand.by_seconds(2),
31
+ )
32
+
33
+ def execute(
34
+ self,
35
+ ctx: WorkflowContext,
36
+ input: T,
37
+ command_results: CommandResults,
38
+ persistence: Persistence,
39
+ communication: Communication,
40
+ ) -> StateDecision:
41
+ return StateDecision.single_next_state(WaitForStateWithStateExecutionIdState2)
42
+
43
+ class WaitForStateWithStateExecutionIdState2(WorkflowState[None]):
44
+ def wait_until(
45
+ self,
46
+ ctx: WorkflowContext,
47
+ input: T,
48
+ persistence: Persistence,
49
+ communication: Communication,
50
+ ) -> CommandRequest:
51
+ return CommandRequest.for_all_command_completed(
52
+ TimerCommand.by_seconds(2),
53
+ )
54
+
55
+ def execute(
56
+ self,
57
+ ctx: WorkflowContext,
58
+ input: T,
59
+ command_results: CommandResults,
60
+ persistence: Persistence,
61
+ communication: Communication,
62
+ ) -> StateDecision:
63
+ return StateDecision.graceful_complete_workflow()
64
+
65
+ class WaitForStateWithStateExecutionIdWorkflow(ObjectWorkflow):
66
+ def get_workflow_states(self) -> StateSchema:
67
+ return StateSchema.with_starting_state(
68
+ WaitForStateWithStateExecutionIdState1(),
69
+ WaitForStateWithStateExecutionIdState2(),
70
+ )
@@ -0,0 +1,71 @@
1
+ # Legacy Materials in this file remain under their original licenses.
2
+ # See LEGACY_NOTICES.md.
3
+
4
+ # Modifications Copyright (c) 2026 Super Durable, Inc.
5
+ #
6
+ # Modifications after the Legacy Cutoff are licensed under the
7
+ # Super Durable Source License 1.0.
8
+ # Legacy Materials remain under their original licenses.
9
+ # See LICENSE and LEGACY_NOTICES.md.
10
+
11
+ from dex.command_request import CommandRequest, TimerCommand
12
+ from dex.command_results import CommandResults
13
+ from dex.communication import Communication
14
+ from dex.persistence import Persistence
15
+ from dex.state_decision import StateDecision
16
+ from dex.state_schema import StateSchema
17
+ from dex.workflow import ObjectWorkflow
18
+ from dex.workflow_context import WorkflowContext
19
+ from dex.workflow_state import T, WorkflowState
20
+
21
+ class WaitForStateWithWaitForKeyState1(WorkflowState[None]):
22
+ def wait_until(
23
+ self,
24
+ ctx: WorkflowContext,
25
+ input: T,
26
+ persistence: Persistence,
27
+ communication: Communication,
28
+ ) -> CommandRequest:
29
+ return CommandRequest.for_all_command_completed(
30
+ TimerCommand.by_seconds(2),
31
+ )
32
+
33
+ def execute(
34
+ self,
35
+ ctx: WorkflowContext,
36
+ input: T,
37
+ command_results: CommandResults,
38
+ persistence: Persistence,
39
+ communication: Communication,
40
+ ) -> StateDecision:
41
+ return StateDecision.single_next_state(
42
+ WaitForStateWithWaitForKeyState2, None, None, "testKey"
43
+ )
44
+
45
+ class WaitForStateWithWaitForKeyState2(WorkflowState[None]):
46
+ def wait_until(
47
+ self,
48
+ ctx: WorkflowContext,
49
+ input: T,
50
+ persistence: Persistence,
51
+ communication: Communication,
52
+ ) -> CommandRequest:
53
+ return CommandRequest.for_all_command_completed(
54
+ TimerCommand.by_seconds(2),
55
+ )
56
+
57
+ def execute(
58
+ self,
59
+ ctx: WorkflowContext,
60
+ input: T,
61
+ command_results: CommandResults,
62
+ persistence: Persistence,
63
+ communication: Communication,
64
+ ) -> StateDecision:
65
+ return StateDecision.graceful_complete_workflow()
66
+
67
+ class WaitForStateWithWaitForKeyWorkflow(ObjectWorkflow):
68
+ def get_workflow_states(self) -> StateSchema:
69
+ return StateSchema.with_starting_state(
70
+ WaitForStateWithWaitForKeyState1(), WaitForStateWithWaitForKeyState2()
71
+ )
@@ -0,0 +1,47 @@
1
+ # Legacy Materials in this file remain under their original licenses.
2
+ # See LEGACY_NOTICES.md.
3
+
4
+ # Modifications Copyright (c) 2026 Super Durable, Inc.
5
+ #
6
+ # Modifications after the Legacy Cutoff are licensed under the
7
+ # Super Durable Source License 1.0.
8
+ # Legacy Materials remain under their original licenses.
9
+ # See LICENSE and LEGACY_NOTICES.md.
10
+
11
+ from dex.command_request import CommandRequest, InternalChannelCommand
12
+ from dex.command_results import CommandResults
13
+ from dex.communication import Communication
14
+ from dex.persistence import Persistence
15
+ from dex.state_decision import StateDecision
16
+ from dex.state_schema import StateSchema
17
+ from dex.workflow import ObjectWorkflow
18
+ from dex.workflow_context import WorkflowContext
19
+ from dex.workflow_state import T, WorkflowState
20
+
21
+ test_channel_name = "test-name"
22
+
23
+ class WaitState(WorkflowState[None]):
24
+ def wait_until(
25
+ self,
26
+ ctx: WorkflowContext,
27
+ input: T,
28
+ persistence: Persistence,
29
+ communication: Communication,
30
+ ) -> CommandRequest:
31
+ return CommandRequest.for_all_command_completed(
32
+ InternalChannelCommand.by_name(test_channel_name)
33
+ )
34
+
35
+ def execute(
36
+ self,
37
+ ctx: WorkflowContext,
38
+ input: T,
39
+ command_results: CommandResults,
40
+ persistence: Persistence,
41
+ communication: Communication,
42
+ ) -> StateDecision:
43
+ return StateDecision.graceful_complete_workflow()
44
+
45
+ class WaitInternalChannelWorkflow(ObjectWorkflow):
46
+ def get_workflow_states(self) -> StateSchema:
47
+ return StateSchema.with_starting_state(WaitState())
@@ -0,0 +1,147 @@
1
+ # Legacy Materials in this file remain under their original licenses.
2
+ # See LEGACY_NOTICES.md.
3
+
4
+ # Modifications Copyright (c) 2026 Super Durable, Inc.
5
+ #
6
+ # Modifications after the Legacy Cutoff are licensed under the
7
+ # Super Durable Source License 1.0.
8
+ # Legacy Materials remain under their original licenses.
9
+ # See LICENSE and LEGACY_NOTICES.md.
10
+
11
+ from dex.dex_api.models.timer_result import TimerStatus
12
+ from dex.command_request import (
13
+ CommandRequest,
14
+ SignalChannelCommand,
15
+ TimerCommand,
16
+ )
17
+ from dex.command_results import (
18
+ CommandResults,
19
+ SignalChannelCommandResult,
20
+ TimerCommandResult,
21
+ )
22
+ from dex.communication import Communication
23
+ from dex.communication_schema import CommunicationMethod, CommunicationSchema
24
+ from dex.dex_api.models import ChannelRequestStatus
25
+ from dex.persistence import Persistence
26
+ from dex.rpc import rpc
27
+ from dex.state_decision import StateDecision
28
+ from dex.state_schema import StateSchema
29
+ from dex.workflow import ObjectWorkflow
30
+ from dex.workflow_context import WorkflowContext
31
+ from dex.workflow_state import T, WorkflowState
32
+
33
+ test_channel_int = "test-int"
34
+ test_channel_none = "test-none"
35
+ test_channel_str = "test-str"
36
+ test_idle_channel_none = "test-idle"
37
+
38
+ test_channel1 = "test-channel1"
39
+ test_channel1_id = "test-channel1-id"
40
+ test_channel2 = "test-channel2"
41
+ test_channel2_id = "test-channel2-id"
42
+ test_timer_id = "test-timer-id"
43
+
44
+ class WaitState1(WorkflowState[None]):
45
+ def wait_until(
46
+ self,
47
+ ctx: WorkflowContext,
48
+ input: T,
49
+ persistence: Persistence,
50
+ communication: Communication,
51
+ ) -> CommandRequest:
52
+ return CommandRequest.for_all_command_completed(
53
+ SignalChannelCommand.by_name(test_channel_int),
54
+ SignalChannelCommand.by_name(test_channel_none),
55
+ SignalChannelCommand.by_name(test_channel_str),
56
+ )
57
+
58
+ def execute(
59
+ self,
60
+ ctx: WorkflowContext,
61
+ input: T,
62
+ command_results: CommandResults,
63
+ persistence: Persistence,
64
+ communication: Communication,
65
+ ) -> StateDecision:
66
+ assert len(command_results.signal_channel_commands) == 3
67
+ sig1 = command_results.signal_channel_commands[0]
68
+ sig2 = command_results.signal_channel_commands[1]
69
+ sig3 = command_results.signal_channel_commands[2]
70
+ assert sig1 == SignalChannelCommandResult(
71
+ test_channel_int, 123, ChannelRequestStatus.RECEIVED, ""
72
+ )
73
+ assert sig2 == SignalChannelCommandResult(
74
+ test_channel_none, None, ChannelRequestStatus.RECEIVED, ""
75
+ )
76
+ assert sig3 == SignalChannelCommandResult(
77
+ test_channel_str, "abc", ChannelRequestStatus.RECEIVED, ""
78
+ )
79
+ return StateDecision.single_next_state(WaitState2, sig3.value)
80
+
81
+ class WaitState2(WorkflowState[str]):
82
+ def wait_until(
83
+ self,
84
+ ctx: WorkflowContext,
85
+ input: str,
86
+ persistence: Persistence,
87
+ communication: Communication,
88
+ ) -> CommandRequest:
89
+ return CommandRequest.for_any_command_combination_completed(
90
+ [
91
+ [
92
+ test_channel1_id,
93
+ test_timer_id,
94
+ ]
95
+ ],
96
+ SignalChannelCommand.by_name(test_channel1, test_channel1_id),
97
+ SignalChannelCommand.by_name(test_channel2, test_channel2_id),
98
+ TimerCommand.by_seconds(1, test_timer_id),
99
+ )
100
+
101
+ def execute(
102
+ self,
103
+ ctx: WorkflowContext,
104
+ input: str,
105
+ command_results: CommandResults,
106
+ persistence: Persistence,
107
+ communication: Communication,
108
+ ) -> StateDecision:
109
+ assert len(command_results.signal_channel_commands) == 2
110
+ assert (
111
+ len(
112
+ [
113
+ r
114
+ for r in command_results.signal_channel_commands
115
+ if r.status == ChannelRequestStatus.RECEIVED
116
+ ]
117
+ )
118
+ == 1
119
+ )
120
+ sig1 = command_results.signal_channel_commands[0]
121
+ tim1 = command_results.timer_commands[0]
122
+ assert sig1 == SignalChannelCommandResult(
123
+ test_channel1, None, ChannelRequestStatus.RECEIVED, test_channel1_id
124
+ )
125
+ assert tim1 == TimerCommandResult(
126
+ TimerStatus.FIRED,
127
+ test_timer_id,
128
+ )
129
+ return StateDecision.graceful_complete_workflow(input)
130
+
131
+ class WaitSignalWorkflow(ObjectWorkflow):
132
+ def get_communication_schema(self) -> CommunicationSchema:
133
+ return CommunicationSchema.create(
134
+ CommunicationMethod.signal_channel_def(test_channel_int, int),
135
+ CommunicationMethod.signal_channel_def(test_channel_none, None),
136
+ CommunicationMethod.signal_channel_def(test_channel_str, str),
137
+ CommunicationMethod.signal_channel_def(test_idle_channel_none, None),
138
+ CommunicationMethod.signal_channel_def(test_channel1, None),
139
+ CommunicationMethod.signal_channel_def(test_channel2, None),
140
+ )
141
+
142
+ def get_workflow_states(self) -> StateSchema:
143
+ return StateSchema.with_starting_state(WaitState1(), WaitState2())
144
+
145
+ @rpc()
146
+ def get_idle_signal_channel_size(self, com: Communication):
147
+ return com.get_signal_channel_size(test_idle_channel_none)
dex/timer.py ADDED
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2026 Super Durable, Inc.
2
+ #
3
+ # Licensed under the Super Durable Source License 1.0.
4
+ # You may not use this file except in compliance with the License.
5
+ # See the LICENSE file in the repository root.
6
+ #
7
+ # SPDX-License-Identifier: LicenseRef-Super-Durable-1.0
8
+
9
+ from datetime import timedelta
10
+
11
+ from dex.condition import Condition, TimerCondition
12
+
13
+
14
+ class Timer:
15
+ @staticmethod
16
+ def by_duration(
17
+ duration: timedelta,
18
+ *,
19
+ condition_id: str | None = None,
20
+ ) -> Condition:
21
+ return TimerCondition(condition_id=condition_id, duration=duration)
dex/type_store.py ADDED
@@ -0,0 +1,99 @@
1
+ # Legacy Materials in this file remain under their original licenses.
2
+ # See LEGACY_NOTICES.md.
3
+
4
+ # Modifications Copyright (c) 2026 Super Durable, Inc.
5
+ #
6
+ # Modifications after the Legacy Cutoff are licensed under the
7
+ # Super Durable Source License 1.0.
8
+ # Legacy Materials remain under their original licenses.
9
+ # See LICENSE and LEGACY_NOTICES.md.
10
+
11
+ from typing import Optional
12
+ from enum import Enum
13
+
14
+ from dex.communication_schema import CommunicationMethod
15
+ from dex.errors import WorkflowDefinitionError, NotRegisteredError
16
+ from dex.persistence_schema import PersistenceField, PersistenceFieldType
17
+
18
+ class Type(Enum):
19
+ INTERNAL_CHANNEL = 1
20
+ DATA_ATTRIBUTE = 2
21
+ # TODO: extend to other types
22
+ # SIGNAL_CHANNEL = 3
23
+
24
+ class TypeStore:
25
+ _class_type: Type
26
+ _name_to_type_store: dict[str, Optional[type]]
27
+ _prefix_to_type_store: dict[str, Optional[type]]
28
+
29
+ def __init__(self, class_type: Type):
30
+ self._class_type = class_type
31
+ self._name_to_type_store = dict()
32
+ self._prefix_to_type_store = dict()
33
+
34
+ def is_valid_name_or_prefix(self, name: str) -> bool:
35
+ return self._validate_name(name)
36
+
37
+ def get_type(self, name: str) -> type:
38
+ is_registered = self._validate_name(name)
39
+
40
+ if not is_registered:
41
+ raise NotRegisteredError(f"{self._class_type} not registered: {name}")
42
+
43
+ t = self._do_get_type(name)
44
+ if t is None:
45
+ raise NotRegisteredError(f"{self._class_type} not registered: {name}")
46
+
47
+ return t
48
+
49
+ def add_internal_channel_def(self, obj: CommunicationMethod):
50
+ if self._class_type != Type.INTERNAL_CHANNEL:
51
+ raise ValueError(
52
+ f"Cannot add internal channel definition to {self._class_type}"
53
+ )
54
+ self._do_add_to_store(obj.is_prefix, obj.name, obj.value_type)
55
+
56
+ def add_data_attribute_def(self, obj: PersistenceField):
57
+ if self._class_type != Type.DATA_ATTRIBUTE:
58
+ raise ValueError(
59
+ f"Cannot add internal channel definition to {self._class_type}"
60
+ )
61
+ self._do_add_to_store(
62
+ obj.field_type == PersistenceFieldType.DataAttributePrefix,
63
+ obj.key,
64
+ obj.value_type,
65
+ )
66
+
67
+ def _validate_name(self, name: str) -> bool:
68
+ if name in self._name_to_type_store:
69
+ return True
70
+
71
+ for prefix in self._prefix_to_type_store.keys():
72
+ if name.startswith(prefix):
73
+ return True
74
+
75
+ return False
76
+
77
+ def _do_get_type(self, name: str) -> Optional[type]:
78
+ if name in self._name_to_type_store:
79
+ t = self._name_to_type_store[name]
80
+ return t if t is not None else type(None)
81
+
82
+ for prefix, t in self._prefix_to_type_store.items():
83
+ if name.startswith(prefix):
84
+ return t if t is not None else type(None)
85
+
86
+ return None
87
+
88
+ def _do_add_to_store(self, is_prefix: bool, name: str, t: Optional[type]):
89
+ if is_prefix:
90
+ store = self._prefix_to_type_store
91
+ else:
92
+ store = self._name_to_type_store
93
+
94
+ if name in store:
95
+ raise WorkflowDefinitionError(
96
+ f"{self._class_type} name/prefix {name} already exists"
97
+ )
98
+
99
+ store[name] = t