dv-flow-mgr 1.0.0.14528489065a1__py3-none-any.whl → 1.5.0__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 +4 -0
- dv_flow/mgr/cmds/cmd_run.py +6 -1
- dv_flow/mgr/cmds/cmd_show.py +3 -3
- dv_flow/mgr/config_def.py +1 -1
- dv_flow/mgr/expr_eval.py +24 -1
- dv_flow/mgr/expr_parser.py +26 -1
- dv_flow/mgr/package.py +13 -6
- dv_flow/mgr/package_def.py +3 -4
- dv_flow/mgr/package_loader.py +252 -120
- dv_flow/mgr/param_def.py +7 -2
- dv_flow/mgr/param_ref_eval.py +3 -0
- dv_flow/mgr/parser.out +258 -138
- dv_flow/mgr/parsetab.py +20 -17
- dv_flow/mgr/std/flow.dv +31 -53
- dv_flow/mgr/std/incdirs.py +18 -0
- dv_flow/mgr/task.py +1 -0
- dv_flow/mgr/task_def.py +5 -1
- dv_flow/mgr/task_graph_builder.py +265 -24
- dv_flow/mgr/task_graph_dot_writer.py +32 -3
- dv_flow/mgr/task_listener_log.py +46 -31
- dv_flow/mgr/task_node.py +3 -0
- dv_flow/mgr/task_node_compound.py +1 -0
- dv_flow/mgr/task_node_ctor_wrapper.py +3 -1
- dv_flow/mgr/task_node_ctxt.py +7 -0
- dv_flow/mgr/task_node_leaf.py +77 -54
- dv_flow/mgr/task_run_ctxt.py +18 -0
- dv_flow/mgr/task_runner.py +8 -5
- dv_flow/mgr/type.py +33 -0
- dv_flow/mgr/type_def.py +4 -2
- dv_flow/mgr/util/util.py +9 -0
- dv_flow/mgr/yaml_srcinfo_loader.py +1 -0
- {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/METADATA +1 -1
- {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/RECORD +37 -35
- {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/WHEEL +1 -1
- {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/entry_points.txt +0 -0
- {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/licenses/LICENSE +0 -0
- {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/top_level.txt +0 -0
dv_flow/mgr/parsetab.py
CHANGED
@@ -6,9 +6,9 @@ _tabversion = '3.10'
|
|
6
6
|
|
7
7
|
_lr_method = 'LALR'
|
8
8
|
|
9
|
-
_lr_signature = 'leftPLUSMINUSPIPEleftTIMESDIVIDECOMMA DIVIDE ID LPAREN MINUS NUMBER PIPE PLUS RPAREN STRING1 STRING2 TIMESexpression : ID LPAREN RPAREN \n | ID LPAREN args RPARENargs : expression \n | args COMMA expressionexpression : expression PLUS expression\n | expression MINUS expression\n | expression TIMES expression\n | expression PIPE expression\n | expression DIVIDE expressionexpression : LPAREN expression RPARENexpression : NUMBERexpression : IDexpression : STRING1expression : STRING2'
|
9
|
+
_lr_signature = 'leftPLUSMINUSPIPEleftTIMESDIVIDECOMMA DIVIDE DOT ID LPAREN MINUS NUMBER PIPE PLUS RPAREN STRING1 STRING2 TIMESexpression : ID LPAREN RPAREN \n | ID LPAREN args RPARENargs : expression \n | args COMMA expressionexpression : expression PLUS expression\n | expression MINUS expression\n | expression TIMES expression\n | expression PIPE expression\n | expression DIVIDE expressionexpression : LPAREN expression RPARENexpression : NUMBERexpression : IDexpression : hier_idhier_id : ID DOT hier_id \n | IDexpression : STRING1expression : STRING2'
|
10
10
|
|
11
|
-
_lr_action_items = {'ID':([0,3,
|
11
|
+
_lr_action_items = {'ID':([0,3,8,9,10,11,12,13,14,28,],[2,2,2,2,2,2,2,2,24,2,]),'LPAREN':([0,2,3,8,9,10,11,12,13,28,],[3,13,3,3,3,3,3,3,3,3,]),'NUMBER':([0,3,8,9,10,11,12,13,28,],[4,4,4,4,4,4,4,4,4,]),'STRING1':([0,3,8,9,10,11,12,13,28,],[6,6,6,6,6,6,6,6,6,]),'STRING2':([0,3,8,9,10,11,12,13,28,],[7,7,7,7,7,7,7,7,7,]),'$end':([1,2,4,5,6,7,16,17,18,19,20,21,24,25,26,27,],[0,-12,-11,-13,-16,-17,-5,-6,-7,-8,-9,-1,-15,-14,-10,-2,]),'PLUS':([1,2,4,5,6,7,15,16,17,18,19,20,21,23,24,25,26,27,29,],[8,-12,-11,-13,-16,-17,8,-5,-6,-7,-8,-9,-1,8,-15,-14,-10,-2,8,]),'MINUS':([1,2,4,5,6,7,15,16,17,18,19,20,21,23,24,25,26,27,29,],[9,-12,-11,-13,-16,-17,9,-5,-6,-7,-8,-9,-1,9,-15,-14,-10,-2,9,]),'TIMES':([1,2,4,5,6,7,15,16,17,18,19,20,21,23,24,25,26,27,29,],[10,-12,-11,-13,-16,-17,10,10,10,-7,10,-9,-1,10,-15,-14,-10,-2,10,]),'PIPE':([1,2,4,5,6,7,15,16,17,18,19,20,21,23,24,25,26,27,29,],[11,-12,-11,-13,-16,-17,11,-5,-6,-7,-8,-9,-1,11,-15,-14,-10,-2,11,]),'DIVIDE':([1,2,4,5,6,7,15,16,17,18,19,20,21,23,24,25,26,27,29,],[12,-12,-11,-13,-16,-17,12,12,12,-7,12,-9,-1,12,-15,-14,-10,-2,12,]),'RPAREN':([2,4,5,6,7,13,15,16,17,18,19,20,21,22,23,24,25,26,27,29,],[-12,-11,-13,-16,-17,21,26,-5,-6,-7,-8,-9,-1,27,-3,-15,-14,-10,-2,-4,]),'COMMA':([2,4,5,6,7,16,17,18,19,20,21,22,23,24,25,26,27,29,],[-12,-11,-13,-16,-17,-5,-6,-7,-8,-9,-1,28,-3,-15,-14,-10,-2,-4,]),'DOT':([2,24,],[14,14,]),}
|
12
12
|
|
13
13
|
_lr_action = {}
|
14
14
|
for _k, _v in _lr_action_items.items():
|
@@ -17,7 +17,7 @@ for _k, _v in _lr_action_items.items():
|
|
17
17
|
_lr_action[_x][_k] = _y
|
18
18
|
del _lr_action_items
|
19
19
|
|
20
|
-
_lr_goto_items = {'expression':([0,3,
|
20
|
+
_lr_goto_items = {'expression':([0,3,8,9,10,11,12,13,28,],[1,15,16,17,18,19,20,23,29,]),'hier_id':([0,3,8,9,10,11,12,13,14,28,],[5,5,5,5,5,5,5,5,25,5,]),'args':([13,],[22,]),}
|
21
21
|
|
22
22
|
_lr_goto = {}
|
23
23
|
for _k, _v in _lr_goto_items.items():
|
@@ -27,18 +27,21 @@ for _k, _v in _lr_goto_items.items():
|
|
27
27
|
del _lr_goto_items
|
28
28
|
_lr_productions = [
|
29
29
|
("S' -> expression","S'",1,None,None,None),
|
30
|
-
('expression -> ID LPAREN RPAREN','expression',3,'p_call','expr_parser.py',
|
31
|
-
('expression -> ID LPAREN args RPAREN','expression',4,'p_call','expr_parser.py',
|
32
|
-
('args -> expression','args',1,'p_args','expr_parser.py',
|
33
|
-
('args -> args COMMA expression','args',3,'p_args','expr_parser.py',
|
34
|
-
('expression -> expression PLUS expression','expression',3,'p_expression_binop','expr_parser.py',
|
35
|
-
('expression -> expression MINUS expression','expression',3,'p_expression_binop','expr_parser.py',
|
36
|
-
('expression -> expression TIMES expression','expression',3,'p_expression_binop','expr_parser.py',
|
37
|
-
('expression -> expression PIPE expression','expression',3,'p_expression_binop','expr_parser.py',
|
38
|
-
('expression -> expression DIVIDE expression','expression',3,'p_expression_binop','expr_parser.py',
|
39
|
-
('expression -> LPAREN expression RPAREN','expression',3,'p_expression_group','expr_parser.py',
|
40
|
-
('expression -> NUMBER','expression',1,'p_expression_number','expr_parser.py',
|
41
|
-
('expression -> ID','expression',1,'p_expression_name','expr_parser.py',
|
42
|
-
('expression ->
|
43
|
-
('
|
30
|
+
('expression -> ID LPAREN RPAREN','expression',3,'p_call','expr_parser.py',208),
|
31
|
+
('expression -> ID LPAREN args RPAREN','expression',4,'p_call','expr_parser.py',209),
|
32
|
+
('args -> expression','args',1,'p_args','expr_parser.py',213),
|
33
|
+
('args -> args COMMA expression','args',3,'p_args','expr_parser.py',214),
|
34
|
+
('expression -> expression PLUS expression','expression',3,'p_expression_binop','expr_parser.py',222),
|
35
|
+
('expression -> expression MINUS expression','expression',3,'p_expression_binop','expr_parser.py',223),
|
36
|
+
('expression -> expression TIMES expression','expression',3,'p_expression_binop','expr_parser.py',224),
|
37
|
+
('expression -> expression PIPE expression','expression',3,'p_expression_binop','expr_parser.py',225),
|
38
|
+
('expression -> expression DIVIDE expression','expression',3,'p_expression_binop','expr_parser.py',226),
|
39
|
+
('expression -> LPAREN expression RPAREN','expression',3,'p_expression_group','expr_parser.py',237),
|
40
|
+
('expression -> NUMBER','expression',1,'p_expression_number','expr_parser.py',241),
|
41
|
+
('expression -> ID','expression',1,'p_expression_name','expr_parser.py',245),
|
42
|
+
('expression -> hier_id','expression',1,'p_expression_hid','expr_parser.py',249),
|
43
|
+
('hier_id -> ID DOT hier_id','hier_id',3,'p_hier_id','expr_parser.py',253),
|
44
|
+
('hier_id -> ID','hier_id',1,'p_hier_id','expr_parser.py',254),
|
45
|
+
('expression -> STRING1','expression',1,'p_expression_string1','expr_parser.py',259),
|
46
|
+
('expression -> STRING2','expression',1,'p_expression_string2','expr_parser.py',263),
|
44
47
|
]
|
dv_flow/mgr/std/flow.dv
CHANGED
@@ -82,6 +82,12 @@ package:
|
|
82
82
|
type: str
|
83
83
|
content:
|
84
84
|
type: str
|
85
|
+
- name: IncDirs
|
86
|
+
shell: pytask
|
87
|
+
run: dv_flow.mgr.std.incdirs.IncDirs
|
88
|
+
doc: |
|
89
|
+
Creates a list of include directories from a set of
|
90
|
+
input files.
|
85
91
|
- name: Exec
|
86
92
|
shell: pytask
|
87
93
|
run: dv_flow.mgr.std.exec.Exec
|
@@ -113,66 +119,38 @@ package:
|
|
113
119
|
types:
|
114
120
|
- name: DataItem
|
115
121
|
with:
|
116
|
-
|
117
|
-
|
122
|
+
type:
|
123
|
+
type: str
|
118
124
|
- name: FileSet
|
119
125
|
uses: std.DataItem
|
120
126
|
with:
|
121
|
-
|
122
|
-
type: str
|
123
|
-
value: "FileSet"
|
124
|
-
- name: basedir
|
125
|
-
type: str
|
126
|
-
- name: files
|
127
|
-
type: list
|
128
|
-
item:
|
127
|
+
filetype:
|
129
128
|
type: str
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# Name of the task that produced this item
|
146
|
-
# - name: id
|
147
|
-
# type: str
|
148
|
-
# kind: metadata
|
149
|
-
# doc: |
|
150
|
-
# Unique identiifer
|
129
|
+
value: ""
|
130
|
+
basedir:
|
131
|
+
type: str
|
132
|
+
files:
|
133
|
+
type:
|
134
|
+
list:
|
135
|
+
item: str
|
136
|
+
incdirs:
|
137
|
+
type:
|
138
|
+
list:
|
139
|
+
item: str
|
140
|
+
defines:
|
141
|
+
type:
|
142
|
+
list:
|
143
|
+
item: str
|
151
144
|
|
152
145
|
- name: Env
|
153
146
|
doc: |
|
154
147
|
Environment variables
|
155
148
|
with:
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
- name: base
|
164
|
-
type: str
|
165
|
-
- name: fileType
|
166
|
-
type: str
|
167
|
-
- name: files
|
168
|
-
type:
|
169
|
-
list:
|
170
|
-
item:
|
171
|
-
type: str
|
149
|
+
vals:
|
150
|
+
type:
|
151
|
+
map:
|
152
|
+
key:
|
153
|
+
type: str
|
154
|
+
val:
|
155
|
+
type: str
|
172
156
|
|
173
|
-
# type:
|
174
|
-
# list: (str,int)
|
175
|
-
# - complex type
|
176
|
-
# type:
|
177
|
-
# object:
|
178
|
-
#
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from dv_flow.mgr import TaskDataResult, TaskDataInput, TaskRunCtxt, FileSet
|
2
|
+
|
3
|
+
async def IncDirs(ctxt : TaskRunCtxt, input : TaskDataInput) -> TaskDataResult:
|
4
|
+
"""
|
5
|
+
IncDirs - create a list of include directories
|
6
|
+
"""
|
7
|
+
outputs = []
|
8
|
+
|
9
|
+
for inp in input.inputs:
|
10
|
+
if hasattr(inp, "basedir") and hasattr(inp, "filetype"):
|
11
|
+
outputs.append(FileSet(
|
12
|
+
filetype=inp.filetype,
|
13
|
+
basedir=inp.basedir,
|
14
|
+
incdirs=[inp.basedir]))
|
15
|
+
return TaskDataResult(
|
16
|
+
status=0,
|
17
|
+
changed=input.changed,
|
18
|
+
output=outputs)
|
dv_flow/mgr/task.py
CHANGED
@@ -23,6 +23,7 @@ class Task(object):
|
|
23
23
|
doc : str = ""
|
24
24
|
paramT : Any = None
|
25
25
|
uses : 'Task' = None
|
26
|
+
iff : str = None
|
26
27
|
needs : List[str] = dc.field(default_factory=list)
|
27
28
|
consumes : Union[ConsumesE, List[Dict[str, Any]]] = dc.field(default=None)
|
28
29
|
passthrough : Union[PassthroughE, List[Dict[str, Any]]] = dc.field(default=None)
|
dv_flow/mgr/task_def.py
CHANGED
@@ -103,6 +103,10 @@ class TaskDef(BaseModel):
|
|
103
103
|
body: List['TaskDef'] = dc.Field(
|
104
104
|
default_factory=list,
|
105
105
|
description="Sub-tasks")
|
106
|
+
iff : Union[str, bool, Any] = dc.Field(
|
107
|
+
default=None,
|
108
|
+
title="Task enable condition",
|
109
|
+
description="Condition that must be true for this task to run")
|
106
110
|
pytask : str = dc.Field(
|
107
111
|
default=None,
|
108
112
|
description="Python-based implementation (deprecated)")
|
@@ -125,7 +129,7 @@ class TaskDef(BaseModel):
|
|
125
129
|
needs : List[Union[str]] = dc.Field(
|
126
130
|
default_factory=list,
|
127
131
|
description="List of tasks that this task depends on")
|
128
|
-
params: Dict[str,Union[str,list,ParamDef]] = dc.Field(
|
132
|
+
params: Dict[str,Union[str,list,bool,ParamDef]] = dc.Field(
|
129
133
|
default_factory=dict,
|
130
134
|
alias="with",
|
131
135
|
description="Parameters for the task")
|
@@ -22,10 +22,12 @@
|
|
22
22
|
import os
|
23
23
|
import dataclasses as dc
|
24
24
|
import logging
|
25
|
+
import pydantic
|
25
26
|
from typing import Callable, Any, Dict, List, Union
|
26
27
|
from .package import Package
|
27
28
|
from .package_def import PackageDef, PackageSpec
|
28
29
|
from .package_loader import PackageLoader
|
30
|
+
from .param_ref_eval import ParamRefEval
|
29
31
|
from .ext_rgy import ExtRgy
|
30
32
|
from .task import Task
|
31
33
|
from .task_def import RundirE
|
@@ -38,7 +40,9 @@ from .task_node_ctor_proxy import TaskNodeCtorProxy
|
|
38
40
|
from .task_node_ctor_task import TaskNodeCtorTask
|
39
41
|
from .task_node_ctor_wrapper import TaskNodeCtorWrapper
|
40
42
|
from .task_node_compound import TaskNodeCompound
|
43
|
+
from .task_node_ctxt import TaskNodeCtxt
|
41
44
|
from .task_node_leaf import TaskNodeLeaf
|
45
|
+
from .type import Type
|
42
46
|
from .std.task_null import TaskNull
|
43
47
|
from .exec_callable import ExecCallable
|
44
48
|
from .null_callable import NullCallable
|
@@ -64,16 +68,21 @@ class TaskGraphBuilder(object):
|
|
64
68
|
loader : PackageLoader = None
|
65
69
|
marker_l : Callable = lambda *args, **kwargs: None
|
66
70
|
_pkg_m : Dict[PackageSpec,Package] = dc.field(default_factory=dict)
|
71
|
+
_pkg_params_m : Dict[str,Any] = dc.field(default_factory=dict)
|
67
72
|
_pkg_spec_s : List[PackageDef] = dc.field(default_factory=list)
|
68
73
|
_shell_m : Dict[str,Callable] = dc.field(default_factory=dict)
|
69
74
|
_task_m : Dict[str,Task] = dc.field(default_factory=dict)
|
75
|
+
_type_m : Dict[str,Type] = dc.field(default_factory=dict)
|
70
76
|
_task_node_m : Dict['TaskSpec',TaskNode] = dc.field(default_factory=dict)
|
77
|
+
_type_node_m : Dict[str,Any] = dc.field(default_factory=dict)
|
71
78
|
_task_ctor_m : Dict[Task,TaskNodeCtor] = dc.field(default_factory=dict)
|
72
79
|
_override_m : Dict[str,str] = dc.field(default_factory=dict)
|
73
80
|
_ns_scope_s : List[TaskNamespaceScope] = dc.field(default_factory=list)
|
74
81
|
_compound_task_ctxt_s : List[CompoundTaskCtxt] = dc.field(default_factory=list)
|
75
82
|
_task_rundir_s : List[List[str]] = dc.field(default_factory=list)
|
76
83
|
_task_node_s : List[TaskNode] = dc.field(default_factory=list)
|
84
|
+
_eval : ParamRefEval = dc.field(default_factory=ParamRefEval)
|
85
|
+
_ctxt : TaskNodeCtxt = None
|
77
86
|
_uses_count : int = 0
|
78
87
|
|
79
88
|
_log : logging.Logger = None
|
@@ -82,18 +91,63 @@ class TaskGraphBuilder(object):
|
|
82
91
|
# Initialize the overrides from the global registry
|
83
92
|
self._log = logging.getLogger(type(self).__name__)
|
84
93
|
self._shell_m.update(ExtRgy.inst()._shell_m)
|
85
|
-
self._task_rundir_s.append([])
|
94
|
+
self._task_rundir_s.append([self.rundir])
|
95
|
+
|
96
|
+
self._eval.set("env", os.environ)
|
97
|
+
|
98
|
+
|
86
99
|
|
87
100
|
if self.root_pkg is not None:
|
88
101
|
# Collect all the tasks
|
89
102
|
pkg_s = set()
|
103
|
+
|
104
|
+
self._ctxt = TaskNodeCtxt(
|
105
|
+
root_pkgdir=self.root_pkg.basedir,
|
106
|
+
root_rundir=self.rundir)
|
107
|
+
|
108
|
+
self._eval.set("root", {
|
109
|
+
"dir": self.root_pkg.basedir
|
110
|
+
})
|
111
|
+
|
112
|
+
params = self.root_pkg.paramT()
|
113
|
+
|
114
|
+
self._expandParams(params, self._eval)
|
115
|
+
|
116
|
+
for key in self.root_pkg.paramT.model_fields.keys():
|
117
|
+
self._eval.set(key, getattr(params, key))
|
118
|
+
|
119
|
+
self._pkg_params_m[self.root_pkg.name] = params
|
120
|
+
|
90
121
|
self._addPackageTasks(self.root_pkg, pkg_s)
|
122
|
+
else:
|
123
|
+
self._ctxt = TaskNodeCtxt(
|
124
|
+
root_pkgdir=None,
|
125
|
+
root_rundir=self.rundir)
|
126
|
+
|
127
|
+
|
128
|
+
def setParam(self, name, value):
|
129
|
+
if self.root_pkg is None:
|
130
|
+
raise Exception("No root package")
|
131
|
+
params = self._pkg_params_m[self.root_pkg.name]
|
132
|
+
|
133
|
+
if not hasattr(params, name):
|
134
|
+
raise Exception("Package %s does not have parameter %s" % (self.root_pkg.name, name))
|
135
|
+
setattr(params, name, value)
|
91
136
|
|
92
137
|
def _addPackageTasks(self, pkg, pkg_s):
|
138
|
+
|
139
|
+
# Build out the package parameters
|
140
|
+
params = pkg.paramT()
|
141
|
+
self._expandParams(params, self._eval)
|
142
|
+
self._pkg_params_m[pkg.name] = params
|
143
|
+
self._eval.set(pkg.name, params)
|
144
|
+
|
93
145
|
if pkg not in pkg_s:
|
94
146
|
pkg_s.add(pkg)
|
95
147
|
for task in pkg.task_m.values():
|
96
148
|
self._addTask(task)
|
149
|
+
for tt in pkg.type_m.values():
|
150
|
+
self._addType(tt)
|
97
151
|
for subpkg in pkg.pkg_m.values():
|
98
152
|
self._addPackageTasks(subpkg, pkg_s)
|
99
153
|
|
@@ -103,6 +157,10 @@ class TaskGraphBuilder(object):
|
|
103
157
|
for st in task.subtasks:
|
104
158
|
self._addTask(st)
|
105
159
|
|
160
|
+
def _addType(self, tt):
|
161
|
+
if tt.name not in self._type_m.keys():
|
162
|
+
self._type_m[tt.name] = tt
|
163
|
+
|
106
164
|
def addOverride(self, key : str, val : str):
|
107
165
|
self._override_m[key] = val
|
108
166
|
|
@@ -220,10 +278,14 @@ class TaskGraphBuilder(object):
|
|
220
278
|
else:
|
221
279
|
raise Exception("task_t (%s) not present" % str(task_t))
|
222
280
|
|
281
|
+
# TODO: need to obtain the package
|
282
|
+
|
283
|
+
|
223
284
|
ret = self._mkTaskNode(
|
224
285
|
task,
|
225
286
|
name=name,
|
226
|
-
srcdir=srcdir
|
287
|
+
srcdir=srcdir,
|
288
|
+
eval=self._eval)
|
227
289
|
|
228
290
|
if needs is not None:
|
229
291
|
for need in needs:
|
@@ -238,6 +300,73 @@ class TaskGraphBuilder(object):
|
|
238
300
|
self._log.debug("<-- mkTaskNode: %s (%d needs)" % (task_t, len(ret.needs)))
|
239
301
|
return ret
|
240
302
|
|
303
|
+
def mkDataItem(self, name, **kwargs):
|
304
|
+
self._log.debug("--> mkDataItem: %s" % name)
|
305
|
+
|
306
|
+
if name in self._type_m.keys():
|
307
|
+
tt = self._type_m[name]
|
308
|
+
else:
|
309
|
+
raise Exception("Type %s does not exist" % name)
|
310
|
+
|
311
|
+
if tt in self._type_node_m.keys():
|
312
|
+
tn = self._type_node_m[tt]
|
313
|
+
else:
|
314
|
+
# tn = self._mkDataItem(tt)
|
315
|
+
tn = tt.paramT
|
316
|
+
self._type_node_m[tt] = tn
|
317
|
+
|
318
|
+
ret = tn()
|
319
|
+
|
320
|
+
for k, v in kwargs.items():
|
321
|
+
if hasattr(ret, k):
|
322
|
+
setattr(ret, k, v)
|
323
|
+
else:
|
324
|
+
raise Exception("Data item %s parameters do not include %s" % (name, k))
|
325
|
+
|
326
|
+
self._log.debug("<-- mkDataItem: %s" % name)
|
327
|
+
return ret
|
328
|
+
|
329
|
+
def _findType(self, pkg, name):
|
330
|
+
tt = None
|
331
|
+
if name in pkg.type_m.keys():
|
332
|
+
tt = pkg.type_m[name]
|
333
|
+
else:
|
334
|
+
for subpkg in pkg.pkg_m.values():
|
335
|
+
tt = self._findType(subpkg, name)
|
336
|
+
if tt is not None:
|
337
|
+
break
|
338
|
+
return tt
|
339
|
+
|
340
|
+
def _mkDataItem(self, tt : Type):
|
341
|
+
field_m = {}
|
342
|
+
|
343
|
+
# Save the type name in each instance
|
344
|
+
field_m["type"] = (str, tt.name)
|
345
|
+
exclude_s = set()
|
346
|
+
exclude_s.add("type")
|
347
|
+
|
348
|
+
self._mkDataItemI(tt, field_m, exclude_s)
|
349
|
+
|
350
|
+
ret = pydantic.create_model(tt.name, **field_m)
|
351
|
+
|
352
|
+
return ret
|
353
|
+
|
354
|
+
def _mkDataItemI(self, tt : Type, field_m, exclude_s):
|
355
|
+
# First, identify cases where the value is set
|
356
|
+
for pt in tt.params.values():
|
357
|
+
if pt.name not in exclude_s:
|
358
|
+
if pt.type is not None:
|
359
|
+
# Defining a new attribute
|
360
|
+
field_m[pt.name] = (str, pt.value)
|
361
|
+
else:
|
362
|
+
# TODO: determine whether
|
363
|
+
field_m[pt.name] = (str, None)
|
364
|
+
if tt.uses is not None:
|
365
|
+
self._mkDataItemI(tt.uses, field_m, exclude_s)
|
366
|
+
|
367
|
+
def _applyParameterOverrides(self, obj, **kwargs):
|
368
|
+
pass
|
369
|
+
|
241
370
|
def _findTask(self, pkg, name):
|
242
371
|
task = None
|
243
372
|
if name in pkg.task_m.keys():
|
@@ -249,26 +378,69 @@ class TaskGraphBuilder(object):
|
|
249
378
|
break
|
250
379
|
return task
|
251
380
|
|
252
|
-
def _mkTaskNode(self,
|
381
|
+
def _mkTaskNode(self,
|
382
|
+
task : Task,
|
383
|
+
name=None,
|
384
|
+
srcdir=None,
|
385
|
+
params=None,
|
386
|
+
hierarchical=False,
|
387
|
+
eval=None):
|
253
388
|
|
254
389
|
if not hierarchical:
|
255
|
-
self._task_rundir_s.append([])
|
390
|
+
self._task_rundir_s.append([self.rundir])
|
391
|
+
|
392
|
+
# If the task has an enable condition, evaluate
|
393
|
+
# that now
|
394
|
+
iff = True
|
395
|
+
if task.iff is not None:
|
396
|
+
self._log.debug("Evaluate iff condition \"%s\"" % task.iff)
|
397
|
+
iff = self._expandParam(task.iff, eval)
|
398
|
+
|
399
|
+
if iff:
|
400
|
+
self._log.debug("Condition \"%s\" is true" % task.iff)
|
401
|
+
else:
|
402
|
+
self._log.debug("Condition \"%s\" is false" % task.iff)
|
256
403
|
|
257
404
|
# Determine how to build this node
|
258
|
-
if
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
405
|
+
if iff:
|
406
|
+
if self._isCompound(task):
|
407
|
+
ret = self._mkTaskCompoundNode(
|
408
|
+
task,
|
409
|
+
name=name,
|
410
|
+
srcdir=srcdir,
|
411
|
+
params=params,
|
412
|
+
hierarchical=hierarchical,
|
413
|
+
eval=eval)
|
414
|
+
else:
|
415
|
+
ret = self._mkTaskLeafNode(
|
416
|
+
task,
|
417
|
+
name=name,
|
418
|
+
srcdir=srcdir,
|
419
|
+
params=params,
|
420
|
+
hierarchical=hierarchical,
|
421
|
+
eval=eval)
|
265
422
|
else:
|
266
|
-
|
267
|
-
task
|
423
|
+
if name is None:
|
424
|
+
name = task.name
|
425
|
+
|
426
|
+
if params is None:
|
427
|
+
params = task.paramT()
|
428
|
+
|
429
|
+
if srcdir is None:
|
430
|
+
srcdir = os.path.dirname(task.srcinfo.file)
|
431
|
+
|
432
|
+
# Create a null task
|
433
|
+
ret = TaskNodeLeaf(
|
268
434
|
name=name,
|
269
435
|
srcdir=srcdir,
|
270
436
|
params=params,
|
271
|
-
|
437
|
+
passthrough=task.passthrough,
|
438
|
+
consumes=task.consumes,
|
439
|
+
task=NullCallable(task.run),
|
440
|
+
ctxt=None,
|
441
|
+
iff=False)
|
442
|
+
self._task_node_m[name] = ret
|
443
|
+
|
272
444
|
|
273
445
|
if not hierarchical:
|
274
446
|
self._task_rundir_s.pop()
|
@@ -287,7 +459,12 @@ class TaskGraphBuilder(object):
|
|
287
459
|
else:
|
288
460
|
return self.mkTaskNode(name)
|
289
461
|
|
290
|
-
def _mkTaskLeafNode(self,
|
462
|
+
def _mkTaskLeafNode(self,
|
463
|
+
task : Task, name=None,
|
464
|
+
srcdir=None,
|
465
|
+
params=None,
|
466
|
+
hierarchical=False,
|
467
|
+
eval=None) -> TaskNode:
|
291
468
|
self._log.debug("--> _mkTaskLeafNode %s" % task.name)
|
292
469
|
|
293
470
|
if name is None:
|
@@ -299,9 +476,26 @@ class TaskGraphBuilder(object):
|
|
299
476
|
if params is None:
|
300
477
|
params = task.paramT()
|
301
478
|
|
479
|
+
eval.set("rundir", "/".join([str(e) for e in self.get_rundir()]))
|
480
|
+
|
481
|
+
# self._log.debug("in_params[2]: %s" % ",".join(p.src for p in in_params))
|
482
|
+
# eval.setVar("in", in_params)
|
483
|
+
# eval.setVar("rundir", rundir)
|
484
|
+
|
485
|
+
# Set variables from the inputs
|
486
|
+
# for need in self.needs:
|
487
|
+
# for name,value in {"rundir" : need[0].rundir}.items():
|
488
|
+
# eval.setVar("%s.%s" % (need[0].name, name), value)
|
489
|
+
|
490
|
+
# expand any variable references
|
491
|
+
self._expandParams(params, eval)
|
492
|
+
|
493
|
+
|
302
494
|
if task.rundir == RundirE.Unique:
|
303
495
|
self.enter_rundir(name)
|
304
496
|
|
497
|
+
# TODO: handle callable in light of overrides
|
498
|
+
|
305
499
|
|
306
500
|
callable = None
|
307
501
|
if task.run is not None:
|
@@ -318,6 +512,7 @@ class TaskGraphBuilder(object):
|
|
318
512
|
name=name,
|
319
513
|
srcdir=srcdir,
|
320
514
|
params=params,
|
515
|
+
ctxt=self._ctxt,
|
321
516
|
passthrough=task.passthrough,
|
322
517
|
consumes=task.consumes,
|
323
518
|
task=callable(task.run))
|
@@ -338,7 +533,13 @@ class TaskGraphBuilder(object):
|
|
338
533
|
self._log.debug("<-- _mkTaskLeafNode %s" % task.name)
|
339
534
|
return node
|
340
535
|
|
341
|
-
def _mkTaskCompoundNode(self,
|
536
|
+
def _mkTaskCompoundNode(self,
|
537
|
+
task : Task,
|
538
|
+
name=None,
|
539
|
+
srcdir=None,
|
540
|
+
params=None,
|
541
|
+
hierarchical=False,
|
542
|
+
eval=None) -> TaskNode:
|
342
543
|
self._log.debug("--> _mkTaskCompoundNode %s" % task.name)
|
343
544
|
|
344
545
|
if name is None:
|
@@ -350,28 +551,41 @@ class TaskGraphBuilder(object):
|
|
350
551
|
if params is None:
|
351
552
|
params = task.paramT()
|
352
553
|
|
554
|
+
# expand any variable references
|
555
|
+
self._expandParams(params, eval)
|
556
|
+
|
353
557
|
if task.rundir == RundirE.Unique:
|
354
558
|
self.enter_rundir(name)
|
355
559
|
|
356
560
|
if task.uses is not None:
|
357
561
|
# This is a compound task that is based on
|
358
562
|
# another. Create the base implementation
|
563
|
+
task_uses = task.uses
|
564
|
+
|
565
|
+
if not self.in_uses():
|
566
|
+
# Determine whether this task is overridden
|
567
|
+
task_uses = self._findOverride(task_uses)
|
568
|
+
|
569
|
+
self.enter_uses()
|
359
570
|
node = self._mkTaskNode(
|
360
|
-
|
571
|
+
task_uses,
|
361
572
|
name=name,
|
362
573
|
srcdir=srcdir,
|
363
574
|
params=params,
|
364
|
-
hierarchical=True
|
575
|
+
hierarchical=True,
|
576
|
+
eval=eval)
|
577
|
+
self.leave_uses()
|
365
578
|
|
366
579
|
if not isinstance(node, TaskNodeCompound):
|
367
580
|
# TODO: need to enclose the leaf node in a compound wrapper
|
368
|
-
raise Exception("Task %s is not compound" %
|
581
|
+
raise Exception("Task %s is not compound" % task_uses)
|
369
582
|
else:
|
370
583
|
# Node represents the terminal node of the sub-DAG
|
371
584
|
node = TaskNodeCompound(
|
372
585
|
name=name,
|
373
586
|
srcdir=srcdir,
|
374
|
-
params=params
|
587
|
+
params=params,
|
588
|
+
ctxt=self._ctxt)
|
375
589
|
|
376
590
|
if len(self._task_node_s):
|
377
591
|
node.parent = self._task_node_s[-1]
|
@@ -391,9 +605,11 @@ class TaskGraphBuilder(object):
|
|
391
605
|
need_n = self._getTaskNode(need.name)
|
392
606
|
if need_n is None:
|
393
607
|
raise Exception("Failed to find need %s" % need.name)
|
394
|
-
|
395
|
-
|
396
|
-
|
608
|
+
elif need_n.iff:
|
609
|
+
self._log.debug("Add need %s with %d dependencies" % (need_n.name, len(need_n.needs)))
|
610
|
+
node.input.needs.append((need_n, False))
|
611
|
+
else:
|
612
|
+
self._log.debug("Needed node %s is not enabled" % need_n.name)
|
397
613
|
self._log.debug("<-- processing needs")
|
398
614
|
|
399
615
|
# TODO: handle strategy
|
@@ -402,7 +618,7 @@ class TaskGraphBuilder(object):
|
|
402
618
|
# For now, build out local tasks and link up the needs
|
403
619
|
tasks = []
|
404
620
|
for t in task.subtasks:
|
405
|
-
nn = self._mkTaskNode(t, hierarchical=True)
|
621
|
+
nn = self._mkTaskNode(t, hierarchical=True, eval=eval)
|
406
622
|
node.tasks.append(nn)
|
407
623
|
# tasks.append((t, self._getTaskNode(t.name)))
|
408
624
|
tasks.append((t, nn))
|
@@ -455,6 +671,28 @@ class TaskGraphBuilder(object):
|
|
455
671
|
|
456
672
|
return node
|
457
673
|
|
674
|
+
def _expandParams(self, params, eval):
|
675
|
+
for name in type(params).model_fields.keys():
|
676
|
+
value = getattr(params, name)
|
677
|
+
new_val = self._expandParam(value, eval)
|
678
|
+
setattr(params, name, new_val)
|
679
|
+
|
680
|
+
def _expandParam(self, value, eval):
|
681
|
+
new_val = value
|
682
|
+
if type(value) == str:
|
683
|
+
if value.find("${{") != -1:
|
684
|
+
print("Expr: %s" % str(value), flush=True)
|
685
|
+
new_val = eval.eval(value)
|
686
|
+
self._log.debug("Param: Evaluate expression \"%s\" => \"%s\"" % (value, new_val))
|
687
|
+
elif isinstance(value, list):
|
688
|
+
new_val = []
|
689
|
+
for i,elem in enumerate(value):
|
690
|
+
if elem.find("${{") != -1:
|
691
|
+
new_val.append(eval.eval(elem))
|
692
|
+
else:
|
693
|
+
new_val.append(elem)
|
694
|
+
return new_val
|
695
|
+
|
458
696
|
def _gatherNeeds(self, task_t, node):
|
459
697
|
self._log.debug("--> _gatherNeeds %s (%d)" % (task_t.name, len(task_t.needs)))
|
460
698
|
if task_t.uses is not None:
|
@@ -477,3 +715,6 @@ class TaskGraphBuilder(object):
|
|
477
715
|
def marker(self, marker):
|
478
716
|
self.marker_l(marker)
|
479
717
|
|
718
|
+
def _findOverride(self, task):
|
719
|
+
return task
|
720
|
+
|