dv-flow-mgr 1.0.0.14370893826a1__py3-none-any.whl → 1.0.0.14392445998a1__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.
@@ -605,7 +605,7 @@ class PackageLoader(object):
605
605
  rundir = base_t.rundir
606
606
 
607
607
  if passthrough is None:
608
- passthrough = PassthroughE.No
608
+ passthrough = PassthroughE.Unused
609
609
  if consumes is None:
610
610
  consumes = ConsumesE.All
611
611
 
@@ -71,6 +71,7 @@ class TaskGraphBuilder(object):
71
71
  _ns_scope_s : List[TaskNamespaceScope] = dc.field(default_factory=list)
72
72
  _compound_task_ctxt_s : List[CompoundTaskCtxt] = dc.field(default_factory=list)
73
73
  _task_rundir_s : List[List[str]] = dc.field(default_factory=list)
74
+ _task_node_s : List[TaskNode] = dc.field(default_factory=list)
74
75
  _uses_count : int = 0
75
76
 
76
77
  _log : logging.Logger = None
@@ -203,51 +204,7 @@ class TaskGraphBuilder(object):
203
204
 
204
205
  def mkTaskGraph(self, task : str, rundir=None) -> TaskNode:
205
206
  return self.mkTaskNode(task, rundir=rundir)
206
- # self._task_node_m.clear()
207
-
208
- # if rundir is not None:
209
- # self._rundir_s.append(rundir)
210
-
211
- # ret = self._mkTaskGraph(task)
212
-
213
- # if rundir is not None:
214
- # self._rundir_s.pop()
215
-
216
- # return ret
217
-
218
- def _mkTaskGraph(self, task : str) -> TaskNode:
219
- if task in self.root_pkg.task_m.keys():
220
- task_t = self.root_pkg.task_m[task]
221
- else:
222
- pass
223
-
224
- if task_t is None:
225
- raise Exception("Failed to find task %s" % task)
226
-
227
- ctor = self._getTaskCtor(task_t)
228
-
229
- params = ctor.mkTaskParams()
230
-
231
- needs = []
232
-
233
- for need in task_t.needs:
234
- need_n = self.findTask(need.name)
235
- if need_n is None:
236
- raise Exception("Failed to find need %s" % need.name)
237
- needs.append(need_n)
238
-
239
- task = ctor.mkTaskNode(
240
- builder=self,
241
- params=params,
242
- name=task,
243
- needs=needs)
244
- task.rundir = self.get_rundir(task.name)
245
- # task.rundir = rundir
246
207
 
247
- self._task_node_m[task.name] = task
248
-
249
- return task
250
-
251
208
  def mkTaskNode(self, task_t, name=None, srcdir=None, needs=None, **kwargs):
252
209
  self._log.debug("--> mkTaskNode: %s" % task_t)
253
210
 
@@ -282,37 +239,59 @@ class TaskGraphBuilder(object):
282
239
  break
283
240
  return task
284
241
 
285
- def _mkTaskNode(self, task : Task, hierarchical=False):
242
+ def _mkTaskNode(self, task : Task, name=None, srcdir=None, params=None, hierarchical=False):
286
243
 
287
244
  if not hierarchical:
288
245
  self._task_rundir_s.append([])
289
246
 
290
247
  # Determine how to build this node
291
- if task.subtasks is not None and len(task.subtasks):
292
- ret = self._mkTaskCompoundNode(task)
248
+ if self._isCompound(task):
249
+ ret = self._mkTaskCompoundNode(
250
+ task,
251
+ name=name,
252
+ srcdir=srcdir,
253
+ params=params,
254
+ hierarchical=hierarchical)
293
255
  else:
294
- ret = self._mkTaskLeafNode(task)
256
+ ret = self._mkTaskLeafNode(
257
+ task,
258
+ name=name,
259
+ srcdir=srcdir,
260
+ params=params,
261
+ hierarchical=hierarchical)
295
262
 
296
263
  if not hierarchical:
297
264
  self._task_rundir_s.pop()
298
265
 
299
266
  return ret
300
267
 
268
+ def _isCompound(self, task):
269
+ if task.subtasks is not None and len(task.subtasks):
270
+ return True
271
+ elif task.uses is not None:
272
+ return self._isCompound(task.uses)
273
+
301
274
  def _getTaskNode(self, name):
302
275
  if name in self._task_node_m.keys():
303
276
  return self._task_node_m[name]
304
277
  else:
305
278
  return self.mkTaskNode(name)
306
279
 
307
- def _mkTaskLeafNode(self, task : Task, name=None) -> TaskNode:
280
+ def _mkTaskLeafNode(self, task : Task, name=None, srcdir=None, params=None, hierarchical=False) -> TaskNode:
308
281
  self._log.debug("--> _mkTaskLeafNode %s" % task.name)
309
- srcdir = os.path.dirname(task.srcinfo.file)
282
+
283
+ if name is None:
284
+ name = task.name
285
+
286
+ if srcdir is None:
287
+ srcdir = os.path.dirname(task.srcinfo.file)
288
+
289
+ if params is None:
290
+ params = task.paramT()
310
291
 
311
292
  if task.rundir == RundirE.Unique:
312
293
  self.enter_rundir(task.name)
313
294
 
314
- if name is None:
315
- name = task.name
316
295
 
317
296
  callable = None
318
297
  if task.run is not None:
@@ -328,19 +307,19 @@ class TaskGraphBuilder(object):
328
307
  node = TaskNodeLeaf(
329
308
  name=name,
330
309
  srcdir=srcdir,
331
- params=task.paramT(),
310
+ params=params,
332
311
  passthrough=task.passthrough,
333
312
  consumes=task.consumes,
334
313
  task=callable(task.run))
335
314
  self._task_node_m[name] = node
336
315
  node.rundir = self.get_rundir()
337
316
 
317
+ if len(self._task_node_s):
318
+ node.parent = self._task_node_s[-1]
319
+
338
320
  # Now, link up the needs
339
321
  self._log.debug("--> processing needs")
340
- for n in task.needs:
341
- self._log.debug("-- need %s" % n.name)
342
- nn = self._getTaskNode(n.name)
343
- node.needs.append((nn, False))
322
+ self._gatherNeeds(task, node)
344
323
  self._log.debug("<-- processing needs")
345
324
 
346
325
  if task.rundir == RundirE.Unique:
@@ -349,23 +328,46 @@ class TaskGraphBuilder(object):
349
328
  self._log.debug("<-- _mkTaskLeafNode %s" % task.name)
350
329
  return node
351
330
 
352
- def _mkTaskCompoundNode(self, task : Task, name=None) -> TaskNode:
331
+ def _mkTaskCompoundNode(self, task : Task, name=None, srcdir=None, params=None, hierarchical=False) -> TaskNode:
353
332
  self._log.debug("--> _mkTaskCompoundNode %s" % task.name)
354
- srcdir = os.path.dirname(task.srcinfo.file)
355
333
 
356
334
  if name is None:
357
335
  name = task.name
358
336
 
337
+ if srcdir is None:
338
+ srcdir = os.path.dirname(task.srcinfo.file)
339
+
340
+ if params is None:
341
+ params = task.paramT()
342
+
359
343
  if task.rundir == RundirE.Unique:
360
344
  self.enter_rundir(task.name)
361
345
 
362
- # Node represents the terminal node of the sub-DAG
363
- node = TaskNodeCompound(
364
- name=name,
365
- srcdir=srcdir,
366
- params=task.paramT()
367
- )
346
+ if task.uses is not None:
347
+ # This is a compound task that is based on
348
+ # another. Create the base implementation
349
+ node = self._mkTaskNode(
350
+ task.uses,
351
+ name=name,
352
+ srcdir=srcdir,
353
+ params=params,
354
+ hierarchical=True)
355
+
356
+ if not isinstance(node, TaskNodeCompound):
357
+ # TODO: need to enclose the leaf node in a compound wrapper
358
+ raise Exception("Task %s is not compound" % task.uses)
359
+ else:
360
+ # Node represents the terminal node of the sub-DAG
361
+ node = TaskNodeCompound(
362
+ name=name,
363
+ srcdir=srcdir,
364
+ params=params)
365
+
366
+ if len(self._task_node_s):
367
+ node.parent = self._task_node_s[-1]
368
+
368
369
  self._task_node_m[name] = node
370
+ self._task_node_s.append(node)
369
371
 
370
372
  node.rundir = self.get_rundir()
371
373
 
@@ -374,11 +376,13 @@ class TaskGraphBuilder(object):
374
376
  node.input.rundir = self.get_rundir()
375
377
  self.leave_rundir()
376
378
 
377
- self._log.debug("--> processing needs")
379
+ self._log.debug("--> processing needs (%s)" % task.name)
378
380
  for need in task.needs:
379
- self._log.debug("-- need: %s" % need.name)
380
- nn = self._getTaskNode(need.name)
381
- node.input.needs.append((nn, False))
381
+ need_n = self._getTaskNode(need.name)
382
+ self._log.debug("Add need %s" % need_n.name)
383
+ if need_n is None:
384
+ raise Exception("Failed to find need %s" % need.name)
385
+ node.input.needs.append((need_n, False))
382
386
  self._log.debug("<-- processing needs")
383
387
 
384
388
  # TODO: handle strategy
@@ -387,11 +391,17 @@ class TaskGraphBuilder(object):
387
391
  # For now, build out local tasks and link up the needs
388
392
  tasks = []
389
393
  for t in task.subtasks:
390
- nn = self._mkTaskNode(t, True)
391
- tasks.append((t, self._getTaskNode(t.name)))
394
+ nn = self._mkTaskNode(t, hierarchical=True)
395
+ node.tasks.append(nn)
396
+ # tasks.append((t, self._getTaskNode(t.name)))
397
+ tasks.append((t, nn))
398
+
399
+ # Pop the node stack, since we're done constructing the body
400
+ self._task_node_s.pop()
392
401
 
393
402
  # Fill in 'needs'
394
403
  for t, tn in tasks:
404
+ self._log.debug("Process node %s" % t.name)
395
405
 
396
406
  referenced = None
397
407
  for tt in task.subtasks:
@@ -400,7 +410,9 @@ class TaskGraphBuilder(object):
400
410
  break
401
411
 
402
412
  refs_internal = None
403
- for nn,_ in tn.needs:
413
+ # Assess how this task is connected to others in the compound node
414
+ for nn,_ in tn.first.needs:
415
+ self._log.debug("Need: %s" % nn.name)
404
416
  for _,tnn in tasks:
405
417
  if nn == tnn:
406
418
  refs_internal = tnn
@@ -414,7 +426,7 @@ class TaskGraphBuilder(object):
414
426
  self._log.debug("Node %s doesn't reference any internal node" % t.name)
415
427
  tn.needs.append((node.input, False))
416
428
  else:
417
- self._log.debug("Node references internal node %s" % refs_internal.name)
429
+ self._log.debug("Node %s references internal node %s" % (t.name, refs_internal.name))
418
430
 
419
431
  if referenced is not None:
420
432
  # Add this task as a dependency of the output
@@ -429,35 +441,18 @@ class TaskGraphBuilder(object):
429
441
 
430
442
  return node
431
443
 
444
+ def _gatherNeeds(self, task_t, node):
445
+ self._log.debug("--> _gatherNeeds %s" % task_t.name)
446
+ if task_t.uses is not None:
447
+ self._gatherNeeds(task_t.uses, node)
448
+
449
+ for need in task_t.needs:
450
+ need_n = self._getTaskNode(need.name)
451
+ if need_n is None:
452
+ raise Exception("Failed to find need %s" % need.name)
453
+ node.needs.append((need_n, False))
454
+ self._log.debug("<-- _gatherNeeds %s" % task_t.name)
432
455
 
433
- def getTaskCtor(self, spec : Union[str,'TaskSpec'], pkg : PackageDef = None) -> 'TaskNodeCtor':
434
- from .task_def import TaskSpec
435
- if type(spec) == str:
436
- spec = TaskSpec(spec)
437
-
438
- self._log.debug("--> getTaskCtor %s" % spec.name)
439
- spec_e = spec.name.split(".")
440
- task_name = spec_e[-1]
441
-
442
- # if len(spec_e) == 1:
443
- # # Just have a task name. Use the current package
444
- # if len(self._pkg_s) == 0:
445
- # raise Exception("No package context for task %s" % spec.name)
446
- # pkg = self._pkg_s[-1]
447
- # else:
448
- # pkg_name = ".".join(spec_e[0:-1])
449
-
450
- # try:
451
- # pkg = self.getPackage(PackageSpec(pkg_name))
452
- # except Exception as e:
453
- # self._log.critical("Failed to find package %s while looking for task %s" % (pkg_name, spec.name))
454
- # raise e
455
-
456
- ctor = pkg.getTaskCtor(task_name)
457
-
458
- self._log.debug("<-- getTaskCtor %s" % spec.name)
459
- return ctor
460
-
461
456
  def error(self, msg, loc=None):
462
457
  if loc is not None:
463
458
  marker = TaskMarker(msg=msg, severity=SeverityE.Error, loc=loc)
@@ -468,217 +463,3 @@ class TaskGraphBuilder(object):
468
463
  def marker(self, marker):
469
464
  self.marker_l(marker)
470
465
 
471
- def _getTaskCtor(self, task : Task) -> TaskNodeCtor:
472
- if task in self._task_ctor_m.keys():
473
- ctor = self._task_ctor_m[task]
474
- else:
475
- ctor = self._mkTaskCtor(task)
476
- self._task_ctor_m[task] = ctor
477
- return ctor
478
-
479
- def _mkTaskCtor(self, task):
480
- srcdir = os.path.dirname(task.srcinfo.file)
481
- self._log.debug("--> mkTaskCtor %s (srcdir: %s)" % (task.name, srcdir))
482
-
483
- if len(task.subtasks) > 0:
484
- self._log.debug("Task has a body")
485
- # Compound task
486
- self._log.debug("Task specifies sub-task implementation")
487
- ctor = self._mkCompoundTaskCtor(task)
488
- else:
489
- self._log.debug("Task doesn't specify a body")
490
- # Shell task or 'null'
491
- ctor = self._mkLeafTaskCtor(task)
492
-
493
- if ctor is None:
494
- raise Exception()
495
-
496
- return ctor
497
-
498
- def _mkLeafTaskCtor(self, task) -> TaskNodeCtor:
499
- self._log.debug("--> _mkLeafTaskCtor")
500
- srcdir = os.path.dirname(task.srcinfo.file)
501
- base_ctor_t : TaskNodeCtor = None
502
- ctor_t : TaskNodeCtor = None
503
- base_params = None
504
- callable = None
505
- # fullname = self.name + "." + task.name
506
- # rundir = task.rundir
507
-
508
- # TODO: should we have the ctor look this up itself?
509
- # Want to confirm that the value can be found.
510
- # Defer final resolution until actual graph building (post-config)
511
- if task.uses is not None:
512
- self._log.debug("Uses: %s" % task.uses.name)
513
-
514
- base_ctor_t = self._getTaskCtor(task.uses)
515
-
516
- if base_ctor_t is None:
517
- self._log.error("Failed to load task ctor %s" % task.uses)
518
- # base_params = base_ctor_t.mkTaskParams()
519
- else:
520
- self._log.debug("No 'uses' specified %s" % task.name)
521
-
522
- self._log.debug("%d needs" % len(task.needs))
523
-
524
- # Determine the implementation constructor first
525
- if task.run is not None:
526
- shell = task.shell if task.shell is not None else "shell"
527
-
528
- if shell in self._shell_m.keys():
529
- self._log.debug("Use shell implementation")
530
- callable = self._shell_m[shell]
531
- else:
532
- self._log.debug("Shell %s not found" % shell)
533
- raise Exception("Shell %s not found" % shell)
534
-
535
- # if taskdef.body.pytask is not None:
536
- # # Built-in impl
537
- # # Now, lookup the class
538
- # self._log.debug("Use PyTask implementation")
539
- # last_dot = taskdef.body.pytask.rfind('.')
540
- # clsname = taskdef.body.pytask[last_dot+1:]
541
- # modname = taskdef.body.pytask[:last_dot]
542
-
543
- # try:
544
- # if modname not in sys.modules:
545
- # if srcdir not in sys.path:
546
- # sys.path.append(srcdir)
547
- # mod = importlib.import_module(modname)
548
- # else:
549
- # mod = sys.modules[modname]
550
- # except ModuleNotFoundError as e:
551
- # raise Exception("Failed to import module %s (_basedir=%s): %s" % (
552
- # modname, self._basedir, str(e)))
553
-
554
- # if not hasattr(mod, clsname):
555
- # raise Exception("Method %s not found in module %s" % (clsname, modname))
556
- # callable = getattr(mod, clsname)
557
- # elif taskdef.body.run is not None:
558
- # callable = self._getRunCallable(taskdef)
559
- else:
560
- # TODO: use null task
561
- pass
562
-
563
- # Determine if we need to use a new
564
- if task.paramT is None:
565
- raise Exception()
566
- paramT = task.paramT
567
- needs = []
568
-
569
- # TODO:
570
- rundir : RundirE = task.rundir
571
-
572
- if callable is not None:
573
- ctor_t = TaskNodeCtorTask(
574
- name=task.name,
575
- srcdir=srcdir,
576
- paramT=task.paramT, # TODO: need to determine the parameter type
577
- passthrough=task.passthrough,
578
- consumes=task.consumes,
579
- needs=needs, # TODO: need to determine the needs
580
- rundir=rundir,
581
- task=callable)
582
- elif base_ctor_t is not None:
583
- # Use the existing (base) to create the implementation
584
- ctor_t = TaskNodeCtorProxy(
585
- name=task.name,
586
- srcdir=srcdir,
587
- paramT=task.paramT, # TODO: need to determine the parameter type
588
- passthrough=task.passthrough,
589
- consumes=task.consumes,
590
- needs=needs,
591
- rundir=rundir,
592
- uses=base_ctor_t)
593
- else:
594
- self._log.debug("Use 'Null' as the class implementation")
595
- ctor_t = TaskNodeCtorTask(
596
- name=task.name,
597
- srcdir=srcdir,
598
- paramT=paramT,
599
- passthrough=task.passthrough,
600
- consumes=task.consumes,
601
- needs=needs,
602
- rundir=rundir,
603
- task=TaskNull)
604
-
605
- self._log.debug("<-- mkTaskCtor %s" % task.name)
606
- return ctor_t
607
-
608
- def _getRunCallable(self, task):
609
- self._log.debug("--> _getRunCallable %s" % task.name)
610
- callable = None
611
- if task.run is not None and task.shell == "python":
612
- # Evaluate a Python script
613
- pass
614
- else:
615
- # run a shell script
616
- shell = None
617
- body = task.run.strip()
618
-
619
- callable = ShellCallable(body=body, shell=shell)
620
- pass
621
- return callable
622
-
623
- def _mkCompoundTaskCtor(self, task) -> TaskNodeCtor:
624
- self._log.debug("--> _mkCompoundTaskCtor %s" % task.name)
625
- srcdir = os.path.dirname(task.srcinfo.file)
626
- base_ctor_t : TaskNodeCtor = None
627
- ctor_t : TaskNodeCtor = None
628
- base_params = None
629
- callable = None
630
-
631
- # fullname = self._getScopeFullname()
632
- fullname = task.name
633
-
634
- if task.uses is not None:
635
- self._log.debug("Uses: %s" % task.uses)
636
- base_ctor_t = task.uses.ctor
637
- base_params = base_ctor_t.mkTaskParams()
638
-
639
- if base_ctor_t is None:
640
- self._log.error("Failed to load task ctor %s" % task.uses)
641
-
642
- # TODO: should build during loading
643
- # passthrough, consumes, needs = self._getPTConsumesNeeds(taskdef, base_ctor_t)
644
- passthrough = []
645
- consumes = []
646
- needs = []
647
-
648
- # Determine if we need to use a new
649
- # paramT = self._getParamT(taskdef, base_params)
650
- paramT = task.paramT
651
-
652
- if base_ctor_t is not None:
653
- ctor_t = TaskNodeCtorCompoundProxy(
654
- name=fullname,
655
- srcdir=srcdir,
656
- paramT=paramT,
657
- passthrough=passthrough,
658
- consumes=consumes,
659
- needs=needs,
660
- task=task,
661
- uses=base_ctor_t)
662
- else:
663
- self._log.debug("No 'uses' specified")
664
- ctor_t = TaskNodeCtorCompound(
665
- name=fullname,
666
- srcdir=srcdir,
667
- paramT=paramT,
668
- passthrough=passthrough,
669
- consumes=consumes,
670
- needs=needs,
671
- task=task)
672
-
673
- for st in task.subtasks:
674
- ctor = self._getTaskCtor(st)
675
- if ctor is None:
676
- raise Exception("ctor for %s is None" % st.name)
677
- ctor_t.tasks.append(st)
678
-
679
- # for t in task.subtasks:
680
- # ctor_t.tasks.append(self._mkTaskCtor(t, srcdir))
681
-
682
-
683
- self._log.debug("<-- mkCompoundTaskCtor %s (%d)" % (task.name, len(ctor_t.tasks)))
684
- return ctor_t
@@ -1,7 +1,7 @@
1
1
  import dataclasses as dc
2
2
  import logging
3
3
  import sys
4
- from typing import ClassVar, Dict, TextIO
4
+ from typing import ClassVar, Dict, Set, TextIO
5
5
  from .task_node import TaskNode
6
6
  from .task_node_compound import TaskNodeCompound
7
7
 
@@ -10,6 +10,7 @@ class TaskGraphDotWriter(object):
10
10
  fp : TextIO = dc.field(default=None)
11
11
  _ind : str = ""
12
12
  _node_id_m : Dict[TaskNode, str] = dc.field(default_factory=dict)
13
+ _processed_needs : Set[TaskNode] = dc.field(default_factory=set)
13
14
  _node_id : int = 1
14
15
  _cluster_id : int = 1
15
16
  _log : ClassVar = logging.getLogger("TaskGraphDotWriter")
@@ -22,48 +23,107 @@ class TaskGraphDotWriter(object):
22
23
  else:
23
24
  self.fp = open(filename, "w")
24
25
  self.println("digraph G {")
25
- self.process_node(node)
26
+ # First, build-out all nodes
27
+ self.build_node(node)
28
+ self.process_needs(node)
26
29
  self.println("}")
27
30
 
28
31
  self.fp.close()
29
32
  self._log.debug("<-- TaskGraphDotWriter::write")
30
33
 
31
- def process_node(self, node):
32
- self._log.debug("--> process_node %s (%d)" % (node.name, len(node.needs),))
33
- node_id = self._node_id
34
- self._node_id += 1
35
- node_name = "n%d" % self._node_id
36
- self._node_id_m[node] = node_name
34
+ def build_node(self, node):
35
+ self._log.debug("--> build_node %s (%d)" % (node.name, len(node.needs),))
37
36
 
38
37
  if isinstance(node, TaskNodeCompound):
39
- self.println("subgraph cluster_%d {" % self._cluster_id)
40
- self._cluster_id += 1
41
- self.inc_ind()
42
- self.println("label=\"%s\";" % node.name)
43
- self.println("color=blue;")
44
- self.println("style=dashed;")
45
- self.process_node(node.input)
46
-
47
- self.println("%s[label=\"%s.out\"];" % (
48
- node_name,
49
- node.name))
38
+ self._log.debug("-- compound node")
39
+ # Find the root and build out any expanded sub-nodes
40
+ root = node
41
+ while root.parent is not None:
42
+ root = root.parent
43
+ self.build_compound_node(root)
50
44
  else:
51
- self.println("%s[label=\"%s\"];" % (
52
- node_name,
53
- node.name))
45
+ # Leaf node
46
+ self._log.debug("-- leaf node")
47
+ node_id = self._node_id
48
+ self._node_id += 1
49
+ node_name = "n%d" % node_id
50
+ self._node_id_m[node] = node_name
51
+ self.println("%s[label=\"%s\"];" % (node_name, node.name))
52
+ self._log.debug("<-- build_node %s (%d)" % (node.name, len(node.needs),))
53
+
54
+ def process_needs(self, node):
55
+ self._log.debug("--> process_needs %s (%d)" % (node.name, len(node.needs),))
56
+
57
+ # if isinstance(node, TaskNodeCompound):
58
+ # self.println("subgraph cluster_%d {" % self._cluster_id)
59
+ # self._cluster_id += 1
60
+ # self.inc_ind()
61
+ # self.println("label=\"%s\";" % node.name)
62
+ # self.println("color=blue;")
63
+ # self.println("style=dashed;")
64
+ # self.process_node(node.input)
54
65
 
55
- for dep in node.needs:
56
- if dep[0] not in self._node_id_m.keys():
57
- self.process_node(dep[0])
66
+ # self.println("%s[label=\"%s.out\"];" % (
67
+ # node_name,
68
+ # node.name))
69
+ # else:
70
+ # self.println("%s[label=\"%s\"];" % (
71
+ # node_name,
72
+ # node.name))
73
+
74
+ for dep,_ in node.needs:
75
+ if dep not in self._node_id_m.keys():
76
+ self.build_node(dep)
77
+ if dep not in self._node_id_m.keys():
78
+ self._log.error("Dep-node not built: %s" % dep.name)
79
+ if node not in self._node_id_m.keys():
80
+ self.build_node(node)
81
+ if node not in self._node_id_m.keys():
82
+ self._log.error("Dep-node not built: %s" % node.name)
58
83
  self.println("%s -> %s;" % (
59
- self._node_id_m[dep[0]],
84
+ self._node_id_m[dep],
60
85
  self._node_id_m[node]))
86
+ if dep not in self._processed_needs:
87
+ self._processed_needs.add(dep)
88
+ self.process_needs(dep)
61
89
 
62
- if isinstance(node, TaskNodeCompound):
63
- self.dec_ind()
64
- self.println("}")
90
+ self._log.debug("<-- process_needs %s (%d)" % (node.name, len(node.needs),))
91
+
92
+ def build_compound_node(self, node):
93
+ """Hierarchical build of a compound root node"""
94
+
95
+ self._log.debug("--> build_compound_node %s (%d)" % (node.name, len(node.tasks),))
96
+
97
+ id = self._cluster_id
98
+ self._cluster_id += 1
99
+ self.println("subgraph cluster_%d {" % id)
100
+ self.inc_ind()
101
+ self.println("label=\"%s\";" % node.name)
102
+ self.println("color=blue;")
103
+ self.println("style=dashed;")
104
+
105
+ task_node_id = self._node_id
106
+ self._node_id += 1
107
+ task_node_name = "n%d" % task_node_id
108
+ self.println("%s[label=\"%s\"];" % (task_node_name, node.name))
109
+ self._node_id_m[node] = task_node_name
110
+
111
+ for n in node.tasks:
112
+ if isinstance(n, TaskNodeCompound):
113
+ # Recurse
114
+ self.build_compound_node(n)
115
+ else:
116
+ # Leaf node
117
+ node_id = self._node_id
118
+ self._node_id += 1
119
+ node_name = "n%d" % node_id
120
+ self._node_id_m[n] = node_name
121
+ leaf_name = n.name[n.name.rfind(".") + 1:]
122
+ self.println("%s[label=\"%s\"];" % (node_name, leaf_name))
123
+ self.dec_ind()
124
+ self.println("}")
65
125
 
66
- self._log.debug("<-- process_node %s (%d)" % (node.name, len(node.needs),))
126
+ self._log.debug("<-- build_compound_node %s (%d)" % (node.name, len(node.tasks),))
67
127
 
68
128
  def println(self, l):
69
129
  self.fp.write("%s%s\n" % (self._ind, l))
dv_flow/mgr/task_node.py CHANGED
@@ -56,6 +56,7 @@ class TaskNode(object):
56
56
  start : float = dc.field(default=None)
57
57
  end : float = dc.field(default=None)
58
58
  save_exec_data : bool = dc.field(default=True)
59
+ parent : 'TaskNode' = dc.field(default=None)
59
60
 
60
61
  _log : ClassVar = logging.getLogger("TaskNode")
61
62
 
@@ -69,6 +70,10 @@ class TaskNode(object):
69
70
  if not isinstance(need, tuple):
70
71
  self.needs[i] = (need, False)
71
72
 
73
+ @property
74
+ def first(self):
75
+ return self
76
+
72
77
  async def do_run(self,
73
78
  runner,
74
79
  rundir,
@@ -46,8 +46,14 @@ class TaskNodeCompound(TaskNode):
46
46
  srcdir=self.srcdir,
47
47
  params=NullParams())
48
48
  self.input.task = null_run
49
+ self.tasks.append(self.input)
50
+
49
51
  return super().__post_init__()
50
52
 
53
+ @property
54
+ def first(self):
55
+ return self.input
56
+
51
57
  async def do_run(self,
52
58
  runner : TaskRunner,
53
59
  rundir,
@@ -98,7 +98,7 @@ class TaskNodeLeaf(TaskNode):
98
98
  else:
99
99
  self._log.debug("consumes(unknown): %s" % str(self.consumes))
100
100
 
101
- for name,field in self.params.model_fields.items():
101
+ for name,field in type(self.params).model_fields.items():
102
102
  value = getattr(self.params, name)
103
103
  if type(value) == str:
104
104
  if value.find("${{") != -1:
@@ -170,7 +170,9 @@ class TaskNodeLeaf(TaskNode):
170
170
  for need,block in self.needs:
171
171
  if not block:
172
172
  output.extend(need.output.output)
173
- else:
173
+ elif self.consumes == ConsumesE.All:
174
+ self._log.debug("All inputs are consumed, so not propagating any")
175
+ elif isinstance(self.consumes, list):
174
176
  # Filter out parameter sets that were consumed
175
177
  self._log.debug("Propagating non-consumed input parameters to output")
176
178
  self._log.debug("consumes: %s" % str(self.consumes))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dv-flow-mgr
3
- Version: 1.0.0.14370893826a1
3
+ Version: 1.0.0.14392445998a1
4
4
  Summary: DV Flow Manager is a build system for silicon design
5
5
  Author-email: Matthew Ballance <matt.ballance@gmail.com>
6
6
  License: Apache License
@@ -18,7 +18,7 @@ dv_flow/mgr/out,sha256=d8GGBi3J43fhdLBlnsUbzBfRe0TD0QTP3nOTz54l2bI,200
18
18
  dv_flow/mgr/package.py,sha256=PvOuNfuy-SlaiMDzT5SU48OlPJrhS9vpNCgX06KNyTo,2336
19
19
  dv_flow/mgr/package_def.py,sha256=-UyeFb_0Sj16RtS2vxtIxTfl-oW7adJjM1I3ZSjcRpc,5729
20
20
  dv_flow/mgr/package_import_spec.py,sha256=aZMpnS9a5NFY76_pYXEuO3-Mkc_xFzy73fdrUe_54Dc,1760
21
- dv_flow/mgr/package_loader.py,sha256=LsPAcCKfAiEapC0I3m3Jv6Ra6YsQCXAqJe3_ETE6m_U,25071
21
+ dv_flow/mgr/package_loader.py,sha256=Z80md4ZhJk6TPVlvYAWlnH1aJvATlB9skIyb1pZ1P8U,25075
22
22
  dv_flow/mgr/param.py,sha256=kkxMRGf6mPjSZJsjgLKH2vJL62Sn0ZESvjBLkEYOp20,1386
23
23
  dv_flow/mgr/param_def.py,sha256=hOBBRLiXJ5DakXkhrLCBAQ9GPlgq-QS52r0aflmIgbg,1832
24
24
  dv_flow/mgr/param_ref_eval.py,sha256=5yH37oIX6f2qmk7GfRgNT5qZx0jm3CJFgB9lLDZZ1yQ,1981
@@ -31,11 +31,11 @@ dv_flow/mgr/srcinfo.py,sha256=xrfp-relVr7hYNbxOjY5jqX4H0nNMm9HK5AAM6_Piyk,366
31
31
  dv_flow/mgr/task.py,sha256=Xe1sCCTN4yJwhB2Aw_rywdlmVPY2CDnuwZisULuOXhw,2036
32
32
  dv_flow/mgr/task_data.py,sha256=lN7Iq8YTitEMGG4rZqYQi6Ri2HuPgBQ5oGQbW-63T8c,12436
33
33
  dv_flow/mgr/task_def.py,sha256=VAjkFay7KxXfZoloZfbiPr6WhURztV2Dxm6-REMQweo,4912
34
- dv_flow/mgr/task_graph_builder.py,sha256=SMGuYXWGwTXchd_ObKFNzbpXmlOTAWr0_YWN4XLbMWI,24178
35
- dv_flow/mgr/task_graph_dot_writer.py,sha256=GxqiYwQJbFgUQdnPCS9vpIYmYFbSXwnXCSbGmjbxC3M,2418
34
+ dv_flow/mgr/task_graph_builder.py,sha256=h0jiGY4VQI-wLJevawHl40wTILiMulA2eZpi0jFJ82A,16739
35
+ dv_flow/mgr/task_graph_dot_writer.py,sha256=fZlNR-ZUFsI5FpH1KFCWJcSpyLSKUh8IhHO9Eavc60c,4925
36
36
  dv_flow/mgr/task_listener_log.py,sha256=QH7hAVO1agYJoOx16XqjWv1c-jk5zb6p6A-hic7OMU0,4150
37
- dv_flow/mgr/task_node.py,sha256=JXq2QimCZKxfhhkdhM-HKk4JbxpIlpW65xUJ0hVlQc0,4981
38
- dv_flow/mgr/task_node_compound.py,sha256=mNu4nf9hVqu2698ue5fpE3FeAOkvJH0Ke2W9V0G3-As,2975
37
+ dv_flow/mgr/task_node.py,sha256=hPlCcped3nCNgOYj4oysVcxu4cHOIUCBUqAevOr20Lc,5086
38
+ dv_flow/mgr/task_node_compound.py,sha256=kmhfcHeqNwYE-XIRh8dsdU_zvLpAzHwVTdr4S3eAtN8,3080
39
39
  dv_flow/mgr/task_node_ctor.py,sha256=YsoVMX5WbpbzcHvEK7ps_ZRV-J7MZ3F8NNozQw7vbog,4418
40
40
  dv_flow/mgr/task_node_ctor_compound.py,sha256=290JdcTnL3b3Gv7s_wRLjdM02ezKhc9QnxZE0mv72i8,4379
41
41
  dv_flow/mgr/task_node_ctor_compound_proxy.py,sha256=D8x54nD8Pd-2-_mr1syhqVeSFfIVf100ldi3bdzmSfI,2073
@@ -43,7 +43,7 @@ dv_flow/mgr/task_node_ctor_def_base.py,sha256=_8QQHKDkONio_ve0Z409yxC0AMO8ocNBPD
43
43
  dv_flow/mgr/task_node_ctor_proxy.py,sha256=ViOFJ64JM4-CGFZNl89BghFuKSQ66kZVqSj4v2PA6VA,1906
44
44
  dv_flow/mgr/task_node_ctor_task.py,sha256=d49g90TyPCMFR8BuWWqp4ym-MW5vGSdDR0V47Ru28JY,2232
45
45
  dv_flow/mgr/task_node_ctor_wrapper.py,sha256=Nb1CVcPHZofnb-iLWDHQWAxlTOdbRrnR9DdSxY8yOec,3626
46
- dv_flow/mgr/task_node_leaf.py,sha256=wp0wCstQ8eyEJwJcbCqdpei6FvLE0C3-EEBPMjGv3-Y,8488
46
+ dv_flow/mgr/task_node_leaf.py,sha256=QZru3SisLZwykpfATJPo8qQJbRwArw0GBvRlLtLB8bs,8658
47
47
  dv_flow/mgr/task_output.py,sha256=ZwyvwnYj_gHOEFAEOH3m24Xfc4Cn77hb1j7LkX8_3C4,1086
48
48
  dv_flow/mgr/task_params_ctor.py,sha256=qlrzibGAFHmbqOu88jEoh1wOSFHu68Gwdgc259-50e8,1915
49
49
  dv_flow/mgr/task_run_ctxt.py,sha256=w1EOG9R16j0eT8fNcOCqlfyFrw277onsSur607eNprY,2811
@@ -66,9 +66,9 @@ dv_flow/mgr/util/__main__.py,sha256=F0LXpCDpYTPalSo0dc1h_qZkip5v1AZYYh-vcYbh5s0,
66
66
  dv_flow/mgr/util/util.py,sha256=cBNt3JJ0PGLlUQFTtBLi12i2j_9gNgSBtKdwS3VfF5Y,1566
67
67
  dv_flow/mgr/util/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
68
  dv_flow/mgr/util/cmds/cmd_schema.py,sha256=IJzZdxCSEgIQ79LpYiM7UqJ9RJ-7yraqmBN2XVgAgXA,1752
69
- dv_flow_mgr-1.0.0.14370893826a1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
70
- dv_flow_mgr-1.0.0.14370893826a1.dist-info/METADATA,sha256=gLrvvQKKh0wI5KalUtQj2i8IRWSVpW5mmCob-EqwoxY,13336
71
- dv_flow_mgr-1.0.0.14370893826a1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
72
- dv_flow_mgr-1.0.0.14370893826a1.dist-info/entry_points.txt,sha256=1roy8wAFM48LabOvr6jiOw0MUs-qE8X3Vf8YykPazxk,50
73
- dv_flow_mgr-1.0.0.14370893826a1.dist-info/top_level.txt,sha256=amfVTkggzYPtWwLqNmRukfz1Buu0pGS2SrYBBLhXm04,8
74
- dv_flow_mgr-1.0.0.14370893826a1.dist-info/RECORD,,
69
+ dv_flow_mgr-1.0.0.14392445998a1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
70
+ dv_flow_mgr-1.0.0.14392445998a1.dist-info/METADATA,sha256=B60agWgNKhS9gxExLemROgmyWl_S8SpiF2OqDjCyAKg,13336
71
+ dv_flow_mgr-1.0.0.14392445998a1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
72
+ dv_flow_mgr-1.0.0.14392445998a1.dist-info/entry_points.txt,sha256=1roy8wAFM48LabOvr6jiOw0MUs-qE8X3Vf8YykPazxk,50
73
+ dv_flow_mgr-1.0.0.14392445998a1.dist-info/top_level.txt,sha256=amfVTkggzYPtWwLqNmRukfz1Buu0pGS2SrYBBLhXm04,8
74
+ dv_flow_mgr-1.0.0.14392445998a1.dist-info/RECORD,,