dv-flow-mgr 0.0.1.14013608039a1__py3-none-any.whl → 0.0.1.14097297609a1__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/__init__.py +2 -2
- dv_flow/mgr/__main__.py +26 -1
- dv_flow/mgr/cmds/cmd_graph.py +82 -0
- dv_flow/mgr/cmds/cmd_show.py +107 -0
- dv_flow/mgr/fileset.py +1 -0
- dv_flow/mgr/package.py +3 -3
- dv_flow/mgr/package_def.py +82 -12
- dv_flow/mgr/std/message.py +1 -1
- dv_flow/mgr/task_data.py +24 -20
- dv_flow/mgr/task_def.py +0 -1
- dv_flow/mgr/task_graph_builder.py +121 -12
- dv_flow/mgr/task_graph_dot_writer.py +78 -0
- dv_flow/mgr/task_node.py +3 -326
- dv_flow/mgr/task_node_compound.py +13 -1
- dv_flow/mgr/task_node_ctor.py +118 -0
- dv_flow/mgr/task_node_ctor_compound.py +117 -0
- dv_flow/mgr/task_node_ctor_compound_proxy.py +65 -0
- dv_flow/mgr/task_node_ctor_def_base.py +47 -0
- dv_flow/mgr/task_node_ctor_proxy.py +56 -0
- dv_flow/mgr/task_node_ctor_task.py +64 -0
- dv_flow/mgr/task_node_ctor_wrapper.py +96 -0
- dv_flow/mgr/task_node_leaf.py +170 -0
- dv_flow/mgr/task_runner.py +11 -6
- {dv_flow_mgr-0.0.1.14013608039a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/METADATA +1 -1
- {dv_flow_mgr-0.0.1.14013608039a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/RECORD +29 -20
- {dv_flow_mgr-0.0.1.14013608039a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/WHEEL +1 -1
- dv_flow/mgr/task.py +0 -181
- dv_flow/mgr/task_ctor.py +0 -64
- {dv_flow_mgr-0.0.1.14013608039a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/entry_points.txt +0 -0
- {dv_flow_mgr-0.0.1.14013608039a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/licenses/LICENSE +0 -0
- {dv_flow_mgr-0.0.1.14013608039a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_node_ctor.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import enum
|
23
|
+
import os
|
24
|
+
import sys
|
25
|
+
import dataclasses as dc
|
26
|
+
import pydantic.dataclasses as pdc
|
27
|
+
import logging
|
28
|
+
import toposort
|
29
|
+
from typing import Any, Callable, ClassVar, Dict, List, Tuple
|
30
|
+
from .task_node import TaskNode
|
31
|
+
from .param import Param
|
32
|
+
|
33
|
+
@dc.dataclass
|
34
|
+
class TaskNodeCtor(object):
|
35
|
+
"""
|
36
|
+
Factory for a specific task type
|
37
|
+
- Produces a task parameters object, applying value-setting instructions
|
38
|
+
- Produces a TaskNode
|
39
|
+
"""
|
40
|
+
name : str
|
41
|
+
srcdir : str
|
42
|
+
paramT : Any
|
43
|
+
passthrough : bool
|
44
|
+
consumes : List[Any]
|
45
|
+
needs : List[str]
|
46
|
+
|
47
|
+
def __call__(self,
|
48
|
+
builder=None,
|
49
|
+
name=None,
|
50
|
+
srcdir=None,
|
51
|
+
params=None,
|
52
|
+
needs=None,
|
53
|
+
passthrough=None,
|
54
|
+
consumes=None,
|
55
|
+
**kwargs):
|
56
|
+
"""Convenience method for direct creation of tasks"""
|
57
|
+
if params is None:
|
58
|
+
params = self.mkTaskParams(kwargs)
|
59
|
+
|
60
|
+
node = self.mkTaskNode(
|
61
|
+
builder=builder,
|
62
|
+
srcdir=srcdir,
|
63
|
+
params=params,
|
64
|
+
name=name,
|
65
|
+
needs=needs)
|
66
|
+
if passthrough is not None:
|
67
|
+
node.passthrough = passthrough
|
68
|
+
else:
|
69
|
+
node.passthrough = self.passthrough
|
70
|
+
if consumes is not None:
|
71
|
+
if node.consumes is None:
|
72
|
+
node.consumes = consumes
|
73
|
+
else:
|
74
|
+
node.consumes.extend(consumes)
|
75
|
+
else:
|
76
|
+
if node.consumes is None:
|
77
|
+
node.consumes = self.consumes
|
78
|
+
|
79
|
+
return node
|
80
|
+
|
81
|
+
def getNeeds(self) -> List[str]:
|
82
|
+
return []
|
83
|
+
|
84
|
+
def mkTaskNode(self,
|
85
|
+
builder,
|
86
|
+
params,
|
87
|
+
srcdir=None,
|
88
|
+
name=None,
|
89
|
+
needs=None) -> TaskNode:
|
90
|
+
raise NotImplementedError("mkTaskNode in type %s" % str(type(self)))
|
91
|
+
|
92
|
+
def mkTaskParams(self, params : Dict = None) -> Any:
|
93
|
+
obj = self.paramT()
|
94
|
+
|
95
|
+
# Apply user-specified params
|
96
|
+
if params is not None:
|
97
|
+
for key,value in params.items():
|
98
|
+
if not hasattr(obj, key):
|
99
|
+
raise Exception("Parameters class %s does not contain field %s" % (
|
100
|
+
str(type(obj)),
|
101
|
+
key))
|
102
|
+
else:
|
103
|
+
if isinstance(value, Param):
|
104
|
+
if value.append is not None:
|
105
|
+
ex_value = getattr(obj, key, [])
|
106
|
+
ex_value.extend(value.append)
|
107
|
+
setattr(obj, key, ex_value)
|
108
|
+
elif value.prepend is not None:
|
109
|
+
ex_value = getattr(obj, key, [])
|
110
|
+
value = value.copy()
|
111
|
+
value.extend(ex_value)
|
112
|
+
setattr(obj, key, value)
|
113
|
+
pass
|
114
|
+
else:
|
115
|
+
raise Exception("Unhandled value spec: %s" % str(value))
|
116
|
+
else:
|
117
|
+
setattr(obj, key, value)
|
118
|
+
return obj
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_node_ctor_compound.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import os
|
23
|
+
import json
|
24
|
+
import dataclasses as dc
|
25
|
+
import logging
|
26
|
+
from pydantic import BaseModel
|
27
|
+
from typing import Any, Callable, ClassVar, Dict, List, Tuple
|
28
|
+
from .task_def import TaskDef
|
29
|
+
from .task_data import TaskDataOutput, TaskDataResult
|
30
|
+
from .task_node import TaskNode
|
31
|
+
from .task_node_ctor import TaskNodeCtor
|
32
|
+
from .task_node_compound import TaskNodeCompound
|
33
|
+
|
34
|
+
@dc.dataclass
|
35
|
+
class TaskNodeCtorCompound(TaskNodeCtor):
|
36
|
+
task_def : TaskDef
|
37
|
+
tasks : List[TaskNodeCtor] = dc.field(default_factory=list)
|
38
|
+
|
39
|
+
_log : ClassVar = logging.getLogger("TaskNodeCtorCompound")
|
40
|
+
|
41
|
+
def mkTaskNode(self, builder, params, srcdir=None, name=None, needs=None) -> 'TaskNode':
|
42
|
+
"""Creates a task object without a base task"""
|
43
|
+
self._log.debug("--> mkTaskNode %s (%d)" % (name, len(self.tasks)))
|
44
|
+
if srcdir is None:
|
45
|
+
srcdir = self.srcdir
|
46
|
+
|
47
|
+
node = TaskNodeCompound(
|
48
|
+
name=name,
|
49
|
+
srcdir=srcdir,
|
50
|
+
params=params,
|
51
|
+
needs=needs)
|
52
|
+
|
53
|
+
|
54
|
+
builder.enter_compound(node)
|
55
|
+
builder.addTask("in", node.input)
|
56
|
+
|
57
|
+
self._buildSubGraph(builder, node)
|
58
|
+
|
59
|
+
builder.leave_compound(node)
|
60
|
+
|
61
|
+
self._log.debug("<-- mkTaskNode %s (%d)" % (name, len(node.needs)))
|
62
|
+
return node
|
63
|
+
|
64
|
+
def _buildSubGraph(self, builder, node):
|
65
|
+
nodes = []
|
66
|
+
|
67
|
+
for t in self.tasks:
|
68
|
+
# Need to get the parent name
|
69
|
+
needs = []
|
70
|
+
for n in t.needs:
|
71
|
+
need_name = "%s.%s" % (builder.package().name, n)
|
72
|
+
task = builder.findTask(n)
|
73
|
+
if task is None:
|
74
|
+
task = builder.findTask(need_name)
|
75
|
+
|
76
|
+
if task is None:
|
77
|
+
raise Exception("Failed to find task %s (%s)" % (n, need_name))
|
78
|
+
self._log.debug("Add %s as dependency of %s" % (
|
79
|
+
task.name, t.name
|
80
|
+
))
|
81
|
+
needs.append(task)
|
82
|
+
sn = t.mkTaskNode(
|
83
|
+
builder=builder,
|
84
|
+
params=t.mkTaskParams(),
|
85
|
+
name=t.name,
|
86
|
+
needs=needs)
|
87
|
+
nodes.append(sn)
|
88
|
+
builder.addTask(t.name, sn)
|
89
|
+
in_t = builder.findTask("in")
|
90
|
+
|
91
|
+
|
92
|
+
for n in nodes:
|
93
|
+
|
94
|
+
# If this node references one of the others, then
|
95
|
+
# it takes input from that node, and not the 'in' node
|
96
|
+
has_ref = False
|
97
|
+
for nt in n.needs:
|
98
|
+
self._log.debug("nt: %s %s" % (nt[0].name, str(n.needs)))
|
99
|
+
if nt[0] in nodes or nt[0] is in_t:
|
100
|
+
has_ref = True
|
101
|
+
break
|
102
|
+
if not has_ref:
|
103
|
+
n.needs.append([builder.findTask("in"), False])
|
104
|
+
|
105
|
+
# Only add a dependency on the node if no other node references it
|
106
|
+
is_ref = False
|
107
|
+
for nt in nodes:
|
108
|
+
for nn in nt.needs:
|
109
|
+
if nn[0] == n:
|
110
|
+
is_ref = True
|
111
|
+
break
|
112
|
+
if not is_ref:
|
113
|
+
node.needs.append([n, False])
|
114
|
+
|
115
|
+
self._log.debug("nodes: %d (%d %d)" % (len(nodes), len(self.tasks), len(node.needs)))
|
116
|
+
|
117
|
+
pass
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import os
|
2
|
+
import json
|
3
|
+
import dataclasses as dc
|
4
|
+
import logging
|
5
|
+
from pydantic import BaseModel
|
6
|
+
from typing import Any, Callable, ClassVar, Dict, List, Tuple
|
7
|
+
from .task_data import TaskDataOutput, TaskDataResult
|
8
|
+
from .task_node import TaskNode
|
9
|
+
from .task_node_compound import TaskNodeCompound
|
10
|
+
from .task_node_ctor import TaskNodeCtor
|
11
|
+
from .task_node_ctor_compound import TaskNodeCtorCompound
|
12
|
+
|
13
|
+
# TaskParamsCtor accepts an evaluation context and returns a task parameter object
|
14
|
+
TaskParamsCtor = Callable[[object], Any]
|
15
|
+
|
16
|
+
@dc.dataclass
|
17
|
+
class TaskNodeCtorCompoundProxy(TaskNodeCtorCompound):
|
18
|
+
"""Task has a 'uses' clause, so we delegate creation of the node"""
|
19
|
+
uses : TaskNodeCtor = dc.field(default=None)
|
20
|
+
|
21
|
+
_log : ClassVar = logging.getLogger("TaskNodeCtorCompoundProxy")
|
22
|
+
|
23
|
+
def mkTaskNode(self, builder, params, srcdir=None, name=None, needs=None) -> 'TaskNode':
|
24
|
+
"""Creates a task object without a base task"""
|
25
|
+
self._log.debug("--> mkTaskNode: %s", name)
|
26
|
+
if srcdir is None:
|
27
|
+
srcdir = self.srcdir
|
28
|
+
|
29
|
+
is_compound_uses = builder.is_compound_uses()
|
30
|
+
|
31
|
+
if not is_compound_uses:
|
32
|
+
# We're at the leaf level
|
33
|
+
node = TaskNodeCompound(
|
34
|
+
name=name,
|
35
|
+
srcdir=srcdir,
|
36
|
+
params=params)
|
37
|
+
|
38
|
+
builder.enter_compound(node)
|
39
|
+
builder.addTask("in", node.input)
|
40
|
+
else:
|
41
|
+
node = None
|
42
|
+
|
43
|
+
builder.enter_compound_uses()
|
44
|
+
|
45
|
+
# Construct the base-task node
|
46
|
+
base_node = self.uses.mkTaskNode(
|
47
|
+
builder=builder,
|
48
|
+
params=params,
|
49
|
+
srcdir=srcdir,
|
50
|
+
name=name + ".super",
|
51
|
+
needs=[node.input])
|
52
|
+
builder.addTask("super", base_node)
|
53
|
+
|
54
|
+
# Build 'uses' node
|
55
|
+
self._buildSubGraph(builder, node)
|
56
|
+
|
57
|
+
builder.leave_compound_uses()
|
58
|
+
|
59
|
+
if not is_compound_uses:
|
60
|
+
builder.leave_compound(node)
|
61
|
+
|
62
|
+
|
63
|
+
self._log.debug("<-- mkTaskNode: %s", name)
|
64
|
+
return node
|
65
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_node_ctor_def_base.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import enum
|
23
|
+
import os
|
24
|
+
import sys
|
25
|
+
import dataclasses as dc
|
26
|
+
import pydantic.dataclasses as pdc
|
27
|
+
import logging
|
28
|
+
import toposort
|
29
|
+
from typing import Any, Callable, ClassVar, Dict, List, Tuple
|
30
|
+
from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
|
31
|
+
from .task_params_ctor import TaskParamsCtor
|
32
|
+
from .param_ref_eval import ParamRefEval
|
33
|
+
from .param import Param
|
34
|
+
from .task_node_ctor import TaskNodeCtor
|
35
|
+
|
36
|
+
@dc.dataclass
|
37
|
+
class TaskNodeCtorDefBase(TaskNodeCtor):
|
38
|
+
"""Task defines its own needs, that will need to be filled in"""
|
39
|
+
needs : List['str']
|
40
|
+
|
41
|
+
def __post_init__(self):
|
42
|
+
if self.needs is None:
|
43
|
+
self.needs = []
|
44
|
+
|
45
|
+
def getNeeds(self) -> List[str]:
|
46
|
+
return self.needs
|
47
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_node_ctor_def_base.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import enum
|
23
|
+
import os
|
24
|
+
import sys
|
25
|
+
import dataclasses as dc
|
26
|
+
import pydantic.dataclasses as pdc
|
27
|
+
import logging
|
28
|
+
import toposort
|
29
|
+
from typing import Any, Callable, ClassVar, Dict, List, Tuple
|
30
|
+
from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
|
31
|
+
from .task_params_ctor import TaskParamsCtor
|
32
|
+
from .param_ref_eval import ParamRefEval
|
33
|
+
from .param import Param
|
34
|
+
from .task_node import TaskNode
|
35
|
+
from .task_node_ctor import TaskNodeCtor
|
36
|
+
from .task_node_ctor_def_base import TaskNodeCtorDefBase
|
37
|
+
|
38
|
+
@dc.dataclass
|
39
|
+
class TaskNodeCtorProxy(TaskNodeCtorDefBase):
|
40
|
+
"""Task has a 'uses' clause, so we delegate creation of the node"""
|
41
|
+
uses : TaskNodeCtor
|
42
|
+
|
43
|
+
def mkTaskNode(self, builder, params, srcdir=None, name=None, needs=None) -> TaskNode:
|
44
|
+
if srcdir is None:
|
45
|
+
srcdir = self.srcdir
|
46
|
+
builder.enter_uses()
|
47
|
+
node = self.uses.mkTaskNode(
|
48
|
+
builder=builder, params=params, srcdir=srcdir, name=name, needs=needs)
|
49
|
+
node.passthrough = self.passthrough
|
50
|
+
node.consumes = self.consumes
|
51
|
+
builder.leave_uses()
|
52
|
+
|
53
|
+
if not builder.in_uses():
|
54
|
+
builder.addTask(name, node)
|
55
|
+
return node
|
56
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_node_ctor_task.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import enum
|
23
|
+
import os
|
24
|
+
import sys
|
25
|
+
import dataclasses as dc
|
26
|
+
import pydantic.dataclasses as pdc
|
27
|
+
import logging
|
28
|
+
import toposort
|
29
|
+
from typing import Any, Callable, ClassVar, Dict, List, Tuple
|
30
|
+
from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
|
31
|
+
from .task_params_ctor import TaskParamsCtor
|
32
|
+
from .param_ref_eval import ParamRefEval
|
33
|
+
from .param import Param
|
34
|
+
from .task_node import TaskNode
|
35
|
+
from .task_node_leaf import TaskNodeLeaf
|
36
|
+
from .task_node_ctor import TaskNodeCtor
|
37
|
+
from .task_node_ctor_def_base import TaskNodeCtorDefBase
|
38
|
+
|
39
|
+
@dc.dataclass
|
40
|
+
class TaskNodeCtorTask(TaskNodeCtorDefBase):
|
41
|
+
task : Callable[['TaskRunner','TaskDataInput'],'TaskDataResult']
|
42
|
+
|
43
|
+
_log : ClassVar[logging.Logger] = logging.getLogger("TaskNodeCtorTask")
|
44
|
+
|
45
|
+
def mkTaskNode(self, builder, params, srcdir=None, name=None, needs=None) -> TaskNode:
|
46
|
+
self._log.debug("--> mkTaskNode needs=%d" % (
|
47
|
+
(len(needs) if needs is not None else -1),
|
48
|
+
))
|
49
|
+
if srcdir is None:
|
50
|
+
srcdir = self.srcdir
|
51
|
+
|
52
|
+
node = TaskNodeLeaf(
|
53
|
+
name=name,
|
54
|
+
srcdir=srcdir,
|
55
|
+
params=params,
|
56
|
+
task=self.task,
|
57
|
+
needs=needs)
|
58
|
+
node.passthrough = self.passthrough
|
59
|
+
node.consumes = self.consumes
|
60
|
+
node.task = self.task
|
61
|
+
builder.addTask(name, node)
|
62
|
+
|
63
|
+
self._log.debug("<-- mkTaskNode")
|
64
|
+
return node
|
@@ -0,0 +1,96 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* task_node_ctor_task.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import enum
|
23
|
+
import os
|
24
|
+
import sys
|
25
|
+
import dataclasses as dc
|
26
|
+
import pydantic.dataclasses as pdc
|
27
|
+
import logging
|
28
|
+
import toposort
|
29
|
+
from typing import Any, Callable, ClassVar, Dict, List, Tuple
|
30
|
+
from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
|
31
|
+
from .task_params_ctor import TaskParamsCtor
|
32
|
+
from .param_ref_eval import ParamRefEval
|
33
|
+
from .param import Param
|
34
|
+
from .task_node import TaskNode
|
35
|
+
from .task_node_leaf import TaskNodeLeaf
|
36
|
+
from .task_node_ctor import TaskNodeCtor
|
37
|
+
from .task_node_ctor_def_base import TaskNodeCtorDefBase
|
38
|
+
|
39
|
+
@dc.dataclass
|
40
|
+
class TaskNodeCtorWrapper(TaskNodeCtor):
|
41
|
+
T : Any
|
42
|
+
|
43
|
+
def mkTaskNode(self, builder, params, srcdir=None, name=None, needs=None) -> TaskNode:
|
44
|
+
node = TaskNodeLeaf(
|
45
|
+
name=name,
|
46
|
+
srcdir=srcdir,
|
47
|
+
params=params,
|
48
|
+
task=self.T,
|
49
|
+
needs=needs)
|
50
|
+
node.passthrough = self.passthrough
|
51
|
+
node.consumes = self.consumes
|
52
|
+
return node
|
53
|
+
|
54
|
+
def mkTaskParams(self, params : Dict = None) -> Any:
|
55
|
+
obj = self.paramT()
|
56
|
+
|
57
|
+
# Apply user-specified params
|
58
|
+
for key,value in params.items():
|
59
|
+
if not hasattr(obj, key):
|
60
|
+
raise Exception("Parameters class %s does not contain field %s" % (
|
61
|
+
str(type(obj)),
|
62
|
+
key))
|
63
|
+
else:
|
64
|
+
if isinstance(value, Param):
|
65
|
+
if value.append is not None:
|
66
|
+
ex_value = getattr(obj, key, [])
|
67
|
+
ex_value.extend(value.append)
|
68
|
+
setattr(obj, key, ex_value)
|
69
|
+
elif value.prepend is not None:
|
70
|
+
ex_value = getattr(obj, key, [])
|
71
|
+
value = value.copy()
|
72
|
+
value.extend(ex_value)
|
73
|
+
setattr(obj, key, value)
|
74
|
+
pass
|
75
|
+
else:
|
76
|
+
raise Exception("Unhandled value spec: %s" % str(value))
|
77
|
+
else:
|
78
|
+
setattr(obj, key, value)
|
79
|
+
return obj
|
80
|
+
|
81
|
+
def task(paramT,passthrough=False,consumes=None):
|
82
|
+
"""Decorator to wrap a task method as a TaskNodeCtor"""
|
83
|
+
def wrapper(T):
|
84
|
+
task_mname = T.__module__
|
85
|
+
task_module = sys.modules[task_mname]
|
86
|
+
ctor = TaskNodeCtorWrapper(
|
87
|
+
name=T.__name__,
|
88
|
+
srcdir=os.path.dirname(os.path.abspath(task_module.__file__)),
|
89
|
+
paramT=paramT,
|
90
|
+
passthrough=passthrough,
|
91
|
+
consumes=consumes,
|
92
|
+
needs=[],
|
93
|
+
T=T)
|
94
|
+
return ctor
|
95
|
+
return wrapper
|
96
|
+
|