ddeutil-workflow 0.0.40__py3-none-any.whl → 0.0.41__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/__init__.py +21 -25
- ddeutil/workflow/api/api.py +1 -1
- ddeutil/workflow/api/routes/logs.py +1 -2
- ddeutil/workflow/api/routes/workflows.py +1 -1
- ddeutil/workflow/conf.py +11 -1
- ddeutil/workflow/job.py +55 -4
- ddeutil/workflow/logs.py +334 -72
- ddeutil/workflow/params.py +1 -0
- ddeutil/workflow/result.py +6 -15
- ddeutil/workflow/{templates.py → reusables.py} +195 -9
- ddeutil/workflow/scheduler.py +1 -1
- ddeutil/workflow/stages.py +188 -24
- ddeutil/workflow/utils.py +11 -0
- ddeutil/workflow/workflow.py +16 -8
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/METADATA +7 -1
- ddeutil_workflow-0.0.41.dist-info/RECORD +31 -0
- ddeutil/workflow/audit.py +0 -257
- ddeutil/workflow/caller.py +0 -179
- ddeutil_workflow-0.0.40.dist-info/RECORD +0 -33
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/top_level.txt +0 -0
ddeutil/workflow/audit.py
DELETED
@@ -1,257 +0,0 @@
|
|
1
|
-
# ------------------------------------------------------------------------------
|
2
|
-
# Copyright (c) 2022 Korawich Anuttra. All rights reserved.
|
3
|
-
# Licensed under the MIT License. See LICENSE in the project root for
|
4
|
-
# license information.
|
5
|
-
# ------------------------------------------------------------------------------
|
6
|
-
"""Audit Log module."""
|
7
|
-
from __future__ import annotations
|
8
|
-
|
9
|
-
import json
|
10
|
-
import os
|
11
|
-
from abc import ABC, abstractmethod
|
12
|
-
from collections.abc import Iterator
|
13
|
-
from datetime import datetime
|
14
|
-
from pathlib import Path
|
15
|
-
from typing import ClassVar, Optional, Union
|
16
|
-
|
17
|
-
from pydantic import BaseModel, Field
|
18
|
-
from pydantic.functional_validators import model_validator
|
19
|
-
from typing_extensions import Self
|
20
|
-
|
21
|
-
from .__types import DictData, TupleStr
|
22
|
-
from .conf import config
|
23
|
-
from .logs import TraceLog, get_dt_tznow, get_trace
|
24
|
-
|
25
|
-
__all__: TupleStr = (
|
26
|
-
"get_audit",
|
27
|
-
"FileAudit",
|
28
|
-
"SQLiteAudit",
|
29
|
-
"Audit",
|
30
|
-
)
|
31
|
-
|
32
|
-
|
33
|
-
class BaseAudit(BaseModel, ABC):
|
34
|
-
"""Base Audit Pydantic Model with abstraction class property that implement
|
35
|
-
only model fields. This model should to use with inherit to logging
|
36
|
-
subclass like file, sqlite, etc.
|
37
|
-
"""
|
38
|
-
|
39
|
-
name: str = Field(description="A workflow name.")
|
40
|
-
release: datetime = Field(description="A release datetime.")
|
41
|
-
type: str = Field(description="A running type before logging.")
|
42
|
-
context: DictData = Field(
|
43
|
-
default_factory=dict,
|
44
|
-
description="A context that receive from a workflow execution result.",
|
45
|
-
)
|
46
|
-
parent_run_id: Optional[str] = Field(
|
47
|
-
default=None, description="A parent running ID."
|
48
|
-
)
|
49
|
-
run_id: str = Field(description="A running ID")
|
50
|
-
update: datetime = Field(default_factory=get_dt_tznow)
|
51
|
-
execution_time: float = Field(default=0, description="An execution time.")
|
52
|
-
|
53
|
-
@model_validator(mode="after")
|
54
|
-
def __model_action(self) -> Self:
|
55
|
-
"""Do before the Audit action with WORKFLOW_AUDIT_ENABLE_WRITE env variable.
|
56
|
-
|
57
|
-
:rtype: Self
|
58
|
-
"""
|
59
|
-
if config.enable_write_audit:
|
60
|
-
self.do_before()
|
61
|
-
return self
|
62
|
-
|
63
|
-
def do_before(self) -> None: # pragma: no cov
|
64
|
-
"""To something before end up of initial log model."""
|
65
|
-
|
66
|
-
@abstractmethod
|
67
|
-
def save(self, excluded: list[str] | None) -> None: # pragma: no cov
|
68
|
-
"""Save this model logging to target logging store."""
|
69
|
-
raise NotImplementedError("Audit should implement ``save`` method.")
|
70
|
-
|
71
|
-
|
72
|
-
class FileAudit(BaseAudit):
|
73
|
-
"""File Audit Pydantic Model that use to saving log data from result of
|
74
|
-
workflow execution. It inherits from BaseAudit model that implement the
|
75
|
-
``self.save`` method for file.
|
76
|
-
"""
|
77
|
-
|
78
|
-
filename_fmt: ClassVar[str] = (
|
79
|
-
"workflow={name}/release={release:%Y%m%d%H%M%S}"
|
80
|
-
)
|
81
|
-
|
82
|
-
def do_before(self) -> None:
|
83
|
-
"""Create directory of release before saving log file."""
|
84
|
-
self.pointer().mkdir(parents=True, exist_ok=True)
|
85
|
-
|
86
|
-
@classmethod
|
87
|
-
def find_audits(cls, name: str) -> Iterator[Self]:
|
88
|
-
"""Generate the audit data that found from logs path with specific a
|
89
|
-
workflow name.
|
90
|
-
|
91
|
-
:param name: A workflow name that want to search release logging data.
|
92
|
-
|
93
|
-
:rtype: Iterator[Self]
|
94
|
-
"""
|
95
|
-
pointer: Path = config.audit_path / f"workflow={name}"
|
96
|
-
if not pointer.exists():
|
97
|
-
raise FileNotFoundError(f"Pointer: {pointer.absolute()}.")
|
98
|
-
|
99
|
-
for file in pointer.glob("./release=*/*.log"):
|
100
|
-
with file.open(mode="r", encoding="utf-8") as f:
|
101
|
-
yield cls.model_validate(obj=json.load(f))
|
102
|
-
|
103
|
-
@classmethod
|
104
|
-
def find_audit_with_release(
|
105
|
-
cls,
|
106
|
-
name: str,
|
107
|
-
release: datetime | None = None,
|
108
|
-
) -> Self:
|
109
|
-
"""Return the audit data that found from logs path with specific
|
110
|
-
workflow name and release values. If a release does not pass to an input
|
111
|
-
argument, it will return the latest release from the current log path.
|
112
|
-
|
113
|
-
:param name: A workflow name that want to search log.
|
114
|
-
:param release: A release datetime that want to search log.
|
115
|
-
|
116
|
-
:raise FileNotFoundError:
|
117
|
-
:raise NotImplementedError: If an input release does not pass to this
|
118
|
-
method. Because this method does not implement latest log.
|
119
|
-
|
120
|
-
:rtype: Self
|
121
|
-
"""
|
122
|
-
if release is None:
|
123
|
-
raise NotImplementedError("Find latest log does not implement yet.")
|
124
|
-
|
125
|
-
pointer: Path = (
|
126
|
-
config.audit_path
|
127
|
-
/ f"workflow={name}/release={release:%Y%m%d%H%M%S}"
|
128
|
-
)
|
129
|
-
if not pointer.exists():
|
130
|
-
raise FileNotFoundError(
|
131
|
-
f"Pointer: ./logs/workflow={name}/"
|
132
|
-
f"release={release:%Y%m%d%H%M%S} does not found."
|
133
|
-
)
|
134
|
-
|
135
|
-
with max(pointer.glob("./*.log"), key=os.path.getctime).open(
|
136
|
-
mode="r", encoding="utf-8"
|
137
|
-
) as f:
|
138
|
-
return cls.model_validate(obj=json.load(f))
|
139
|
-
|
140
|
-
@classmethod
|
141
|
-
def is_pointed(cls, name: str, release: datetime) -> bool:
|
142
|
-
"""Check the release log already pointed or created at the destination
|
143
|
-
log path.
|
144
|
-
|
145
|
-
:param name: A workflow name.
|
146
|
-
:param release: A release datetime.
|
147
|
-
|
148
|
-
:rtype: bool
|
149
|
-
:return: Return False if the release log was not pointed or created.
|
150
|
-
"""
|
151
|
-
# NOTE: Return False if enable writing log flag does not set.
|
152
|
-
if not config.enable_write_audit:
|
153
|
-
return False
|
154
|
-
|
155
|
-
# NOTE: create pointer path that use the same logic of pointer method.
|
156
|
-
pointer: Path = config.audit_path / cls.filename_fmt.format(
|
157
|
-
name=name, release=release
|
158
|
-
)
|
159
|
-
|
160
|
-
return pointer.exists()
|
161
|
-
|
162
|
-
def pointer(self) -> Path:
|
163
|
-
"""Return release directory path that was generated from model data.
|
164
|
-
|
165
|
-
:rtype: Path
|
166
|
-
"""
|
167
|
-
return config.audit_path / self.filename_fmt.format(
|
168
|
-
name=self.name, release=self.release
|
169
|
-
)
|
170
|
-
|
171
|
-
def save(self, excluded: list[str] | None) -> Self:
|
172
|
-
"""Save logging data that receive a context data from a workflow
|
173
|
-
execution result.
|
174
|
-
|
175
|
-
:param excluded: An excluded list of key name that want to pass in the
|
176
|
-
model_dump method.
|
177
|
-
|
178
|
-
:rtype: Self
|
179
|
-
"""
|
180
|
-
trace: TraceLog = get_trace(self.run_id, self.parent_run_id)
|
181
|
-
|
182
|
-
# NOTE: Check environ variable was set for real writing.
|
183
|
-
if not config.enable_write_audit:
|
184
|
-
trace.debug("[LOG]: Skip writing log cause config was set")
|
185
|
-
return self
|
186
|
-
|
187
|
-
log_file: Path = (
|
188
|
-
self.pointer() / f"{self.parent_run_id or self.run_id}.log"
|
189
|
-
)
|
190
|
-
log_file.write_text(
|
191
|
-
json.dumps(
|
192
|
-
self.model_dump(exclude=excluded),
|
193
|
-
default=str,
|
194
|
-
indent=2,
|
195
|
-
),
|
196
|
-
encoding="utf-8",
|
197
|
-
)
|
198
|
-
return self
|
199
|
-
|
200
|
-
|
201
|
-
class SQLiteAudit(BaseAudit): # pragma: no cov
|
202
|
-
"""SQLite Audit Pydantic Model."""
|
203
|
-
|
204
|
-
table_name: ClassVar[str] = "audits"
|
205
|
-
schemas: ClassVar[
|
206
|
-
str
|
207
|
-
] = """
|
208
|
-
workflow str,
|
209
|
-
release int,
|
210
|
-
type str,
|
211
|
-
context json,
|
212
|
-
parent_run_id int,
|
213
|
-
run_id int,
|
214
|
-
update datetime
|
215
|
-
primary key ( run_id )
|
216
|
-
"""
|
217
|
-
|
218
|
-
def save(self, excluded: list[str] | None) -> SQLiteAudit:
|
219
|
-
"""Save logging data that receive a context data from a workflow
|
220
|
-
execution result.
|
221
|
-
"""
|
222
|
-
trace: TraceLog = get_trace(self.run_id, self.parent_run_id)
|
223
|
-
|
224
|
-
# NOTE: Check environ variable was set for real writing.
|
225
|
-
if not config.enable_write_audit:
|
226
|
-
trace.debug("[LOG]: Skip writing log cause config was set")
|
227
|
-
return self
|
228
|
-
|
229
|
-
raise NotImplementedError("SQLiteAudit does not implement yet.")
|
230
|
-
|
231
|
-
|
232
|
-
class RemoteFileAudit(FileAudit): # pragma: no cov
|
233
|
-
"""Remote File Audit Pydantic Model."""
|
234
|
-
|
235
|
-
def save(self, excluded: list[str] | None) -> RemoteFileAudit: ...
|
236
|
-
|
237
|
-
|
238
|
-
class RedisAudit(BaseAudit): # pragma: no cov
|
239
|
-
"""Redis Audit Pydantic Model."""
|
240
|
-
|
241
|
-
def save(self, excluded: list[str] | None) -> RedisAudit: ...
|
242
|
-
|
243
|
-
|
244
|
-
Audit = Union[
|
245
|
-
FileAudit,
|
246
|
-
SQLiteAudit,
|
247
|
-
]
|
248
|
-
|
249
|
-
|
250
|
-
def get_audit() -> type[Audit]: # pragma: no cov
|
251
|
-
"""Get an audit class that dynamic base on the config audit path value.
|
252
|
-
|
253
|
-
:rtype: type[Audit]
|
254
|
-
"""
|
255
|
-
if config.audit_path.is_file():
|
256
|
-
return SQLiteAudit
|
257
|
-
return FileAudit
|
ddeutil/workflow/caller.py
DELETED
@@ -1,179 +0,0 @@
|
|
1
|
-
# ------------------------------------------------------------------------------
|
2
|
-
# Copyright (c) 2022 Korawich Anuttra. All rights reserved.
|
3
|
-
# Licensed under the MIT License. See LICENSE in the project root for
|
4
|
-
# license information.
|
5
|
-
# ------------------------------------------------------------------------------
|
6
|
-
from __future__ import annotations
|
7
|
-
|
8
|
-
import inspect
|
9
|
-
import logging
|
10
|
-
from dataclasses import dataclass
|
11
|
-
from functools import wraps
|
12
|
-
from importlib import import_module
|
13
|
-
from typing import Any, Callable, Protocol, TypeVar
|
14
|
-
|
15
|
-
try:
|
16
|
-
from typing import ParamSpec
|
17
|
-
except ImportError:
|
18
|
-
from typing_extensions import ParamSpec
|
19
|
-
|
20
|
-
from ddeutil.core import lazy
|
21
|
-
|
22
|
-
from .__types import Re
|
23
|
-
from .conf import config
|
24
|
-
|
25
|
-
T = TypeVar("T")
|
26
|
-
P = ParamSpec("P")
|
27
|
-
|
28
|
-
logger = logging.getLogger("ddeutil.workflow")
|
29
|
-
logging.getLogger("asyncio").setLevel(logging.INFO)
|
30
|
-
|
31
|
-
|
32
|
-
class TagFunc(Protocol):
|
33
|
-
"""Tag Function Protocol"""
|
34
|
-
|
35
|
-
name: str
|
36
|
-
tag: str
|
37
|
-
|
38
|
-
def __call__(self, *args, **kwargs): ... # pragma: no cov
|
39
|
-
|
40
|
-
|
41
|
-
ReturnTagFunc = Callable[P, TagFunc]
|
42
|
-
DecoratorTagFunc = Callable[[Callable[[...], Any]], ReturnTagFunc]
|
43
|
-
|
44
|
-
|
45
|
-
def tag(
|
46
|
-
name: str, alias: str | None = None
|
47
|
-
) -> DecoratorTagFunc: # pragma: no cov
|
48
|
-
"""Tag decorator function that set function attributes, ``tag`` and ``name``
|
49
|
-
for making registries variable.
|
50
|
-
|
51
|
-
:param: name: (str) A tag name for make different use-case of a function.
|
52
|
-
:param: alias: (str) A alias function name that keeping in registries.
|
53
|
-
If this value does not supply, it will use original function name
|
54
|
-
from `__name__` argument.
|
55
|
-
|
56
|
-
:rtype: Callable[P, TagFunc]
|
57
|
-
"""
|
58
|
-
|
59
|
-
def func_internal(func: Callable[[...], Any]) -> ReturnTagFunc:
|
60
|
-
func.tag = name
|
61
|
-
func.name = alias or func.__name__.replace("_", "-")
|
62
|
-
|
63
|
-
@wraps(func)
|
64
|
-
def wrapped(*args: P.args, **kwargs: P.kwargs) -> TagFunc:
|
65
|
-
return func(*args, **kwargs)
|
66
|
-
|
67
|
-
@wraps(func)
|
68
|
-
async def awrapped(*args: P.args, **kwargs: P.kwargs) -> TagFunc:
|
69
|
-
return await func(*args, **kwargs)
|
70
|
-
|
71
|
-
return awrapped if inspect.iscoroutinefunction(func) else wrapped
|
72
|
-
|
73
|
-
return func_internal
|
74
|
-
|
75
|
-
|
76
|
-
Registry = dict[str, Callable[[], TagFunc]]
|
77
|
-
|
78
|
-
|
79
|
-
def make_registry(submodule: str) -> dict[str, Registry]:
|
80
|
-
"""Return registries of all functions that able to called with task.
|
81
|
-
|
82
|
-
:param submodule: (str) A module prefix that want to import registry.
|
83
|
-
|
84
|
-
:rtype: dict[str, Registry]
|
85
|
-
"""
|
86
|
-
rs: dict[str, Registry] = {}
|
87
|
-
regis_calls: list[str] = config.regis_call
|
88
|
-
regis_calls.extend(["ddeutil.vendors"])
|
89
|
-
for module in regis_calls:
|
90
|
-
# NOTE: try to sequential import task functions
|
91
|
-
try:
|
92
|
-
importer = import_module(f"{module}.{submodule}")
|
93
|
-
except ModuleNotFoundError:
|
94
|
-
continue
|
95
|
-
|
96
|
-
for fstr, func in inspect.getmembers(importer, inspect.isfunction):
|
97
|
-
# NOTE: check function attribute that already set tag by
|
98
|
-
# ``utils.tag`` decorator.
|
99
|
-
if not (
|
100
|
-
hasattr(func, "tag") and hasattr(func, "name")
|
101
|
-
): # pragma: no cov
|
102
|
-
continue
|
103
|
-
|
104
|
-
# NOTE: Define type of the func value.
|
105
|
-
func: TagFunc
|
106
|
-
|
107
|
-
# NOTE: Create new register name if it not exists
|
108
|
-
if func.name not in rs:
|
109
|
-
rs[func.name] = {func.tag: lazy(f"{module}.{submodule}.{fstr}")}
|
110
|
-
continue
|
111
|
-
|
112
|
-
if func.tag in rs[func.name]:
|
113
|
-
raise ValueError(
|
114
|
-
f"The tag {func.tag!r} already exists on "
|
115
|
-
f"{module}.{submodule}, you should change this tag name or "
|
116
|
-
f"change it func name."
|
117
|
-
)
|
118
|
-
rs[func.name][func.tag] = lazy(f"{module}.{submodule}.{fstr}")
|
119
|
-
|
120
|
-
return rs
|
121
|
-
|
122
|
-
|
123
|
-
@dataclass(frozen=True)
|
124
|
-
class CallSearchData:
|
125
|
-
"""Call Search dataclass that use for receive regular expression grouping
|
126
|
-
dict from searching call string value.
|
127
|
-
"""
|
128
|
-
|
129
|
-
path: str
|
130
|
-
func: str
|
131
|
-
tag: str
|
132
|
-
|
133
|
-
|
134
|
-
def extract_call(call: str) -> Callable[[], TagFunc]:
|
135
|
-
"""Extract Call function from string value to call partial function that
|
136
|
-
does run it at runtime.
|
137
|
-
|
138
|
-
:param call: (str) A call value that able to match with Task regex.
|
139
|
-
|
140
|
-
The format of call value should contain 3 regular expression groups
|
141
|
-
which match with the below config format:
|
142
|
-
|
143
|
-
>>> "^(?P<path>[^/@]+)/(?P<func>[^@]+)@(?P<tag>.+)$"
|
144
|
-
|
145
|
-
Examples:
|
146
|
-
>>> extract_call("tasks/el-postgres-to-delta@polars")
|
147
|
-
...
|
148
|
-
>>> extract_call("tasks/return-type-not-valid@raise")
|
149
|
-
...
|
150
|
-
|
151
|
-
:raise NotImplementedError: When the searching call's function result does
|
152
|
-
not exist in the registry.
|
153
|
-
:raise NotImplementedError: When the searching call's tag result does not
|
154
|
-
exist in the registry with its function key.
|
155
|
-
|
156
|
-
:rtype: Callable[[], TagFunc]
|
157
|
-
"""
|
158
|
-
if not (found := Re.RE_TASK_FMT.search(call)):
|
159
|
-
raise ValueError(
|
160
|
-
f"Call {call!r} does not match with the call regex format."
|
161
|
-
)
|
162
|
-
|
163
|
-
# NOTE: Pass the searching call string to `path`, `func`, and `tag`.
|
164
|
-
call: CallSearchData = CallSearchData(**found.groupdict())
|
165
|
-
|
166
|
-
# NOTE: Registry object should implement on this package only.
|
167
|
-
rgt: dict[str, Registry] = make_registry(f"{call.path}")
|
168
|
-
if call.func not in rgt:
|
169
|
-
raise NotImplementedError(
|
170
|
-
f"`REGISTER-MODULES.{call.path}.registries` does not "
|
171
|
-
f"implement registry: {call.func!r}."
|
172
|
-
)
|
173
|
-
|
174
|
-
if call.tag not in rgt[call.func]:
|
175
|
-
raise NotImplementedError(
|
176
|
-
f"tag: {call.tag!r} does not found on registry func: "
|
177
|
-
f"`REGISTER-MODULES.{call.path}.registries.{call.func}`"
|
178
|
-
)
|
179
|
-
return rgt[call.func][call.tag]
|
@@ -1,33 +0,0 @@
|
|
1
|
-
ddeutil/workflow/__about__.py,sha256=4_L4aAteV6ecIgxXQuBmMHF6LoFXtYgCVakxe2GlHjk,28
|
2
|
-
ddeutil/workflow/__cron.py,sha256=h8rLeIUAAEB2SdZ4Jhch7LU1Yl3bbJ-iNNJ3tQ0eYVM,28095
|
3
|
-
ddeutil/workflow/__init__.py,sha256=hIM2Ha-7F3YF3aLsu4IY3N-UvD_EE1ai6DO6WL2mILg,1908
|
4
|
-
ddeutil/workflow/__types.py,sha256=8jBdbfb3aZSetjz0mvNrpGHwwxJff7mK8_4v41cLqlc,4316
|
5
|
-
ddeutil/workflow/audit.py,sha256=BpzLI6ZKXi6xQO8C2sAHxSi8RAfF31dMPdjn3DbYlw8,8364
|
6
|
-
ddeutil/workflow/caller.py,sha256=M7_nan1DbRUAHEIQoQc1qIX4AHgI5fKFNx0KDbzhDMk,5736
|
7
|
-
ddeutil/workflow/conf.py,sha256=USYzITPwBS5Q_pl3DTTdFK8OxeL9GQu4GUXqi8nKpJo,11819
|
8
|
-
ddeutil/workflow/context.py,sha256=vsk4JQL7t3KsnKPfshw3O7YrPFo2h4rnnNd3B-G9Kj4,1700
|
9
|
-
ddeutil/workflow/cron.py,sha256=j8EeoHst70toRfnD_frix41vrI-eLYVJkZ9yeJtpfnI,8871
|
10
|
-
ddeutil/workflow/exceptions.py,sha256=fO37f9p7lOjIJgVOpKE_1X44yJTwBepyukZV9a7NNm4,1241
|
11
|
-
ddeutil/workflow/job.py,sha256=LCQf_3gyTmnj6aAQ0ksz4lJxU10-F5MfVFHczkWt_VE,28669
|
12
|
-
ddeutil/workflow/logs.py,sha256=mAKQjNri-oourd3dBLLG3Fqoo4QG27U9IO2h6IqCOU0,10196
|
13
|
-
ddeutil/workflow/params.py,sha256=qw9XJyjh2ocf9pf6h_XiYHLOvQN4R5TMqPElmItKnRM,8019
|
14
|
-
ddeutil/workflow/result.py,sha256=cDkItrhpzZfMS1Oj8IZX8O-KBD4KZYDi43XJZvvC3Gc,4318
|
15
|
-
ddeutil/workflow/scheduler.py,sha256=daNdcTp8dQN0gXuK3cg7K7idspOcqKNmfOLTWirNEUM,27652
|
16
|
-
ddeutil/workflow/stages.py,sha256=ONBR7GjgLEbA21wNioBrhOucwqj6M1v2ht5JhipoWSg,36994
|
17
|
-
ddeutil/workflow/templates.py,sha256=yA2xgrSXcxfBxNT2hc6v06HkVY_0RKsc1UwdJRip9EE,11554
|
18
|
-
ddeutil/workflow/utils.py,sha256=Fz5y-LK_JfikDfvMKcFaxad_VvCnr7UC2C9KFCbzPNA,7105
|
19
|
-
ddeutil/workflow/workflow.py,sha256=8ForojeLboLL6dHmV5-NjtU9o4mIL7NtY2F2NFxdqZY,49400
|
20
|
-
ddeutil/workflow/api/__init__.py,sha256=F53NMBWtb9IKaDWkPU5KvybGGfKAcbehgn6TLBwHuuM,21
|
21
|
-
ddeutil/workflow/api/api.py,sha256=gGQtqkzyJNaJIfka_w2M1lrCS3Ep46re2Dznsk9RxYQ,5191
|
22
|
-
ddeutil/workflow/api/log.py,sha256=NMTnOnsBrDB5129329xF2myLdrb-z9k1MQrmrP7qXJw,1818
|
23
|
-
ddeutil/workflow/api/repeat.py,sha256=cycd1-91j-4v6uY1SkrZHd9l95e-YgVC4UCSNNFuGJ8,5277
|
24
|
-
ddeutil/workflow/api/routes/__init__.py,sha256=qoGtOMyVgQ5nTUc8J8wH27A8isaxl3IFCX8qoyibeCY,484
|
25
|
-
ddeutil/workflow/api/routes/job.py,sha256=YVta083i8vU8-o4WdKFwDpfdC9vN1dZ6goZSmNlQXHA,1954
|
26
|
-
ddeutil/workflow/api/routes/logs.py,sha256=uEQ6k5PwRg-k0eSiSFArXfyeDq5xzepxILrRnwgAe1I,5373
|
27
|
-
ddeutil/workflow/api/routes/schedules.py,sha256=uWYDOwlV8w56hKQmfkQFwdZ6t2gZSJeCdBIzMmJenAQ,4824
|
28
|
-
ddeutil/workflow/api/routes/workflows.py,sha256=KVywA7vD9b4QrfmWBdSFF5chj34yJe1zNCzl6iBMeGI,4538
|
29
|
-
ddeutil_workflow-0.0.40.dist-info/licenses/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
|
30
|
-
ddeutil_workflow-0.0.40.dist-info/METADATA,sha256=AdIiZTWsPhfcVba7x2OrWw5CN3y0OQB-dRdBb9RQh2o,19501
|
31
|
-
ddeutil_workflow-0.0.40.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
32
|
-
ddeutil_workflow-0.0.40.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
|
33
|
-
ddeutil_workflow-0.0.40.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|