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.
Files changed (37) hide show
  1. dv_flow/mgr/__init__.py +4 -0
  2. dv_flow/mgr/cmds/cmd_run.py +6 -1
  3. dv_flow/mgr/cmds/cmd_show.py +3 -3
  4. dv_flow/mgr/config_def.py +1 -1
  5. dv_flow/mgr/expr_eval.py +24 -1
  6. dv_flow/mgr/expr_parser.py +26 -1
  7. dv_flow/mgr/package.py +13 -6
  8. dv_flow/mgr/package_def.py +3 -4
  9. dv_flow/mgr/package_loader.py +252 -120
  10. dv_flow/mgr/param_def.py +7 -2
  11. dv_flow/mgr/param_ref_eval.py +3 -0
  12. dv_flow/mgr/parser.out +258 -138
  13. dv_flow/mgr/parsetab.py +20 -17
  14. dv_flow/mgr/std/flow.dv +31 -53
  15. dv_flow/mgr/std/incdirs.py +18 -0
  16. dv_flow/mgr/task.py +1 -0
  17. dv_flow/mgr/task_def.py +5 -1
  18. dv_flow/mgr/task_graph_builder.py +265 -24
  19. dv_flow/mgr/task_graph_dot_writer.py +32 -3
  20. dv_flow/mgr/task_listener_log.py +46 -31
  21. dv_flow/mgr/task_node.py +3 -0
  22. dv_flow/mgr/task_node_compound.py +1 -0
  23. dv_flow/mgr/task_node_ctor_wrapper.py +3 -1
  24. dv_flow/mgr/task_node_ctxt.py +7 -0
  25. dv_flow/mgr/task_node_leaf.py +77 -54
  26. dv_flow/mgr/task_run_ctxt.py +18 -0
  27. dv_flow/mgr/task_runner.py +8 -5
  28. dv_flow/mgr/type.py +33 -0
  29. dv_flow/mgr/type_def.py +4 -2
  30. dv_flow/mgr/util/util.py +9 -0
  31. dv_flow/mgr/yaml_srcinfo_loader.py +1 -0
  32. {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/METADATA +1 -1
  33. {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/RECORD +37 -35
  34. {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/WHEEL +1 -1
  35. {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/entry_points.txt +0 -0
  36. {dv_flow_mgr-1.0.0.14528489065a1.dist-info → dv_flow_mgr-1.5.0.dist-info}/licenses/LICENSE +0 -0
  37. {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,7,8,9,10,11,12,24,],[2,2,2,2,2,2,2,2,2,]),'LPAREN':([0,2,3,7,8,9,10,11,12,24,],[3,12,3,3,3,3,3,3,3,3,]),'NUMBER':([0,3,7,8,9,10,11,12,24,],[4,4,4,4,4,4,4,4,4,]),'STRING1':([0,3,7,8,9,10,11,12,24,],[5,5,5,5,5,5,5,5,5,]),'STRING2':([0,3,7,8,9,10,11,12,24,],[6,6,6,6,6,6,6,6,6,]),'$end':([1,2,4,5,6,14,15,16,17,18,19,22,23,],[0,-12,-11,-13,-14,-5,-6,-7,-8,-9,-1,-10,-2,]),'PLUS':([1,2,4,5,6,13,14,15,16,17,18,19,21,22,23,25,],[7,-12,-11,-13,-14,7,-5,-6,-7,-8,-9,-1,7,-10,-2,7,]),'MINUS':([1,2,4,5,6,13,14,15,16,17,18,19,21,22,23,25,],[8,-12,-11,-13,-14,8,-5,-6,-7,-8,-9,-1,8,-10,-2,8,]),'TIMES':([1,2,4,5,6,13,14,15,16,17,18,19,21,22,23,25,],[9,-12,-11,-13,-14,9,9,9,-7,9,-9,-1,9,-10,-2,9,]),'PIPE':([1,2,4,5,6,13,14,15,16,17,18,19,21,22,23,25,],[10,-12,-11,-13,-14,10,-5,-6,-7,-8,-9,-1,10,-10,-2,10,]),'DIVIDE':([1,2,4,5,6,13,14,15,16,17,18,19,21,22,23,25,],[11,-12,-11,-13,-14,11,11,11,-7,11,-9,-1,11,-10,-2,11,]),'RPAREN':([2,4,5,6,12,13,14,15,16,17,18,19,20,21,22,23,25,],[-12,-11,-13,-14,19,22,-5,-6,-7,-8,-9,-1,23,-3,-10,-2,-4,]),'COMMA':([2,4,5,6,14,15,16,17,18,19,20,21,22,23,25,],[-12,-11,-13,-14,-5,-6,-7,-8,-9,-1,24,-3,-10,-2,-4,]),}
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,7,8,9,10,11,12,24,],[1,13,14,15,16,17,18,21,25,]),'args':([12,],[20,]),}
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',180),
31
- ('expression -> ID LPAREN args RPAREN','expression',4,'p_call','expr_parser.py',181),
32
- ('args -> expression','args',1,'p_args','expr_parser.py',185),
33
- ('args -> args COMMA expression','args',3,'p_args','expr_parser.py',186),
34
- ('expression -> expression PLUS expression','expression',3,'p_expression_binop','expr_parser.py',194),
35
- ('expression -> expression MINUS expression','expression',3,'p_expression_binop','expr_parser.py',195),
36
- ('expression -> expression TIMES expression','expression',3,'p_expression_binop','expr_parser.py',196),
37
- ('expression -> expression PIPE expression','expression',3,'p_expression_binop','expr_parser.py',197),
38
- ('expression -> expression DIVIDE expression','expression',3,'p_expression_binop','expr_parser.py',198),
39
- ('expression -> LPAREN expression RPAREN','expression',3,'p_expression_group','expr_parser.py',209),
40
- ('expression -> NUMBER','expression',1,'p_expression_number','expr_parser.py',213),
41
- ('expression -> ID','expression',1,'p_expression_name','expr_parser.py',217),
42
- ('expression -> STRING1','expression',1,'p_expression_string1','expr_parser.py',221),
43
- ('expression -> STRING2','expression',1,'p_expression_string2','expr_parser.py',225),
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
- - name: type
117
- type: str
122
+ type:
123
+ type: str
118
124
  - name: FileSet
119
125
  uses: std.DataItem
120
126
  with:
121
- - name: filetype
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
- # - name: TaskDataItem
132
- # doc: |
133
- # Base type for a data element produced by a task.
134
- # TaskDataItem is never used directly
135
- # with:
136
- # - name: kind
137
- # type: str
138
- # kind: metadata
139
- # doc: |
140
- # Kind of data item
141
- # - name: src
142
- # type: str
143
- # kind: metadata
144
- # doc: |
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
- - name: doc
157
-
158
- - name: FileSet
159
- uses: TaskDataItem
160
- with:
161
- - name: kind
162
- value: "FileSet"
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, task : Task, name=None, srcdir=None, params=None, hierarchical=False):
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 self._isCompound(task):
259
- ret = self._mkTaskCompoundNode(
260
- task,
261
- name=name,
262
- srcdir=srcdir,
263
- params=params,
264
- hierarchical=hierarchical)
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
- ret = self._mkTaskLeafNode(
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
- hierarchical=hierarchical)
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, task : Task, name=None, srcdir=None, params=None, hierarchical=False) -> TaskNode:
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, task : Task, name=None, srcdir=None, params=None, hierarchical=False) -> TaskNode:
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
- task.uses,
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" % task.uses)
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
- self._log.debug("Add need %s with %d dependencies" % (need_n.name, len(need_n.needs)))
395
- node.input.needs.append((need_n, False))
396
- # node.needs.append((need_n, False))
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
+