flowweave 2.0.1__tar.gz → 3.0.2__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.
- {flowweave-2.0.1 → flowweave-3.0.2}/PKG-INFO +5 -1
- flowweave-3.0.2/README.md +16 -0
- flowweave-3.0.2/flowweave/__init__.py +6 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave/base.py +24 -7
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave/cli.py +3 -3
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave/flowweave.py +110 -69
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave/message.py +8 -8
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave.egg-info/PKG-INFO +5 -1
- {flowweave-2.0.1 → flowweave-3.0.2}/pyproject.toml +1 -1
- flowweave-2.0.1/README.md +0 -12
- flowweave-2.0.1/flowweave/__init__.py +0 -6
- {flowweave-2.0.1 → flowweave-3.0.2}/LICENSE +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave/schema/flow.json +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave/schema/op_code.json +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave.egg-info/SOURCES.txt +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave.egg-info/dependency_links.txt +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave.egg-info/entry_points.txt +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave.egg-info/requires.txt +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/flowweave.egg-info/top_level.txt +0 -0
- {flowweave-2.0.1 → flowweave-3.0.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowweave
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.2
|
|
4
4
|
Summary: YAML-based workflow runner for task orchestration
|
|
5
5
|
Author: syatch
|
|
6
6
|
License: MIT
|
|
@@ -16,6 +16,10 @@ Dynamic: license-file
|
|
|
16
16
|
# FlowWeave
|
|
17
17
|
YAML-based workflow runner for task orchestration
|
|
18
18
|
|
|
19
|
+
Although this version is more stable, it takes a few seconds to start up.
|
|
20
|
+
|
|
21
|
+
Therefore, [Lite version](https://github.com/syatch/flowweave-lite) is recommended.
|
|
22
|
+
|
|
19
23
|
This project is in early development.
|
|
20
24
|
|
|
21
25
|
## Installation
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# FlowWeave
|
|
2
|
+
YAML-based workflow runner for task orchestration
|
|
3
|
+
|
|
4
|
+
Although this version is more stable, it takes a few seconds to start up.
|
|
5
|
+
|
|
6
|
+
Therefore, [Lite version](https://github.com/syatch/flowweave-lite) is recommended.
|
|
7
|
+
|
|
8
|
+
This project is in early development.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Install FlowWeave using pip:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install flowweave
|
|
16
|
+
```
|
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
# Standard library
|
|
2
2
|
from enum import IntEnum
|
|
3
|
+
import importlib
|
|
3
4
|
from typing import IO, Optional
|
|
4
5
|
|
|
5
6
|
from colorama import Fore
|
|
6
7
|
|
|
7
|
-
class
|
|
8
|
+
class FlowWeaveResult(IntEnum):
|
|
8
9
|
FAIL = 0
|
|
9
10
|
SUCCESS = 1
|
|
10
11
|
IGNORE = 2
|
|
11
12
|
|
|
12
13
|
class TaskData:
|
|
14
|
+
def __getstate__(self):
|
|
15
|
+
state = self.__dict__.copy()
|
|
16
|
+
state["task_class_path"] = (
|
|
17
|
+
self.task_class.__module__,
|
|
18
|
+
self.task_class.__name__,
|
|
19
|
+
)
|
|
20
|
+
del state["task_class"]
|
|
21
|
+
return state
|
|
22
|
+
|
|
23
|
+
def __setstate__(self, state):
|
|
24
|
+
module_name, class_name = state["task_class_path"]
|
|
25
|
+
module = importlib.import_module(module_name)
|
|
26
|
+
state["task_class"] = getattr(module, class_name)
|
|
27
|
+
del state["task_class_path"]
|
|
28
|
+
self.__dict__.update(state)
|
|
29
|
+
|
|
13
30
|
def __init__(self,
|
|
14
31
|
name,
|
|
15
32
|
task_class,
|
|
@@ -30,17 +47,17 @@ class TaskData:
|
|
|
30
47
|
self.do_only = do_only
|
|
31
48
|
self.show_log = show_log
|
|
32
49
|
|
|
33
|
-
class
|
|
50
|
+
class FlowWeaveTask:
|
|
34
51
|
def __init__(self, prev_future):
|
|
35
52
|
self.prev_future = prev_future
|
|
36
53
|
self.return_data = None
|
|
37
54
|
|
|
38
|
-
def __call__(self)
|
|
39
|
-
result = self.run()
|
|
40
|
-
return result
|
|
55
|
+
def __call__(self):
|
|
56
|
+
result, return_data = self.run()
|
|
57
|
+
return result, return_data
|
|
41
58
|
|
|
42
|
-
def run(self)
|
|
43
|
-
return
|
|
59
|
+
def run(self):
|
|
60
|
+
return FlowWeaveResult.SUCCESS, self.return_data
|
|
44
61
|
|
|
45
62
|
def set_task_data(self, task_data: TaskData) -> None:
|
|
46
63
|
self.task_data = task_data
|
|
@@ -8,7 +8,7 @@ import colorama
|
|
|
8
8
|
|
|
9
9
|
# Local application / relative imports
|
|
10
10
|
from .flowweave import FlowWeave
|
|
11
|
-
from .base import
|
|
11
|
+
from .base import FlowWeaveResult
|
|
12
12
|
|
|
13
13
|
def get_setting_path(args):
|
|
14
14
|
setting_path = None
|
|
@@ -59,7 +59,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
59
59
|
return parser
|
|
60
60
|
|
|
61
61
|
def main() -> None:
|
|
62
|
-
result =
|
|
62
|
+
result = FlowWeaveResult.SUCCESS
|
|
63
63
|
|
|
64
64
|
colorama.init(autoreset=True)
|
|
65
65
|
|
|
@@ -72,7 +72,7 @@ def main() -> None:
|
|
|
72
72
|
if not setting_path:
|
|
73
73
|
parser.error("run requires flow_file")
|
|
74
74
|
results = FlowWeave.run(setting_file=setting_path, parallel=args.parallel, show_log = args.log)
|
|
75
|
-
result = all(x ==
|
|
75
|
+
result = all(x == FlowWeaveResult.SUCCESS for x in results)
|
|
76
76
|
elif args.command == "info":
|
|
77
77
|
if args.flow_file:
|
|
78
78
|
show_flow_op(setting_path, args.flow_file, info=True)
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Standard library
|
|
2
|
-
import
|
|
2
|
+
from functools import reduce
|
|
3
3
|
import importlib
|
|
4
4
|
from importlib.resources import files
|
|
5
|
+
import inspect
|
|
5
6
|
import itertools
|
|
6
7
|
import json
|
|
7
8
|
import logging
|
|
8
9
|
from pathlib import Path
|
|
10
|
+
import pickle
|
|
9
11
|
import sys
|
|
10
12
|
|
|
11
13
|
# Third-party
|
|
@@ -14,7 +16,7 @@ import yaml
|
|
|
14
16
|
from prefect import flow, task, get_run_logger
|
|
15
17
|
|
|
16
18
|
# Local application / relative imports
|
|
17
|
-
from .base import
|
|
19
|
+
from .base import FlowWeaveResult, TaskData, FlowWeaveTask
|
|
18
20
|
from .message import FlowMessage
|
|
19
21
|
|
|
20
22
|
class StageData():
|
|
@@ -38,15 +40,17 @@ class StageData():
|
|
|
38
40
|
text += "==========="
|
|
39
41
|
return text
|
|
40
42
|
|
|
41
|
-
class
|
|
42
|
-
task_class = None
|
|
43
|
-
|
|
43
|
+
class TaskRunner():
|
|
44
44
|
@task
|
|
45
45
|
def start(prev_future, task_data: TaskData):
|
|
46
|
+
if hasattr(prev_future, "result"):
|
|
47
|
+
prev_future = prev_future.result()
|
|
48
|
+
|
|
49
|
+
return_data = None
|
|
46
50
|
try:
|
|
47
|
-
task_instance = task_data.task_class
|
|
51
|
+
task_instance = task_data.task_class(prev_future)
|
|
48
52
|
except AttributeError:
|
|
49
|
-
raise TypeError(f"{task_data.task_class}
|
|
53
|
+
raise TypeError(f"Failed to get instance of '{task_data.task_class}'")
|
|
50
54
|
|
|
51
55
|
# set task member variables
|
|
52
56
|
setattr(task_instance, "task_data", task_data)
|
|
@@ -60,37 +64,44 @@ class FlowWeaveTask():
|
|
|
60
64
|
if task_data.show_log:
|
|
61
65
|
FlowWeave._print_log(f"Task option {key} not found: ignore")
|
|
62
66
|
run_task = True
|
|
63
|
-
|
|
67
|
+
|
|
68
|
+
if prev_future is not None:
|
|
64
69
|
if "pre_success" == task_data.do_only:
|
|
65
|
-
run_task = True if (
|
|
70
|
+
run_task = True if (FlowWeaveResult.SUCCESS == prev_future.get("result")) else False
|
|
66
71
|
elif "pre_fail" == task_data.do_only:
|
|
67
|
-
run_task = True if (
|
|
72
|
+
run_task = True if (FlowWeaveResult.FAIL == prev_future.get("result")) else False
|
|
68
73
|
|
|
69
74
|
if run_task:
|
|
70
|
-
|
|
75
|
+
TaskRunner.message_task_start(prev_future, task_data)
|
|
71
76
|
|
|
72
77
|
try:
|
|
73
78
|
task_result, return_data = task_instance()
|
|
74
79
|
except Exception as e:
|
|
75
80
|
FlowMessage.error(e)
|
|
76
|
-
task_result =
|
|
81
|
+
task_result = FlowWeaveResult.FAIL
|
|
77
82
|
|
|
78
83
|
FlowMessage.task_end(task_data, task_result)
|
|
79
84
|
else:
|
|
80
|
-
|
|
81
|
-
task_result =
|
|
85
|
+
TaskRunner.message_task_ignore(prev_future, task_data)
|
|
86
|
+
task_result = FlowWeaveResult.IGNORE
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
if return_data is not None:
|
|
90
|
+
pickle.dumps(return_data)
|
|
91
|
+
except Exception:
|
|
92
|
+
raise TypeError(f"Task '{task_data.name}' return_data is not serializable")
|
|
82
93
|
|
|
83
94
|
return {"name" : task_data.name, "option" : task_data.option, "data" : return_data, "result" : task_result}
|
|
84
95
|
|
|
85
96
|
def message_task_start(prev_future, task_data: TaskData):
|
|
86
|
-
if prev_future:
|
|
97
|
+
if prev_future is not None:
|
|
87
98
|
prev_task_name = prev_future.get("name")
|
|
88
99
|
FlowMessage.task_start_link(prev_task_name, task_data)
|
|
89
100
|
else:
|
|
90
101
|
FlowMessage.task_start(task_data)
|
|
91
102
|
|
|
92
103
|
def message_task_ignore(prev_future, task_data: TaskData):
|
|
93
|
-
if prev_future:
|
|
104
|
+
if prev_future is not None:
|
|
94
105
|
prev_task_name = prev_future.get("name")
|
|
95
106
|
FlowMessage.task_ignore_link(task_data, prev_task_name)
|
|
96
107
|
else:
|
|
@@ -98,7 +109,7 @@ class FlowWeaveTask():
|
|
|
98
109
|
|
|
99
110
|
class FlowWeave():
|
|
100
111
|
@flow
|
|
101
|
-
def run(setting_file: str, parallel: bool = False, show_log: bool = False) -> list[
|
|
112
|
+
def run(setting_file: str, parallel: bool = False, show_log: bool = False) -> list[FlowWeaveResult]:
|
|
102
113
|
if not show_log:
|
|
103
114
|
logging.getLogger("prefect").setLevel(logging.CRITICAL)
|
|
104
115
|
|
|
@@ -177,7 +188,7 @@ class FlowWeave():
|
|
|
177
188
|
op_source = flow_data.get("op_source")
|
|
178
189
|
op_source_list = op_source if isinstance(op_source, list) else [op_source]
|
|
179
190
|
for source in op_source_list:
|
|
180
|
-
source_name = f"task
|
|
191
|
+
source_name = f"task.{source}"
|
|
181
192
|
setting_file = f"{source_name.replace('.', '/')}/op_code.yml"
|
|
182
193
|
return_dic |= FlowWeave._get_op_dic_from_setting_file(setting_file, info=info)
|
|
183
194
|
|
|
@@ -207,27 +218,43 @@ class FlowWeave():
|
|
|
207
218
|
op_dic = setting.get("op", {})
|
|
208
219
|
for op, op_info in op_dic.items():
|
|
209
220
|
script_name = op_info.get('script')
|
|
210
|
-
op_class = FlowWeave._get_op_class(source_name, script_name,
|
|
221
|
+
op_class = FlowWeave._get_op_class(source_name, script_name, FlowWeaveTask)
|
|
211
222
|
|
|
212
223
|
return_dic[str(op)] = op_class
|
|
213
224
|
|
|
214
225
|
return return_dic
|
|
215
226
|
|
|
216
|
-
def _get_op_class(source_name: str, script_name: str,
|
|
227
|
+
def _get_op_class(source_name: str, script_name: str, base_class):
|
|
217
228
|
module_name = f"{source_name}.{script_name}"
|
|
229
|
+
|
|
218
230
|
try:
|
|
219
231
|
module = importlib.import_module(module_name)
|
|
220
232
|
except Exception as e:
|
|
221
233
|
raise RuntimeError(f"Failed to import {module_name}: {e}")
|
|
222
234
|
|
|
223
|
-
|
|
224
|
-
raise RuntimeError(f"'Task' class not found in {module_name}")
|
|
235
|
+
candidates = []
|
|
225
236
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
237
|
+
for _, obj in inspect.getmembers(module, inspect.isclass):
|
|
238
|
+
if obj.__module__ != module.__name__:
|
|
239
|
+
continue
|
|
240
|
+
|
|
241
|
+
if issubclass(obj, base_class) and obj is not base_class:
|
|
242
|
+
candidates.append(obj)
|
|
243
|
+
|
|
244
|
+
if len(candidates) == 0:
|
|
245
|
+
raise RuntimeError(
|
|
246
|
+
f"No subclass of {base_class.__name__} found in {module_name}"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
if len(candidates) > 1:
|
|
250
|
+
names = ", ".join(c.__name__ for c in candidates)
|
|
251
|
+
raise RuntimeError(
|
|
252
|
+
f"Multiple subclasses of {base_class.__name__} found in {module_name}: {names}"
|
|
253
|
+
)
|
|
229
254
|
|
|
230
|
-
|
|
255
|
+
cls = candidates[0]
|
|
256
|
+
|
|
257
|
+
return cls
|
|
231
258
|
|
|
232
259
|
def _get_global_option_comb(global_option: dict) -> list:
|
|
233
260
|
keys = list(global_option.keys())
|
|
@@ -246,8 +273,8 @@ class FlowWeave():
|
|
|
246
273
|
return all_combinations
|
|
247
274
|
|
|
248
275
|
@task
|
|
249
|
-
def run_flow(flow_data: dict, global_cmb: dict, op_dic: dict, part: int, all: int, show_log: bool = False) ->
|
|
250
|
-
flow_result =
|
|
276
|
+
def run_flow(flow_data: dict, global_cmb: dict, op_dic: dict, part: int, all: int, show_log: bool = False) -> FlowWeaveResult:
|
|
277
|
+
flow_result = FlowWeaveResult.SUCCESS
|
|
251
278
|
|
|
252
279
|
if show_log:
|
|
253
280
|
text = "= Flow =\n"
|
|
@@ -255,7 +282,7 @@ class FlowWeave():
|
|
|
255
282
|
text += "========"
|
|
256
283
|
FlowWeave._print_log(text)
|
|
257
284
|
|
|
258
|
-
default_option = flow_data.get("default_option")
|
|
285
|
+
default_option = flow_data.get("default_option", {})
|
|
259
286
|
|
|
260
287
|
stage_list = flow_data.get("flow")
|
|
261
288
|
for stage in stage_list:
|
|
@@ -269,10 +296,10 @@ class FlowWeave():
|
|
|
269
296
|
FlowWeave._print_log(str(stage_data))
|
|
270
297
|
|
|
271
298
|
result = FlowWeave._run_stage(stage_data, show_log)
|
|
272
|
-
if
|
|
273
|
-
flow_result =
|
|
299
|
+
if FlowWeaveResult.FAIL == result:
|
|
300
|
+
flow_result = FlowWeaveResult.FAIL
|
|
274
301
|
|
|
275
|
-
FlowMessage.stage_end(stage, part, all,
|
|
302
|
+
FlowMessage.stage_end(stage, part, all, result)
|
|
276
303
|
|
|
277
304
|
return flow_result
|
|
278
305
|
|
|
@@ -293,7 +320,7 @@ class FlowWeave():
|
|
|
293
320
|
logger.info(f"{text}")
|
|
294
321
|
|
|
295
322
|
def _run_stage(stage_data: StageData, show_log: bool = False):
|
|
296
|
-
stage_result =
|
|
323
|
+
stage_result = FlowWeaveResult.SUCCESS
|
|
297
324
|
|
|
298
325
|
all_futures = []
|
|
299
326
|
|
|
@@ -306,11 +333,23 @@ class FlowWeave():
|
|
|
306
333
|
|
|
307
334
|
for f in all_futures:
|
|
308
335
|
result = f.result()
|
|
309
|
-
if
|
|
310
|
-
stage_result =
|
|
336
|
+
if FlowWeaveResult.FAIL == result.get("result"):
|
|
337
|
+
stage_result = FlowWeaveResult.FAIL
|
|
311
338
|
|
|
312
339
|
return stage_result
|
|
313
340
|
|
|
341
|
+
def _deep_merge(a: dict, b: dict) -> dict:
|
|
342
|
+
result = copy.deepcopy(a)
|
|
343
|
+
for k, v in b.items():
|
|
344
|
+
if k in result and isinstance(result[k], dict) and isinstance(v, dict):
|
|
345
|
+
result[k] = FlowWeave._deep_merge(result[k], v)
|
|
346
|
+
else:
|
|
347
|
+
result[k] = v
|
|
348
|
+
return result
|
|
349
|
+
|
|
350
|
+
def _deep_merge_many(*dicts):
|
|
351
|
+
return reduce(FlowWeave._deep_merge, dicts)
|
|
352
|
+
|
|
314
353
|
def _run_task(stage_data: dict, task_name: str, prev_future = None, visited = None, show_log: bool = False):
|
|
315
354
|
if visited is None:
|
|
316
355
|
visited = set()
|
|
@@ -318,40 +357,42 @@ class FlowWeave():
|
|
|
318
357
|
raise Exception(f"Cycle detected at task '{task_name}' in {visited}")
|
|
319
358
|
visited.add(task_name)
|
|
320
359
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
default_option
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
future = task_module.start.submit(prev_future, task_data)
|
|
360
|
+
try:
|
|
361
|
+
task_dic = stage_data.stage_info.get(task_name)
|
|
362
|
+
if task_dic is None:
|
|
363
|
+
raise KeyError(f"Task '{task_name}' not found in stage '{stage_data.name}'")
|
|
364
|
+
|
|
365
|
+
task_module = stage_data.op_dic.get(task_dic.get('op'))
|
|
366
|
+
if not task_module:
|
|
367
|
+
raise Exception(f"module of op '{task_dic.get('op')}' for '{task_name}' not found")
|
|
368
|
+
|
|
369
|
+
default_option = stage_data.default_option or {}
|
|
370
|
+
global_option = stage_data.global_option or {}
|
|
371
|
+
task_option = FlowWeave._deep_merge_many(default_option, global_option, task_dic.get("option", {}))
|
|
372
|
+
|
|
373
|
+
task_data = TaskData(name=task_name,
|
|
374
|
+
task_class=task_module,
|
|
375
|
+
option=task_option,
|
|
376
|
+
stage_name=stage_data.name,
|
|
377
|
+
flow_part=stage_data.flow_part,
|
|
378
|
+
flow_all=stage_data.flow_all,
|
|
379
|
+
do_only=task_dic.get("do_only"),
|
|
380
|
+
show_log=show_log)
|
|
381
|
+
if prev_future is None:
|
|
382
|
+
future = TaskRunner.start.submit(None, task_data)
|
|
383
|
+
else:
|
|
384
|
+
future = TaskRunner.start.submit(prev_future, task_data)
|
|
347
385
|
|
|
348
|
-
|
|
349
|
-
|
|
386
|
+
links = task_dic.get("chain", {}).get("next", [])
|
|
387
|
+
links = links if isinstance(links, list) else [links]
|
|
350
388
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
389
|
+
futures = [future]
|
|
390
|
+
for link in links:
|
|
391
|
+
futures.extend(
|
|
392
|
+
FlowWeave._run_task(stage_data, link, future, visited.copy(), show_log)
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
return futures
|
|
356
396
|
|
|
357
|
-
|
|
397
|
+
finally:
|
|
398
|
+
visited.remove(task_name)
|
|
@@ -5,7 +5,7 @@ from typing import IO, Optional
|
|
|
5
5
|
from colorama import Fore
|
|
6
6
|
|
|
7
7
|
# Local application / relative imports
|
|
8
|
-
from .base import
|
|
8
|
+
from .base import FlowWeaveResult, TaskData
|
|
9
9
|
|
|
10
10
|
class FlowMessage:
|
|
11
11
|
@staticmethod
|
|
@@ -17,14 +17,14 @@ class FlowMessage:
|
|
|
17
17
|
print(*args, sep=sep, end=end, file=file, flush=flush)
|
|
18
18
|
|
|
19
19
|
@staticmethod
|
|
20
|
-
def get_result_text(result:
|
|
20
|
+
def get_result_text(result: FlowWeaveResult) -> str:
|
|
21
21
|
text = ""
|
|
22
22
|
|
|
23
|
-
if
|
|
23
|
+
if FlowWeaveResult.SUCCESS == result:
|
|
24
24
|
text = f"{Fore.GREEN}SUCCESS"
|
|
25
|
-
elif
|
|
25
|
+
elif FlowWeaveResult.IGNORE == result:
|
|
26
26
|
text = f"{Fore.CYAN}IGNORE"
|
|
27
|
-
elif
|
|
27
|
+
elif FlowWeaveResult.FAIL == result:
|
|
28
28
|
text = f"{Fore.RED}FAIL"
|
|
29
29
|
else:
|
|
30
30
|
text = f"{Fore.MAGENTA}UNKNOWN: {result.name}({result.value})"
|
|
@@ -42,7 +42,7 @@ class FlowMessage:
|
|
|
42
42
|
FlowMessage._print(text)
|
|
43
43
|
|
|
44
44
|
@staticmethod
|
|
45
|
-
def flow_end(part: int, all: int, result:
|
|
45
|
+
def flow_end(part: int, all: int, result: FlowWeaveResult) -> None:
|
|
46
46
|
result_text = FlowMessage.get_result_text(result)
|
|
47
47
|
text = f"{Fore.YELLOW}[Flow {part} / {all}] Finish - {result_text}"
|
|
48
48
|
FlowMessage._print(text)
|
|
@@ -53,7 +53,7 @@ class FlowMessage:
|
|
|
53
53
|
FlowMessage._print(text)
|
|
54
54
|
|
|
55
55
|
@staticmethod
|
|
56
|
-
def stage_end(stage: str, part: int, all: int, result:
|
|
56
|
+
def stage_end(stage: str, part: int, all: int, result: FlowWeaveResult) -> None:
|
|
57
57
|
result_text = FlowMessage.get_result_text(result)
|
|
58
58
|
text = f"{Fore.MAGENTA}[Flow {part} / {all}] Finish Stage {stage} - {result_text}"
|
|
59
59
|
FlowMessage._print(text)
|
|
@@ -79,7 +79,7 @@ class FlowMessage:
|
|
|
79
79
|
FlowMessage._print(text)
|
|
80
80
|
|
|
81
81
|
@staticmethod
|
|
82
|
-
def task_end(task_data: TaskData, result:
|
|
82
|
+
def task_end(task_data: TaskData, result: FlowWeaveResult) -> None:
|
|
83
83
|
result_text = FlowMessage.get_result_text(result)
|
|
84
84
|
text = f"{Fore.CYAN}[Flow {task_data.flow_part} / {task_data.flow_all}] Finish Task {task_data.stage_name}/{task_data.name} - {result_text}"
|
|
85
85
|
FlowMessage._print(text)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowweave
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.2
|
|
4
4
|
Summary: YAML-based workflow runner for task orchestration
|
|
5
5
|
Author: syatch
|
|
6
6
|
License: MIT
|
|
@@ -16,6 +16,10 @@ Dynamic: license-file
|
|
|
16
16
|
# FlowWeave
|
|
17
17
|
YAML-based workflow runner for task orchestration
|
|
18
18
|
|
|
19
|
+
Although this version is more stable, it takes a few seconds to start up.
|
|
20
|
+
|
|
21
|
+
Therefore, [Lite version](https://github.com/syatch/flowweave-lite) is recommended.
|
|
22
|
+
|
|
19
23
|
This project is in early development.
|
|
20
24
|
|
|
21
25
|
## Installation
|
flowweave-2.0.1/README.md
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|