dv-flow-mgr 0.0.1.13478128278a1__tar.gz → 0.0.1.13525773676a1__tar.gz

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 (97) hide show
  1. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/PKG-INFO +1 -1
  2. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/Steps.md +5 -0
  3. dv_flow_mgr-0.0.1.13525773676a1/docs/Tasks.md +19 -0
  4. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/pyproject.toml +1 -1
  5. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/expr_eval.py +13 -3
  6. dv_flow_mgr-0.0.1.13525773676a1/src/dv_flow/mgr/param_ref_eval.py +44 -0
  7. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_data.py +8 -3
  8. dv_flow_mgr-0.0.1.13525773676a1/src/dv_flow/mgr/task_node.py +142 -0
  9. dv_flow_mgr-0.0.1.13525773676a1/src/dv_flow/mgr/task_runner.py +121 -0
  10. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow_mgr.egg-info/PKG-INFO +1 -1
  11. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow_mgr.egg-info/SOURCES.txt +3 -0
  12. dv_flow_mgr-0.0.1.13525773676a1/tests/unit/test_pytask_smoke.py +141 -0
  13. dv_flow_mgr-0.0.1.13478128278a1/src/dv_flow/mgr/task_runner.py +0 -46
  14. dv_flow_mgr-0.0.1.13478128278a1/tests/unit/test_pytask_smoke.py +0 -59
  15. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/.github/workflows/ci.yml +0 -0
  16. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/.gitignore +0 -0
  17. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/.vscode/settings.json +0 -0
  18. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/LICENSE +0 -0
  19. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/README.md +0 -0
  20. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/KeyArchitecture.md +0 -0
  21. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/Makefile +0 -0
  22. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/Notes.md +0 -0
  23. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/Roadmap.md +0 -0
  24. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/RundirLayout.md +0 -0
  25. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/Stages.md +0 -0
  26. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/TypesAndDefs.md +0 -0
  27. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/Usecases.md +0 -0
  28. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/conf.py +0 -0
  29. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/index.rst +0 -0
  30. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/intro.rst +0 -0
  31. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/quickstart.rst +0 -0
  32. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/docs/reference.rst +0 -0
  33. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/ivpm.yaml +0 -0
  34. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/setup.cfg +0 -0
  35. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/__init__.py +0 -0
  36. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/__main__.py +0 -0
  37. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/cmds/cmd_run.py +0 -0
  38. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/expr_parser.py +0 -0
  39. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/fileset.py +0 -0
  40. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/fragment_def.py +0 -0
  41. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/out +0 -0
  42. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/package.py +0 -0
  43. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/package_def.py +0 -0
  44. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/package_import_spec.py +0 -0
  45. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/param_def.py +0 -0
  46. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/parsetab.py +0 -0
  47. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/pkg_rgy.py +0 -0
  48. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/share/flow.json +0 -0
  49. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/std/fileset.py +0 -0
  50. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/std/flow.dv +0 -0
  51. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/std/message.py +0 -0
  52. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/std/task_null.py +0 -0
  53. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task.py +0 -0
  54. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_ctor.py +0 -0
  55. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_def.py +0 -0
  56. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_exec_data.py +0 -0
  57. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_graph_builder.py +0 -0
  58. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_graph_runner.py +0 -0
  59. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_graph_runner_local.py +0 -0
  60. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_impl_data.py +0 -0
  61. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_memento.py +0 -0
  62. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_output.py +0 -0
  63. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/task_params_ctor.py +0 -0
  64. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/type.py +0 -0
  65. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/type_def.py +0 -0
  66. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow/mgr/util.py +0 -0
  67. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow_mgr.egg-info/dependency_links.txt +0 -0
  68. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow_mgr.egg-info/entry_points.txt +0 -0
  69. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow_mgr.egg-info/requires.txt +0 -0
  70. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/src/dv_flow_mgr.egg-info/top_level.txt +0 -0
  71. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/examples/example1/example1.flow +0 -0
  72. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/system/test_depends.py +0 -0
  73. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/system/test_pkg_discovery.py +0 -0
  74. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/system/test_stdlib.py +0 -0
  75. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/__init__.py +0 -0
  76. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1/files1/file1_1.sv +0 -0
  77. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1/files1/file1_2.sv +0 -0
  78. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1/files2/file2_1.sv +0 -0
  79. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1/files2/file2_2.sv +0 -0
  80. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1/flow.dv +0 -0
  81. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1 copy/files1/file1_1.sv +0 -0
  82. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1 copy/files1/file1_2.sv +0 -0
  83. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1 copy/files2/file2_1.sv +0 -0
  84. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1 copy/files2/file2_2.sv +0 -0
  85. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/fileset/test1 copy/test1.dfs +0 -0
  86. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/proj1/proj1.dfs +0 -0
  87. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/proj2/proj2.dfs +0 -0
  88. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/data/proj3/proj3.dfs +0 -0
  89. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_data_merge.py +0 -0
  90. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_expr_eval.py +0 -0
  91. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_expr_parser.py +0 -0
  92. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_fileset.py +0 -0
  93. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_parse.py +0 -0
  94. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_pyclass.py +0 -0
  95. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_smoke copy.sav +0 -0
  96. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_smoke.py +0 -0
  97. {dv_flow_mgr-0.0.1.13478128278a1 → dv_flow_mgr-0.0.1.13525773676a1}/tests/unit/test_stdlib.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: dv-flow-mgr
3
- Version: 0.0.1.13478128278a1
3
+ Version: 0.0.1.13525773676a1
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
@@ -104,6 +104,11 @@ runner.run(simImg)
104
104
 
105
105
  factory.addTaskType(MyTask.ctor)
106
106
 
107
+ # Proper values
108
+ - Show that can pass individual values
109
+ - Need to test append/prepend/path-append/path-prepend
110
+ - Need to process and expand expressions
111
+ -
107
112
 
108
113
 
109
114
 
@@ -0,0 +1,19 @@
1
+
2
+ A task graph is composed of task nodes. A task is defined as the combination
3
+ of:
4
+ - behavior
5
+ - parameters data structure
6
+ - rules/process for specifying parameter values
7
+
8
+ Task behavior must:
9
+ - accept input data composed of:
10
+ - parameter data structure with values populated
11
+ - change notification
12
+ - (optional) meta-data
13
+ - produce result data composed of:
14
+ - list of parameter sets
15
+ - change notification
16
+ - (optional) meta-data
17
+ - (optional) markers
18
+ - execution status
19
+
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "dv-flow-mgr"
8
- version = "0.0.1.13478128278a1"
8
+ version = "0.0.1.13525773676a1"
9
9
  dependencies = [
10
10
  'pydantic',
11
11
  'pyyaml',
@@ -9,16 +9,26 @@ class ExprEval(ExprVisitor):
9
9
  variables : Dict[str, object] = dc.field(default_factory=dict)
10
10
  value : Any = None
11
11
 
12
- def eval(self, e : Expr):
12
+ def eval(self, e : Expr) -> str:
13
13
  self.value = None
14
14
  e.accept(self)
15
- return self.value
15
+
16
+ val = self._toString(self.value)
17
+
18
+ return val
19
+
20
+ def _toString(self, val):
21
+ if isinstance(val, list):
22
+ val = '[' + ",".join(self._toString(v) for v in val) + ']'
23
+ elif hasattr(val, "model_dump_json"):
24
+ val = val.model_dump_json()
25
+ return val
16
26
 
17
27
  def visitExprId(self, e : ExprId):
18
28
  if e.id in self.variables:
19
29
  self.value = self.variables[e.id]
20
30
  else:
21
- raise Exception("Variable %s not found" % e.id)
31
+ raise Exception("Variable '%s' not found" % e.id)
22
32
 
23
33
  def visitExprString(self, e : ExprString):
24
34
  self.value = e.value
@@ -0,0 +1,44 @@
1
+ import dataclasses as dc
2
+ import json
3
+ from .expr_eval import ExprEval
4
+ from .expr_parser import ExprParser
5
+
6
+ @dc.dataclass
7
+ class ParamRefEval(object):
8
+
9
+ parser : ExprParser = ExprParser()
10
+ expr_eval : ExprEval = ExprEval()
11
+
12
+ def eval(self, val : str) -> str:
13
+ idx = 0
14
+
15
+ while True:
16
+ idx = val.find("${{", idx)
17
+
18
+ if idx != -1:
19
+ eidx = val.find("}}", idx+1)
20
+
21
+ if eidx == -1:
22
+ raise Exception("unterminated variable ref")
23
+
24
+ ref = val[idx+3:eidx].strip()
25
+ print("ref: %s" % ref)
26
+
27
+ expr_ast = self.parser.parse(ref)
28
+ print("expr_ast: %s" % str(expr_ast))
29
+ exp_val = self.expr_eval.eval(expr_ast)
30
+ print("exp_val: %s" % str(exp_val))
31
+
32
+ # Replacing [idx..eidx+2] with len(exp_val)
33
+ val = val[:idx] + exp_val + val[eidx+2:]
34
+ idx += len(exp_val)
35
+
36
+
37
+
38
+ else:
39
+ break
40
+
41
+ return val
42
+
43
+ def setVar(self, name, value):
44
+ self.expr_eval.variables[name] = value
@@ -37,6 +37,10 @@ class TaskMarker(BaseModel):
37
37
  severity : str
38
38
  loc : TaskMarkerLoc = dc.Field(default=None)
39
39
 
40
+ class TaskParameterSet(BaseModel):
41
+ task : str = None # Name of the task that produced this param set
42
+ seq : int = -1 # Order in which the param-set must appear
43
+
40
44
  class TaskDataInput(BaseModel):
41
45
  changed : bool
42
46
  srcdir : str
@@ -46,14 +50,15 @@ class TaskDataInput(BaseModel):
46
50
 
47
51
  class TaskDataResult(BaseModel):
48
52
  changed : bool = dc.Field(default=True)
49
- output : List[Any] = dc.Field(default_factory=list)
53
+ output : List[TaskParameterSet] = dc.Field(default_factory=list)
50
54
  memento : Any = dc.Field(default=None)
51
55
  markers : List[TaskMarker] = dc.Field(default_factory=list)
52
56
  status : int = dc.Field(default=0)
53
57
 
54
58
  class TaskDataOutput(BaseModel):
55
- changed : bool
56
- output : List[Any]
59
+ changed : bool = True
60
+ output : List[TaskParameterSet] = dc.Field(default_factory=list)
61
+ dep_m : Dict[str,List[str]] = dc.Field(default_factory=dict)
57
62
 
58
63
  class TaskDataParamOpE(enum.Enum):
59
64
  Set = enum.auto()
@@ -0,0 +1,142 @@
1
+
2
+ import dataclasses as dc
3
+ import pydantic.dataclasses as pdc
4
+ import logging
5
+ from typing import Any, Callable, ClassVar, Dict, List
6
+ from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
7
+ from .task_params_ctor import TaskParamsCtor
8
+ from .param_ref_eval import ParamRefEval
9
+
10
+ @dc.dataclass
11
+ class TaskNode(object):
12
+ """Executable view of a task"""
13
+ # Ctor fields -- must specify on construction
14
+ name : str
15
+ srcdir : str
16
+ # This can be the resolved parameters
17
+ params : TaskParamsCtor
18
+
19
+ task : Callable[['TaskRunner','TaskDataInput'],'TaskDataResult']
20
+
21
+ # Runtime fields -- these get populated during execution
22
+ changed : bool = False
23
+ needs : List['TaskNode'] = dc.field(default_factory=list)
24
+ rundir : str = dc.field(default=None)
25
+ output : TaskDataOutput = dc.field(default=None)
26
+
27
+ _log : ClassVar = logging.getLogger("TaskNode")
28
+
29
+ async def do_run(self,
30
+ runner,
31
+ rundir,
32
+ memento : Any = None) -> 'TaskDataResult':
33
+ changed = False
34
+ for dep in self.needs:
35
+ changed |= dep.changed
36
+
37
+ # TODO: Form dep-map from inputs
38
+ # TODO: Order param sets according to dep-map
39
+ in_params = []
40
+ for need in self.needs:
41
+ in_params.extend(need.output.output)
42
+
43
+ # TODO: create an evaluator for substituting param values
44
+ eval = ParamRefEval()
45
+
46
+ eval.setVar("in", in_params)
47
+
48
+ for name,field in self.params.model_fields.items():
49
+ value = getattr(self.params, name)
50
+ if value.find("${{") != -1:
51
+ new_val = eval.eval(value)
52
+ setattr(self.params, name, new_val)
53
+ print("TODO: expand")
54
+ print("Field: %s %s" % (name, str(value)))
55
+ pass
56
+
57
+ input = TaskDataInput(
58
+ changed=changed,
59
+ srcdir=self.srcdir,
60
+ rundir=rundir,
61
+ params=self.params,
62
+ memento=memento)
63
+
64
+ # TODO: notify of task start
65
+ ret : TaskDataResult = await self.task(self, input)
66
+ # TODO: notify of task complete
67
+
68
+ # TODO: form a dep map from the outgoing param sets
69
+ dep_m = {}
70
+
71
+ # Store the result
72
+ self.output = TaskDataOutput(
73
+ changed=ret.changed,
74
+ dep_m=dep_m,
75
+ output=ret.output.copy())
76
+
77
+ # TODO:
78
+
79
+ return ret
80
+
81
+ def __hash__(self):
82
+ return id(self)
83
+
84
+ @staticmethod
85
+ def task(paramT):
86
+ def wrapper(T):
87
+ ctor = TaskNodeCtorWrapper(T.__name__, T, paramT)
88
+ return ctor
89
+ return wrapper
90
+
91
+ @dc.dataclass
92
+ class TaskNodeCtor(object):
93
+ """
94
+ Factory for a specific task type
95
+ - Produces a task parameters object, applying value-setting instructions
96
+ - Produces a TaskNode
97
+ """
98
+ name : str
99
+
100
+
101
+ def mkTaskNode(self, srcdir, params, name=None) -> TaskNode:
102
+ raise NotImplementedError("mkTaskNode in type %s" % str(type(self)))
103
+
104
+ def mkTaskParams(self, params : Dict) -> Any:
105
+ raise NotImplementedError("mkTaskParams in type %s" % str(type(self)))
106
+
107
+ @dc.dataclass
108
+ class TaskNodeCtorWrapper(TaskNodeCtor):
109
+ T : Any
110
+ paramT : Any
111
+
112
+ def __call__(self,
113
+ srcdir,
114
+ name=None,
115
+ params=None,
116
+ needs=None,
117
+ **kwargs):
118
+ """Convenience method for direct creation of tasks"""
119
+ if params is None:
120
+ params = self.mkTaskParams(kwargs)
121
+
122
+ node = self.mkTaskNode(srcdir, params, name)
123
+ if needs is not None:
124
+ node.needs.extend(needs)
125
+ return node
126
+
127
+ def mkTaskNode(self, srcdir, params, name=None) -> TaskNode:
128
+ node = TaskNode(name, srcdir, params, self.T)
129
+ return node
130
+
131
+ def mkTaskParams(self, params : Dict) -> Any:
132
+ obj = self.paramT()
133
+
134
+ # Apply user-specified params
135
+ for key,value in params.items():
136
+ if not hasattr(obj, key):
137
+ raise Exception("Parameters class %s does not contain field %s" % (
138
+ str(type(obj)),
139
+ key))
140
+ else:
141
+ setattr(obj, key, value)
142
+ return obj
@@ -0,0 +1,121 @@
1
+ import asyncio
2
+ import dataclasses as dc
3
+ from toposort import toposort
4
+ from typing import Any, Callable, List, Tuple, Union
5
+ from .task_data import TaskDataInput, TaskDataOutput, TaskDataResult
6
+ from .task_node import TaskNode
7
+
8
+ @dc.dataclass
9
+ class TaskRunner(object):
10
+ rundir : str
11
+
12
+ # List of [Listener:Callable[Task],Recurisve:bool]
13
+ listeners : List[Tuple[Callable['Task','Reason'], bool]] = dc.field(default_factory=list)
14
+
15
+ async def do_run(self,
16
+ task : 'Task',
17
+ memento : Any = None) -> 'TaskDataResult':
18
+ return await self.run(task, memento)
19
+
20
+ async def run(self,
21
+ task : 'Task',
22
+ memento : Any = None) -> 'TaskDataResult':
23
+ pass
24
+
25
+ @dc.dataclass
26
+ class TaskSetRunner(TaskRunner):
27
+ nproc : int = 8
28
+
29
+ async def run(self, task : Union[TaskNode,List[TaskNode]]):
30
+ # First, build a depedency map
31
+ tasks = task if isinstance(task, list) else [task]
32
+ dep_m = {}
33
+ for t in tasks:
34
+ self._buildDepMap(dep_m, t)
35
+
36
+ print("dep_m: %s" % str(dep_m))
37
+
38
+ order = list(toposort(dep_m))
39
+
40
+ active_task_l = []
41
+ done_task_s = set()
42
+ for active_s in order:
43
+ done = True
44
+ for t in active_s:
45
+ while len(active_task_l) >= self.nproc and t not in done_task_s:
46
+ # Wait for at least one job to complete
47
+ done, pending = await asyncio.wait(at[1] for at in active_task_l)
48
+ for d in done:
49
+ for i in range(len(active_task_l)):
50
+ if active_task_l[i][1] == d:
51
+ tt = active_task_l[i][0]
52
+ done_task_s.add(tt)
53
+ active_task_l.pop(i)
54
+ break
55
+ if t not in done_task_s:
56
+ coro = asyncio.Task(t.do_run(
57
+ self,
58
+ self.rundir, # TODO
59
+ None)) # TODO: memento
60
+ active_task_l.append((t, coro))
61
+
62
+ # Now, wait for tasks to complete
63
+ if len(active_task_l):
64
+ coros = list(at[1] for at in active_task_l)
65
+ res = await asyncio.gather(*coros)
66
+
67
+
68
+ pass
69
+
70
+ def _buildDepMap(self, dep_m, task : TaskNode):
71
+ if task not in dep_m.keys():
72
+ dep_m[task] = set(task.needs)
73
+ for need in task.needs:
74
+ self._buildDepMap(dep_m, need)
75
+
76
+ @dc.dataclass
77
+ class SingleTaskRunner(TaskRunner):
78
+
79
+ async def run(self,
80
+ task : 'Task',
81
+ memento : Any = None) -> 'TaskDataResult':
82
+ changed = False
83
+ for dep in task.needs:
84
+ changed |= dep.changed
85
+
86
+ # TODO: create an evaluator for substituting param values
87
+ eval = None
88
+
89
+ for field in dc.fields(task.params):
90
+ print("Field: %s" % field.name)
91
+
92
+ input = TaskDataInput(
93
+ changed=changed,
94
+ srcdir=task.srcdir,
95
+ rundir=self.rundir,
96
+ params=task.params,
97
+ memento=memento)
98
+
99
+ # TODO: notify of task start
100
+ ret : TaskDataResult = await task.task(self, input)
101
+ # TODO: notify of task complete
102
+
103
+ # Store the result
104
+ task.output = TaskDataOutput(
105
+ changed=ret.changed,
106
+ output=ret.output.copy())
107
+
108
+ # # By definition, none of this have run, since we just ran
109
+ # for dep in task.dependents:
110
+ # is_sat = True
111
+ # for need in dep.needs:
112
+ # if need.output is None:
113
+ # is_sat = False
114
+ # break
115
+
116
+ # if is_sat:
117
+ # # TODO: queue task for evaluation
118
+ # pass
119
+ # TODO:
120
+
121
+ return ret
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: dv-flow-mgr
3
- Version: 0.0.1.13478128278a1
3
+ Version: 0.0.1.13525773676a1
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
@@ -12,6 +12,7 @@ docs/Roadmap.md
12
12
  docs/RundirLayout.md
13
13
  docs/Stages.md
14
14
  docs/Steps.md
15
+ docs/Tasks.md
15
16
  docs/TypesAndDefs.md
16
17
  docs/Usecases.md
17
18
  docs/conf.py
@@ -30,6 +31,7 @@ src/dv_flow/mgr/package.py
30
31
  src/dv_flow/mgr/package_def.py
31
32
  src/dv_flow/mgr/package_import_spec.py
32
33
  src/dv_flow/mgr/param_def.py
34
+ src/dv_flow/mgr/param_ref_eval.py
33
35
  src/dv_flow/mgr/parsetab.py
34
36
  src/dv_flow/mgr/pkg_rgy.py
35
37
  src/dv_flow/mgr/task.py
@@ -42,6 +44,7 @@ src/dv_flow/mgr/task_graph_runner.py
42
44
  src/dv_flow/mgr/task_graph_runner_local.py
43
45
  src/dv_flow/mgr/task_impl_data.py
44
46
  src/dv_flow/mgr/task_memento.py
47
+ src/dv_flow/mgr/task_node.py
45
48
  src/dv_flow/mgr/task_output.py
46
49
  src/dv_flow/mgr/task_params_ctor.py
47
50
  src/dv_flow/mgr/task_runner.py
@@ -0,0 +1,141 @@
1
+ import asyncio
2
+ import pytest
3
+ import dataclasses as dc
4
+ from pydantic import BaseModel
5
+ from dv_flow.mgr.task import Task
6
+ from dv_flow.mgr.task_data import TaskDataResult, TaskMarker, TaskParameterSet
7
+ from dv_flow.mgr.task_node import task as t_decorator
8
+ from dv_flow.mgr.task_runner import SingleTaskRunner, TaskSetRunner
9
+
10
+
11
+ def test_smoke_1(tmpdir):
12
+
13
+ @dc.dataclass
14
+ class Params(object):
15
+ p1 : str = None
16
+
17
+ called = False
18
+
19
+ @t_decorator(Params)
20
+ async def MyTask(runner, input):
21
+ nonlocal called
22
+ called = True
23
+ print("Hello from run")
24
+ return TaskDataResult()
25
+
26
+ task = MyTask("srcdir", p1="p1")
27
+ runner = SingleTaskRunner("rundir")
28
+
29
+ result = asyncio.run(runner.run(task))
30
+
31
+ assert called
32
+
33
+ def test_smoke_2(tmpdir):
34
+
35
+ @dc.dataclass
36
+ class Params(object):
37
+ p1 : str = None
38
+
39
+ called = False
40
+ @Task.ctor(Params)
41
+ class MyTask(Task):
42
+ async def run(self, runner, input):
43
+ nonlocal called
44
+ called = True
45
+ print("Hello from run")
46
+ return TaskDataResult(
47
+ markers=[TaskMarker(msg="testing", severity="info")]
48
+ )
49
+
50
+ task = MyTask.mkTask("task1", "srcdir", MyTask.mkParams(
51
+ p1="p1"
52
+ ))
53
+ runner = SingleTaskRunner("rundir")
54
+
55
+ result = asyncio.run(runner.run(task))
56
+
57
+ assert called
58
+ assert result is not None
59
+ assert len(result.markers) == 1
60
+
61
+ def test_smoke_3(tmpdir):
62
+
63
+ @dc.dataclass
64
+ class Params(object):
65
+ p1 : str = None
66
+
67
+ called = []
68
+
69
+ @t_decorator(Params)
70
+ async def MyTask1(runner, input):
71
+ nonlocal called
72
+ called.append(("MyTask1", input.params.p1))
73
+ return TaskDataResult()
74
+
75
+ @t_decorator(Params)
76
+ async def MyTask2(runner, input):
77
+ nonlocal called
78
+ called.append(("MyTask2", input.params.p1))
79
+ return TaskDataResult()
80
+
81
+ @t_decorator(Params)
82
+ async def MyTask3(runner, input):
83
+ nonlocal called
84
+ called.append(("MyTask3", input.params.p1))
85
+ return TaskDataResult()
86
+
87
+ task1 = MyTask1("srcdir", p1="1")
88
+ task2 = MyTask2("srcdir", p1="2")
89
+ task3 = MyTask3("srcdir", p1="3", needs=[task1, task2])
90
+ runner = TaskSetRunner("rundir")
91
+
92
+ result = asyncio.run(runner.run(task3))
93
+
94
+ assert len(called) == 3
95
+ assert called[-1][0] == "MyTask3"
96
+ assert called[-1][1] == "3"
97
+
98
+ def test_smoke_4(tmpdir):
99
+
100
+ class Params(BaseModel):
101
+ p1 : str = None
102
+
103
+ class TaskData(TaskParameterSet):
104
+ val : int = -1
105
+
106
+ called = []
107
+
108
+ @t_decorator(Params)
109
+ async def MyTask1(runner, input):
110
+ nonlocal called
111
+ called.append(("MyTask1", input.params.p1))
112
+ return TaskDataResult(
113
+ output=[TaskData(val=1)]
114
+ )
115
+
116
+ @t_decorator(Params)
117
+ async def MyTask2(runner, input):
118
+ nonlocal called
119
+ called.append(("MyTask2", input.params.p1))
120
+ return TaskDataResult(
121
+ output=[TaskData(val=2)]
122
+ )
123
+
124
+ @t_decorator(Params)
125
+ async def MyTask3(runner, input):
126
+ nonlocal called
127
+ called.append(("MyTask3", input.params.p1))
128
+ return TaskDataResult()
129
+
130
+ task1 = MyTask1("srcdir", p1="1")
131
+ task2 = MyTask2("srcdir", p1="2")
132
+ task3 = MyTask3("srcdir",
133
+ p1="${{ in }}",
134
+ needs=[task1, task2])
135
+ runner = TaskSetRunner("rundir")
136
+
137
+ result = asyncio.run(runner.run(task3))
138
+
139
+ assert len(called) == 3
140
+ assert called[-1][0] == "MyTask3"
141
+ assert called[-1][1] == "3"
@@ -1,46 +0,0 @@
1
- import dataclasses as dc
2
- from .task_data import TaskDataInput, TaskDataResult
3
- from typing import Any, Callable, List, Tuple
4
-
5
- @dc.dataclass
6
- class TaskRunner(object):
7
- rundir : str
8
-
9
- # List of [Listener:Callable[Task],Recurisve:bool]
10
- listeners : List[Tuple[Callable['Task','Reason'], bool]] = dc.field(default_factory=list)
11
-
12
- async def do_run(self,
13
- task : 'Task',
14
- memento : Any = None) -> 'TaskDataResult':
15
- return await self.run(task, memento)
16
-
17
- async def run(self,
18
- task : 'Task',
19
- memento : Any = None) -> 'TaskDataResult':
20
- pass
21
-
22
- @dc.dataclass
23
- class SingleTaskRunner(TaskRunner):
24
-
25
- async def run(self,
26
- task : 'Task',
27
- memento : Any = None) -> 'TaskDataResult':
28
- changed = False
29
- for dep in task.needs:
30
- changed |= dep.changed
31
-
32
- # TODO: create an evaluator for substituting param values
33
- eval = None
34
-
35
- params = task.params.mk(eval)
36
-
37
- input = TaskDataInput(
38
- changed=changed,
39
- srcdir=task.srcdir,
40
- rundir=self.rundir,
41
- params=params,
42
- memento=memento)
43
-
44
- ret = await task.run(self, input)
45
-
46
- return ret
@@ -1,59 +0,0 @@
1
- import asyncio
2
- import pytest
3
- import dataclasses as dc
4
- from dv_flow.mgr.task import Task
5
- from dv_flow.mgr.task_data import TaskDataResult, TaskMarker
6
- from dv_flow.mgr.task_runner import SingleTaskRunner
7
-
8
-
9
- def test_smoke_1(tmpdir):
10
-
11
- @dc.dataclass
12
- class Params(object):
13
- p1 : str
14
-
15
- called = False
16
- @Task.ctor(Params)
17
- class MyTask(Task):
18
- async def run(self, runner, input):
19
- nonlocal called
20
- called = True
21
- print("Hello from run")
22
- pass
23
-
24
- task = MyTask("task1", "srcdir", MyTask.mkParams("p1"))
25
- runner = SingleTaskRunner("rundir")
26
-
27
- result = asyncio.run(runner.run(task))
28
-
29
- assert called
30
-
31
- def test_smoke_2(tmpdir):
32
-
33
- @dc.dataclass
34
- class Params(object):
35
- p1 : str = None
36
-
37
- called = False
38
- @Task.ctor(Params)
39
- class MyTask(Task):
40
- async def run(self, runner, input):
41
- nonlocal called
42
- called = True
43
- print("Hello from run")
44
- return TaskDataResult(
45
- markers=[TaskMarker(msg="testing", severity="info")]
46
- )
47
-
48
- task = MyTask.mkTask("task1", "srcdir", MyTask.mkParams(
49
- p1="p1"
50
- ))
51
- runner = SingleTaskRunner("rundir")
52
-
53
- result = asyncio.run(runner.run(task))
54
-
55
- assert called
56
- assert result is not None
57
- assert len(result.markers) == 1
58
-
59
-