ddeutil-workflow 0.0.55__tar.gz → 0.0.57__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 (74) hide show
  1. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/PKG-INFO +41 -35
  2. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/README.md +38 -32
  3. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/pyproject.toml +8 -4
  4. ddeutil_workflow-0.0.57/src/ddeutil/workflow/__about__.py +1 -0
  5. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__cron.py +26 -12
  6. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__init__.py +4 -2
  7. ddeutil_workflow-0.0.57/src/ddeutil/workflow/__main__.py +30 -0
  8. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__types.py +1 -0
  9. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/conf.py +163 -101
  10. ddeutil_workflow-0.0.55/src/ddeutil/workflow/cron.py → ddeutil_workflow-0.0.57/src/ddeutil/workflow/event.py +37 -20
  11. ddeutil_workflow-0.0.57/src/ddeutil/workflow/exceptions.py +87 -0
  12. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/job.py +87 -58
  13. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/logs.py +13 -5
  14. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/result.py +9 -4
  15. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/scheduler.py +38 -73
  16. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/stages.py +370 -147
  17. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/utils.py +37 -6
  18. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/workflow.py +243 -302
  19. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/PKG-INFO +41 -35
  20. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/SOURCES.txt +5 -4
  21. ddeutil_workflow-0.0.57/src/ddeutil_workflow.egg-info/entry_points.txt +2 -0
  22. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/requires.txt +2 -2
  23. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test__cron.py +27 -21
  24. ddeutil_workflow-0.0.57/tests/test_conf.py +218 -0
  25. ddeutil_workflow-0.0.55/tests/test_cron_on.py → ddeutil_workflow-0.0.57/tests/test_event.py +56 -22
  26. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_job.py +20 -21
  27. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_job_exec.py +93 -68
  28. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_job_exec_strategy.py +9 -20
  29. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_params.py +1 -4
  30. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_release.py +7 -20
  31. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_release_queue.py +1 -1
  32. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_result.py +16 -28
  33. ddeutil_workflow-0.0.57/tests/test_reusables_call_tag.py +121 -0
  34. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule.py +6 -9
  35. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule_workflow.py +1 -1
  36. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_stage.py +22 -27
  37. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_stage_handler_exec.py +280 -243
  38. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_utils.py +30 -4
  39. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow.py +112 -115
  40. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow_exec.py +158 -137
  41. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow_exec_job.py +10 -28
  42. ddeutil_workflow-0.0.57/tests/test_workflow_poke.py +168 -0
  43. ddeutil_workflow-0.0.57/tests/test_workflow_release.py +153 -0
  44. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow_task.py +34 -17
  45. ddeutil_workflow-0.0.55/src/ddeutil/workflow/__about__.py +0 -1
  46. ddeutil_workflow-0.0.55/src/ddeutil/workflow/__main__.py +0 -0
  47. ddeutil_workflow-0.0.55/src/ddeutil/workflow/exceptions.py +0 -57
  48. ddeutil_workflow-0.0.55/tests/test_conf.py +0 -160
  49. ddeutil_workflow-0.0.55/tests/test_reusables_call_tag.py +0 -252
  50. ddeutil_workflow-0.0.55/tests/test_workflow_exec_poke.py +0 -171
  51. ddeutil_workflow-0.0.55/tests/test_workflow_exec_release.py +0 -125
  52. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/LICENSE +0 -0
  53. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/setup.cfg +0 -0
  54. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/__init__.py +0 -0
  55. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/logs.py +0 -0
  56. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
  57. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/job.py +0 -0
  58. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/logs.py +0 -0
  59. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/schedules.py +0 -0
  60. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
  61. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/utils.py +0 -0
  62. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/params.py +0 -0
  63. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/reusables.py +0 -0
  64. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
  65. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
  66. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test__regex.py +0 -0
  67. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_logs_audit.py +0 -0
  68. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_logs_trace.py +0 -0
  69. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_reusables_template.py +0 -0
  70. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_reusables_template_filter.py +0 -0
  71. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule_pending.py +0 -0
  72. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule_tasks.py +0 -0
  73. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_scheduler_control.py +0 -0
  74. {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_strategy.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.55
3
+ Version: 0.0.57
4
4
  Summary: Lightweight workflow orchestration
5
5
  Author-email: ddeutils <korawich.anu@gmail.com>
6
6
  License: MIT
@@ -22,8 +22,8 @@ Classifier: Programming Language :: Python :: 3.13
22
22
  Requires-Python: >=3.9.13
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
- Requires-Dist: ddeutil[checksum]>=0.4.7
26
- Requires-Dist: ddeutil-io[toml,yaml]>=0.2.11
25
+ Requires-Dist: ddeutil[checksum]>=0.4.8
26
+ Requires-Dist: ddeutil-io[toml,yaml]>=0.2.12
27
27
  Requires-Dist: pydantic==2.11.1
28
28
  Requires-Dist: python-dotenv==1.1.0
29
29
  Requires-Dist: schedule<2.0.0,==1.2.2
@@ -250,42 +250,48 @@ from ddeutil.workflow import Workflow, Result
250
250
 
251
251
  workflow: Workflow = Workflow.from_conf('run-py-local')
252
252
  result: Result = workflow.execute(
253
- params={"source-extract": "USD-THB", "asat-dt": "2024-01-01"}
253
+ params={"source-extract": "USD-THB", "run-date": "2024-01-01"}
254
254
  )
255
255
  ```
256
256
 
257
- So, this package provide the `Schedule` template for this action, and you can dynamic
258
- pass the parameters for changing align with that running time by the `release` prefix.
259
-
260
- ```yaml
261
- schedule-run-local-wf:
262
-
263
- # Validate model that use to parsing exists for template file
264
- type: Schedule
265
- workflows:
266
-
267
- # Map existing workflow that want to deploy with scheduler application.
268
- # It allows you to pass release parameter that dynamic change depend on the
269
- # current context of this scheduler application releasing that time.
270
- - name: run-py-local
271
- params:
272
- source-extract: "USD-THB"
273
- asat-dt: "${{ release.logical_date }}"
274
- ```
275
-
276
- The main method of the `Schedule` model that use to running is `pending`. If you
277
- do not pass the `stop` date on this method, it will use config with `WORKFLOW_APP_STOP_BOUNDARY_DELTA`
278
- key for generate this stop date.
279
-
280
- ```python
281
- from ddeutil.workflow import Schedule
257
+ > [!NOTE]
258
+ > So, this package provide the `Schedule` template for this action, and you can
259
+ > pass the parameters dynamically for changing align with that running time by
260
+ > the `release` prefix.
261
+ >
262
+ > ```yaml
263
+ > schedule-run-local-wf:
264
+ >
265
+ > # Validate model that use to parsing exists for template file
266
+ > type: Schedule
267
+ > workflows:
268
+ >
269
+ > # Map existing workflow that want to deploy with scheduler application.
270
+ > # It allows you to pass release parameter that dynamic change depend on the
271
+ > # current context of this scheduler application releasing that time.
272
+ > - name: run-py-local
273
+ > params:
274
+ > source-extract: "USD-THB"
275
+ > run-date: "${{ release.logical_date }}"
276
+ > ```
277
+ >
278
+ > The main method of the `Schedule` model that use to running is `pending`. If you
279
+ > do not pass the `stop` date on this method, it will use config with
280
+ > `WORKFLOW_APP_STOP_BOUNDARY_DELTA` key for generate this stop date.
281
+ >
282
+ > ```python
283
+ > from ddeutil.workflow import Schedule
284
+ >
285
+ > (
286
+ > Schedule
287
+ > .from_conf("schedule-run-local-wf")
288
+ > .pending(stop=None)
289
+ > )
290
+ > ```
282
291
 
283
- (
284
- Schedule
285
- .from_conf("schedule-run-local-wf")
286
- .pending(stop=None)
287
- )
288
- ```
292
+ > [!WARNING]
293
+ > The scheduler feature is the expensive feature of this project. You should
294
+ > avoid to use it and find a scheduler tool instead.
289
295
 
290
296
  ## :cookie: Configuration
291
297
 
@@ -205,42 +205,48 @@ from ddeutil.workflow import Workflow, Result
205
205
 
206
206
  workflow: Workflow = Workflow.from_conf('run-py-local')
207
207
  result: Result = workflow.execute(
208
- params={"source-extract": "USD-THB", "asat-dt": "2024-01-01"}
208
+ params={"source-extract": "USD-THB", "run-date": "2024-01-01"}
209
209
  )
210
210
  ```
211
211
 
212
- So, this package provide the `Schedule` template for this action, and you can dynamic
213
- pass the parameters for changing align with that running time by the `release` prefix.
214
-
215
- ```yaml
216
- schedule-run-local-wf:
217
-
218
- # Validate model that use to parsing exists for template file
219
- type: Schedule
220
- workflows:
221
-
222
- # Map existing workflow that want to deploy with scheduler application.
223
- # It allows you to pass release parameter that dynamic change depend on the
224
- # current context of this scheduler application releasing that time.
225
- - name: run-py-local
226
- params:
227
- source-extract: "USD-THB"
228
- asat-dt: "${{ release.logical_date }}"
229
- ```
230
-
231
- The main method of the `Schedule` model that use to running is `pending`. If you
232
- do not pass the `stop` date on this method, it will use config with `WORKFLOW_APP_STOP_BOUNDARY_DELTA`
233
- key for generate this stop date.
234
-
235
- ```python
236
- from ddeutil.workflow import Schedule
212
+ > [!NOTE]
213
+ > So, this package provide the `Schedule` template for this action, and you can
214
+ > pass the parameters dynamically for changing align with that running time by
215
+ > the `release` prefix.
216
+ >
217
+ > ```yaml
218
+ > schedule-run-local-wf:
219
+ >
220
+ > # Validate model that use to parsing exists for template file
221
+ > type: Schedule
222
+ > workflows:
223
+ >
224
+ > # Map existing workflow that want to deploy with scheduler application.
225
+ > # It allows you to pass release parameter that dynamic change depend on the
226
+ > # current context of this scheduler application releasing that time.
227
+ > - name: run-py-local
228
+ > params:
229
+ > source-extract: "USD-THB"
230
+ > run-date: "${{ release.logical_date }}"
231
+ > ```
232
+ >
233
+ > The main method of the `Schedule` model that use to running is `pending`. If you
234
+ > do not pass the `stop` date on this method, it will use config with
235
+ > `WORKFLOW_APP_STOP_BOUNDARY_DELTA` key for generate this stop date.
236
+ >
237
+ > ```python
238
+ > from ddeutil.workflow import Schedule
239
+ >
240
+ > (
241
+ > Schedule
242
+ > .from_conf("schedule-run-local-wf")
243
+ > .pending(stop=None)
244
+ > )
245
+ > ```
237
246
 
238
- (
239
- Schedule
240
- .from_conf("schedule-run-local-wf")
241
- .pending(stop=None)
242
- )
243
- ```
247
+ > [!WARNING]
248
+ > The scheduler feature is the expensive feature of this project. You should
249
+ > avoid to use it and find a scheduler tool instead.
244
250
 
245
251
  ## :cookie: Configuration
246
252
 
@@ -25,8 +25,8 @@ classifiers = [
25
25
  ]
26
26
  requires-python = ">=3.9.13"
27
27
  dependencies = [
28
- "ddeutil[checksum]>=0.4.7",
29
- "ddeutil-io[yaml,toml]>=0.2.11",
28
+ "ddeutil[checksum]>=0.4.8",
29
+ "ddeutil-io[yaml,toml]>=0.2.12",
30
30
  "pydantic==2.11.1",
31
31
  "python-dotenv==1.1.0",
32
32
  "schedule==1.2.2,<2.0.0",
@@ -57,6 +57,9 @@ docker = [
57
57
  Homepage = "https://github.com/ddeutils/ddeutil-workflow/"
58
58
  "Source Code" = "https://github.com/ddeutils/ddeutil-workflow/"
59
59
 
60
+ [project.scripts]
61
+ workflow-cli = "ddeutil.workflow.__main__:app"
62
+
60
63
  [tool.setuptools.dynamic]
61
64
  version = {attr = "ddeutil.workflow.__about__.__version__"}
62
65
 
@@ -79,9 +82,10 @@ source = ["src.ddeutil.workflow"]
79
82
  omit = [
80
83
  "src/ddeutil/workflow/__about__.py",
81
84
  "src/ddeutil/workflow/__cron.py",
85
+ "src/ddeutil/workflow/__main__.py",
82
86
  "src/ddeutil/workflow/api/__init__.py",
83
- "src/ddeutil/workflow/api/log.py",
84
- "src/ddeutil/workflow/api/repeat.py",
87
+ "src/ddeutil/workflow/api/logs.py",
88
+ "src/ddeutil/workflow/api/utils.py",
85
89
  "src/ddeutil/workflow/api/routes/__init__.py",
86
90
  "src/ddeutil/workflow/api/routes/job.py",
87
91
  "src/ddeutil/workflow/api/routes/logs.py",
@@ -0,0 +1 @@
1
+ __version__: str = "0.0.57"
@@ -502,10 +502,10 @@ class CronPart:
502
502
  except IndexError:
503
503
  next_value: int = -1
504
504
  if value != (next_value - 1):
505
- # NOTE: ``next_value`` is not the subsequent number
505
+ # NOTE: `next_value` is not the subsequent number
506
506
  if start_number is None:
507
507
  # NOTE:
508
- # The last number of the list ``self.values`` is not in a
508
+ # The last number of the list `self.values` is not in a
509
509
  # range.
510
510
  multi_dim_values.append(value)
511
511
  else:
@@ -703,11 +703,14 @@ class CronJob:
703
703
  *,
704
704
  tz: str | None = None,
705
705
  ) -> CronRunner:
706
- """Returns the schedule datetime runner with this cronjob. It would run
707
- ``next``, ``prev``, or ``reset`` to generate running date that you want.
706
+ """Returns CronRunner instance that be datetime runner with this
707
+ cronjob. It can use `next`, `prev`, or `reset` methods to generate
708
+ running date.
708
709
 
709
- :param date: An initial date that want to mark as the start point.
710
- :param tz: A string timezone that want to change on runner.
710
+ :param date: (datetime) An initial date that want to mark as the start
711
+ point. (Default is use the current datetime)
712
+ :param tz: (str) A string timezone that want to change on runner.
713
+ (Default is None)
711
714
 
712
715
  :rtype: CronRunner
713
716
  """
@@ -743,6 +746,10 @@ class CronJobYear(CronJob):
743
746
  class CronRunner:
744
747
  """Create an instance of Date Runner object for datetime generate with
745
748
  cron schedule object value.
749
+
750
+ :param cron: (CronJob | CronJobYear)
751
+ :param date: (datetime)
752
+ :param tz: (str)
746
753
  """
747
754
 
748
755
  shift_limit: ClassVar[int] = 25
@@ -761,11 +768,17 @@ class CronRunner:
761
768
  cron: CronJob | CronJobYear,
762
769
  date: datetime | None = None,
763
770
  *,
764
- tz: str | None = None,
771
+ tz: str | ZoneInfo | None = None,
765
772
  ) -> None:
766
- # NOTE: Prepare timezone if this value does not set, it will use UTC.
767
- self.tz: ZoneInfo = ZoneInfo("UTC")
773
+ self.tz: ZoneInfo | None = None
768
774
  if tz:
775
+ if isinstance(tz, ZoneInfo):
776
+ self.tz = tz
777
+ elif not isinstance(tz, str):
778
+ raise TypeError(
779
+ "Invalid type of `tz` parameter, it should be str or "
780
+ "ZoneInfo instance."
781
+ )
769
782
  try:
770
783
  self.tz = ZoneInfo(tz)
771
784
  except ZoneInfoNotFoundError as err:
@@ -777,9 +790,10 @@ class CronRunner:
777
790
  raise ValueError(
778
791
  "Input schedule start time is not a valid datetime object."
779
792
  )
780
- if tz is None:
781
- self.tz = date.tzinfo
782
- self.date: datetime = date.astimezone(self.tz)
793
+ if tz is not None:
794
+ self.date: datetime = date.astimezone(self.tz)
795
+ else:
796
+ self.date: datetime = date
783
797
  else:
784
798
  self.date: datetime = datetime.now(tz=self.tz)
785
799
 
@@ -7,16 +7,18 @@ from .__cron import CronJob, CronRunner
7
7
  from .__types import DictData, DictStr, Matrix, Re, TupleStr
8
8
  from .conf import (
9
9
  Config,
10
- Loader,
10
+ FileLoad,
11
11
  config,
12
12
  env,
13
13
  )
14
- from .cron import *
14
+ from .event import *
15
15
  from .exceptions import *
16
16
  from .job import *
17
17
  from .logs import (
18
18
  Audit,
19
19
  AuditModel,
20
+ FileAudit,
21
+ FileTrace,
20
22
  Trace,
21
23
  TraceData,
22
24
  TraceMeta,
@@ -0,0 +1,30 @@
1
+ import typer
2
+
3
+ app = typer.Typer()
4
+
5
+
6
+ @app.callback()
7
+ def callback():
8
+ """
9
+ Awesome Portal Gun
10
+ """
11
+
12
+
13
+ @app.command()
14
+ def provision():
15
+ """
16
+ Shoot the portal gun
17
+ """
18
+ typer.echo("Shooting portal gun")
19
+
20
+
21
+ @app.command()
22
+ def job():
23
+ """
24
+ Load the portal gun
25
+ """
26
+ typer.echo("Loading portal gun")
27
+
28
+
29
+ if __name__ == "__main__":
30
+ app()
@@ -20,6 +20,7 @@ from typing import Any, Optional, TypedDict, Union
20
20
 
21
21
  from typing_extensions import Self
22
22
 
23
+ StrOrInt = Union[str, int]
23
24
  TupleStr = tuple[str, ...]
24
25
  DictData = dict[str, Any]
25
26
  DictStr = dict[str, str]