flowweave 3.0.0__py3-none-any.whl → 3.0.2__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.
flowweave/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "3.0.0"
1
+ __version__ = "3.0.2"
2
2
  __author__ = "syatch"
3
3
  __license__ = "MIT"
4
4
 
flowweave/base.py CHANGED
@@ -1,5 +1,6 @@
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
@@ -10,6 +11,22 @@ class FlowWeaveResult(IntEnum):
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,
flowweave/flowweave.py CHANGED
@@ -1,5 +1,4 @@
1
1
  # Standard library
2
- import copy
3
2
  from functools import reduce
4
3
  import importlib
5
4
  from importlib.resources import files
@@ -8,6 +7,7 @@ import itertools
8
7
  import json
9
8
  import logging
10
9
  from pathlib import Path
10
+ import pickle
11
11
  import sys
12
12
 
13
13
  # Third-party
@@ -43,6 +43,10 @@ class StageData():
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
51
  task_instance = task_data.task_class(prev_future)
48
52
  except AttributeError:
@@ -60,7 +64,8 @@ class TaskRunner():
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
- if prev_future:
67
+
68
+ if prev_future is not None:
64
69
  if "pre_success" == task_data.do_only:
65
70
  run_task = True if (FlowWeaveResult.SUCCESS == prev_future.get("result")) else False
66
71
  elif "pre_fail" == task_data.do_only:
@@ -80,17 +85,23 @@ class TaskRunner():
80
85
  TaskRunner.message_task_ignore(prev_future, task_data)
81
86
  task_result = FlowWeaveResult.IGNORE
82
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")
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 TaskRunner():
98
109
 
99
110
  class FlowWeave():
100
111
  @flow
101
- def run(setting_file: str, parallel: bool = False, show_log: bool = False) -> list[str]:
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/{source}"
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
 
@@ -262,7 +273,7 @@ class FlowWeave():
262
273
  return all_combinations
263
274
 
264
275
  @task
265
- def run_flow(flow_data: dict, global_cmb: dict, op_dic: dict, part: int, all: int, show_log: bool = False) -> list[str]:
276
+ def run_flow(flow_data: dict, global_cmb: dict, op_dic: dict, part: int, all: int, show_log: bool = False) -> FlowWeaveResult:
266
277
  flow_result = FlowWeaveResult.SUCCESS
267
278
 
268
279
  if show_log:
@@ -271,7 +282,7 @@ class FlowWeave():
271
282
  text += "========"
272
283
  FlowWeave._print_log(text)
273
284
 
274
- default_option = flow_data.get("default_option")
285
+ default_option = flow_data.get("default_option", {})
275
286
 
276
287
  stage_list = flow_data.get("flow")
277
288
  for stage in stage_list:
@@ -288,7 +299,7 @@ class FlowWeave():
288
299
  if FlowWeaveResult.FAIL == result:
289
300
  flow_result = FlowWeaveResult.FAIL
290
301
 
291
- FlowMessage.stage_end(stage, part, all, flow_result)
302
+ FlowMessage.stage_end(stage, part, all, result)
292
303
 
293
304
  return flow_result
294
305
 
@@ -328,7 +339,7 @@ class FlowWeave():
328
339
  return stage_result
329
340
 
330
341
  def _deep_merge(a: dict, b: dict) -> dict:
331
- result = a.copy()
342
+ result = copy.deepcopy(a)
332
343
  for k, v in b.items():
333
344
  if k in result and isinstance(result[k], dict) and isinstance(v, dict):
334
345
  result[k] = FlowWeave._deep_merge(result[k], v)
@@ -346,36 +357,42 @@ class FlowWeave():
346
357
  raise Exception(f"Cycle detected at task '{task_name}' in {visited}")
347
358
  visited.add(task_name)
348
359
 
349
- task_dic = stage_data.stage_info.get(task_name)
350
-
351
- task_module = stage_data.op_dic.get(task_dic.get('op'))
352
- if not task_module:
353
- raise Exception(f"module of op '{task_dic.get('op')}' for '{task_name}' not found")
354
-
355
- default_option = stage_data.default_option or {}
356
- global_option = stage_data.global_option or {}
357
- task_option = FlowWeave._deep_merge_many(default_option, global_option, task_dic.get("option", {}))
358
-
359
- task_data = TaskData(name=task_name,
360
- task_class=task_module,
361
- option=task_option,
362
- stage_name=stage_data.name,
363
- flow_part=stage_data.flow_part,
364
- flow_all=stage_data.flow_all,
365
- do_only=task_dic.get("do_only"),
366
- show_log=show_log)
367
- if prev_future is None:
368
- future = TaskRunner.start.submit(None, task_data)
369
- else:
370
- future = TaskRunner.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)
371
385
 
372
- links = task_dic.get("chain", {}).get("next", [])
373
- links = links if isinstance(links, list) else [links]
386
+ links = task_dic.get("chain", {}).get("next", [])
387
+ links = links if isinstance(links, list) else [links]
374
388
 
375
- futures = [future]
376
- for link in links:
377
- futures.extend(
378
- FlowWeave._run_task(stage_data, link, future, visited.copy(), show_log)
379
- )
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
380
396
 
381
- return futures
397
+ finally:
398
+ visited.remove(task_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flowweave
3
- Version: 3.0.0
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,13 @@
1
+ flowweave/__init__.py,sha256=mO0zI_6wJsS2Gd4hE20UjTNiiNBSRWuwURV02UQwTgo,151
2
+ flowweave/base.py,sha256=Z9nctdS2Uin0MDMRxhQooJP-XuxkgWXBd83Qls0GQjE,3072
3
+ flowweave/cli.py,sha256=xO3hWlMlK9RLniXwQGHHq21IpX9PGki1n3UCR9VAvmQ,2651
4
+ flowweave/flowweave.py,sha256=KhyTD20KOiZLeUX2knggQ5LyNb2awCOrwp19AE5SYRA,15116
5
+ flowweave/message.py,sha256=2tvWW0rEQFjJFwb4Zu7ht2zb6iTRVLIux3jX3P2KzIU,3780
6
+ flowweave/schema/flow.json,sha256=K7EAcH2KqniAPdNJWJdLiOYC77D2SGg50SOU2frC7LU,1810
7
+ flowweave/schema/op_code.json,sha256=C9JeyBvSC6fA8Ss0exk3nsPjTRq_2XpK2gshvAcavbQ,414
8
+ flowweave-3.0.2.dist-info/licenses/LICENSE,sha256=iN7x3Cz45_nCPCn23daVPqs0m_ZWPvTdayE2jg2OSmY,1203
9
+ flowweave-3.0.2.dist-info/METADATA,sha256=IhKSliT_YX1ZEbD2cUaasuD-4hnTqRh17oKwbedhfZ0,744
10
+ flowweave-3.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
11
+ flowweave-3.0.2.dist-info/entry_points.txt,sha256=qV4hkGzamuf-N1eNz-h_tRQ89Wa_py2jIdOSTeGAE1M,49
12
+ flowweave-3.0.2.dist-info/top_level.txt,sha256=7fLs0F6CROwWhmjP9CyKODB25HJohoougiOCCL1YD_Y,10
13
+ flowweave-3.0.2.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- flowweave/__init__.py,sha256=hFKSVXLXkc5VTBybQshM0N9uvhA02lAiCsImk-bp3K8,151
2
- flowweave/base.py,sha256=o5spY8XxfoP585Qxw02o7xIz9phJUXnVjKXCLUmhsFk,2514
3
- flowweave/cli.py,sha256=xO3hWlMlK9RLniXwQGHHq21IpX9PGki1n3UCR9VAvmQ,2651
4
- flowweave/flowweave.py,sha256=5bnVxfrQ2NzW8pssHyz_OLwIRaB_3GcijyXmX3dKWAQ,14413
5
- flowweave/message.py,sha256=2tvWW0rEQFjJFwb4Zu7ht2zb6iTRVLIux3jX3P2KzIU,3780
6
- flowweave/schema/flow.json,sha256=K7EAcH2KqniAPdNJWJdLiOYC77D2SGg50SOU2frC7LU,1810
7
- flowweave/schema/op_code.json,sha256=C9JeyBvSC6fA8Ss0exk3nsPjTRq_2XpK2gshvAcavbQ,414
8
- flowweave-3.0.0.dist-info/licenses/LICENSE,sha256=iN7x3Cz45_nCPCn23daVPqs0m_ZWPvTdayE2jg2OSmY,1203
9
- flowweave-3.0.0.dist-info/METADATA,sha256=sSjhmn-nA2LXYMT_ZMO8R6xWyhQDgvmxXZO04W-n5I8,580
10
- flowweave-3.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
11
- flowweave-3.0.0.dist-info/entry_points.txt,sha256=qV4hkGzamuf-N1eNz-h_tRQ89Wa_py2jIdOSTeGAE1M,49
12
- flowweave-3.0.0.dist-info/top_level.txt,sha256=7fLs0F6CROwWhmjP9CyKODB25HJohoougiOCCL1YD_Y,10
13
- flowweave-3.0.0.dist-info/RECORD,,