ddeutil-workflow 0.0.84__py3-none-any.whl → 0.0.86__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.
- ddeutil/workflow/__about__.py +1 -1
- ddeutil/workflow/__init__.py +4 -4
- ddeutil/workflow/api/routes/job.py +3 -2
- ddeutil/workflow/audits.py +8 -6
- ddeutil/workflow/conf.py +9 -20
- ddeutil/workflow/errors.py +34 -19
- ddeutil/workflow/job.py +303 -159
- ddeutil/workflow/plugins/providers/az.py +2 -2
- ddeutil/workflow/result.py +46 -55
- ddeutil/workflow/stages.py +540 -458
- ddeutil/workflow/traces.py +259 -261
- ddeutil/workflow/workflow.py +304 -361
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/METADATA +13 -16
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/RECORD +18 -18
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/top_level.txt +0 -0
@@ -89,9 +89,9 @@ try:
|
|
89
89
|
from azure.core.exceptions import AzureError
|
90
90
|
from azure.storage.blob import BlobServiceClient
|
91
91
|
|
92
|
-
AZURE_AVAILABLE = True
|
92
|
+
AZURE_AVAILABLE: bool = True
|
93
93
|
except ImportError:
|
94
|
-
AZURE_AVAILABLE = False
|
94
|
+
AZURE_AVAILABLE: bool = False
|
95
95
|
|
96
96
|
from pydantic import BaseModel, Field
|
97
97
|
|
ddeutil/workflow/result.py
CHANGED
@@ -12,30 +12,29 @@ states and the Result dataclass for context transfer between workflow components
|
|
12
12
|
from __future__ import annotations
|
13
13
|
|
14
14
|
from dataclasses import field
|
15
|
+
from datetime import datetime
|
15
16
|
from enum import Enum
|
16
17
|
from typing import Any, Optional, TypedDict, Union
|
17
18
|
|
18
19
|
from pydantic import ConfigDict
|
19
20
|
from pydantic.dataclasses import dataclass
|
20
|
-
from pydantic.functional_validators import model_validator
|
21
21
|
from typing_extensions import NotRequired, Self
|
22
22
|
|
23
|
-
from . import
|
23
|
+
from .__types import DictData
|
24
|
+
from .errors import (
|
25
|
+
BaseError,
|
26
|
+
ErrorData,
|
24
27
|
JobCancelError,
|
25
|
-
JobError,
|
26
28
|
JobSkipError,
|
29
|
+
ResultError,
|
27
30
|
StageCancelError,
|
28
|
-
StageError,
|
29
31
|
StageNestedCancelError,
|
30
|
-
StageNestedError,
|
31
32
|
StageNestedSkipError,
|
32
33
|
StageSkipError,
|
33
34
|
WorkflowCancelError,
|
34
|
-
|
35
|
+
WorkflowSkipError,
|
35
36
|
)
|
36
|
-
from .
|
37
|
-
from .audits import Trace, get_trace
|
38
|
-
from .errors import ErrorData, ResultError
|
37
|
+
from .traces import Trace, get_trace
|
39
38
|
from .utils import default_gen_id
|
40
39
|
|
41
40
|
|
@@ -110,11 +109,11 @@ def validate_statuses(statuses: list[Status]) -> Status:
|
|
110
109
|
Status: Final consolidated status based on workflow logic
|
111
110
|
|
112
111
|
Example:
|
113
|
-
|
112
|
+
Case: Mixed statuses - FAILED takes priority
|
114
113
|
>>> validate_statuses([SUCCESS, FAILED, SUCCESS])
|
115
114
|
>>> # Returns: FAILED
|
116
115
|
|
117
|
-
|
116
|
+
Case: All same status
|
118
117
|
>>> validate_statuses([SUCCESS, SUCCESS, SUCCESS])
|
119
118
|
>>> # Returns: SUCCESS
|
120
119
|
"""
|
@@ -131,21 +130,7 @@ def validate_statuses(statuses: list[Status]) -> Status:
|
|
131
130
|
|
132
131
|
|
133
132
|
def get_status_from_error(
|
134
|
-
error: Union[
|
135
|
-
StageError,
|
136
|
-
StageCancelError,
|
137
|
-
StageSkipError,
|
138
|
-
StageNestedCancelError,
|
139
|
-
StageNestedError,
|
140
|
-
StageNestedSkipError,
|
141
|
-
JobError,
|
142
|
-
JobCancelError,
|
143
|
-
JobSkipError,
|
144
|
-
WorkflowError,
|
145
|
-
WorkflowCancelError,
|
146
|
-
Exception,
|
147
|
-
BaseException,
|
148
|
-
]
|
133
|
+
error: Union[BaseError, Exception, BaseException]
|
149
134
|
) -> Status:
|
150
135
|
"""Get the Status from the error object.
|
151
136
|
|
@@ -155,7 +140,10 @@ def get_status_from_error(
|
|
155
140
|
Returns:
|
156
141
|
Status: The status from the specific exception class.
|
157
142
|
"""
|
158
|
-
if isinstance(
|
143
|
+
if isinstance(
|
144
|
+
error,
|
145
|
+
(StageNestedSkipError, StageSkipError, JobSkipError, WorkflowSkipError),
|
146
|
+
):
|
159
147
|
return SKIP
|
160
148
|
elif isinstance(
|
161
149
|
error,
|
@@ -189,25 +177,8 @@ class Result:
|
|
189
177
|
extras: DictData = field(default_factory=dict, compare=False, repr=False)
|
190
178
|
status: Status = field(default=WAIT)
|
191
179
|
context: Optional[DictData] = field(default=None)
|
192
|
-
info: DictData = field(default_factory=dict)
|
193
180
|
run_id: str = field(default_factory=default_gen_id)
|
194
181
|
parent_run_id: Optional[str] = field(default=None)
|
195
|
-
trace: Optional[Trace] = field(default=None, compare=False, repr=False)
|
196
|
-
|
197
|
-
@model_validator(mode="after")
|
198
|
-
def __prepare_trace(self) -> Self:
|
199
|
-
"""Prepare trace field that want to pass after its initialize step.
|
200
|
-
|
201
|
-
:rtype: Self
|
202
|
-
"""
|
203
|
-
if self.trace is None: # pragma: no cov
|
204
|
-
self.trace: Trace = get_trace(
|
205
|
-
self.run_id,
|
206
|
-
parent_run_id=self.parent_run_id,
|
207
|
-
extras=self.extras,
|
208
|
-
)
|
209
|
-
|
210
|
-
return self
|
211
182
|
|
212
183
|
@classmethod
|
213
184
|
def from_trace(cls, trace: Trace):
|
@@ -216,7 +187,13 @@ class Result:
|
|
216
187
|
run_id=trace.run_id,
|
217
188
|
parent_run_id=trace.parent_run_id,
|
218
189
|
extras=trace.extras,
|
219
|
-
|
190
|
+
)
|
191
|
+
|
192
|
+
def gen_trace(self) -> Trace:
|
193
|
+
return get_trace(
|
194
|
+
self.run_id,
|
195
|
+
parent_run_id=self.parent_run_id,
|
196
|
+
extras=self.extras,
|
220
197
|
)
|
221
198
|
|
222
199
|
def catch(
|
@@ -251,18 +228,16 @@ class Result:
|
|
251
228
|
self.__dict__["context"][k].update(kwargs[k])
|
252
229
|
# NOTE: Exclude the `info` key for update information data.
|
253
230
|
elif k == "info":
|
254
|
-
|
231
|
+
if "info" in self.__dict__["context"]:
|
232
|
+
self.__dict__["context"].update(kwargs[k])
|
233
|
+
else:
|
234
|
+
self.__dict__["context"]["info"] = kwargs[k]
|
255
235
|
else:
|
256
236
|
raise ResultError(
|
257
237
|
f"The key {k!r} does not exists on context data."
|
258
238
|
)
|
259
239
|
return self
|
260
240
|
|
261
|
-
def make_info(self, data: DictData) -> Self:
|
262
|
-
"""Making information."""
|
263
|
-
self.__dict__["info"].update(data)
|
264
|
-
return self
|
265
|
-
|
266
241
|
|
267
242
|
def catch(
|
268
243
|
context: DictData,
|
@@ -292,19 +267,35 @@ def catch(
|
|
292
267
|
context[k].update(kwargs[k])
|
293
268
|
# NOTE: Exclude the `info` key for update information data.
|
294
269
|
elif k == "info":
|
295
|
-
|
296
|
-
|
297
|
-
|
270
|
+
if "info" in context:
|
271
|
+
context.update(kwargs[k])
|
272
|
+
else:
|
273
|
+
context["info"] = kwargs[k]
|
274
|
+
# ARCHIVE:
|
275
|
+
# else:
|
276
|
+
# raise ResultError(f"The key {k!r} does not exist on context data.")
|
298
277
|
return context
|
299
278
|
|
300
279
|
|
280
|
+
class Info(TypedDict):
|
281
|
+
exec_start: datetime
|
282
|
+
exec_end: NotRequired[datetime]
|
283
|
+
exec_latency: NotRequired[float]
|
284
|
+
|
285
|
+
|
286
|
+
class System(TypedDict):
|
287
|
+
__sys_release_dryrun_mode: NotRequired[bool]
|
288
|
+
__sys_exec_break_circle: NotRequired[str]
|
289
|
+
|
290
|
+
|
301
291
|
class Context(TypedDict):
|
302
292
|
"""Context dict typed."""
|
303
293
|
|
304
294
|
status: Status
|
295
|
+
info: Info
|
296
|
+
sys: NotRequired[System]
|
305
297
|
context: NotRequired[DictData]
|
306
298
|
errors: NotRequired[Union[list[ErrorData], ErrorData]]
|
307
|
-
info: NotRequired[DictData]
|
308
299
|
|
309
300
|
|
310
301
|
class Layer(str, Enum):
|