ddeutil-workflow 0.0.30__py3-none-any.whl → 0.0.32__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.
- ddeutil/workflow/__about__.py +1 -1
- ddeutil/workflow/__cron.py +1 -0
- ddeutil/workflow/__init__.py +5 -1
- ddeutil/workflow/api/api.py +4 -6
- ddeutil/workflow/api/route.py +4 -4
- ddeutil/workflow/conf.py +4 -0
- ddeutil/workflow/cron.py +77 -21
- ddeutil/workflow/exceptions.py +3 -0
- ddeutil/workflow/job.py +2 -0
- ddeutil/workflow/params.py +21 -1
- ddeutil/workflow/result.py +1 -0
- ddeutil/workflow/scheduler.py +156 -50
- ddeutil/workflow/stage.py +13 -1
- ddeutil/workflow/templates.py +13 -4
- ddeutil/workflow/utils.py +36 -10
- ddeutil/workflow/workflow.py +118 -87
- {ddeutil_workflow-0.0.30.dist-info → ddeutil_workflow-0.0.32.dist-info}/METADATA +27 -3
- ddeutil_workflow-0.0.32.dist-info/RECORD +25 -0
- ddeutil_workflow-0.0.30.dist-info/RECORD +0 -25
- {ddeutil_workflow-0.0.30.dist-info → ddeutil_workflow-0.0.32.dist-info}/LICENSE +0 -0
- {ddeutil_workflow-0.0.30.dist-info → ddeutil_workflow-0.0.32.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.30.dist-info → ddeutil_workflow-0.0.32.dist-info}/top_level.txt +0 -0
ddeutil/workflow/workflow.py
CHANGED
@@ -29,7 +29,8 @@ from concurrent.futures import (
|
|
29
29
|
)
|
30
30
|
from dataclasses import field
|
31
31
|
from datetime import datetime, timedelta
|
32
|
-
from
|
32
|
+
from enum import Enum
|
33
|
+
from functools import partial, total_ordering
|
33
34
|
from heapq import heappop, heappush
|
34
35
|
from queue import Queue
|
35
36
|
from textwrap import dedent
|
@@ -53,21 +54,33 @@ from .utils import (
|
|
53
54
|
cut_id,
|
54
55
|
gen_id,
|
55
56
|
get_dt_now,
|
56
|
-
|
57
|
+
reach_next_minute,
|
58
|
+
wait_to_next_minute,
|
57
59
|
)
|
58
60
|
|
59
61
|
logger = get_logger("ddeutil.workflow")
|
60
62
|
|
61
63
|
__all__: TupleStr = (
|
62
|
-
"Workflow",
|
63
64
|
"Release",
|
64
65
|
"ReleaseQueue",
|
66
|
+
"ReleaseType",
|
67
|
+
"Workflow",
|
65
68
|
"WorkflowTask",
|
66
69
|
)
|
67
70
|
|
68
71
|
|
72
|
+
class ReleaseType(str, Enum):
|
73
|
+
"""Release Type Enum support the type field on the Release dataclass."""
|
74
|
+
|
75
|
+
DEFAULT: str = "manual"
|
76
|
+
TASK: str = "task"
|
77
|
+
POKE: str = "poking"
|
78
|
+
|
79
|
+
|
69
80
|
@total_ordering
|
70
|
-
@dataclass(
|
81
|
+
@dataclass(
|
82
|
+
config=ConfigDict(arbitrary_types_allowed=True, use_enum_values=True)
|
83
|
+
)
|
71
84
|
class Release:
|
72
85
|
"""Release Pydantic dataclass object that use for represent
|
73
86
|
the release data that use with the `workflow.release` method."""
|
@@ -76,7 +89,7 @@ class Release:
|
|
76
89
|
offset: float
|
77
90
|
end_date: datetime
|
78
91
|
runner: CronRunner
|
79
|
-
type:
|
92
|
+
type: ReleaseType = field(default=ReleaseType.DEFAULT)
|
80
93
|
|
81
94
|
def __repr__(self) -> str:
|
82
95
|
return repr(f"{self.date:%Y-%m-%d %H:%M:%S}")
|
@@ -94,13 +107,16 @@ class Release:
|
|
94
107
|
"""
|
95
108
|
if isinstance(dt, str):
|
96
109
|
dt: datetime = datetime.fromisoformat(dt)
|
110
|
+
elif not isinstance(dt, datetime):
|
111
|
+
raise TypeError(
|
112
|
+
"The `from_dt` need argument type be str or datetime only."
|
113
|
+
)
|
97
114
|
|
98
115
|
return cls(
|
99
116
|
date=dt,
|
100
117
|
offset=0,
|
101
118
|
end_date=dt + timedelta(days=1),
|
102
119
|
runner=CronJob("* * * * *").schedule(dt.replace(tzinfo=config.tz)),
|
103
|
-
type="manual",
|
104
120
|
)
|
105
121
|
|
106
122
|
def __eq__(self, other: Release | datetime) -> bool:
|
@@ -174,13 +190,6 @@ class ReleaseQueue:
|
|
174
190
|
|
175
191
|
:rtype: bool
|
176
192
|
"""
|
177
|
-
# NOTE: Old logic to peeking the first release from waiting queue.
|
178
|
-
#
|
179
|
-
# first_value: Release = heappop(self.queue)
|
180
|
-
# heappush(self.queue, first_value)
|
181
|
-
#
|
182
|
-
# return first_value
|
183
|
-
#
|
184
193
|
return self.queue[0]
|
185
194
|
|
186
195
|
def check_queue(self, value: Release | datetime) -> bool:
|
@@ -477,7 +486,7 @@ class Workflow(BaseModel):
|
|
477
486
|
*,
|
478
487
|
run_id: str | None = None,
|
479
488
|
log: type[Log] = None,
|
480
|
-
queue: ReleaseQueue |
|
489
|
+
queue: ReleaseQueue | None = None,
|
481
490
|
override_log_name: str | None = None,
|
482
491
|
) -> Result:
|
483
492
|
"""Release the workflow execution with overriding parameter with the
|
@@ -487,7 +496,7 @@ class Workflow(BaseModel):
|
|
487
496
|
This method allow workflow use log object to save the execution
|
488
497
|
result to log destination like file log to the local `/logs` directory.
|
489
498
|
|
490
|
-
|
499
|
+
Steps:
|
491
500
|
- Initialize ReleaseQueue and Release if they do not pass.
|
492
501
|
- Create release data for pass to parameter templating function.
|
493
502
|
- Execute this workflow with mapping release data to its parameters.
|
@@ -497,7 +506,7 @@ class Workflow(BaseModel):
|
|
497
506
|
|
498
507
|
:param release: A release datetime or Release object.
|
499
508
|
:param params: A workflow parameter that pass to execute method.
|
500
|
-
:param queue: A
|
509
|
+
:param queue: A ReleaseQueue that use for mark complete.
|
501
510
|
:param run_id: A workflow running ID for this release.
|
502
511
|
:param log: A log class that want to save the execution result.
|
503
512
|
:param queue: A ReleaseQueue object.
|
@@ -510,13 +519,14 @@ class Workflow(BaseModel):
|
|
510
519
|
name: str = override_log_name or self.name
|
511
520
|
run_id: str = run_id or gen_id(name, unique=True)
|
512
521
|
rs_release: Result = Result(run_id=run_id)
|
513
|
-
rs_release_type: str = "release"
|
514
522
|
|
515
|
-
|
516
|
-
|
517
|
-
|
523
|
+
if queue is not None and not isinstance(queue, ReleaseQueue):
|
524
|
+
raise TypeError(
|
525
|
+
"The queue argument should be ReleaseQueue object only."
|
526
|
+
)
|
518
527
|
|
519
528
|
# VALIDATE: Change release value to Release object.
|
529
|
+
rs_release_type: str = "release"
|
520
530
|
if isinstance(release, datetime):
|
521
531
|
rs_release_type: str = "datetime"
|
522
532
|
release: Release = Release.from_dt(release)
|
@@ -548,24 +558,26 @@ class Workflow(BaseModel):
|
|
548
558
|
)
|
549
559
|
|
550
560
|
rs.set_parent_run_id(run_id)
|
551
|
-
rs_log: Log = log.model_validate(
|
552
|
-
{
|
553
|
-
"name": name,
|
554
|
-
"release": release.date,
|
555
|
-
"type": release.type,
|
556
|
-
"context": rs.context,
|
557
|
-
"parent_run_id": rs.parent_run_id,
|
558
|
-
"run_id": rs.run_id,
|
559
|
-
}
|
560
|
-
)
|
561
561
|
|
562
562
|
# NOTE: Saving execution result to destination of the input log object.
|
563
563
|
logger.debug(f"({cut_id(run_id)}) [LOG]: Writing log: {name!r}.")
|
564
|
-
|
564
|
+
(
|
565
|
+
log.model_validate(
|
566
|
+
{
|
567
|
+
"name": name,
|
568
|
+
"release": release.date,
|
569
|
+
"type": release.type,
|
570
|
+
"context": rs.context,
|
571
|
+
"parent_run_id": rs.parent_run_id,
|
572
|
+
"run_id": rs.run_id,
|
573
|
+
}
|
574
|
+
).save(excluded=None)
|
575
|
+
)
|
565
576
|
|
566
577
|
# NOTE: Remove this release from running.
|
567
|
-
queue
|
568
|
-
|
578
|
+
if queue is not None:
|
579
|
+
queue.remove_running(release)
|
580
|
+
queue.mark_complete(release)
|
569
581
|
|
570
582
|
# NOTE: Remove the params key from the result context for deduplicate.
|
571
583
|
context: dict[str, Any] = rs.context
|
@@ -594,8 +606,16 @@ class Workflow(BaseModel):
|
|
594
606
|
*,
|
595
607
|
force_run: bool = False,
|
596
608
|
) -> ReleaseQueue:
|
597
|
-
"""Generate
|
598
|
-
the
|
609
|
+
"""Generate Release from all on values from the on field and store them
|
610
|
+
to the ReleaseQueue object.
|
611
|
+
|
612
|
+
Steps:
|
613
|
+
- For-loop all the on value in the on field.
|
614
|
+
- Create Release object from the current date that not reach the end
|
615
|
+
date.
|
616
|
+
- Check this release do not store on the release queue object.
|
617
|
+
Generate the next date if it exists.
|
618
|
+
- Push this release to the release queue
|
599
619
|
|
600
620
|
:param offset: An offset in second unit for time travel.
|
601
621
|
:param end_date: An end datetime object.
|
@@ -621,7 +641,7 @@ class Workflow(BaseModel):
|
|
621
641
|
offset=offset,
|
622
642
|
end_date=end_date,
|
623
643
|
runner=runner,
|
624
|
-
type=
|
644
|
+
type=ReleaseType.POKE,
|
625
645
|
)
|
626
646
|
|
627
647
|
while queue.check_queue(workflow_release) or (
|
@@ -633,7 +653,7 @@ class Workflow(BaseModel):
|
|
633
653
|
offset=offset,
|
634
654
|
end_date=end_date,
|
635
655
|
runner=runner,
|
636
|
-
type=
|
656
|
+
type=ReleaseType.POKE,
|
637
657
|
)
|
638
658
|
|
639
659
|
if runner.date > end_date:
|
@@ -662,6 +682,9 @@ class Workflow(BaseModel):
|
|
662
682
|
This method will observe its schedule that nearing to run with the
|
663
683
|
``self.release()`` method.
|
664
684
|
|
685
|
+
The limitation of this method is not allow run a date that less
|
686
|
+
than the current date.
|
687
|
+
|
665
688
|
:param start_date: A start datetime object.
|
666
689
|
:param params: A parameters that want to pass to the release method.
|
667
690
|
:param run_id: A workflow running ID for this poke.
|
@@ -678,6 +701,12 @@ class Workflow(BaseModel):
|
|
678
701
|
log: type[Log] = log or get_log()
|
679
702
|
run_id: str = run_id or gen_id(self.name, unique=True)
|
680
703
|
|
704
|
+
# VALIDATE: Check the periods value should gather than 0.
|
705
|
+
if periods <= 0:
|
706
|
+
raise WorkflowException(
|
707
|
+
"The period of poking should be int and grater or equal than 1."
|
708
|
+
)
|
709
|
+
|
681
710
|
# NOTE: If this workflow does not set the on schedule, it will return
|
682
711
|
# empty result.
|
683
712
|
if len(self.on) == 0:
|
@@ -687,23 +716,25 @@ class Workflow(BaseModel):
|
|
687
716
|
)
|
688
717
|
return []
|
689
718
|
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
719
|
+
# NOTE: Create the current date that change microsecond to 0
|
720
|
+
current_date: datetime = datetime.now(tz=config.tz).replace(
|
721
|
+
microsecond=0
|
722
|
+
)
|
694
723
|
|
695
724
|
# NOTE: Create start_date and offset variables.
|
696
|
-
current_date: datetime = datetime.now(tz=config.tz)
|
697
|
-
|
698
725
|
if start_date and start_date <= current_date:
|
699
|
-
start_date = start_date.replace(tzinfo=config.tz)
|
726
|
+
start_date = start_date.replace(tzinfo=config.tz).replace(
|
727
|
+
microsecond=0
|
728
|
+
)
|
700
729
|
offset: float = (current_date - start_date).total_seconds()
|
701
730
|
else:
|
731
|
+
# NOTE: Force change start date if it gathers than the current date,
|
732
|
+
# or it does not pass to this method.
|
702
733
|
start_date: datetime = current_date
|
703
734
|
offset: float = 0
|
704
735
|
|
705
|
-
# NOTE:
|
706
|
-
# value.
|
736
|
+
# NOTE: The end date is using to stop generate queue with an input
|
737
|
+
# periods value.
|
707
738
|
end_date: datetime = start_date + timedelta(minutes=periods)
|
708
739
|
|
709
740
|
logger.info(
|
@@ -715,17 +746,17 @@ class Workflow(BaseModel):
|
|
715
746
|
results: list[Result] = []
|
716
747
|
|
717
748
|
# NOTE: Create empty ReleaseQueue object.
|
718
|
-
|
749
|
+
q: ReleaseQueue = ReleaseQueue()
|
719
750
|
|
720
|
-
# NOTE:
|
721
|
-
|
722
|
-
|
723
|
-
end_date=
|
724
|
-
queue=wf_queue,
|
725
|
-
log=log,
|
726
|
-
force_run=force_run,
|
751
|
+
# NOTE: Create reusable partial function and add Release to the release
|
752
|
+
# queue object.
|
753
|
+
partial_queue = partial(
|
754
|
+
self.queue, offset, end_date, log=log, force_run=force_run
|
727
755
|
)
|
728
|
-
|
756
|
+
partial_queue(q)
|
757
|
+
|
758
|
+
# NOTE: Return the empty result if it does not have any Release.
|
759
|
+
if not q.is_queued:
|
729
760
|
logger.info(
|
730
761
|
f"({cut_id(run_id)}) [POKING]: {self.name!r} does not have "
|
731
762
|
f"any queue."
|
@@ -741,34 +772,27 @@ class Workflow(BaseModel):
|
|
741
772
|
|
742
773
|
futures: list[Future] = []
|
743
774
|
|
744
|
-
while
|
775
|
+
while q.is_queued:
|
745
776
|
|
746
|
-
# NOTE: Pop the latest Release object from queue.
|
747
|
-
release: Release = heappop(
|
777
|
+
# NOTE: Pop the latest Release object from the release queue.
|
778
|
+
release: Release = heappop(q.queue)
|
748
779
|
|
749
|
-
if (
|
750
|
-
release.date - get_dt_now(tz=config.tz, offset=offset)
|
751
|
-
).total_seconds() > 60:
|
780
|
+
if reach_next_minute(release.date, tz=config.tz, offset=offset):
|
752
781
|
logger.debug(
|
753
|
-
f"({cut_id(run_id)}) [POKING]:
|
754
|
-
f"release
|
782
|
+
f"({cut_id(run_id)}) [POKING]: The latest release, "
|
783
|
+
f"{release.date:%Y-%m-%d %H:%M:%S}, is not able to run "
|
784
|
+
f"on this minute"
|
755
785
|
)
|
756
|
-
heappush(
|
757
|
-
|
786
|
+
heappush(q.queue, release)
|
787
|
+
wait_to_next_minute(get_dt_now(tz=config.tz, offset=offset))
|
758
788
|
|
759
789
|
# WARNING: I already call queue poking again because issue
|
760
790
|
# about the every minute crontab.
|
761
|
-
|
762
|
-
offset,
|
763
|
-
end_date,
|
764
|
-
queue=wf_queue,
|
765
|
-
log=log,
|
766
|
-
force_run=force_run,
|
767
|
-
)
|
791
|
+
partial_queue(q)
|
768
792
|
continue
|
769
793
|
|
770
794
|
# NOTE: Push the latest Release to the running queue.
|
771
|
-
heappush(
|
795
|
+
heappush(q.running, release)
|
772
796
|
|
773
797
|
futures.append(
|
774
798
|
executor.submit(
|
@@ -776,17 +800,11 @@ class Workflow(BaseModel):
|
|
776
800
|
release=release,
|
777
801
|
params=params,
|
778
802
|
log=log,
|
779
|
-
queue=
|
803
|
+
queue=q,
|
780
804
|
)
|
781
805
|
)
|
782
806
|
|
783
|
-
|
784
|
-
offset,
|
785
|
-
end_date,
|
786
|
-
queue=wf_queue,
|
787
|
-
log=log,
|
788
|
-
force_run=force_run,
|
789
|
-
)
|
807
|
+
partial_queue(q)
|
790
808
|
|
791
809
|
# WARNING: This poking method does not allow to use fail-fast
|
792
810
|
# logic to catching parallel execution result.
|
@@ -1148,20 +1166,31 @@ class WorkflowTask:
|
|
1148
1166
|
release: datetime | Release | None = None,
|
1149
1167
|
run_id: str | None = None,
|
1150
1168
|
log: type[Log] = None,
|
1151
|
-
queue: ReleaseQueue |
|
1169
|
+
queue: ReleaseQueue | None = None,
|
1152
1170
|
) -> Result:
|
1153
1171
|
"""Release the workflow task data.
|
1154
1172
|
|
1155
1173
|
:param release: A release datetime or Release object.
|
1156
1174
|
:param run_id: A workflow running ID for this release.
|
1157
1175
|
:param log: A log class that want to save the execution result.
|
1158
|
-
:param queue: A ReleaseQueue object.
|
1176
|
+
:param queue: A ReleaseQueue object that use to mark complete.
|
1159
1177
|
|
1160
1178
|
:rtype: Result
|
1161
1179
|
"""
|
1162
1180
|
log: type[Log] = log or get_log()
|
1163
1181
|
|
1164
1182
|
if release is None:
|
1183
|
+
|
1184
|
+
if queue is None:
|
1185
|
+
raise ValueError(
|
1186
|
+
"If pass None release value, you should to pass the queue"
|
1187
|
+
"for generate this release."
|
1188
|
+
)
|
1189
|
+
elif not isinstance(queue, ReleaseQueue):
|
1190
|
+
raise TypeError(
|
1191
|
+
"The queue argument should be ReleaseQueue object only."
|
1192
|
+
)
|
1193
|
+
|
1165
1194
|
if queue.check_queue(self.runner.date):
|
1166
1195
|
release = self.runner.next
|
1167
1196
|
|
@@ -1170,6 +1199,7 @@ class WorkflowTask:
|
|
1170
1199
|
else:
|
1171
1200
|
release = self.runner.date
|
1172
1201
|
|
1202
|
+
# NOTE: Call the workflow release method.
|
1173
1203
|
return self.workflow.release(
|
1174
1204
|
release=release,
|
1175
1205
|
params=self.values,
|
@@ -1186,8 +1216,9 @@ class WorkflowTask:
|
|
1186
1216
|
log: type[Log],
|
1187
1217
|
*,
|
1188
1218
|
force_run: bool = False,
|
1189
|
-
):
|
1190
|
-
"""Generate Release to
|
1219
|
+
) -> ReleaseQueue:
|
1220
|
+
"""Generate Release from the runner field and store it to the
|
1221
|
+
ReleaseQueue object.
|
1191
1222
|
|
1192
1223
|
:param end_date: An end datetime object.
|
1193
1224
|
:param queue: A workflow queue object.
|
@@ -1205,7 +1236,7 @@ class WorkflowTask:
|
|
1205
1236
|
offset=0,
|
1206
1237
|
end_date=end_date,
|
1207
1238
|
runner=self.runner,
|
1208
|
-
type=
|
1239
|
+
type=ReleaseType.TASK,
|
1209
1240
|
)
|
1210
1241
|
|
1211
1242
|
while queue.check_queue(workflow_release) or (
|
@@ -1217,7 +1248,7 @@ class WorkflowTask:
|
|
1217
1248
|
offset=0,
|
1218
1249
|
end_date=end_date,
|
1219
1250
|
runner=self.runner,
|
1220
|
-
type=
|
1251
|
+
type=ReleaseType.TASK,
|
1221
1252
|
)
|
1222
1253
|
|
1223
1254
|
if self.runner.date > end_date:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: ddeutil-workflow
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.32
|
4
4
|
Summary: Lightweight workflow orchestration
|
5
5
|
Author-email: ddeutils <korawich.anu@gmail.com>
|
6
6
|
License: MIT
|
@@ -110,7 +110,7 @@ flowchart LR
|
|
110
110
|
E -.->|read| G
|
111
111
|
```
|
112
112
|
|
113
|
-
> [!
|
113
|
+
> [!WARNING]
|
114
114
|
> _Disclaimer_: I inspire the dynamic statement from the [**GitHub Action**](https://github.com/features/actions)
|
115
115
|
> with `.yml` files and all configs file from several data orchestration framework
|
116
116
|
> tools from my experience on Data Engineer. :grimacing:
|
@@ -192,7 +192,17 @@ The above workflow template is main executor pipeline that you want to do. If yo
|
|
192
192
|
want to schedule this workflow, you want to dynamic its parameters change base on
|
193
193
|
execution time such as `run-date` should change base on that workflow running date.
|
194
194
|
|
195
|
-
|
195
|
+
```python
|
196
|
+
from ddeutil.workflow import Workflow, Result
|
197
|
+
|
198
|
+
workflow: Workflow = Workflow.from_loader('run-py-local')
|
199
|
+
result: Result = workflow.execute(
|
200
|
+
params={"source-extract": "USD-THB", "asat-dt": "2024-01-01"}
|
201
|
+
)
|
202
|
+
```
|
203
|
+
|
204
|
+
So, this package provide the `Schedule` template for this action, and you can dynamic
|
205
|
+
pass the parameters for changing align with that running time by the `release` prefix.
|
196
206
|
|
197
207
|
```yaml
|
198
208
|
schedule-run-local-wf:
|
@@ -210,6 +220,20 @@ schedule-run-local-wf:
|
|
210
220
|
asat-dt: "${{ release.logical_date }}"
|
211
221
|
```
|
212
222
|
|
223
|
+
The main method of the `Schedule` model that use to running is `pending`. If you
|
224
|
+
do not pass the `stop` date on this method, it will use config with `WORKFLOW_APP_STOP_BOUNDARY_DELTA`
|
225
|
+
key for generate this stop date.
|
226
|
+
|
227
|
+
```python
|
228
|
+
from ddeutil.workflow import Schedule
|
229
|
+
|
230
|
+
(
|
231
|
+
Schedule
|
232
|
+
.from_loader("schedule-run-local-wf")
|
233
|
+
.pending(stop=None)
|
234
|
+
)
|
235
|
+
```
|
236
|
+
|
213
237
|
## :cookie: Configuration
|
214
238
|
|
215
239
|
The main configuration that use to dynamic changing this workflow engine for your
|
@@ -0,0 +1,25 @@
|
|
1
|
+
ddeutil/workflow/__about__.py,sha256=xnsfT_lwFz-qKzFIHbOUGMgvgpOAAANig-X3brDri44,28
|
2
|
+
ddeutil/workflow/__cron.py,sha256=3i-wmjTlh0ADCzN9pLKaWHzJkXzC72aIBmVEQSbyCCE,26895
|
3
|
+
ddeutil/workflow/__init__.py,sha256=pRIZIGwC7Xs8Ur7-jHPIAMLriD5If9zOPc-ZmKZS2XQ,1678
|
4
|
+
ddeutil/workflow/__types.py,sha256=CK1jfzyHP9P-MB0ElhpJZ59ZFGJC9MkQuAop5739_9k,4304
|
5
|
+
ddeutil/workflow/conf.py,sha256=6yGbSi69lsccYgnrwTzdjdPhU54hUop2e1GjBNres08,17663
|
6
|
+
ddeutil/workflow/cron.py,sha256=j8EeoHst70toRfnD_frix41vrI-eLYVJkZ9yeJtpfnI,8871
|
7
|
+
ddeutil/workflow/exceptions.py,sha256=5ghT443VLq0IeU87loHNEqqrrrctklP7YfxwJ51ImWU,949
|
8
|
+
ddeutil/workflow/hook.py,sha256=MgZFlTGvaRSBrTouZGlxwYpKQoKDOT26PNhESeL3LY0,5469
|
9
|
+
ddeutil/workflow/job.py,sha256=siph5FBU5Ah2CHWZyXotHJKMemFWQXSBqSdwk8b_6p8,24366
|
10
|
+
ddeutil/workflow/params.py,sha256=LKR7jXyxTb5NVrFav_fl2y9xo3p7qL1S9h-i6CtvNwE,5851
|
11
|
+
ddeutil/workflow/result.py,sha256=8LItqF-Xe6pAAWkAsY_QFkKBOA0fEBh97I2og3CZsPc,3409
|
12
|
+
ddeutil/workflow/scheduler.py,sha256=r26ZKpx0kuaL0hMJ39tIyZaeFMwhcwitUzBh-ge2ZJg,24394
|
13
|
+
ddeutil/workflow/stage.py,sha256=vUne9aUZX7G8K5BkBwirAjXSVwVvAoBt8HXbqUMEgns,24329
|
14
|
+
ddeutil/workflow/templates.py,sha256=A0JgZFGkBv-AX-EskZj656nG5zFd3j1PpLpyXihf6Xg,10967
|
15
|
+
ddeutil/workflow/utils.py,sha256=rTDQKaaber7cRqzJjWpCP9OTbarti1UMKdLgH6VRjFM,6709
|
16
|
+
ddeutil/workflow/workflow.py,sha256=ET1otR5VcfnOMoNiW7EMb1_wIaxNw9yWsBXS5kVWG9s,43428
|
17
|
+
ddeutil/workflow/api/__init__.py,sha256=F53NMBWtb9IKaDWkPU5KvybGGfKAcbehgn6TLBwHuuM,21
|
18
|
+
ddeutil/workflow/api/api.py,sha256=AwcUkE6S2Txz4hZOD10TsUkuFiKQ47rpMYMYpl7ssis,3954
|
19
|
+
ddeutil/workflow/api/repeat.py,sha256=zyvsrXKk-3-_N8ZRZSki0Mueshugum2jtqctEOp9QSc,4927
|
20
|
+
ddeutil/workflow/api/route.py,sha256=A9YPfchPNRyN6ev5sg1Z12zSi8JEQ6yZEea0EFPQp8k,8591
|
21
|
+
ddeutil_workflow-0.0.32.dist-info/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
|
22
|
+
ddeutil_workflow-0.0.32.dist-info/METADATA,sha256=FYn_uM88ehiyBBZto8ECxmWHwBPtFGHAOcBPkaRBNFU,15552
|
23
|
+
ddeutil_workflow-0.0.32.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
24
|
+
ddeutil_workflow-0.0.32.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
|
25
|
+
ddeutil_workflow-0.0.32.dist-info/RECORD,,
|
@@ -1,25 +0,0 @@
|
|
1
|
-
ddeutil/workflow/__about__.py,sha256=zSy9Xk11PPZkgJ5Db1_kZp2yzt5inkEHVJWwFHPWlmk,28
|
2
|
-
ddeutil/workflow/__cron.py,sha256=uA8XcbY_GwA9rJSHaHUaXaJyGDObJN0ZeYlJSinL8y8,26880
|
3
|
-
ddeutil/workflow/__init__.py,sha256=dghn2lFl3Own4Pyq7SFHu-FMymOgLontJ6aCfxea9h4,1606
|
4
|
-
ddeutil/workflow/__types.py,sha256=CK1jfzyHP9P-MB0ElhpJZ59ZFGJC9MkQuAop5739_9k,4304
|
5
|
-
ddeutil/workflow/conf.py,sha256=7lj_Im9jsa95fWUo19Q4-ZAcHa8Pu1HW-vaLgvrjNUM,17559
|
6
|
-
ddeutil/workflow/cron.py,sha256=OLgniUxmrn65gzckk-uTmE2Pk1enJJyjYUKVeBbDQz0,7522
|
7
|
-
ddeutil/workflow/exceptions.py,sha256=XUnpJSuxOyataClP0w_gpYjzn-NIwZK2BHro-J7Yw24,895
|
8
|
-
ddeutil/workflow/hook.py,sha256=MgZFlTGvaRSBrTouZGlxwYpKQoKDOT26PNhESeL3LY0,5469
|
9
|
-
ddeutil/workflow/job.py,sha256=XcewyALsLYYq94ycF6mkj3Ydr6if683z7t1oBqEVInE,24290
|
10
|
-
ddeutil/workflow/params.py,sha256=svCjmFgEhim8yFJVjZhFmKP8JqTDHQ5EPhwJHVuDGno,5289
|
11
|
-
ddeutil/workflow/result.py,sha256=k4pcj5KjbEcEPymsEUXeGY4gyLMfPkMTO6YDrAtfk7Q,3408
|
12
|
-
ddeutil/workflow/scheduler.py,sha256=f3d7c5SVgY5Q1JsHQ6cH513CJmJkh4l8YcKAGYudJRc,20426
|
13
|
-
ddeutil/workflow/stage.py,sha256=wn8CARTvFJY4ZK1SwjzH8sKoMRz_eIeSGUMgnDWNi6g,24031
|
14
|
-
ddeutil/workflow/templates.py,sha256=bVU_8gnMQmdhhw3W28ZqwmpEaOx10Nx_aauqiLS0lqg,10807
|
15
|
-
ddeutil/workflow/utils.py,sha256=8LTqpvRPfrEYxsxhwszk6GKkyjrswxnwF3r_9vE8szw,6059
|
16
|
-
ddeutil/workflow/workflow.py,sha256=ZLbG-K2gSNAsDGiHPjbtJd7rsEFf6jfVGAVB_9jpy84,42103
|
17
|
-
ddeutil/workflow/api/__init__.py,sha256=F53NMBWtb9IKaDWkPU5KvybGGfKAcbehgn6TLBwHuuM,21
|
18
|
-
ddeutil/workflow/api/api.py,sha256=Ma9R8yuQAhowG_hox-k53swFsf5IAvheEnSxNQ-8DaQ,4039
|
19
|
-
ddeutil/workflow/api/repeat.py,sha256=zyvsrXKk-3-_N8ZRZSki0Mueshugum2jtqctEOp9QSc,4927
|
20
|
-
ddeutil/workflow/api/route.py,sha256=v96jNbgjM1cJ2MpVSRWs2kgRqF8DQElEBdRZrVFEpEw,8578
|
21
|
-
ddeutil_workflow-0.0.30.dist-info/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
|
22
|
-
ddeutil_workflow-0.0.30.dist-info/METADATA,sha256=zbVHOL41qpFRG83SacZVYK9tS2JRTCM61cpnSXty9LU,14868
|
23
|
-
ddeutil_workflow-0.0.30.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
24
|
-
ddeutil_workflow-0.0.30.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
|
25
|
-
ddeutil_workflow-0.0.30.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|