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.
Files changed (60) hide show
  1. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/PKG-INFO +1 -1
  2. ddeutil_workflow-0.0.77/src/ddeutil/workflow/__about__.py +1 -0
  3. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/conf.py +26 -10
  4. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/reusables.py +5 -4
  5. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/stages.py +2 -2
  6. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/utils.py +8 -2
  7. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/workflow.py +4 -0
  8. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/PKG-INFO +1 -1
  9. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_conf.py +14 -4
  10. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_template.py +6 -0
  11. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_release.py +1 -0
  12. ddeutil_workflow-0.0.76/src/ddeutil/workflow/__about__.py +0 -1
  13. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/LICENSE +0 -0
  14. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/README.md +0 -0
  15. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/pyproject.toml +0 -0
  16. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/setup.cfg +0 -0
  17. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__cron.py +0 -0
  18. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__init__.py +0 -0
  19. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__main__.py +0 -0
  20. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/__types.py +0 -0
  21. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/__init__.py +0 -0
  22. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/log_conf.py +0 -0
  23. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
  24. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/job.py +0 -0
  25. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/logs.py +0 -0
  26. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
  27. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/audits.py +0 -0
  28. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/cli.py +0 -0
  29. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/errors.py +0 -0
  30. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/event.py +0 -0
  31. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/job.py +0 -0
  32. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/params.py +0 -0
  33. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/result.py +0 -0
  34. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil/workflow/traces.py +0 -0
  35. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/SOURCES.txt +0 -0
  36. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
  37. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/entry_points.txt +0 -0
  38. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/requires.txt +0 -0
  39. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
  40. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test__cron.py +0 -0
  41. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test__regex.py +0 -0
  42. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_audits.py +0 -0
  43. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_cli.py +0 -0
  44. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_errors.py +0 -0
  45. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_event.py +0 -0
  46. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_job.py +0 -0
  47. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_job_exec.py +0 -0
  48. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_job_exec_strategy.py +0 -0
  49. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_params.py +0 -0
  50. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_result.py +0 -0
  51. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_call_tag.py +0 -0
  52. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_func_model.py +0 -0
  53. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_reusables_template_filter.py +0 -0
  54. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_strategy.py +0 -0
  55. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_traces.py +0 -0
  56. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_utils.py +0 -0
  57. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow.py +0 -0
  58. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_exec.py +0 -0
  59. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_exec_job.py +0 -0
  60. {ddeutil_workflow-0.0.76 → ddeutil_workflow-0.0.77}/tests/test_workflow_rerun.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.76
3
+ Version: 0.0.77
4
4
  Summary: Lightweight workflow orchestration with YAML template
5
5
  Author-email: ddeutils <korawich.anu@gmail.com>
6
6
  License: MIT
@@ -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
- :param obj: (object | str) An object that want to validate matching
331
- before return.
332
- :param path: (Path) A config path object.
333
- :param paths: (list[Path]) A list of config path object.
334
- :param excluded: An included list of data key that want to filter from
335
- data.
336
- :param extras: (DictData) An extra parameter that use to override core
337
- config values.
338
- :param ignore_filename: (str) An ignore filename. Default is
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
- return type(value)([pass_env(i) for i in value])
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
- return type(value)(
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
- return type(value)([filter_func(i) for i in value])
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
- return type(value)([dump_all(i, by_alias=by_alias) for i in value])
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=(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.76
3
+ Version: 0.0.77
4
4
  Summary: Lightweight workflow orchestration with YAML template
5
5
  Author-email: ddeutils <korawich.anu@gmail.com>
6
6
  License: MIT
@@ -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
- print(url)
243
+ assert url.scheme == "sqlite"
244
+ assert url.path == "/home/warehouse/sqlite.db"
236
245
 
237
246
  url: ParseResult = urlparse("file:./data.db")
238
- print(url)
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):
@@ -79,6 +79,7 @@ def test_workflow_release():
79
79
  rs: Result = workflow.release(
80
80
  release=release,
81
81
  params={"asat-dt": datetime(2024, 10, 1)},
82
+ runs_metadata={"runs_by": "nobody"},
82
83
  )
83
84
  assert rs.status == SUCCESS
84
85
  assert rs.context == {
@@ -1 +0,0 @@
1
- __version__: str = "0.0.76"