dv-flow-mgr 0.0.1.13478128278a1__py3-none-any.whl → 0.0.1.13489806632a1__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.
- dv_flow/mgr/task_node.py +80 -0
- dv_flow/mgr/task_runner.py +122 -6
- {dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/METADATA +1 -1
- {dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/RECORD +8 -7
- {dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/LICENSE +0 -0
- {dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/WHEEL +0 -0
- {dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/entry_points.txt +0 -0
- {dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/top_level.txt +0 -0
dv_flow/mgr/task_node.py
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
import dataclasses as dc
|
3
|
+
import logging
|
4
|
+
from typing import Any, Callable, ClassVar, Dict, List
|
5
|
+
from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
|
6
|
+
from .task_params_ctor import TaskParamsCtor
|
7
|
+
|
8
|
+
@dc.dataclass
|
9
|
+
class TaskNode(object):
|
10
|
+
"""Executable view of a task"""
|
11
|
+
# Ctor fields -- must specify on construction
|
12
|
+
name : str
|
13
|
+
srcdir : str
|
14
|
+
# This can be the resolved parameters
|
15
|
+
params : TaskParamsCtor
|
16
|
+
|
17
|
+
task : Callable[['TaskRunner','TaskDataInput'],'TaskDataResult']
|
18
|
+
|
19
|
+
# Runtime fields -- these get populated during execution
|
20
|
+
changed : bool = False
|
21
|
+
needs : List['TaskNode'] = dc.field(default_factory=list)
|
22
|
+
rundir : str = dc.field(default=None)
|
23
|
+
output : TaskDataOutput = dc.field(default=None)
|
24
|
+
|
25
|
+
_log : ClassVar = logging.getLogger("TaskNode")
|
26
|
+
|
27
|
+
def __hash__(self):
|
28
|
+
return id(self)
|
29
|
+
|
30
|
+
@staticmethod
|
31
|
+
def task(paramT):
|
32
|
+
def wrapper(T):
|
33
|
+
ctor = TaskNodeCtorWrapper(T.__name__, T, paramT)
|
34
|
+
return ctor
|
35
|
+
return wrapper
|
36
|
+
|
37
|
+
@dc.dataclass
|
38
|
+
class TaskNodeCtor(object):
|
39
|
+
"""
|
40
|
+
Factory for a specific task type
|
41
|
+
- Produces a task parameters object, applying value-setting instructions
|
42
|
+
- Produces a TaskNode
|
43
|
+
"""
|
44
|
+
name : str
|
45
|
+
|
46
|
+
|
47
|
+
def mkTaskNode(self, srcdir, params, name=None) -> TaskNode:
|
48
|
+
raise NotImplementedError("mkTaskNode in type %s" % str(type(self)))
|
49
|
+
|
50
|
+
def mkTaskParams(self, params : Dict) -> Any:
|
51
|
+
raise NotImplementedError("mkTaskParams in type %s" % str(type(self)))
|
52
|
+
|
53
|
+
@dc.dataclass
|
54
|
+
class TaskNodeCtorWrapper(TaskNodeCtor):
|
55
|
+
T : Any
|
56
|
+
paramT : Any
|
57
|
+
|
58
|
+
def __call__(self,
|
59
|
+
srcdir,
|
60
|
+
name=None,
|
61
|
+
params=None,
|
62
|
+
needs=None,
|
63
|
+
**kwargs):
|
64
|
+
"""Convenience method for direct creation of tasks"""
|
65
|
+
if params is None:
|
66
|
+
params = self.mkTaskParams(kwargs)
|
67
|
+
|
68
|
+
node = self.mkTaskNode(srcdir, params, name)
|
69
|
+
if needs is not None:
|
70
|
+
node.needs.extend(needs)
|
71
|
+
return node
|
72
|
+
|
73
|
+
def mkTaskNode(self, srcdir, params, name=None) -> TaskNode:
|
74
|
+
node = TaskNode(name, srcdir, params, self.T)
|
75
|
+
return node
|
76
|
+
|
77
|
+
def mkTaskParams(self, params : Dict) -> Any:
|
78
|
+
obj = self.paramT()
|
79
|
+
# TODO: apply user-specified params
|
80
|
+
return obj
|
dv_flow/mgr/task_runner.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
import asyncio
|
1
2
|
import dataclasses as dc
|
2
|
-
from
|
3
|
-
from typing import Any, Callable, List, Tuple
|
3
|
+
from toposort import toposort
|
4
|
+
from typing import Any, Callable, List, Tuple, Union
|
5
|
+
from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
|
6
|
+
from .task_node import TaskNode
|
4
7
|
|
5
8
|
@dc.dataclass
|
6
9
|
class TaskRunner(object):
|
@@ -19,6 +22,98 @@ class TaskRunner(object):
|
|
19
22
|
memento : Any = None) -> 'TaskDataResult':
|
20
23
|
pass
|
21
24
|
|
25
|
+
@dc.dataclass
|
26
|
+
class TaskSetRunner(TaskRunner):
|
27
|
+
nproc : int = 8
|
28
|
+
|
29
|
+
async def run(self, task : Union[TaskNode,List[TaskNode]]):
|
30
|
+
# First, build a depedency map
|
31
|
+
tasks = task if isinstance(task, list) else [task]
|
32
|
+
dep_m = {}
|
33
|
+
for t in tasks:
|
34
|
+
self._buildDepMap(dep_m, t)
|
35
|
+
|
36
|
+
print("dep_m: %s" % str(dep_m))
|
37
|
+
|
38
|
+
order = list(toposort(dep_m))
|
39
|
+
|
40
|
+
active_task_l = []
|
41
|
+
done_task_s = set()
|
42
|
+
for active_s in order:
|
43
|
+
done = True
|
44
|
+
for t in active_s:
|
45
|
+
while len(active_task_l) >= self.nproc and t not in done_task_s:
|
46
|
+
# Wait for at least one job to complete
|
47
|
+
done, pending = await asyncio.wait(at[1] for at in active_task_l)
|
48
|
+
for d in done:
|
49
|
+
for i in range(len(active_task_l)):
|
50
|
+
if active_task_l[i][1] == d:
|
51
|
+
tt = active_task_l[i][0]
|
52
|
+
done_task_s.add(tt)
|
53
|
+
active_task_l.pop(i)
|
54
|
+
break
|
55
|
+
if t not in done_task_s:
|
56
|
+
coro = asyncio.Task(self.do_run(t))
|
57
|
+
active_task_l.append((t, coro))
|
58
|
+
|
59
|
+
# Now, wait for tasks to complete
|
60
|
+
if len(active_task_l):
|
61
|
+
coros = list(at[1] for at in active_task_l)
|
62
|
+
res = await asyncio.gather(*coros)
|
63
|
+
|
64
|
+
|
65
|
+
pass
|
66
|
+
|
67
|
+
async def do_run(self,
|
68
|
+
task : 'TaskNode',
|
69
|
+
memento : Any = None) -> 'TaskDataResult':
|
70
|
+
changed = False
|
71
|
+
for dep in task.needs:
|
72
|
+
changed |= dep.changed
|
73
|
+
|
74
|
+
# TODO: create an evaluator for substituting param values
|
75
|
+
eval = None
|
76
|
+
|
77
|
+
for field in dc.fields(task.params):
|
78
|
+
print("Field: %s" % field.name)
|
79
|
+
|
80
|
+
input = TaskDataInput(
|
81
|
+
changed=changed,
|
82
|
+
srcdir=task.srcdir,
|
83
|
+
rundir=self.rundir,
|
84
|
+
params=task.params,
|
85
|
+
memento=memento)
|
86
|
+
|
87
|
+
# TODO: notify of task start
|
88
|
+
ret : TaskDataResult = await task.task(self, input)
|
89
|
+
# TODO: notify of task complete
|
90
|
+
|
91
|
+
# Store the result
|
92
|
+
task.output = TaskDataOutput(
|
93
|
+
changed=ret.changed,
|
94
|
+
output=ret.output.copy())
|
95
|
+
|
96
|
+
# # By definition, none of this have run, since we just ran
|
97
|
+
# for dep in task.dependents:
|
98
|
+
# is_sat = True
|
99
|
+
# for need in dep.needs:
|
100
|
+
# if need.output is None:
|
101
|
+
# is_sat = False
|
102
|
+
# break
|
103
|
+
|
104
|
+
# if is_sat:
|
105
|
+
# # TODO: queue task for evaluation
|
106
|
+
# pass
|
107
|
+
# TODO:
|
108
|
+
|
109
|
+
return ret
|
110
|
+
|
111
|
+
def _buildDepMap(self, dep_m, task : TaskNode):
|
112
|
+
if task not in dep_m.keys():
|
113
|
+
dep_m[task] = set(task.needs)
|
114
|
+
for need in task.needs:
|
115
|
+
self._buildDepMap(dep_m, need)
|
116
|
+
|
22
117
|
@dc.dataclass
|
23
118
|
class SingleTaskRunner(TaskRunner):
|
24
119
|
|
@@ -32,15 +127,36 @@ class SingleTaskRunner(TaskRunner):
|
|
32
127
|
# TODO: create an evaluator for substituting param values
|
33
128
|
eval = None
|
34
129
|
|
35
|
-
|
130
|
+
for field in dc.fields(task.params):
|
131
|
+
print("Field: %s" % field.name)
|
36
132
|
|
37
133
|
input = TaskDataInput(
|
38
134
|
changed=changed,
|
39
135
|
srcdir=task.srcdir,
|
40
136
|
rundir=self.rundir,
|
41
|
-
params=params,
|
137
|
+
params=task.params,
|
42
138
|
memento=memento)
|
43
|
-
|
44
|
-
|
139
|
+
|
140
|
+
# TODO: notify of task start
|
141
|
+
ret : TaskDataResult = await task.task(self, input)
|
142
|
+
# TODO: notify of task complete
|
143
|
+
|
144
|
+
# Store the result
|
145
|
+
task.output = TaskDataOutput(
|
146
|
+
changed=ret.changed,
|
147
|
+
output=ret.output.copy())
|
148
|
+
|
149
|
+
# # By definition, none of this have run, since we just ran
|
150
|
+
# for dep in task.dependents:
|
151
|
+
# is_sat = True
|
152
|
+
# for need in dep.needs:
|
153
|
+
# if need.output is None:
|
154
|
+
# is_sat = False
|
155
|
+
# break
|
156
|
+
|
157
|
+
# if is_sat:
|
158
|
+
# # TODO: queue task for evaluation
|
159
|
+
# pass
|
160
|
+
# TODO:
|
45
161
|
|
46
162
|
return ret
|
{dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/RECORD
RENAMED
@@ -21,9 +21,10 @@ dv_flow/mgr/task_graph_runner.py,sha256=jUGI49QvxUCfQoKQDDk2psbeapIcCg72qNOW1Jip
|
|
21
21
|
dv_flow/mgr/task_graph_runner_local.py,sha256=OrydPwtQ8E7hYWvSXx0h7lI3nfUNFyklULhsyMwz9dA,4687
|
22
22
|
dv_flow/mgr/task_impl_data.py,sha256=bFPijoKrh9x7fZN2DsvRJp0UHo-gGM0VjtDQISyfhFk,321
|
23
23
|
dv_flow/mgr/task_memento.py,sha256=C7VTQpBhDEoYuDmE6YTM-6TLMLnqHp6Y0Vat1aTgtCs,1096
|
24
|
+
dv_flow/mgr/task_node.py,sha256=wcvxdtrRNwPwV494DerrB79PFYAv6bPdWZDvRGQ0V6Q,2318
|
24
25
|
dv_flow/mgr/task_output.py,sha256=l-W-FvVo6YDah1RQS-I9N0KUtB3vp-kl7lxIdmNz0l4,178
|
25
26
|
dv_flow/mgr/task_params_ctor.py,sha256=aXgB8o9xFPjaEjGW_xYkEC0N0apzGzGUPDj7g2ZLvus,1112
|
26
|
-
dv_flow/mgr/task_runner.py,sha256=
|
27
|
+
dv_flow/mgr/task_runner.py,sha256=5vCKM2UFxdHB9OslUVIx5Ipc0r04Cizvrc2YSKGMqqI,5055
|
27
28
|
dv_flow/mgr/type.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
29
|
dv_flow/mgr/type_def.py,sha256=KdhuNlfw-NKU-4VZFCnMPyj775yEB7cpr5tz73a9yuQ,259
|
29
30
|
dv_flow/mgr/util.py,sha256=06eVyURF4ga-s8C9Sd3ZSDebwO4QS0XXaB8xADVbWRc,1437
|
@@ -33,9 +34,9 @@ dv_flow/mgr/std/fileset.py,sha256=uP7bGntRq-Tn5_GEFnt0_J_OAmfvep3GlCwCuE8by4o,27
|
|
33
34
|
dv_flow/mgr/std/flow.dv,sha256=j9wLrF3Ghh1ZLbJxmk7WiNiRYUYEer-8CCUA5hsgtfk,1409
|
34
35
|
dv_flow/mgr/std/message.py,sha256=BPTHnEMD4tBufQ9LvsS9Sa_0xjaJATbBpwqosWslvVA,193
|
35
36
|
dv_flow/mgr/std/task_null.py,sha256=KObmjG_4D08GJ1k6neqKIQrFY72Sj0jLnwXxEkq5HA0,321
|
36
|
-
dv_flow_mgr-0.0.1.
|
37
|
-
dv_flow_mgr-0.0.1.
|
38
|
-
dv_flow_mgr-0.0.1.
|
39
|
-
dv_flow_mgr-0.0.1.
|
40
|
-
dv_flow_mgr-0.0.1.
|
41
|
-
dv_flow_mgr-0.0.1.
|
37
|
+
dv_flow_mgr-0.0.1.13489806632a1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
38
|
+
dv_flow_mgr-0.0.1.13489806632a1.dist-info/METADATA,sha256=iGQC00bCbcchWcesU4kXOBNBn-ggHWurn1YqLBKB610,13276
|
39
|
+
dv_flow_mgr-0.0.1.13489806632a1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
40
|
+
dv_flow_mgr-0.0.1.13489806632a1.dist-info/entry_points.txt,sha256=1roy8wAFM48LabOvr6jiOw0MUs-qE8X3Vf8YykPazxk,50
|
41
|
+
dv_flow_mgr-0.0.1.13489806632a1.dist-info/top_level.txt,sha256=amfVTkggzYPtWwLqNmRukfz1Buu0pGS2SrYBBLhXm04,8
|
42
|
+
dv_flow_mgr-0.0.1.13489806632a1.dist-info/RECORD,,
|
{dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/LICENSE
RENAMED
File without changes
|
{dv_flow_mgr-0.0.1.13478128278a1.dist-info → dv_flow_mgr-0.0.1.13489806632a1.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|