ddeutil-workflow 0.0.55__py3-none-any.whl → 0.0.57__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.
@@ -3,7 +3,6 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
- # [x] Use dynamic config
7
6
  """The main schedule running is `schedule_runner` function that trigger the
8
7
  multiprocess of `schedule_control` function for listing schedules on the
9
8
  config by `Loader.finds(Schedule)`.
@@ -17,6 +16,11 @@ functions; `workflow_task`, and `workflow_monitor`.
17
16
  The `schedule_task` will run `task.release` method in threading object
18
17
  for multithreading strategy. This `release` method will run only one crontab
19
18
  value with the on field.
19
+
20
+ Steps:
21
+ - Extract all schedule config on the conf path.
22
+ - Slice schedules to multiprocess
23
+ - Start running task.
20
24
  """
21
25
  from __future__ import annotations
22
26
 
@@ -34,7 +38,7 @@ from heapq import heappop, heappush
34
38
  from pathlib import Path
35
39
  from textwrap import dedent
36
40
  from threading import Thread
37
- from typing import Callable, Optional, TypedDict, Union
41
+ from typing import Any, Callable, Optional, TypedDict, Union
38
42
 
39
43
  from pydantic import BaseModel, Field, ValidationInfo
40
44
  from pydantic.functional_validators import field_validator, model_validator
@@ -52,8 +56,8 @@ except ImportError: # pragma: no cov
52
56
 
53
57
  from .__cron import CronRunner
54
58
  from .__types import DictData, TupleStr
55
- from .conf import Loader, SimLoad, dynamic
56
- from .cron import On
59
+ from .conf import FileLoad, Loader, dynamic
60
+ from .event import On
57
61
  from .exceptions import ScheduleException, WorkflowException
58
62
  from .logs import Audit, get_audit
59
63
  from .result import SUCCESS, Result
@@ -113,21 +117,15 @@ class ScheduleWorkflow(BaseModel):
113
117
  )
114
118
 
115
119
  @model_validator(mode="before")
116
- def __prepare_before__(cls, values: DictData) -> DictData:
117
- """Prepare incoming values before validating with model fields.
118
-
119
- :rtype: DictData
120
- """
121
- # VALIDATE: Prepare a workflow name that should not include space.
122
- if name := values.get("name"):
123
- values["name"] = name.replace(" ", "_")
124
-
125
- # VALIDATE: Add default the alias field with the name.
126
- if not values.get("alias"):
127
- values["alias"] = values.get("name")
128
-
129
- cls.__bypass_on(values, extras=values.get("extras"))
130
- return values
120
+ def __prepare_before__(cls, data: Any) -> Any:
121
+ """Prepare incoming values before validating with model fields."""
122
+ if isinstance(data, dict):
123
+ # VALIDATE: Add default the alias field with the name.
124
+ if "alias" not in data:
125
+ data["alias"] = data.get("name")
126
+
127
+ cls.__bypass_on(data, extras=data.get("extras"))
128
+ return data
131
129
 
132
130
  @classmethod
133
131
  def __bypass_on(
@@ -135,8 +133,10 @@ class ScheduleWorkflow(BaseModel):
135
133
  ) -> DictData:
136
134
  """Bypass and prepare the on data to loaded config data.
137
135
 
138
- :param data: A data that want to validate for model initialization.
139
- :param extras: An extra parameter that want to override core config.
136
+ :param data: (DictData) A data that want to validate for the model
137
+ initialization.
138
+ :param extras: (DictData) An extra parameter that want to override core
139
+ config values.
140
140
 
141
141
  :rtype: DictData
142
142
  """
@@ -151,7 +151,7 @@ class ScheduleWorkflow(BaseModel):
151
151
  # NOTE: Pass on value to Loader and keep on model object to on
152
152
  # field.
153
153
  data["on"] = [
154
- Loader(n, externals=extras).data if isinstance(n, str) else n
154
+ FileLoad(n, externals=extras).data if isinstance(n, str) else n
155
155
  for n in on
156
156
  ]
157
157
 
@@ -162,6 +162,10 @@ class ScheduleWorkflow(BaseModel):
162
162
  """Validate the on fields should not contain duplicate values and if it
163
163
  contains every minute value, it should have only one on value.
164
164
 
165
+ :param value: (list[On]) A list of `On` object.
166
+ :param info: (ValidationInfo) An validation info object for getting an
167
+ extra parameter.
168
+
165
169
  :rtype: list[On]
166
170
  """
167
171
  set_ons: set[str] = {str(on.cronjob) for on in value}
@@ -191,23 +195,22 @@ class ScheduleWorkflow(BaseModel):
191
195
  This task creation need queue to tracking release date already
192
196
  mapped or not.
193
197
 
194
- :param start_date: A start date that get from the workflow schedule.
195
- :param queue: A mapping of name and list of datetime for queue.
198
+ :param start_date: (datetime) A start datetime that get from the
199
+ workflow schedule.
200
+ :param queue: (dict[str, ReleaseQueue]) A mapping of name and list of
201
+ datetime for queue.
196
202
 
197
203
  :rtype: list[WorkflowTask]
198
204
  :return: Return the list of WorkflowTask object from the specific
199
205
  input datetime that mapping with the on field.
200
206
  """
201
- workflow_tasks: list[WorkflowTask] = []
202
-
203
- # NOTE: Loading workflow model from the name of workflow.
204
207
  wf: Workflow = Workflow.from_conf(self.name, extras=self.extras)
205
208
  wf_queue: ReleaseQueue = queue[self.alias]
206
209
 
207
210
  # IMPORTANT: Create the default 'on' value if it does not pass the `on`
208
211
  # field to the Schedule object.
209
212
  ons: list[On] = self.on or wf.on.copy()
210
-
213
+ workflow_tasks: list[WorkflowTask] = []
211
214
  for on in ons:
212
215
 
213
216
  # NOTE: Create CronRunner instance from the start_date param.
@@ -250,7 +253,7 @@ class Schedule(BaseModel):
250
253
  )
251
254
  workflows: list[ScheduleWorkflow] = Field(
252
255
  default_factory=list,
253
- description="A list of ScheduleWorkflow models.",
256
+ description="A list of ScheduleWorkflow model.",
254
257
  )
255
258
 
256
259
  @field_validator("desc", mode="after")
@@ -267,6 +270,8 @@ class Schedule(BaseModel):
267
270
  def from_conf(
268
271
  cls,
269
272
  name: str,
273
+ *,
274
+ path: Optional[Path] = None,
270
275
  extras: DictData | None = None,
271
276
  ) -> Self:
272
277
  """Create Schedule instance from the Loader object that only receive
@@ -274,6 +279,7 @@ class Schedule(BaseModel):
274
279
  searching configuration data of this schedule model in conf path.
275
280
 
276
281
  :param name: (str) A schedule name that want to pass to Loader object.
282
+ :param path: (Path) An override config path.
277
283
  :param extras: An extra parameters that want to pass to Loader
278
284
  object.
279
285
 
@@ -281,55 +287,14 @@ class Schedule(BaseModel):
281
287
 
282
288
  :rtype: Self
283
289
  """
284
- loader: Loader = Loader(name, externals=(extras or {}))
290
+ loader: Loader = FileLoad(name, path=path, extras=extras)
285
291
 
286
292
  # NOTE: Validate the config type match with current connection model
287
293
  if loader.type != cls.__name__:
288
294
  raise ValueError(f"Type {loader.type} does not match with {cls}")
289
295
 
290
296
  loader_data: DictData = copy.deepcopy(loader.data)
291
-
292
- # NOTE: Add name to loader data
293
- loader_data["name"] = name.replace(" ", "_")
294
-
295
- if extras:
296
- loader_data["extras"] = extras
297
-
298
- return cls.model_validate(obj=loader_data)
299
-
300
- @classmethod
301
- def from_path(
302
- cls,
303
- name: str,
304
- path: Path,
305
- extras: DictData | None = None,
306
- ) -> Self:
307
- """Create Schedule instance from the SimLoad object that receive an
308
- input schedule name and conf path. The loader object will use this
309
- schedule name to searching configuration data of this schedule model
310
- in conf path.
311
-
312
- :param name: (str) A schedule name that want to pass to Loader object.
313
- :param path: (Path) A config path that want to search.
314
- :param extras: An external parameters that want to pass to Loader
315
- object.
316
-
317
- :raise ValueError: If the type does not match with current object.
318
-
319
- :rtype: Self
320
- """
321
- loader: SimLoad = SimLoad(
322
- name, conf_path=path, externals=(extras or {})
323
- )
324
-
325
- # NOTE: Validate the config type match with current connection model
326
- if loader.type != cls.__name__:
327
- raise ValueError(f"Type {loader.type} does not match with {cls}")
328
-
329
- loader_data: DictData = copy.deepcopy(loader.data)
330
-
331
- # NOTE: Add name to loader data
332
- loader_data["name"] = name.replace(" ", "_")
297
+ loader_data["name"] = name
333
298
 
334
299
  if extras:
335
300
  loader_data["extras"] = extras
@@ -738,7 +703,7 @@ def schedule_control(
738
703
  :rtype: Result
739
704
  """
740
705
  audit: type[Audit] = audit or get_audit(extras=extras)
741
- result: Result = Result().set_parent_run_id(parent_run_id)
706
+ result: Result = Result.construct_with_rs_or_id(parent_run_id=parent_run_id)
742
707
 
743
708
  # NOTE: Create the start and stop datetime.
744
709
  start_date: datetime = datetime.now(tz=dynamic("tz", extras=extras))