ddeutil-workflow 0.0.62__py3-none-any.whl → 0.0.63__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 +2 -24
- ddeutil/workflow/conf.py +36 -4
- ddeutil/workflow/event.py +2 -1
- ddeutil/workflow/reusables.py +70 -13
- ddeutil/workflow/stages.py +30 -24
- {ddeutil_workflow-0.0.62.dist-info → ddeutil_workflow-0.0.63.dist-info}/METADATA +11 -5
- {ddeutil_workflow-0.0.62.dist-info → ddeutil_workflow-0.0.63.dist-info}/RECORD +12 -12
- {ddeutil_workflow-0.0.62.dist-info → ddeutil_workflow-0.0.63.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.62.dist-info → ddeutil_workflow-0.0.63.dist-info}/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.62.dist-info → ddeutil_workflow-0.0.63.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.62.dist-info → ddeutil_workflow-0.0.63.dist-info}/top_level.txt +0 -0
ddeutil/workflow/__about__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__: str = "0.0.
|
1
|
+
__version__: str = "0.0.63"
|
ddeutil/workflow/__init__.py
CHANGED
@@ -5,12 +5,7 @@
|
|
5
5
|
# ------------------------------------------------------------------------------
|
6
6
|
from .__cron import CronJob, CronRunner
|
7
7
|
from .__types import DictData, DictStr, Matrix, Re, TupleStr
|
8
|
-
from .conf import
|
9
|
-
Config,
|
10
|
-
FileLoad,
|
11
|
-
config,
|
12
|
-
env,
|
13
|
-
)
|
8
|
+
from .conf import *
|
14
9
|
from .event import *
|
15
10
|
from .exceptions import *
|
16
11
|
from .job import *
|
@@ -37,24 +32,7 @@ from .result import (
|
|
37
32
|
Result,
|
38
33
|
Status,
|
39
34
|
)
|
40
|
-
from .reusables import
|
41
|
-
FILTERS,
|
42
|
-
FilterFunc,
|
43
|
-
FilterRegistry,
|
44
|
-
ReturnTagFunc,
|
45
|
-
TagFunc,
|
46
|
-
custom_filter,
|
47
|
-
extract_call,
|
48
|
-
get_args_const,
|
49
|
-
has_template,
|
50
|
-
make_filter_registry,
|
51
|
-
make_registry,
|
52
|
-
map_post_filter,
|
53
|
-
not_in_template,
|
54
|
-
param2template,
|
55
|
-
str2template,
|
56
|
-
tag,
|
57
|
-
)
|
35
|
+
from .reusables import *
|
58
36
|
from .scheduler import (
|
59
37
|
Schedule,
|
60
38
|
ScheduleWorkflow,
|
ddeutil/workflow/conf.py
CHANGED
@@ -18,8 +18,9 @@ from typing import Final, Optional, Protocol, TypeVar, Union
|
|
18
18
|
from zoneinfo import ZoneInfo
|
19
19
|
|
20
20
|
from ddeutil.core import str2bool
|
21
|
-
from ddeutil.io import YamlFlResolve
|
21
|
+
from ddeutil.io import YamlFlResolve, search_env_replace
|
22
22
|
from ddeutil.io.paths import glob_files, is_ignored, read_ignore
|
23
|
+
from pydantic import SecretStr
|
23
24
|
|
24
25
|
from .__types import DictData
|
25
26
|
|
@@ -321,15 +322,16 @@ class FileLoad(BaseLoad):
|
|
321
322
|
*,
|
322
323
|
path: Optional[Path] = None,
|
323
324
|
paths: Optional[list[Path]] = None,
|
324
|
-
excluded: list[str]
|
325
|
+
excluded: Optional[list[str]] = None,
|
325
326
|
extras: Optional[DictData] = None,
|
326
327
|
) -> Iterator[tuple[str, DictData]]:
|
327
328
|
"""Find all data that match with object type in config path. This class
|
328
329
|
method can use include and exclude list of identity name for filter and
|
329
330
|
adds-on.
|
330
331
|
|
331
|
-
:param obj: An object that want to validate matching before
|
332
|
-
|
332
|
+
:param obj: (object) An object that want to validate matching before
|
333
|
+
return.
|
334
|
+
:param path: (Path) A config path object.
|
333
335
|
:param paths: (list[Path]) A list of config path object.
|
334
336
|
:param excluded: An included list of data key that want to filter from
|
335
337
|
data.
|
@@ -474,3 +476,33 @@ class Loader(Protocol): # pragma: no cov
|
|
474
476
|
def finds(
|
475
477
|
cls, obj: object, *args, **kwargs
|
476
478
|
) -> Iterator[tuple[str, DictData]]: ...
|
479
|
+
|
480
|
+
|
481
|
+
def pass_env(value: T) -> T: # pragma: no cov
|
482
|
+
"""Passing environment variable to an input value.
|
483
|
+
|
484
|
+
:param value: (Any) A value that want to pass env var searching.
|
485
|
+
|
486
|
+
:rtype: Any
|
487
|
+
"""
|
488
|
+
if isinstance(value, dict):
|
489
|
+
return {k: pass_env(value[k]) for k in value}
|
490
|
+
elif isinstance(value, (list, tuple, set)):
|
491
|
+
return type(value)([pass_env(i) for i in value])
|
492
|
+
if not isinstance(value, str):
|
493
|
+
return value
|
494
|
+
|
495
|
+
rs: str = search_env_replace(value)
|
496
|
+
return None if rs == "null" else rs
|
497
|
+
|
498
|
+
|
499
|
+
class WorkflowSecret(SecretStr): # pragma: no cov
|
500
|
+
"""Workflow Secret String model."""
|
501
|
+
|
502
|
+
def get_secret_value(self) -> str:
|
503
|
+
"""Override get_secret_value by adding pass_env before return the
|
504
|
+
real-value.
|
505
|
+
|
506
|
+
:rtype: str
|
507
|
+
"""
|
508
|
+
return pass_env(super().get_secret_value())
|
ddeutil/workflow/event.py
CHANGED
@@ -17,6 +17,7 @@ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
17
17
|
from pydantic import BaseModel, ConfigDict, Field, ValidationInfo
|
18
18
|
from pydantic.functional_serializers import field_serializer
|
19
19
|
from pydantic.functional_validators import field_validator, model_validator
|
20
|
+
from pydantic_extra_types.timezone_name import TimeZoneName
|
20
21
|
from typing_extensions import Self
|
21
22
|
|
22
23
|
from .__cron import WEEKDAYS, CronJob, CronJobYear, CronRunner, Options
|
@@ -92,7 +93,7 @@ class Crontab(BaseModel):
|
|
92
93
|
),
|
93
94
|
]
|
94
95
|
tz: Annotated[
|
95
|
-
|
96
|
+
TimeZoneName,
|
96
97
|
Field(
|
97
98
|
description="A timezone string value",
|
98
99
|
alias="timezone",
|
ddeutil/workflow/reusables.py
CHANGED
@@ -14,7 +14,16 @@ from ast import Call, Constant, Expr, Module, Name, parse
|
|
14
14
|
from datetime import datetime
|
15
15
|
from functools import wraps
|
16
16
|
from importlib import import_module
|
17
|
-
from typing import
|
17
|
+
from typing import (
|
18
|
+
Any,
|
19
|
+
Callable,
|
20
|
+
Literal,
|
21
|
+
Optional,
|
22
|
+
Protocol,
|
23
|
+
TypeVar,
|
24
|
+
Union,
|
25
|
+
get_type_hints,
|
26
|
+
)
|
18
27
|
|
19
28
|
try:
|
20
29
|
from typing import ParamSpec
|
@@ -23,6 +32,7 @@ except ImportError:
|
|
23
32
|
|
24
33
|
from ddeutil.core import getdot, import_string, lazy
|
25
34
|
from ddeutil.io import search_env_replace
|
35
|
+
from pydantic import BaseModel, create_model
|
26
36
|
from pydantic.dataclasses import dataclass
|
27
37
|
|
28
38
|
from .__types import DictData, Re
|
@@ -231,6 +241,7 @@ def not_in_template(value: Any, *, not_in: str = "matrix.") -> bool:
|
|
231
241
|
|
232
242
|
:param value: A value that want to find parameter template prefix.
|
233
243
|
:param not_in: The not-in string that use in the `.startswith` function.
|
244
|
+
(Default is `matrix.`)
|
234
245
|
|
235
246
|
:rtype: bool
|
236
247
|
"""
|
@@ -279,7 +290,7 @@ def str2template(
|
|
279
290
|
:param value: (str) A string value that want to map with params.
|
280
291
|
:param params: (DictData) A parameter value that getting with matched
|
281
292
|
regular expression.
|
282
|
-
:param filters: A mapping of filter registry.
|
293
|
+
:param filters: (dict[str, FilterRegistry]) A mapping of filter registry.
|
283
294
|
:param registers: (Optional[list[str]]) Override list of register.
|
284
295
|
|
285
296
|
:rtype: str
|
@@ -304,12 +315,14 @@ def str2template(
|
|
304
315
|
]
|
305
316
|
|
306
317
|
# NOTE: from validate step, it guarantees that caller exists in params.
|
318
|
+
# I recommend to avoid logging params context on this case because it
|
319
|
+
# can include secret value.
|
307
320
|
try:
|
308
321
|
getter: Any = getdot(caller, params)
|
309
|
-
except ValueError
|
322
|
+
except ValueError:
|
310
323
|
raise UtilException(
|
311
324
|
f"Parameters does not get dot with caller: {caller!r}."
|
312
|
-
) from
|
325
|
+
) from None
|
313
326
|
|
314
327
|
# NOTE:
|
315
328
|
# If type of getter caller is not string type, and it does not use to
|
@@ -341,10 +354,11 @@ def param2template(
|
|
341
354
|
"""Pass param to template string that can search by ``RE_CALLER`` regular
|
342
355
|
expression.
|
343
356
|
|
344
|
-
:param value: A value that want to map with params
|
345
|
-
:param params: A parameter value that getting with matched
|
346
|
-
expression.
|
347
|
-
:param filters: A filter mapping for mapping
|
357
|
+
:param value: (Any) A value that want to map with params.
|
358
|
+
:param params: (DictData) A parameter value that getting with matched
|
359
|
+
regular expression.
|
360
|
+
:param filters: (dict[str, FilterRegistry]) A filter mapping for mapping
|
361
|
+
with `map_post_filter` func.
|
348
362
|
:param extras: (Optional[list[str]]) An Override extras.
|
349
363
|
|
350
364
|
:rtype: Any
|
@@ -376,8 +390,8 @@ def datetime_format(value: datetime, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
|
|
376
390
|
|
377
391
|
Examples:
|
378
392
|
|
379
|
-
|
380
|
-
|
393
|
+
>>> "${{ start-date | fmt('%Y%m%d') }}"
|
394
|
+
>>> "${{ start-date | fmt }}"
|
381
395
|
|
382
396
|
:param value: (datetime) A datetime value that want to format to string
|
383
397
|
value.
|
@@ -399,7 +413,7 @@ def coalesce(value: Optional[T], default: Any) -> T:
|
|
399
413
|
|
400
414
|
Examples:
|
401
415
|
|
402
|
-
|
416
|
+
>>> "${{ value | coalesce('foo') }}"
|
403
417
|
|
404
418
|
:param value: A value that want to check nullable.
|
405
419
|
:param default: A default value that use to returned value if an input
|
@@ -412,7 +426,14 @@ def coalesce(value: Optional[T], default: Any) -> T:
|
|
412
426
|
def get_item(
|
413
427
|
value: DictData, key: Union[str, int], default: Optional[Any] = None
|
414
428
|
) -> Any:
|
415
|
-
"""Get a value with an input specific key.
|
429
|
+
"""Get a value with an input specific key.
|
430
|
+
|
431
|
+
Examples:
|
432
|
+
|
433
|
+
>>> "${{ value | getitem('key') }}"
|
434
|
+
>>> "${{ value | getitem('key', 'default') }}"
|
435
|
+
|
436
|
+
"""
|
416
437
|
if not isinstance(value, dict):
|
417
438
|
raise UtilException(
|
418
439
|
f"The value that pass to `getitem` filter should be `dict` not "
|
@@ -422,7 +443,14 @@ def get_item(
|
|
422
443
|
|
423
444
|
|
424
445
|
@custom_filter("getindex") # pragma: no cov
|
425
|
-
def get_index(value: list[Any], index: int):
|
446
|
+
def get_index(value: list[Any], index: int) -> Any:
|
447
|
+
"""Get a value with an input specific index.
|
448
|
+
|
449
|
+
Examples:
|
450
|
+
|
451
|
+
>>> "${{ value | getindex(1) }}"
|
452
|
+
|
453
|
+
"""
|
426
454
|
if not isinstance(value, list):
|
427
455
|
raise UtilException(
|
428
456
|
f"The value that pass to `getindex` filter should be `list` not "
|
@@ -605,3 +633,32 @@ def extract_call(
|
|
605
633
|
f"`REGISTER.{call.path}.registries.{call.func}`"
|
606
634
|
)
|
607
635
|
return rgt[call.func][call.tag]
|
636
|
+
|
637
|
+
|
638
|
+
def create_model_from_caller(func: Callable) -> BaseModel: # pragma: no cov
|
639
|
+
"""Create model from the caller function. This function will use for
|
640
|
+
validate the caller function argument typed-hint that valid with the args
|
641
|
+
field.
|
642
|
+
|
643
|
+
:param func: A caller function.
|
644
|
+
|
645
|
+
:rtype: BaseModel
|
646
|
+
"""
|
647
|
+
sig: inspect.Signature = inspect.signature(func)
|
648
|
+
type_hints: dict[str, Any] = get_type_hints(func)
|
649
|
+
fields: dict[str, Any] = {}
|
650
|
+
for name in sig.parameters:
|
651
|
+
param: inspect.Parameter = sig.parameters[name]
|
652
|
+
if param.kind in (
|
653
|
+
inspect.Parameter.VAR_KEYWORD,
|
654
|
+
inspect.Parameter.VAR_POSITIONAL,
|
655
|
+
):
|
656
|
+
continue
|
657
|
+
if param.default != inspect.Parameter.empty:
|
658
|
+
fields[name] = (type_hints[name], param.default)
|
659
|
+
else:
|
660
|
+
fields[name] = (type_hints[name], ...)
|
661
|
+
|
662
|
+
return create_model(
|
663
|
+
"".join(i.title() for i in func.__name__.split("_")), **fields
|
664
|
+
)
|
ddeutil/workflow/stages.py
CHANGED
@@ -60,7 +60,7 @@ from pydantic.functional_validators import model_validator
|
|
60
60
|
from typing_extensions import Self
|
61
61
|
|
62
62
|
from .__types import DictData, DictStr, StrOrInt, StrOrNone, TupleStr
|
63
|
-
from .conf import dynamic
|
63
|
+
from .conf import dynamic, pass_env
|
64
64
|
from .exceptions import StageException, to_dict
|
65
65
|
from .result import CANCEL, FAILED, SUCCESS, WAIT, Result, Status
|
66
66
|
from .reusables import TagFunc, extract_call, not_in_template, param2template
|
@@ -626,10 +626,10 @@ class BashStage(BaseAsyncStage):
|
|
626
626
|
await f.write(f"#!/bin/{f_shebang}\n\n")
|
627
627
|
|
628
628
|
# NOTE: add setting environment variable before bash skip statement.
|
629
|
-
await f.writelines([f"{k}='{env[k]}';\n" for k in env])
|
629
|
+
await f.writelines(pass_env([f"{k}='{env[k]}';\n" for k in env]))
|
630
630
|
|
631
631
|
# NOTE: make sure that shell script file does not have `\r` char.
|
632
|
-
await f.write("\n" + bash.replace("\r\n", "\n"))
|
632
|
+
await f.write("\n" + pass_env(bash.replace("\r\n", "\n")))
|
633
633
|
|
634
634
|
# NOTE: Make this .sh file able to executable.
|
635
635
|
make_exec(f"./{f_name}")
|
@@ -662,10 +662,10 @@ class BashStage(BaseAsyncStage):
|
|
662
662
|
f.write(f"#!/bin/{f_shebang}\n\n")
|
663
663
|
|
664
664
|
# NOTE: add setting environment variable before bash skip statement.
|
665
|
-
f.writelines([f"{k}='{env[k]}';\n" for k in env])
|
665
|
+
f.writelines(pass_env([f"{k}='{env[k]}';\n" for k in env]))
|
666
666
|
|
667
667
|
# NOTE: make sure that shell script file does not have `\r` char.
|
668
|
-
f.write("\n" + bash.replace("\r\n", "\n"))
|
668
|
+
f.write("\n" + pass_env(bash.replace("\r\n", "\n")))
|
669
669
|
|
670
670
|
# NOTE: Make this .sh file able to executable.
|
671
671
|
make_exec(f"./{f_name}")
|
@@ -895,7 +895,9 @@ class PyStage(BaseAsyncStage):
|
|
895
895
|
# WARNING: The exec build-in function is very dangerous. So, it
|
896
896
|
# should use the re module to validate exec-string before running.
|
897
897
|
exec(
|
898
|
-
|
898
|
+
pass_env(
|
899
|
+
param2template(dedent(self.run), params, extras=self.extras)
|
900
|
+
),
|
899
901
|
gb,
|
900
902
|
lc,
|
901
903
|
)
|
@@ -1060,12 +1062,12 @@ class CallStage(BaseAsyncStage):
|
|
1060
1062
|
args: DictData = {"result": result} | param2template(
|
1061
1063
|
self.args, params, extras=self.extras
|
1062
1064
|
)
|
1063
|
-
|
1065
|
+
sig = inspect.signature(call_func)
|
1064
1066
|
necessary_params: list[str] = []
|
1065
1067
|
has_keyword: bool = False
|
1066
|
-
for k in
|
1068
|
+
for k in sig.parameters:
|
1067
1069
|
if (
|
1068
|
-
v :=
|
1070
|
+
v := sig.parameters[k]
|
1069
1071
|
).default == Parameter.empty and v.kind not in (
|
1070
1072
|
Parameter.VAR_KEYWORD,
|
1071
1073
|
Parameter.VAR_POSITIONAL,
|
@@ -1083,7 +1085,7 @@ class CallStage(BaseAsyncStage):
|
|
1083
1085
|
f"does not set to args, {list(args.keys())}."
|
1084
1086
|
)
|
1085
1087
|
|
1086
|
-
if "result" not in
|
1088
|
+
if "result" not in sig.parameters and not has_keyword:
|
1087
1089
|
args.pop("result")
|
1088
1090
|
|
1089
1091
|
args = self.parse_model_args(call_func, args, result)
|
@@ -1149,12 +1151,12 @@ class CallStage(BaseAsyncStage):
|
|
1149
1151
|
args: DictData = {"result": result} | param2template(
|
1150
1152
|
self.args, params, extras=self.extras
|
1151
1153
|
)
|
1152
|
-
|
1154
|
+
sig = inspect.signature(call_func)
|
1153
1155
|
necessary_params: list[str] = []
|
1154
1156
|
has_keyword: bool = False
|
1155
|
-
for k in
|
1157
|
+
for k in sig.parameters:
|
1156
1158
|
if (
|
1157
|
-
v :=
|
1159
|
+
v := sig.parameters[k]
|
1158
1160
|
).default == Parameter.empty and v.kind not in (
|
1159
1161
|
Parameter.VAR_KEYWORD,
|
1160
1162
|
Parameter.VAR_POSITIONAL,
|
@@ -1172,7 +1174,7 @@ class CallStage(BaseAsyncStage):
|
|
1172
1174
|
f"does not set to args, {list(args.keys())}."
|
1173
1175
|
)
|
1174
1176
|
|
1175
|
-
if "result" not in
|
1177
|
+
if "result" not in sig.parameters and not has_keyword:
|
1176
1178
|
args.pop("result")
|
1177
1179
|
|
1178
1180
|
args = self.parse_model_args(call_func, args, result)
|
@@ -1295,7 +1297,7 @@ class TriggerStage(BaseStage):
|
|
1295
1297
|
_trigger: str = param2template(self.trigger, params, extras=self.extras)
|
1296
1298
|
result.trace.info(f"[STAGE]: Execute Trigger-Stage: {_trigger!r}")
|
1297
1299
|
rs: Result = Workflow.from_conf(
|
1298
|
-
name=_trigger,
|
1300
|
+
name=pass_env(_trigger),
|
1299
1301
|
extras=self.extras | {"stage_raise_error": True},
|
1300
1302
|
).execute(
|
1301
1303
|
params=param2template(self.params, params, extras=self.extras),
|
@@ -2417,9 +2419,11 @@ class DockerStage(BaseStage): # pragma: no cov
|
|
2417
2419
|
)
|
2418
2420
|
|
2419
2421
|
resp = client.api.pull(
|
2420
|
-
repository=
|
2421
|
-
tag=self.tag,
|
2422
|
-
auth_config=
|
2422
|
+
repository=pass_env(self.image),
|
2423
|
+
tag=pass_env(self.tag),
|
2424
|
+
auth_config=pass_env(
|
2425
|
+
param2template(self.auth, params, extras=self.extras)
|
2426
|
+
),
|
2423
2427
|
stream=True,
|
2424
2428
|
decode=True,
|
2425
2429
|
)
|
@@ -2438,10 +2442,10 @@ class DockerStage(BaseStage): # pragma: no cov
|
|
2438
2442
|
|
2439
2443
|
unique_image_name: str = f"{self.image}_{datetime.now():%Y%m%d%H%M%S%f}"
|
2440
2444
|
container = client.containers.run(
|
2441
|
-
image=f"{self.image}:{self.tag}",
|
2445
|
+
image=pass_env(f"{self.image}:{self.tag}"),
|
2442
2446
|
name=unique_image_name,
|
2443
|
-
environment=self.env,
|
2444
|
-
volumes=(
|
2447
|
+
environment=pass_env(self.env),
|
2448
|
+
volumes=pass_env(
|
2445
2449
|
{
|
2446
2450
|
Path.cwd()
|
2447
2451
|
/ f".docker.{result.run_id}.logs": {
|
@@ -2549,8 +2553,10 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
2549
2553
|
f_name: str = f"{run_id}.py"
|
2550
2554
|
with open(f"./{f_name}", mode="w", newline="\n") as f:
|
2551
2555
|
# NOTE: Create variable mapping that write before running statement.
|
2552
|
-
vars_str: str =
|
2553
|
-
|
2556
|
+
vars_str: str = pass_env(
|
2557
|
+
"\n ".join(
|
2558
|
+
f"{var} = {value!r}" for var, value in values.items()
|
2559
|
+
)
|
2554
2560
|
)
|
2555
2561
|
|
2556
2562
|
# NOTE: `uv` supports PEP 723 — inline TOML metadata.
|
@@ -2568,7 +2574,7 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
2568
2574
|
)
|
2569
2575
|
|
2570
2576
|
# NOTE: make sure that py script file does not have `\r` char.
|
2571
|
-
f.write("\n" + py.replace("\r\n", "\n"))
|
2577
|
+
f.write("\n" + pass_env(py.replace("\r\n", "\n")))
|
2572
2578
|
|
2573
2579
|
# NOTE: Make this .py file able to executable.
|
2574
2580
|
make_exec(f"./{f_name}")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ddeutil-workflow
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.63
|
4
4
|
Summary: Lightweight workflow orchestration
|
5
5
|
Author-email: ddeutils <korawich.anu@gmail.com>
|
6
6
|
License: MIT
|
@@ -25,6 +25,7 @@ License-File: LICENSE
|
|
25
25
|
Requires-Dist: ddeutil[checksum]>=0.4.8
|
26
26
|
Requires-Dist: ddeutil-io[toml,yaml]>=0.2.13
|
27
27
|
Requires-Dist: pydantic==2.11.4
|
28
|
+
Requires-Dist: pydantic-extra-types==2.10.4
|
28
29
|
Requires-Dist: python-dotenv==1.1.0
|
29
30
|
Requires-Dist: schedule<2.0.0,==1.2.2
|
30
31
|
Provides-Extra: all
|
@@ -215,19 +216,23 @@ registry-caller/
|
|
215
216
|
This function will store as module that will import from `WORKFLOW_CORE_REGISTRY_CALLER`
|
216
217
|
value (This config can override by extra parameters with `registry_caller` key).
|
217
218
|
|
219
|
+
> [!NOTE]
|
220
|
+
> You can use Pydantic Model as argument of your caller function. The core workflow
|
221
|
+
> engine will auto use the `model_validate` method before run your caller function.
|
222
|
+
|
218
223
|
```python
|
219
|
-
from ddeutil.workflow import Result, tag
|
224
|
+
from ddeutil.workflow import Result, WorkflowSecret, tag
|
220
225
|
from ddeutil.workflow.exceptions import StageException
|
221
|
-
from pydantic import BaseModel
|
226
|
+
from pydantic import BaseModel
|
222
227
|
|
223
228
|
class AwsCredential(BaseModel):
|
224
229
|
path: str
|
225
230
|
access_client_id: str
|
226
|
-
access_client_secret:
|
231
|
+
access_client_secret: WorkflowSecret
|
227
232
|
|
228
233
|
class RestAuth(BaseModel):
|
229
234
|
type: str
|
230
|
-
keys:
|
235
|
+
keys: WorkflowSecret
|
231
236
|
|
232
237
|
@tag("requests", alias="get-api-with-oauth-to-s3")
|
233
238
|
def get_api_with_oauth_to_s3(
|
@@ -243,6 +248,7 @@ def get_api_with_oauth_to_s3(
|
|
243
248
|
result.trace.info(f"... {method}: {url}")
|
244
249
|
if method != "post":
|
245
250
|
raise StageException(f"RestAPI does not support for {method} action.")
|
251
|
+
# NOTE: If you want to use secret, you can use `auth.keys.get_secret_value()`.
|
246
252
|
return {"records": 1000}
|
247
253
|
```
|
248
254
|
|
@@ -1,18 +1,18 @@
|
|
1
|
-
ddeutil/workflow/__about__.py,sha256=
|
1
|
+
ddeutil/workflow/__about__.py,sha256=xnUKKC8j_qfLMiPiNf3P8eAETFo17HtTgo2_-q1Nkvw,28
|
2
2
|
ddeutil/workflow/__cron.py,sha256=BOKQcreiex0SAigrK1gnLxpvOeF3aca_rQwyz9Kfve4,28751
|
3
|
-
ddeutil/workflow/__init__.py,sha256=
|
3
|
+
ddeutil/workflow/__init__.py,sha256=4QIAmK-p6Oex3VPrFCSwo8brhpL7_mEF3AQQlZdTqvs,1030
|
4
4
|
ddeutil/workflow/__main__.py,sha256=x-sYedl4T8p6054aySk-EQX6vhytvPR0HvaBNYxMzp0,364
|
5
5
|
ddeutil/workflow/__types.py,sha256=uNfoRbVmNK5O37UUMVnqcmoghD9oMS1q9fXC0APnjSI,4584
|
6
|
-
ddeutil/workflow/conf.py,sha256=
|
7
|
-
ddeutil/workflow/event.py,sha256=
|
6
|
+
ddeutil/workflow/conf.py,sha256=kjjFZmBK7SzSpQnMJ0KKzB2I0Zcn4oGA6uLdHRRroj0,15828
|
7
|
+
ddeutil/workflow/event.py,sha256=S2eJAZZx_V5TuQ0l417hFVCtjWXnfNPZBgSCICzxQ48,11041
|
8
8
|
ddeutil/workflow/exceptions.py,sha256=TKHBIlfquz3yEb8_kg6UXpxVLKxstt3QA9a1XYsLPJk,2455
|
9
9
|
ddeutil/workflow/job.py,sha256=Php1b3n6c-jddel8PTSa61kAW22QBTetzoLVR4XXM4E,35240
|
10
10
|
ddeutil/workflow/logs.py,sha256=iVtyl8i69y7t07tAuWkihc54WlkHCcBy_Ur0WtzJ_lM,31367
|
11
11
|
ddeutil/workflow/params.py,sha256=1u8gXs1ZyMq-2eD9H8L7Yjfu5t7b_OzjA0fJvhxdYWY,12505
|
12
12
|
ddeutil/workflow/result.py,sha256=4M9VCcveI8Yz6ZrnI-67SZlry-Z8G7e0hziy1k-pklk,5906
|
13
|
-
ddeutil/workflow/reusables.py,sha256=
|
13
|
+
ddeutil/workflow/reusables.py,sha256=gbSHUptdEar5HSfBx13ldHJw0IBGF6BShQB3XpPd3Wg,20812
|
14
14
|
ddeutil/workflow/scheduler.py,sha256=OsEyj2zscQ-3bDMk2z7UtKlCWLlgoGjaRFt17o1B1ew,27263
|
15
|
-
ddeutil/workflow/stages.py,sha256=
|
15
|
+
ddeutil/workflow/stages.py,sha256=4JBcgXxxpDfwUFob30ocWwVqoxuk7t-WoDlj8dh8Dqs,93482
|
16
16
|
ddeutil/workflow/utils.py,sha256=rcaDwXaEs4SCdcBKWx4ZCEtpnNfPI8du7Er6b_rg8t4,9569
|
17
17
|
ddeutil/workflow/workflow.py,sha256=8Z_h8OtNHkaGf8MJixTHNeXsyA4mBlYtHDqj0oEVFBs,44858
|
18
18
|
ddeutil/workflow/api/__init__.py,sha256=kY30dL8HPY8tY_GBmm7y_3OdoXzB1-EA2a96PLU0AQw,5278
|
@@ -23,9 +23,9 @@ ddeutil/workflow/api/routes/job.py,sha256=8X5VLDJH6PumyNIY6JGRNBsf2gWN0eG9DzxRPS
|
|
23
23
|
ddeutil/workflow/api/routes/logs.py,sha256=U6vOni3wd-ZTOwd3yVdSOpgyRmNdcgfngU5KlLM3Cww,5383
|
24
24
|
ddeutil/workflow/api/routes/schedules.py,sha256=14RnaJKEGMSJtncI1H_QQVZNBe_jDS40PPRO6qFc3i0,4805
|
25
25
|
ddeutil/workflow/api/routes/workflows.py,sha256=GJu5PiXEylswrXylEImpncySjeU9chrvrtjhiMCw2RQ,4529
|
26
|
-
ddeutil_workflow-0.0.
|
27
|
-
ddeutil_workflow-0.0.
|
28
|
-
ddeutil_workflow-0.0.
|
29
|
-
ddeutil_workflow-0.0.
|
30
|
-
ddeutil_workflow-0.0.
|
31
|
-
ddeutil_workflow-0.0.
|
26
|
+
ddeutil_workflow-0.0.63.dist-info/licenses/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
|
27
|
+
ddeutil_workflow-0.0.63.dist-info/METADATA,sha256=9h5mIv3IdcYoOG9Qaz02PgCm2KOJqjkDCS09WjDCAUo,19748
|
28
|
+
ddeutil_workflow-0.0.63.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
29
|
+
ddeutil_workflow-0.0.63.dist-info/entry_points.txt,sha256=qDTpPSauL0ciO6T4iSVt8bJeYrVEkkoEEw_RlGx6Kgk,63
|
30
|
+
ddeutil_workflow-0.0.63.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
|
31
|
+
ddeutil_workflow-0.0.63.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|