ddeutil-workflow 0.0.50__tar.gz → 0.0.52__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 (69) hide show
  1. {ddeutil_workflow-0.0.50/src/ddeutil_workflow.egg-info → ddeutil_workflow-0.0.52}/PKG-INFO +69 -13
  2. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/README.md +66 -10
  3. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/pyproject.toml +2 -2
  4. ddeutil_workflow-0.0.52/src/ddeutil/workflow/__about__.py +1 -0
  5. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/__init__.py +7 -56
  6. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/conf.py +2 -2
  7. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/cron.py +46 -20
  8. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/job.py +181 -100
  9. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/logs.py +22 -18
  10. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/params.py +56 -16
  11. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/reusables.py +4 -2
  12. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/scheduler.py +5 -1
  13. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/stages.py +320 -154
  14. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/workflow.py +83 -74
  15. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52/src/ddeutil_workflow.egg-info}/PKG-INFO +69 -13
  16. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil_workflow.egg-info/requires.txt +2 -2
  17. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_conf.py +4 -1
  18. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_job.py +14 -6
  19. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_job_exec_strategy.py +2 -2
  20. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_params.py +17 -0
  21. ddeutil_workflow-0.0.52/tests/test_result.py +105 -0
  22. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_stage.py +29 -0
  23. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_stage_handler_exec.py +258 -47
  24. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_workflow_exec.py +70 -5
  25. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_workflow_exec_release.py +4 -4
  26. ddeutil_workflow-0.0.50/src/ddeutil/workflow/__about__.py +0 -1
  27. ddeutil_workflow-0.0.50/tests/test_result.py +0 -59
  28. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/LICENSE +0 -0
  29. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/setup.cfg +0 -0
  30. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/__cron.py +0 -0
  31. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/__main__.py +0 -0
  32. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/__types.py +0 -0
  33. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/__init__.py +0 -0
  34. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/api.py +0 -0
  35. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/log.py +0 -0
  36. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/repeat.py +0 -0
  37. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
  38. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/routes/job.py +0 -0
  39. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/routes/logs.py +0 -0
  40. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/routes/schedules.py +0 -0
  41. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
  42. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/exceptions.py +0 -0
  43. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/result.py +0 -0
  44. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil/workflow/utils.py +0 -0
  45. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil_workflow.egg-info/SOURCES.txt +0 -0
  46. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
  47. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
  48. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test__cron.py +0 -0
  49. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test__regex.py +0 -0
  50. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_cron_on.py +0 -0
  51. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_job_exec.py +0 -0
  52. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_job_strategy.py +0 -0
  53. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_logs_audit.py +0 -0
  54. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_logs_trace.py +0 -0
  55. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_release.py +0 -0
  56. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_release_queue.py +0 -0
  57. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_reusables_call_tag.py +0 -0
  58. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_reusables_template.py +0 -0
  59. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_reusables_template_filter.py +0 -0
  60. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_schedule.py +0 -0
  61. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_schedule_pending.py +0 -0
  62. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_schedule_tasks.py +0 -0
  63. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_schedule_workflow.py +0 -0
  64. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_scheduler_control.py +0 -0
  65. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_utils.py +0 -0
  66. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_workflow.py +0 -0
  67. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_workflow_exec_job.py +0 -0
  68. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_workflow_exec_poke.py +0 -0
  69. {ddeutil_workflow-0.0.50 → ddeutil_workflow-0.0.52}/tests/test_workflow_task.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.50
3
+ Version: 0.0.52
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.6
26
- Requires-Dist: ddeutil-io[toml,yaml]>=0.2.10
25
+ Requires-Dist: ddeutil[checksum]>=0.4.7
26
+ Requires-Dist: ddeutil-io[toml,yaml]>=0.2.11
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
@@ -139,7 +139,8 @@ flowchart LR
139
139
 
140
140
  ## 📦 Installation
141
141
 
142
- This project need `ddeutil` and `ddeutil-io` extension namespace packages.
142
+ This project need `ddeutil` and `ddeutil-io` extension namespace packages to be
143
+ the base deps.
143
144
  If you want to install this package with application add-ons, you should add
144
145
  `app` in installation;
145
146
 
@@ -148,7 +149,7 @@ If you want to install this package with application add-ons, you should add
148
149
  | Python | `ddeutil-workflow` | :heavy_check_mark: |
149
150
  | FastAPI Server | `ddeutil-workflow[api]` | :heavy_check_mark: |
150
151
 
151
- ## :beers: Usage
152
+ ## 🎯 Usage
152
153
 
153
154
  This is examples that use workflow file for running common Data Engineering
154
155
  use-case.
@@ -198,12 +199,54 @@ run-py-local:
198
199
 
199
200
  # Arguments of target data that want to land.
200
201
  writing_mode: flatten
201
- aws_s3_path: my-data/open-data/${{ params.source-extract }}
202
+ aws:
203
+ path: my-data/open-data/${{ params.source-extract }}
202
204
 
203
- # This Authentication code should implement with your custom call
204
- # function. The template allow you to use environment variable.
205
- aws_access_client_id: ${AWS_ACCESS_CLIENT_ID}
206
- aws_access_client_secret: ${AWS_ACCESS_CLIENT_SECRET}
205
+ # This Authentication code should implement with your custom call
206
+ # function. The template allow you to use environment variable.
207
+ access_client_id: ${AWS_ACCESS_CLIENT_ID}
208
+ access_client_secret: ${AWS_ACCESS_CLIENT_SECRET}
209
+ ```
210
+
211
+ Before execute this workflow, you should implement caller function first.
212
+
213
+ ```text
214
+ registry-caller/
215
+ ╰─ tasks.py
216
+ ```
217
+
218
+ This function will store as module that will import from `WORKFLOW_CORE_REGISTRY_CALLER`
219
+ value (This config can override by extra parameters with `registry_caller` key).
220
+
221
+ ```python
222
+ from ddeutil.workflow import Result, tag
223
+ from ddeutil.workflow.exceptions import StageException
224
+ from pydantic import BaseModel, SecretStr
225
+
226
+ class AwsCredential(BaseModel):
227
+ path: str
228
+ access_client_id: str
229
+ access_client_secret: SecretStr
230
+
231
+ class RestAuth(BaseModel):
232
+ type: str
233
+ keys: SecretStr
234
+
235
+ @tag("requests", alias="get-api-with-oauth-to-s3")
236
+ def get_api_with_oauth_to_s3(
237
+ method: str,
238
+ url: str,
239
+ body: dict[str, str],
240
+ auth: RestAuth,
241
+ writing_node: str,
242
+ aws: AwsCredential,
243
+ result: Result,
244
+ ) -> dict[str, int]:
245
+ result.trace.info("[CALLER]: Start get data via RestAPI to S3.")
246
+ result.trace.info(f"... {method}: {url}")
247
+ if method != "post":
248
+ raise StageException(f"RestAPI does not support for {method} action.")
249
+ return {"records": 1000}
207
250
  ```
208
251
 
209
252
  The above workflow template is main executor pipeline that you want to do. If you
@@ -298,13 +341,15 @@ only.
298
341
  ## :rocket: Deployment
299
342
 
300
343
  This package able to run as an application service for receive manual trigger
301
- from the master node via RestAPI or use to be Scheduler background service
302
- like crontab job but via Python API.
344
+ from any node via RestAPI or use to be Scheduler background application
345
+ like crontab job but via Python API or FastAPI app.
303
346
 
304
347
  ### API Server
305
348
 
349
+ This server use FastAPI package to be the base application.
350
+
306
351
  ```shell
307
- (venv) $ uvicorn ddeutil.workflow.api:app \
352
+ (.venv) $ uvicorn ddeutil.workflow.api:app \
308
353
  --host 127.0.0.1 \
309
354
  --port 80 \
310
355
  --no-access-log
@@ -314,8 +359,19 @@ like crontab job but via Python API.
314
359
  > If this package already deploy, it is able to use multiprocess;
315
360
  > `uvicorn ddeutil.workflow.api:app --host 127.0.0.1 --port 80 --workers 4`
316
361
 
362
+ ### Local Schedule
363
+
364
+ > [!WARNING]
365
+ > This CLI does not implement yet.
366
+
367
+ ```shell
368
+ (.venv) $ ddeutil-workflow schedule
369
+ ```
370
+
317
371
  ### Docker Container
318
372
 
373
+ Build a Docker container from this package.
374
+
319
375
  ```shell
320
376
  $ docker build -t ddeutil-workflow:latest -f .container/Dockerfile .
321
377
  $ docker run -i ddeutil-workflow:latest ddeutil-workflow
@@ -94,7 +94,8 @@ flowchart LR
94
94
 
95
95
  ## 📦 Installation
96
96
 
97
- This project need `ddeutil` and `ddeutil-io` extension namespace packages.
97
+ This project need `ddeutil` and `ddeutil-io` extension namespace packages to be
98
+ the base deps.
98
99
  If you want to install this package with application add-ons, you should add
99
100
  `app` in installation;
100
101
 
@@ -103,7 +104,7 @@ If you want to install this package with application add-ons, you should add
103
104
  | Python | `ddeutil-workflow` | :heavy_check_mark: |
104
105
  | FastAPI Server | `ddeutil-workflow[api]` | :heavy_check_mark: |
105
106
 
106
- ## :beers: Usage
107
+ ## 🎯 Usage
107
108
 
108
109
  This is examples that use workflow file for running common Data Engineering
109
110
  use-case.
@@ -153,12 +154,54 @@ run-py-local:
153
154
 
154
155
  # Arguments of target data that want to land.
155
156
  writing_mode: flatten
156
- aws_s3_path: my-data/open-data/${{ params.source-extract }}
157
+ aws:
158
+ path: my-data/open-data/${{ params.source-extract }}
157
159
 
158
- # This Authentication code should implement with your custom call
159
- # function. The template allow you to use environment variable.
160
- aws_access_client_id: ${AWS_ACCESS_CLIENT_ID}
161
- aws_access_client_secret: ${AWS_ACCESS_CLIENT_SECRET}
160
+ # This Authentication code should implement with your custom call
161
+ # function. The template allow you to use environment variable.
162
+ access_client_id: ${AWS_ACCESS_CLIENT_ID}
163
+ access_client_secret: ${AWS_ACCESS_CLIENT_SECRET}
164
+ ```
165
+
166
+ Before execute this workflow, you should implement caller function first.
167
+
168
+ ```text
169
+ registry-caller/
170
+ ╰─ tasks.py
171
+ ```
172
+
173
+ This function will store as module that will import from `WORKFLOW_CORE_REGISTRY_CALLER`
174
+ value (This config can override by extra parameters with `registry_caller` key).
175
+
176
+ ```python
177
+ from ddeutil.workflow import Result, tag
178
+ from ddeutil.workflow.exceptions import StageException
179
+ from pydantic import BaseModel, SecretStr
180
+
181
+ class AwsCredential(BaseModel):
182
+ path: str
183
+ access_client_id: str
184
+ access_client_secret: SecretStr
185
+
186
+ class RestAuth(BaseModel):
187
+ type: str
188
+ keys: SecretStr
189
+
190
+ @tag("requests", alias="get-api-with-oauth-to-s3")
191
+ def get_api_with_oauth_to_s3(
192
+ method: str,
193
+ url: str,
194
+ body: dict[str, str],
195
+ auth: RestAuth,
196
+ writing_node: str,
197
+ aws: AwsCredential,
198
+ result: Result,
199
+ ) -> dict[str, int]:
200
+ result.trace.info("[CALLER]: Start get data via RestAPI to S3.")
201
+ result.trace.info(f"... {method}: {url}")
202
+ if method != "post":
203
+ raise StageException(f"RestAPI does not support for {method} action.")
204
+ return {"records": 1000}
162
205
  ```
163
206
 
164
207
  The above workflow template is main executor pipeline that you want to do. If you
@@ -253,13 +296,15 @@ only.
253
296
  ## :rocket: Deployment
254
297
 
255
298
  This package able to run as an application service for receive manual trigger
256
- from the master node via RestAPI or use to be Scheduler background service
257
- like crontab job but via Python API.
299
+ from any node via RestAPI or use to be Scheduler background application
300
+ like crontab job but via Python API or FastAPI app.
258
301
 
259
302
  ### API Server
260
303
 
304
+ This server use FastAPI package to be the base application.
305
+
261
306
  ```shell
262
- (venv) $ uvicorn ddeutil.workflow.api:app \
307
+ (.venv) $ uvicorn ddeutil.workflow.api:app \
263
308
  --host 127.0.0.1 \
264
309
  --port 80 \
265
310
  --no-access-log
@@ -269,8 +314,19 @@ like crontab job but via Python API.
269
314
  > If this package already deploy, it is able to use multiprocess;
270
315
  > `uvicorn ddeutil.workflow.api:app --host 127.0.0.1 --port 80 --workers 4`
271
316
 
317
+ ### Local Schedule
318
+
319
+ > [!WARNING]
320
+ > This CLI does not implement yet.
321
+
322
+ ```shell
323
+ (.venv) $ ddeutil-workflow schedule
324
+ ```
325
+
272
326
  ### Docker Container
273
327
 
328
+ Build a Docker container from this package.
329
+
274
330
  ```shell
275
331
  $ docker build -t ddeutil-workflow:latest -f .container/Dockerfile .
276
332
  $ docker run -i ddeutil-workflow:latest ddeutil-workflow
@@ -25,8 +25,8 @@ classifiers = [
25
25
  ]
26
26
  requires-python = ">=3.9.13"
27
27
  dependencies = [
28
- "ddeutil[checksum]>=0.4.6",
29
- "ddeutil-io[yaml,toml]>=0.2.10",
28
+ "ddeutil[checksum]>=0.4.7",
29
+ "ddeutil-io[yaml,toml]>=0.2.11",
30
30
  "pydantic==2.11.1",
31
31
  "python-dotenv==1.1.0",
32
32
  "schedule==1.2.2,<2.0.0",
@@ -0,0 +1 @@
1
+ __version__: str = "0.0.52"
@@ -11,25 +11,9 @@ from .conf import (
11
11
  config,
12
12
  env,
13
13
  )
14
- from .cron import (
15
- On,
16
- YearOn,
17
- interval2crontab,
18
- )
19
- from .exceptions import (
20
- JobException,
21
- ParamValueException,
22
- StageException,
23
- UtilException,
24
- WorkflowException,
25
- )
26
- from .job import (
27
- Job,
28
- RunsOn,
29
- Strategy,
30
- local_execute,
31
- local_execute_strategy,
32
- )
14
+ from .cron import *
15
+ from .exceptions import *
16
+ from .job import *
33
17
  from .logs import (
34
18
  Audit,
35
19
  AuditModel,
@@ -41,13 +25,7 @@ from .logs import (
41
25
  get_dt_tznow,
42
26
  get_trace,
43
27
  )
44
- from .params import (
45
- ChoiceParam,
46
- DatetimeParam,
47
- IntParam,
48
- Param,
49
- StrParam,
50
- )
28
+ from .params import *
51
29
  from .result import (
52
30
  CANCEL,
53
31
  FAILED,
@@ -82,33 +60,6 @@ from .scheduler import (
82
60
  schedule_runner,
83
61
  schedule_task,
84
62
  )
85
- from .stages import (
86
- BashStage,
87
- CallStage,
88
- EmptyStage,
89
- ForEachStage,
90
- ParallelStage,
91
- PyStage,
92
- Stage,
93
- TriggerStage,
94
- )
95
- from .utils import (
96
- batch,
97
- cross_product,
98
- default_gen_id,
99
- delay,
100
- filter_func,
101
- gen_id,
102
- get_diff_sec,
103
- get_dt_now,
104
- make_exec,
105
- reach_next_minute,
106
- replace_sec,
107
- wait_to_next_minute,
108
- )
109
- from .workflow import (
110
- Release,
111
- ReleaseQueue,
112
- Workflow,
113
- WorkflowTask,
114
- )
63
+ from .stages import *
64
+ from .utils import *
65
+ from .workflow import *
@@ -360,13 +360,13 @@ def dynamic(
360
360
  :param extras: An extra values that pass at run-time.
361
361
  """
362
362
  rsx: Optional[T] = extras[key] if extras and key in extras else None
363
- rs: Optional[T] = f or getattr(config, key, None)
363
+ rs: Optional[T] = getattr(config, key, None) if f is None else f
364
364
  if rsx is not None and not isinstance(rsx, type(rs)):
365
365
  raise TypeError(
366
366
  f"Type of config {key!r} from extras: {rsx!r} does not valid "
367
367
  f"as config {type(rs)}."
368
368
  )
369
- return rsx or rs
369
+ return rsx if rsx is not None else rs
370
370
 
371
371
 
372
372
  class Loader(SimLoad):
@@ -16,18 +16,13 @@ from pydantic.functional_validators import field_validator, model_validator
16
16
  from typing_extensions import Self
17
17
 
18
18
  from .__cron import WEEKDAYS, CronJob, CronJobYear, CronRunner, Options
19
- from .__types import DictData, DictStr, TupleStr
19
+ from .__types import DictData, DictStr
20
20
  from .conf import Loader
21
21
 
22
- __all__: TupleStr = (
23
- "On",
24
- "YearOn",
25
- "interval2crontab",
26
- )
27
-
28
22
 
29
23
  def interval2crontab(
30
24
  interval: Literal["daily", "weekly", "monthly"],
25
+ *,
31
26
  day: str | None = None,
32
27
  time: str = "00:00",
33
28
  ) -> str:
@@ -67,7 +62,7 @@ class On(BaseModel):
67
62
  """On Pydantic model (Warped crontab object by model).
68
63
 
69
64
  See Also:
70
- * ``generate()`` is the main use-case of this schedule object.
65
+ * `generate()` is the main use-case of this schedule object.
71
66
  """
72
67
 
73
68
  model_config = ConfigDict(arbitrary_types_allowed=True)
@@ -76,12 +71,18 @@ class On(BaseModel):
76
71
  DictData,
77
72
  Field(
78
73
  default_factory=dict,
79
- description="An extras mapping parameters.",
74
+ description=(
75
+ "An extras parameters that want to pass to the CronJob field."
76
+ ),
80
77
  ),
81
78
  ]
82
79
  cronjob: Annotated[
83
80
  CronJob,
84
- Field(description="A Cronjob object of this schedule."),
81
+ Field(
82
+ description=(
83
+ "A Cronjob object that use for validate and generate datetime.",
84
+ ),
85
+ ),
85
86
  ]
86
87
  tz: Annotated[
87
88
  str,
@@ -118,6 +119,8 @@ class On(BaseModel):
118
119
 
119
120
  :param name: A name of config that will get from loader.
120
121
  :param extras: An extra parameter that will keep in extras.
122
+
123
+ :rtype: Self
121
124
  """
122
125
  extras: DictData = extras or {}
123
126
  loader: Loader = Loader(name, externals=extras)
@@ -142,9 +145,7 @@ class On(BaseModel):
142
145
  )
143
146
  )
144
147
  if "cronjob" not in loader_data:
145
- raise ValueError(
146
- "Config does not set ``cronjob`` or ``interval`` keys"
147
- )
148
+ raise ValueError("Config does not set `cronjob` or `interval` keys")
148
149
  return cls.model_validate(
149
150
  obj=dict(
150
151
  cronjob=loader_data.pop("cronjob"),
@@ -155,7 +156,13 @@ class On(BaseModel):
155
156
 
156
157
  @model_validator(mode="before")
157
158
  def __prepare_values(cls, values: DictData) -> DictData:
158
- """Extract tz key from value and change name to timezone key."""
159
+ """Extract tz key from value and change name to timezone key.
160
+
161
+ :param values: (DictData) A data that want to pass for create an On
162
+ model.
163
+
164
+ :rtype: DictData
165
+ """
159
166
  if tz := values.pop("tz", None):
160
167
  values["timezone"] = tz
161
168
  return values
@@ -170,8 +177,8 @@ class On(BaseModel):
170
177
  try:
171
178
  _ = ZoneInfo(value)
172
179
  return value
173
- except ZoneInfoNotFoundError as err:
174
- raise ValueError(f"Invalid timezone: {value}") from err
180
+ except ZoneInfoNotFoundError as e:
181
+ raise ValueError(f"Invalid timezone: {value}") from e
175
182
 
176
183
  @field_validator(
177
184
  "cronjob", mode="before", json_schema_input_type=Union[CronJob, str]
@@ -180,9 +187,13 @@ class On(BaseModel):
180
187
  cls, value: str | CronJob, info: ValidationInfo
181
188
  ) -> CronJob:
182
189
  """Prepare crontab value that able to receive with string type.
183
- This step will get options kwargs from extras and pass to the
190
+ This step will get options kwargs from extras field and pass to the
184
191
  CronJob object.
185
192
 
193
+ :param value: (str | CronJobYear) A cronjob value that want to create.
194
+ :param info: (ValidationInfo) A validation info object that use to get
195
+ the extra parameters for create cronjob.
196
+
186
197
  :rtype: CronJob
187
198
  """
188
199
  extras: DictData = info.data.get("extras", {})
@@ -203,12 +214,17 @@ class On(BaseModel):
203
214
  def __serialize_cronjob(self, value: CronJob) -> str:
204
215
  """Serialize the cronjob field that store with CronJob object.
205
216
 
217
+ :param value: (CronJob) The CronJob field.
218
+
206
219
  :rtype: str
207
220
  """
208
221
  return str(value)
209
222
 
210
223
  def generate(self, start: str | datetime) -> CronRunner:
211
- """Return Cron runner object.
224
+ """Return CronRunner object from an initial datetime.
225
+
226
+ :param start: (str | datetime) A string or datetime for generate the
227
+ CronRunner object.
212
228
 
213
229
  :rtype: CronRunner
214
230
  """
@@ -242,16 +258,26 @@ class YearOn(On):
242
258
  # NOTE: This is fields of the base schedule.
243
259
  cronjob: Annotated[
244
260
  CronJobYear,
245
- Field(description="Cron job of this schedule"),
261
+ Field(
262
+ description=(
263
+ "A Cronjob object that use for validate and generate datetime.",
264
+ ),
265
+ ),
246
266
  ]
247
267
 
248
268
  @field_validator(
249
- "cronjob", mode="before", json_schema_input_type=Union[CronJob, str]
269
+ "cronjob", mode="before", json_schema_input_type=Union[CronJobYear, str]
250
270
  )
251
271
  def __prepare_cronjob(
252
272
  cls, value: str | CronJobYear, info: ValidationInfo
253
273
  ) -> CronJobYear:
254
274
  """Prepare crontab value that able to receive with string type.
275
+ This step will get options kwargs from extras field and pass to the
276
+ CronJobYear object.
277
+
278
+ :param value: (str | CronJobYear) A cronjob value that want to create.
279
+ :param info: (ValidationInfo) A validation info object that use to get
280
+ the extra parameters for create cronjob.
255
281
 
256
282
  :rtype: CronJobYear
257
283
  """