ddeutil-workflow 0.0.76__tar.gz → 0.0.77__tar.gz
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-0.0.76 → ddeutil_workflow-0.0.77}/PKG-INFO +1 -1
- ddeutil_workflow-0.0.77/src/ddeutil/workflow/__about__.py +1 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/conf.py +26 -10
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/reusables.py +5 -4
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/stages.py +2 -2
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/utils.py +8 -2
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/workflow.py +4 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/PKG-INFO +1 -1
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_conf.py +14 -4
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_template.py +6 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_release.py +1 -0
- ddeutil_workflow-0.0.76/src/ddeutil/workflow/__about__.py +0 -1
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/LICENSE +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/README.md +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/pyproject.toml +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/setup.cfg +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__cron.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__init__.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__main__.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__types.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/__init__.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/log_conf.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/job.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/logs.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/audits.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/cli.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/errors.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/event.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/job.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/params.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/result.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/traces.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/SOURCES.txt +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/requires.txt +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test__cron.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test__regex.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_audits.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_cli.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_errors.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_event.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_job.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_job_exec.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_job_exec_strategy.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_params.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_result.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_call_tag.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_func_model.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_template_filter.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_strategy.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_traces.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_utils.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_exec.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_exec_job.py +0 -0
- {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_rerun.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__: str = "0.0.77"
|
@@ -322,25 +322,30 @@ class YamlParser:
|
|
322
322
|
excluded: Optional[list[str]] = None,
|
323
323
|
extras: Optional[DictData] = None,
|
324
324
|
ignore_filename: Optional[str] = None,
|
325
|
+
tags: Optional[list[str]] = None,
|
325
326
|
) -> Iterator[tuple[str, DictData]]:
|
326
327
|
"""Find all data that match with object type in config path. This class
|
327
328
|
method can use include and exclude list of identity name for filter and
|
328
329
|
adds-on.
|
329
330
|
|
330
|
-
:
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
data
|
336
|
-
|
337
|
-
|
338
|
-
|
331
|
+
Args:
|
332
|
+
obj: (object | str) An object that want to validate matching
|
333
|
+
before return.
|
334
|
+
path: (Path) A config path object.
|
335
|
+
paths: (list[Path]) A list of config path object.
|
336
|
+
excluded: An included list of data key that want to filter from
|
337
|
+
data.
|
338
|
+
extras: (DictData) An extra parameter that use to override core
|
339
|
+
config values.
|
340
|
+
ignore_filename: (str) An ignore filename. Default is
|
339
341
|
``.confignore`` filename.
|
342
|
+
tags: (list[str])
|
343
|
+
A list of tag that want to filter.
|
340
344
|
|
341
345
|
:rtype: Iterator[tuple[str, DictData]]
|
342
346
|
"""
|
343
347
|
excluded: list[str] = excluded or []
|
348
|
+
tags: list[str] = tags or []
|
344
349
|
path: Path = dynamic("conf_path", f=path, extras=extras)
|
345
350
|
paths: Optional[list[Path]] = paths or (extras or {}).get("conf_paths")
|
346
351
|
if not paths:
|
@@ -366,6 +371,14 @@ class YamlParser:
|
|
366
371
|
if key in excluded:
|
367
372
|
continue
|
368
373
|
|
374
|
+
if (
|
375
|
+
tags
|
376
|
+
and (ts := data[key].get("tags"))
|
377
|
+
and isinstance(ts, list)
|
378
|
+
and all(t not in tags for t in ts)
|
379
|
+
): # pragma: no cov
|
380
|
+
continue
|
381
|
+
|
369
382
|
if (t := data.get("type")) and t == obj_type:
|
370
383
|
marking: tuple[float, DictData] = (
|
371
384
|
file.lstat().st_mtime,
|
@@ -469,7 +482,10 @@ def pass_env(value: T) -> T: # pragma: no cov
|
|
469
482
|
if isinstance(value, dict):
|
470
483
|
return {k: pass_env(value[k]) for k in value}
|
471
484
|
elif isinstance(value, (list, tuple, set)):
|
472
|
-
|
485
|
+
try:
|
486
|
+
return type(value)(pass_env(i) for i in value)
|
487
|
+
except TypeError:
|
488
|
+
return value
|
473
489
|
if not isinstance(value, str):
|
474
490
|
return value
|
475
491
|
|
@@ -421,12 +421,13 @@ def param2template(
|
|
421
421
|
for k in value
|
422
422
|
}
|
423
423
|
elif isinstance(value, (list, tuple, set)):
|
424
|
-
|
425
|
-
|
424
|
+
try:
|
425
|
+
return type(value)(
|
426
426
|
param2template(i, params, context, filters, extras=extras)
|
427
427
|
for i in value
|
428
|
-
|
429
|
-
|
428
|
+
)
|
429
|
+
except TypeError:
|
430
|
+
return value
|
430
431
|
elif not isinstance(value, str):
|
431
432
|
return value
|
432
433
|
return str2template(
|
@@ -329,7 +329,7 @@ class BaseStage(BaseModel, ABC):
|
|
329
329
|
parent_run_id=parent_run_id,
|
330
330
|
event=event,
|
331
331
|
)
|
332
|
-
if result_caught.status == WAIT:
|
332
|
+
if result_caught.status == WAIT: # pragma: no cov
|
333
333
|
raise StageError(
|
334
334
|
"Status from execution should not return waiting status."
|
335
335
|
)
|
@@ -656,7 +656,7 @@ class BaseAsyncStage(BaseStage, ABC):
|
|
656
656
|
parent_run_id=parent_run_id,
|
657
657
|
event=event,
|
658
658
|
)
|
659
|
-
if result_caught.status == WAIT:
|
659
|
+
if result_caught.status == WAIT: # pragma: no cov
|
660
660
|
raise StageError(
|
661
661
|
"Status from execution should not return waiting status."
|
662
662
|
)
|
@@ -271,7 +271,10 @@ def filter_func(value: T) -> T:
|
|
271
271
|
if isinstance(value, dict):
|
272
272
|
return {k: filter_func(value[k]) for k in value}
|
273
273
|
elif isinstance(value, (list, tuple, set)):
|
274
|
-
|
274
|
+
try:
|
275
|
+
return type(value)(filter_func(i) for i in value)
|
276
|
+
except TypeError:
|
277
|
+
return value
|
275
278
|
|
276
279
|
if isfunction(value):
|
277
280
|
# NOTE: If it wants to improve to get this function, it is able to save
|
@@ -338,7 +341,10 @@ def dump_all(
|
|
338
341
|
if isinstance(value, dict):
|
339
342
|
return {k: dump_all(value[k], by_alias=by_alias) for k in value}
|
340
343
|
elif isinstance(value, (list, tuple, set)):
|
341
|
-
|
344
|
+
try:
|
345
|
+
return type(value)(dump_all(i, by_alias=by_alias) for i in value)
|
346
|
+
except TypeError:
|
347
|
+
return value
|
342
348
|
elif isinstance(value, BaseModel):
|
343
349
|
return value.model_dump(by_alias=by_alias)
|
344
350
|
return value
|
@@ -152,6 +152,10 @@ class Workflow(BaseModel):
|
|
152
152
|
default_factory=dict,
|
153
153
|
description="A mapping of job ID and job model that already loaded.",
|
154
154
|
)
|
155
|
+
tags: list[str] = Field(
|
156
|
+
default_factory=list,
|
157
|
+
description="A list of tag that use for simple grouping workflow.",
|
158
|
+
)
|
155
159
|
created_at: datetime = Field(
|
156
160
|
default_factory=get_dt_now,
|
157
161
|
description=(
|
@@ -61,7 +61,10 @@ def test_load_file(target_path: Path):
|
|
61
61
|
"type": "Workflow",
|
62
62
|
"desc": "Test multi config path",
|
63
63
|
"env": "${WORKFLOW_LOG_TIMEZONE}",
|
64
|
-
}
|
64
|
+
},
|
65
|
+
"test_load_not_set_type": {
|
66
|
+
"desc": "Test load not set type.",
|
67
|
+
},
|
65
68
|
},
|
66
69
|
f,
|
67
70
|
)
|
@@ -92,6 +95,12 @@ def test_load_file(target_path: Path):
|
|
92
95
|
with pytest.raises(TypeError):
|
93
96
|
YamlParser("test_load_file", extras={"conf_paths": target_path})
|
94
97
|
|
98
|
+
load = YamlParser(
|
99
|
+
"test_load_not_set_type", extras={"conf_paths": [target_path]}
|
100
|
+
)
|
101
|
+
with pytest.raises(ValueError):
|
102
|
+
_ = load.type
|
103
|
+
|
95
104
|
|
96
105
|
def test_load_file_finds(target_path: Path):
|
97
106
|
dummy_file: Path = target_path / "01_test_simple_file.yaml"
|
@@ -227,12 +236,13 @@ def test_parse_url():
|
|
227
236
|
assert url.path == "./logs"
|
228
237
|
|
229
238
|
url: ParseResult = urlparse("file:///./logs")
|
230
|
-
print(url)
|
231
239
|
assert url.scheme == "file"
|
232
240
|
assert url.path == "/./logs"
|
233
241
|
|
234
242
|
url: ParseResult = urlparse("sqlite:///home/warehouse/sqlite.db")
|
235
|
-
|
243
|
+
assert url.scheme == "sqlite"
|
244
|
+
assert url.path == "/home/warehouse/sqlite.db"
|
236
245
|
|
237
246
|
url: ParseResult = urlparse("file:./data.db")
|
238
|
-
|
247
|
+
assert url.scheme == "file"
|
248
|
+
assert url.path == "./data.db"
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
from datetime import datetime
|
3
3
|
from typing import Any
|
4
|
+
from urllib.parse import urlparse
|
4
5
|
|
5
6
|
import pytest
|
6
7
|
from ddeutil.workflow.errors import UtilError
|
@@ -35,11 +36,14 @@ def test_param2template():
|
|
35
36
|
"${{ params.src }}-${WORKFLOW_LOG_TIMEZONE:-}"
|
36
37
|
"${WORKFLOW_DUMMY:-}"
|
37
38
|
),
|
39
|
+
"url": urlparse("file:./conf"),
|
40
|
+
"set": {"${{ params.src }}", "${{ params.value }}"},
|
38
41
|
},
|
39
42
|
params={
|
40
43
|
"params": {
|
41
44
|
"src": "foo",
|
42
45
|
"value": -10,
|
46
|
+
"url": urlparse("file:./conf"),
|
43
47
|
},
|
44
48
|
},
|
45
49
|
)
|
@@ -49,6 +53,8 @@ def test_param2template():
|
|
49
53
|
"int_but_str": "value is 10",
|
50
54
|
"list": ["foo", -10],
|
51
55
|
"str_env": "foo-Asia/Bangkok-",
|
56
|
+
"url": urlparse("file:./conf"),
|
57
|
+
"set": {"foo", -10},
|
52
58
|
} == value
|
53
59
|
|
54
60
|
with pytest.raises(UtilError):
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__: str = "0.0.76"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/workflows.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
{ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/entry_points.txt
RENAMED
File without changes
|
{ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/requires.txt
RENAMED
File without changes
|
{ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|