ddeutil-workflow 0.0.67__py3-none-any.whl → 0.0.69__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/utils.py CHANGED
@@ -6,15 +6,13 @@
6
6
  """Utility function model."""
7
7
  from __future__ import annotations
8
8
 
9
- import asyncio
10
9
  import stat
11
10
  import time
12
11
  from collections.abc import Iterator
13
12
  from datetime import date, datetime, timedelta
14
- from functools import wraps
15
13
  from hashlib import md5
16
14
  from inspect import isfunction
17
- from itertools import chain, islice, product
15
+ from itertools import product
18
16
  from pathlib import Path
19
17
  from random import randrange
20
18
  from typing import Any, Final, Optional, TypeVar, Union, overload
@@ -258,34 +256,6 @@ def cross_product(matrix: Matrix) -> Iterator[DictData]:
258
256
  )
259
257
 
260
258
 
261
- def batch(iterable: Union[Iterator[Any], range], n: int) -> Iterator[Any]:
262
- """Batch data into iterators of length n. The last batch may be shorter.
263
-
264
- Example:
265
- >>> for b in batch(iter('ABCDEFG'), 3):
266
- ... print(list(b))
267
- ['A', 'B', 'C']
268
- ['D', 'E', 'F']
269
- ['G']
270
-
271
- :param iterable:
272
- :param n: (int) A number of returning batch size.
273
-
274
- :rtype: Iterator[Any]
275
- """
276
- if n < 1:
277
- raise ValueError("n must be at least one")
278
-
279
- it: Iterator[Any] = iter(iterable)
280
- while True:
281
- chunk_it = islice(it, n)
282
- try:
283
- first_el = next(chunk_it)
284
- except StopIteration:
285
- return
286
- yield chain((first_el,), chunk_it)
287
-
288
-
289
259
  def cut_id(run_id: str, *, num: int = 6) -> str:
290
260
  """Cutting running ID with length.
291
261
 
@@ -325,24 +295,3 @@ def dump_all(
325
295
  elif isinstance(value, BaseModel):
326
296
  return value.model_dump(by_alias=by_alias)
327
297
  return value
328
-
329
-
330
- def awaitable(func):
331
- """Dynamic function to async or not depend on the called statement."""
332
-
333
- @wraps(func)
334
- async def async_wrapper(*args, **kwargs):
335
- return func(*args, **kwargs)
336
-
337
- @wraps(func)
338
- def sync_wrapper(*args, **kwargs):
339
- return func(*args, **kwargs)
340
-
341
- def dispatch(*args, **kwargs):
342
- try:
343
- asyncio.get_running_loop()
344
- return async_wrapper(*args, **kwargs)
345
- except RuntimeError:
346
- return sync_wrapper(*args, **kwargs)
347
-
348
- return dispatch
@@ -27,17 +27,17 @@ from threading import Event
27
27
  from typing import Any, Optional
28
28
  from zoneinfo import ZoneInfo
29
29
 
30
- from pydantic import BaseModel, Field, ValidationInfo
30
+ from pydantic import BaseModel, Field
31
31
  from pydantic.functional_validators import field_validator, model_validator
32
32
  from typing_extensions import Self
33
33
 
34
34
  from . import get_status_from_error
35
35
  from .__types import DictData
36
- from .conf import FileLoad, Loader, dynamic
36
+ from .audits import Audit, get_audit
37
+ from .conf import YamlParser, dynamic
37
38
  from .errors import WorkflowCancelError, WorkflowError, WorkflowTimeoutError
38
39
  from .event import Crontab
39
40
  from .job import Job
40
- from .logs import Audit, get_audit
41
41
  from .params import Param
42
42
  from .result import (
43
43
  CANCEL,
@@ -112,7 +112,6 @@ class Workflow(BaseModel):
112
112
  *,
113
113
  path: Optional[Path] = None,
114
114
  extras: DictData | None = None,
115
- loader: type[Loader] = None,
116
115
  ) -> Self:
117
116
  """Create Workflow instance from the Loader object that only receive
118
117
  an input workflow name. The loader object will use this workflow name to
@@ -122,14 +121,12 @@ class Workflow(BaseModel):
122
121
  :param path: (Path) An override config path.
123
122
  :param extras: (DictData) An extra parameters that want to override core
124
123
  config values.
125
- :param loader: A loader class for override default loader object.
126
124
 
127
125
  :raise ValueError: If the type does not match with current object.
128
126
 
129
127
  :rtype: Self
130
128
  """
131
- loader: type[Loader] = loader or FileLoad
132
- load: Loader = loader(name, path=path, extras=extras)
129
+ load: YamlParser = YamlParser(name, path=path, extras=extras)
133
130
 
134
131
  # NOTE: Validate the config type match with current connection model
135
132
  if load.type != cls.__name__:
@@ -141,7 +138,7 @@ class Workflow(BaseModel):
141
138
  if extras:
142
139
  data["extras"] = extras
143
140
 
144
- cls.__bypass_on__(data, path=load.path, extras=extras, loader=loader)
141
+ cls.__bypass_on__(data, path=load.path, extras=extras)
145
142
  return cls.model_validate(obj=data)
146
143
 
147
144
  @classmethod
@@ -150,7 +147,6 @@ class Workflow(BaseModel):
150
147
  data: DictData,
151
148
  path: Path,
152
149
  extras: DictData | None = None,
153
- loader: type[Loader] = None,
154
150
  ) -> DictData:
155
151
  """Bypass the on data to loaded config data.
156
152
 
@@ -171,7 +167,7 @@ class Workflow(BaseModel):
171
167
  # field.
172
168
  data["on"] = [
173
169
  (
174
- (loader or FileLoad)(n, path=path, extras=extras).data
170
+ YamlParser(n, path=path, extras=extras).data
175
171
  if isinstance(n, str)
176
172
  else n
177
173
  )
@@ -206,7 +202,6 @@ class Workflow(BaseModel):
206
202
  def __on_no_dup_and_reach_limit__(
207
203
  cls,
208
204
  value: list[Crontab],
209
- info: ValidationInfo,
210
205
  ) -> list[Crontab]:
211
206
  """Validate the on fields should not contain duplicate values and if it
212
207
  contains the every minute value more than one value, it will remove to
@@ -237,12 +232,9 @@ class Workflow(BaseModel):
237
232
  f"{list(set_tz)}."
238
233
  )
239
234
 
240
- extras: Optional[DictData] = info.data.get("extras")
241
- if len(set_ons) > (
242
- conf := dynamic("max_cron_per_workflow", extras=extras)
243
- ):
235
+ if len(set_ons) > 10:
244
236
  raise ValueError(
245
- f"The number of the on should not more than {conf} crontabs."
237
+ "The number of the on should not more than 10 crontabs."
246
238
  )
247
239
  return value
248
240
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.67
3
+ Version: 0.0.69
4
4
  Summary: Lightweight workflow orchestration with YAML template
5
5
  Author-email: ddeutils <korawich.anu@gmail.com>
6
6
  License: MIT
@@ -24,10 +24,10 @@ Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Requires-Dist: ddeutil[checksum]>=0.4.8
26
26
  Requires-Dist: ddeutil-io[toml,yaml]>=0.2.14
27
- Requires-Dist: pydantic==2.11.4
27
+ Requires-Dist: pydantic==2.11.5
28
28
  Requires-Dist: pydantic-extra-types==2.10.4
29
29
  Requires-Dist: python-dotenv==1.1.0
30
- Requires-Dist: typer==0.15.4
30
+ Requires-Dist: typer>=0.16.0
31
31
  Provides-Extra: all
32
32
  Requires-Dist: fastapi<1.0.0,>=0.115.0; extra == "all"
33
33
  Requires-Dist: uvicorn; extra == "all"
@@ -61,12 +61,13 @@ by a `.yaml` template.
61
61
 
62
62
  ---
63
63
 
64
- **:pushpin: <u>Rules of This Workflow engine</u>**:
64
+ **:pushpin: <u>Rules of This Workflow</u>**:
65
65
 
66
66
  1. The Minimum frequency unit of built-in scheduling is **1 Minute** 🕘
67
67
  2. **Can not** re-run only failed stage and its pending downstream ↩️
68
68
  3. All parallel tasks inside workflow core engine use **Multi-Threading** pool
69
69
  (Python 3.13 unlock GIL 🐍🔓)
70
+ 4. Recommend to pass a **Secret Value** with environment variable in YAML template 🔐
70
71
 
71
72
  ---
72
73
 
@@ -230,14 +231,17 @@ class RestAuth(BaseModel):
230
231
 
231
232
  @tag("requests", alias="get-api-with-oauth-to-s3")
232
233
  def get_api_with_oauth_to_s3(
233
- method: str,
234
- url: str,
235
- body: dict[str, str],
236
- auth: RestAuth,
237
- writing_node: str,
238
- aws: AwsCredential,
239
- result: Result,
234
+ method: str,
235
+ url: str,
236
+ body: dict[str, str],
237
+ auth: RestAuth,
238
+ writing_node: str,
239
+ aws: AwsCredential,
240
+ result: Result,
240
241
  ) -> dict[str, int]:
242
+ """Get the data from RestAPI via Authenticate with OAuth and then store to
243
+ AWS S3 service.
244
+ """
241
245
  result.trace.info("[CALLER]: Start get data via RestAPI to S3.")
242
246
  result.trace.info(f"... {method}: {url}")
243
247
  if method != "post":
@@ -269,24 +273,22 @@ it will use default value and do not raise any error to you.
269
273
  > The config value that you will set on the environment should combine with
270
274
  > prefix, component, and name which is `WORKFLOW_{component}_{name}` (Upper case).
271
275
 
272
- | Name | Component | Default | Description |
273
- |:-----------------------------|:---------:|:--------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|
274
- | **REGISTRY_CALLER** | Core | `.` | List of importable string for the call stage. |
275
- | **REGISTRY_FILTER** | Core | `ddeutil.workflow.templates` | List of importable string for the filter template. |
276
- | **CONF_PATH** | Core | `./conf` | The config path that keep all template `.yaml` files. |
277
- | **TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. |
278
- | **STAGE_DEFAULT_ID** | Core | `false` | A flag that enable default stage ID that use for catch an execution output. |
279
- | **MAX_CRON_PER_WORKFLOW** | Core | `5` | |
280
- | **MAX_QUEUE_COMPLETE_HIST** | Core | `16` | |
281
- | **GENERATE_ID_SIMPLE_MODE** | Core | `true` | A flog that enable generating ID with `md5` algorithm. |
282
- | **DEBUG_MODE** | Log | `true` | A flag that enable logging with debug level mode. |
283
- | **FORMAT** | Log | `%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d,%(thread)-5d) [%(levelname)-7s] %(message)-120s (%(filename)s:%(lineno)s)` | |
284
- | **FORMAT_FILE** | Log | `{datetime} ({process:5d}, {thread:5d}) {message:120s} ({filename}:{lineno})` | |
285
- | **DATETIME_FORMAT** | Log | `%Y-%m-%d %H:%M:%S` | |
286
- | **TRACE_PATH** | Log | `./logs` | The log path of the workflow saving log. |
287
- | **TRACE_ENABLE_WRITE** | Log | `false` | |
288
- | **AUDIT_PATH** | Log | `./audits` | |
289
- | **AUDIT_ENABLE_WRITE** | Log | `true` | A flag that enable logging object saving log to its destination. |
276
+ | Name | Component | Default | Description |
277
+ |:-----------------------------|:---------:|:--------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------|
278
+ | **REGISTRY_CALLER** | CORE | `.` | List of importable string for the call stage. |
279
+ | **REGISTRY_FILTER** | CORE | `ddeutil.workflow.templates` | List of importable string for the filter template. |
280
+ | **CONF_PATH** | CORE | `./conf` | The config path that keep all template `.yaml` files. |
281
+ | **TIMEZONE** | CORE | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. |
282
+ | **STAGE_DEFAULT_ID** | CORE | `false` | A flag that enable default stage ID that use for catch an execution output. |
283
+ | **GENERATE_ID_SIMPLE_MODE** | CORE | `true` | A flog that enable generating ID with `md5` algorithm. |
284
+ | **DEBUG_MODE** | LOG | `true` | A flag that enable logging with debug level mode. |
285
+ | **FORMAT** | LOG | `%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d,%(thread)-5d) [%(levelname)-7s] %(message)-120s (%(filename)s:%(lineno)s)` | A trace message console format. |
286
+ | **FORMAT_FILE** | LOG | `{datetime} ({process:5d}, {thread:5d}) {message:120s} ({filename}:{lineno})` | A trace message format that use to write to target pointer. |
287
+ | **DATETIME_FORMAT** | LOG | `%Y-%m-%d %H:%M:%S` | A datetime format of the trace log. |
288
+ | **TRACE_PATH** | LOG | `./logs` | A pointer of trace log that use to store. |
289
+ | **TRACE_ENABLE_WRITE** | LOG | `false` | A flag that enable writing trace log. |
290
+ | **AUDIT_PATH** | LOG | `./audits` | A pointer of audit log that use to store. |
291
+ | **AUDIT_ENABLE_WRITE** | LOG | `true` | A flag that enable writing audit log after end execution in the workflow release step. |
290
292
 
291
293
  ## :rocket: Deployment
292
294
 
@@ -0,0 +1,30 @@
1
+ ddeutil/workflow/__about__.py,sha256=wwXPhnyUKhGfDURjazLxeC2yPB5gr3G3n0ZD73ZnhYY,28
2
+ ddeutil/workflow/__cron.py,sha256=BOKQcreiex0SAigrK1gnLxpvOeF3aca_rQwyz9Kfve4,28751
3
+ ddeutil/workflow/__init__.py,sha256=HUy9XkBe7ttpUupJS4JDuj3aGp2QmJZfz8m2kHAIwdw,927
4
+ ddeutil/workflow/__main__.py,sha256=Qd-f8z2Q2vpiEP2x6PBFsJrpACWDVxFKQk820MhFmHo,59
5
+ ddeutil/workflow/__types.py,sha256=uNfoRbVmNK5O37UUMVnqcmoghD9oMS1q9fXC0APnjSI,4584
6
+ ddeutil/workflow/audits.py,sha256=1pg4a5wdZCAKOqMr1Z_ofzRAFsDarN1BIJenWwn9xkg,11435
7
+ ddeutil/workflow/cli.py,sha256=ems4Ewc2UGmjUwPjbobVsP3igfBZcz6Crf3PQM15w4E,3449
8
+ ddeutil/workflow/conf.py,sha256=ct7CtebGhWfXk6509CZsKh45hkWMzTD5cVghmINa0Hk,13577
9
+ ddeutil/workflow/errors.py,sha256=4DaKnyUm8RrUyQA5qakgW0ycSQLO7j-owyoh79LWQ5c,2893
10
+ ddeutil/workflow/event.py,sha256=e3xcECfMvH6K8Tff9cjCXIItVJjOmlonAQ0l253l6T0,11110
11
+ ddeutil/workflow/job.py,sha256=qcbKSOa39256nfJHL0vKJsHrelcRujX5KET2IEGS8dw,38995
12
+ ddeutil/workflow/params.py,sha256=Pco3DyjptC5Jkx53dhLL9xlIQdJvNAZs4FLzMUfXpbQ,12402
13
+ ddeutil/workflow/result.py,sha256=ctxNSaY9tZPHEAUgvDkjWWu2APeTmlZCf1Hb0XVbbFo,8173
14
+ ddeutil/workflow/reusables.py,sha256=jPrOCbxagqRvRFGXJzIyDa1wKV5AZ4crZyJ10cldQP0,21620
15
+ ddeutil/workflow/stages.py,sha256=kzMEMRTEuG52EOw51zyVO6LE-oiiqTIRUCk_OMcWZTM,106506
16
+ ddeutil/workflow/traces.py,sha256=GranGEgizx-R6wDJjVjkoCNVHlgOc6-wHi9zD5DH3D8,24059
17
+ ddeutil/workflow/utils.py,sha256=oKrhB-HOogeaO9RGXbe2vAs30A3rMMQxUd2B5pOw8zg,9131
18
+ ddeutil/workflow/workflow.py,sha256=jcSwOTaigVgiHElmlM1iK3g6rDMDd5PGni0ZcIxgH2U,27859
19
+ ddeutil/workflow/api/__init__.py,sha256=W3fe6_NLHSUzr4Tsu79w3pmvrYjpLeP3zBk4mtpPyqg,2843
20
+ ddeutil/workflow/api/log_conf.py,sha256=WfS3udDLSyrP-C80lWOvxxmhd_XWKvQPkwDqKblcH3E,1834
21
+ ddeutil/workflow/api/routes/__init__.py,sha256=JRaJZB0D6mgR17MbZo8yLtdYDtD62AA8MdKlFqhG84M,420
22
+ ddeutil/workflow/api/routes/job.py,sha256=x809G5gCbJS257txj9eLLTbCbFK8ercXWzPDLuv5gEM,2953
23
+ ddeutil/workflow/api/routes/logs.py,sha256=HiXw93PeIiaK_xJjM8lbD2ED1Il-W1iM51085nc7qmg,5286
24
+ ddeutil/workflow/api/routes/workflows.py,sha256=D76cdLb2_9Dkfe2_8xt06CvPhAyJMqxyYkUgAs8Qlnw,4402
25
+ ddeutil_workflow-0.0.69.dist-info/licenses/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
26
+ ddeutil_workflow-0.0.69.dist-info/METADATA,sha256=wXzNozF5KKoYdTX_JuFz3qOla_YCKjrXCTd7wFd-kb4,15207
27
+ ddeutil_workflow-0.0.69.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
+ ddeutil_workflow-0.0.69.dist-info/entry_points.txt,sha256=qDTpPSauL0ciO6T4iSVt8bJeYrVEkkoEEw_RlGx6Kgk,63
29
+ ddeutil_workflow-0.0.69.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
30
+ ddeutil_workflow-0.0.69.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,59 +0,0 @@
1
- from ..conf import config
2
-
3
- LOGGING_CONFIG = { # pragma: no cov
4
- "version": 1,
5
- "disable_existing_loggers": False,
6
- "formatters": {
7
- "standard": {
8
- "format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
9
- },
10
- "custom_formatter": {
11
- "format": config.log_format,
12
- "datefmt": config.log_datetime_format,
13
- },
14
- },
15
- "root": {
16
- "level": "DEBUG" if config.debug else "INFO",
17
- },
18
- "handlers": {
19
- "default": {
20
- "formatter": "standard",
21
- "class": "logging.StreamHandler",
22
- "stream": "ext://sys.stderr",
23
- },
24
- "stream_handler": {
25
- "formatter": "custom_formatter",
26
- "class": "logging.StreamHandler",
27
- "stream": "ext://sys.stdout",
28
- },
29
- "file_handler": {
30
- "formatter": "custom_formatter",
31
- "class": "logging.handlers.RotatingFileHandler",
32
- "filename": "logs/app.log",
33
- "maxBytes": 1024 * 1024 * 1,
34
- "backupCount": 3,
35
- },
36
- },
37
- "loggers": {
38
- "uvicorn": {
39
- "handlers": ["default", "file_handler"],
40
- "level": "DEBUG" if config.debug else "INFO",
41
- "propagate": False,
42
- },
43
- "uvicorn.access": {
44
- "handlers": ["stream_handler", "file_handler"],
45
- "level": "DEBUG" if config.debug else "INFO",
46
- "propagate": False,
47
- },
48
- "uvicorn.error": {
49
- "handlers": ["stream_handler", "file_handler"],
50
- "level": "DEBUG" if config.debug else "INFO",
51
- "propagate": False,
52
- },
53
- # "uvicorn.asgi": {
54
- # "handlers": ["stream_handler", "file_handler"],
55
- # "level": "TRACE",
56
- # "propagate": False,
57
- # },
58
- },
59
- }
@@ -1,29 +0,0 @@
1
- ddeutil/workflow/__about__.py,sha256=JZ9Er-4hkPGd0SSb_wI8VFJvPCjm8q09g7oG_MshBMo,28
2
- ddeutil/workflow/__cron.py,sha256=BOKQcreiex0SAigrK1gnLxpvOeF3aca_rQwyz9Kfve4,28751
3
- ddeutil/workflow/__init__.py,sha256=JfFZlPRDgR2J0rb0SRejt1OSrOrD3GGv9Um14z8MMfs,901
4
- ddeutil/workflow/__main__.py,sha256=Qd-f8z2Q2vpiEP2x6PBFsJrpACWDVxFKQk820MhFmHo,59
5
- ddeutil/workflow/__types.py,sha256=uNfoRbVmNK5O37UUMVnqcmoghD9oMS1q9fXC0APnjSI,4584
6
- ddeutil/workflow/cli.py,sha256=YtfNfozYRvQyohhYVcZ2_8o_IBXOpmok531eYw0DScM,1555
7
- ddeutil/workflow/conf.py,sha256=w1WDWZDCvRVDSz2HnJxeqySzpYWSubJZjTVjXO9imK0,14669
8
- ddeutil/workflow/errors.py,sha256=4DaKnyUm8RrUyQA5qakgW0ycSQLO7j-owyoh79LWQ5c,2893
9
- ddeutil/workflow/event.py,sha256=S2eJAZZx_V5TuQ0l417hFVCtjWXnfNPZBgSCICzxQ48,11041
10
- ddeutil/workflow/job.py,sha256=qcbKSOa39256nfJHL0vKJsHrelcRujX5KET2IEGS8dw,38995
11
- ddeutil/workflow/logs.py,sha256=4rL8TsRJsYVqyPfLjFW5bSoWtRwUgwmaRONu7nnVxQ8,31374
12
- ddeutil/workflow/params.py,sha256=Pco3DyjptC5Jkx53dhLL9xlIQdJvNAZs4FLzMUfXpbQ,12402
13
- ddeutil/workflow/result.py,sha256=GU84psZFiJ4LRf_HXgz-R98YN4lOUkER0VR7x9DDdOU,7922
14
- ddeutil/workflow/reusables.py,sha256=jPrOCbxagqRvRFGXJzIyDa1wKV5AZ4crZyJ10cldQP0,21620
15
- ddeutil/workflow/stages.py,sha256=xsJactN-Qk5Yg7ooXfoq-JVdlduIAdXXJUzCKFJuWGA,105093
16
- ddeutil/workflow/utils.py,sha256=slhBbsBNl0yaSk9EOiCK6UL-o7smgHVsLT7svRqAWXU,10436
17
- ddeutil/workflow/workflow.py,sha256=AcSGqsH1N4LqWhYIcCPy9CoV_AGlXUrBgjpl-gniv6g,28267
18
- ddeutil/workflow/api/__init__.py,sha256=0UIilYwW29RL6HrCRHACSWvnATJVLSJzXiCMny0bHQk,2627
19
- ddeutil/workflow/api/logs.py,sha256=NMTnOnsBrDB5129329xF2myLdrb-z9k1MQrmrP7qXJw,1818
20
- ddeutil/workflow/api/routes/__init__.py,sha256=jC1pM7q4_eo45IyO3hQbbe6RnL9B8ibRq_K6aCMP6Ag,434
21
- ddeutil/workflow/api/routes/job.py,sha256=32TkNm7QY9gt6fxIqEPjDqPgc8XqDiMPjUb7disSrCw,2143
22
- ddeutil/workflow/api/routes/logs.py,sha256=QJH8IF102897WLfCJ29-1g15wl29M9Yq6omroZfbahs,5305
23
- ddeutil/workflow/api/routes/workflows.py,sha256=Gmg3e-K5rfi95pbRtWI_aIr5C089sIde_vefZVvh3U0,4420
24
- ddeutil_workflow-0.0.67.dist-info/licenses/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
25
- ddeutil_workflow-0.0.67.dist-info/METADATA,sha256=w9iP1ofTfKIdirH9WSZf5rMOA4MrqMKM5jJk1hFO3oU,16072
26
- ddeutil_workflow-0.0.67.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
27
- ddeutil_workflow-0.0.67.dist-info/entry_points.txt,sha256=qDTpPSauL0ciO6T4iSVt8bJeYrVEkkoEEw_RlGx6Kgk,63
28
- ddeutil_workflow-0.0.67.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
29
- ddeutil_workflow-0.0.67.dist-info/RECORD,,