dv-flow-mgr 0.0.1.13979842530a1__py3-none-any.whl → 0.0.1.14097297609a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dv_flow/mgr/__init__.py +2 -2
- dv_flow/mgr/__main__.py +26 -1
- dv_flow/mgr/cmds/cmd_graph.py +82 -0
- dv_flow/mgr/cmds/cmd_run.py +2 -2
- dv_flow/mgr/cmds/cmd_show.py +107 -0
- dv_flow/mgr/fileset.py +1 -0
- dv_flow/mgr/fragment_def.py +1 -1
- dv_flow/mgr/package.py +3 -3
- dv_flow/mgr/package_def.py +121 -33
- dv_flow/mgr/param_def.py +8 -3
- dv_flow/mgr/std/message.py +1 -1
- dv_flow/mgr/task_data.py +24 -20
- dv_flow/mgr/task_def.py +0 -1
- dv_flow/mgr/task_graph_builder.py +121 -12
- dv_flow/mgr/task_graph_dot_writer.py +78 -0
- dv_flow/mgr/task_node.py +3 -326
- dv_flow/mgr/task_node_compound.py +13 -1
- dv_flow/mgr/task_node_ctor.py +118 -0
- dv_flow/mgr/task_node_ctor_compound.py +117 -0
- dv_flow/mgr/task_node_ctor_compound_proxy.py +65 -0
- dv_flow/mgr/task_node_ctor_def_base.py +47 -0
- dv_flow/mgr/task_node_ctor_proxy.py +56 -0
- dv_flow/mgr/task_node_ctor_task.py +64 -0
- dv_flow/mgr/task_node_ctor_wrapper.py +96 -0
- dv_flow/mgr/task_node_leaf.py +170 -0
- dv_flow/mgr/task_runner.py +11 -6
- dv_flow/mgr/util/__init__.py +3 -0
- dv_flow/mgr/util/__main__.py +36 -0
- dv_flow/mgr/util/cmds/__init__.py +0 -0
- dv_flow/mgr/util/cmds/cmd_schema.py +63 -0
- dv_flow/mgr/{util.py → util/util.py} +1 -1
- {dv_flow_mgr-0.0.1.13979842530a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/METADATA +1 -1
- dv_flow_mgr-0.0.1.14097297609a1.dist-info/RECORD +57 -0
- {dv_flow_mgr-0.0.1.13979842530a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/WHEEL +1 -1
- dv_flow/mgr/task.py +0 -181
- dv_flow/mgr/task_ctor.py +0 -64
- dv_flow_mgr-0.0.1.13979842530a1.dist-info/RECORD +0 -44
- {dv_flow_mgr-0.0.1.13979842530a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/entry_points.txt +0 -0
- {dv_flow_mgr-0.0.1.13979842530a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/licenses/LICENSE +0 -0
- {dv_flow_mgr-0.0.1.13979842530a1.dist-info → dv_flow_mgr-0.0.1.14097297609a1.dist-info}/top_level.txt +0 -0
dv_flow/mgr/__init__.py
CHANGED
@@ -21,10 +21,10 @@
|
|
21
21
|
#****************************************************************************
|
22
22
|
from .package_def import *
|
23
23
|
from .pkg_rgy import PkgRgy
|
24
|
-
from .task import *
|
25
24
|
from .task_data import *
|
26
25
|
from .task_graph_builder import TaskGraphBuilder
|
27
|
-
from .
|
26
|
+
from .task_runner import TaskRunner
|
27
|
+
from .task_node_ctor_wrapper import task
|
28
28
|
from .task_runner import TaskSetRunner
|
29
29
|
from .task_listener_log import TaskListenerLog
|
30
30
|
|
dv_flow/mgr/__main__.py
CHANGED
@@ -21,10 +21,14 @@
|
|
21
21
|
#****************************************************************************
|
22
22
|
import argparse
|
23
23
|
import logging
|
24
|
+
from .cmds.cmd_graph import CmdGraph
|
24
25
|
from .cmds.cmd_run import CmdRun
|
26
|
+
from .cmds.cmd_show import CmdShow
|
25
27
|
|
26
28
|
def get_parser():
|
27
|
-
parser = argparse.ArgumentParser(
|
29
|
+
parser = argparse.ArgumentParser(
|
30
|
+
description='dv_flow_mgr',
|
31
|
+
prog='dfm')
|
28
32
|
# parser.add_argument("-d", "--debug",
|
29
33
|
# help="Enable debug",
|
30
34
|
# action="store_true")
|
@@ -36,6 +40,16 @@ def get_parser():
|
|
36
40
|
# action="store_true")
|
37
41
|
subparsers = parser.add_subparsers(required=True)
|
38
42
|
|
43
|
+
graph_parser = subparsers.add_parser('graph',
|
44
|
+
help='Generates the graph of a task')
|
45
|
+
graph_parser.add_argument("task", nargs="?", help="task to graph")
|
46
|
+
graph_parser.add_argument("-f", "--format", help="Specifies the output format",
|
47
|
+
default="dot")
|
48
|
+
graph_parser.add_argument("-o", "--output",
|
49
|
+
help="Specifies the output file",
|
50
|
+
default="-")
|
51
|
+
graph_parser.set_defaults(func=CmdGraph())
|
52
|
+
|
39
53
|
run_parser = subparsers.add_parser('run', help='run a flow')
|
40
54
|
run_parser.add_argument("tasks", nargs='*', help="tasks to run")
|
41
55
|
run_parser.add_argument("-j",
|
@@ -43,6 +57,17 @@ def get_parser():
|
|
43
57
|
type=int, default=-1)
|
44
58
|
run_parser.set_defaults(func=CmdRun())
|
45
59
|
|
60
|
+
show_parser = subparsers.add_parser('show',
|
61
|
+
help='Display information about a task or tasks')
|
62
|
+
show_parser.add_argument("task", nargs='?', help="task to show")
|
63
|
+
show_parser.add_argument("-a", "--all",
|
64
|
+
action="store_true",
|
65
|
+
help="Shows all tasks required for the subject to run")
|
66
|
+
show_parser.add_argument("-v", "--verbose",
|
67
|
+
action="store_true",
|
68
|
+
help="Shows additional information about tasks")
|
69
|
+
show_parser.set_defaults(func=CmdShow())
|
70
|
+
|
46
71
|
return parser
|
47
72
|
|
48
73
|
def main():
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* cmd_graph.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import asyncio
|
23
|
+
import os
|
24
|
+
import logging
|
25
|
+
from typing import ClassVar
|
26
|
+
from ..util import loadProjPkgDef
|
27
|
+
from ..task_graph_builder import TaskGraphBuilder
|
28
|
+
from ..task_runner import TaskSetRunner
|
29
|
+
from ..task_listener_log import TaskListenerLog
|
30
|
+
from ..pkg_rgy import PkgRgy
|
31
|
+
from ..task_graph_dot_writer import TaskGraphDotWriter
|
32
|
+
|
33
|
+
|
34
|
+
class CmdGraph(object):
|
35
|
+
_log : ClassVar = logging.getLogger("CmdGraph")
|
36
|
+
|
37
|
+
def __call__(self, args):
|
38
|
+
|
39
|
+
# First, find the project we're working with
|
40
|
+
pkg = loadProjPkgDef(os.getcwd())
|
41
|
+
|
42
|
+
if pkg is None:
|
43
|
+
raise Exception("Failed to find a 'flow.dv' file that defines a package in %s or its parent directories" % os.getcwd())
|
44
|
+
|
45
|
+
self._log.debug("Root flow file defines package: %s" % pkg.name)
|
46
|
+
|
47
|
+
if args.task is None:
|
48
|
+
# Print out available tasks
|
49
|
+
tasks = []
|
50
|
+
for task in pkg.tasks:
|
51
|
+
tasks.append(task)
|
52
|
+
for frag in pkg._fragment_l:
|
53
|
+
for task in frag.tasks:
|
54
|
+
tasks.append(task)
|
55
|
+
tasks.sort(key=lambda x: x.name)
|
56
|
+
|
57
|
+
max_name_len = 0
|
58
|
+
for t in tasks:
|
59
|
+
if len(t.name) > max_name_len:
|
60
|
+
max_name_len = len(t.name)
|
61
|
+
|
62
|
+
print("No task specified. Available Tasks:")
|
63
|
+
for t in tasks:
|
64
|
+
desc = t.desc
|
65
|
+
if desc is None or t.desc == "":
|
66
|
+
"<no descripion>"
|
67
|
+
print("%s - %s" % (t.name.ljust(max_name_len), desc))
|
68
|
+
else:
|
69
|
+
rundir = os.path.join(pkg._basedir, "rundir")
|
70
|
+
|
71
|
+
builder = TaskGraphBuilder(root_pkg=pkg, rundir=rundir)
|
72
|
+
|
73
|
+
t = builder.mkTaskGraph(pkg.name + "." + args.task)
|
74
|
+
|
75
|
+
TaskGraphDotWriter().write(
|
76
|
+
t,
|
77
|
+
"-"
|
78
|
+
)
|
79
|
+
|
80
|
+
return 0
|
81
|
+
|
82
|
+
|
dv_flow/mgr/cmds/cmd_run.py
CHANGED
@@ -50,7 +50,7 @@ class CmdRun(object):
|
|
50
50
|
tasks = []
|
51
51
|
for task in pkg.tasks:
|
52
52
|
tasks.append(task)
|
53
|
-
for frag in pkg.
|
53
|
+
for frag in pkg._fragment_l:
|
54
54
|
for task in frag.tasks:
|
55
55
|
tasks.append(task)
|
56
56
|
tasks.sort(key=lambda x: x.name)
|
@@ -75,7 +75,7 @@ class CmdRun(object):
|
|
75
75
|
# Maybe separate into a task-graph builder and a task-graph runner
|
76
76
|
|
77
77
|
# TODO: allow user to specify run root -- maybe relative to some fixed directory?
|
78
|
-
rundir = os.path.join(pkg.
|
78
|
+
rundir = os.path.join(pkg._basedir, "rundir")
|
79
79
|
|
80
80
|
builder = TaskGraphBuilder(root_pkg=pkg, rundir=rundir)
|
81
81
|
runner = TaskSetRunner(rundir)
|
@@ -0,0 +1,107 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* cmd_show.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023-2025 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import asyncio
|
23
|
+
import os
|
24
|
+
import logging
|
25
|
+
import toposort
|
26
|
+
from typing import ClassVar
|
27
|
+
from ..util import loadProjPkgDef
|
28
|
+
from ..task_graph_builder import TaskGraphBuilder
|
29
|
+
from ..task_runner import TaskSetRunner
|
30
|
+
from ..task_listener_log import TaskListenerLog
|
31
|
+
from ..pkg_rgy import PkgRgy
|
32
|
+
from ..task_graph_dot_writer import TaskGraphDotWriter
|
33
|
+
|
34
|
+
|
35
|
+
class CmdShow(object):
|
36
|
+
_log : ClassVar = logging.getLogger("CmdGraph")
|
37
|
+
|
38
|
+
def __call__(self, args):
|
39
|
+
|
40
|
+
# First, find the project we're working with
|
41
|
+
pkg = loadProjPkgDef(os.getcwd())
|
42
|
+
|
43
|
+
if pkg is None:
|
44
|
+
raise Exception("Failed to find a 'flow.dv' file that defines a package in %s or its parent directories" % os.getcwd())
|
45
|
+
|
46
|
+
self._log.debug("Root flow file defines package: %s" % pkg.name)
|
47
|
+
|
48
|
+
if args.task is None:
|
49
|
+
# Print out available tasks
|
50
|
+
tasks = []
|
51
|
+
for task in pkg.tasks:
|
52
|
+
tasks.append(task)
|
53
|
+
for frag in pkg._fragment_l:
|
54
|
+
for task in frag.tasks:
|
55
|
+
tasks.append(task)
|
56
|
+
tasks.sort(key=lambda x: x.name)
|
57
|
+
|
58
|
+
max_name_len = 0
|
59
|
+
for t in tasks:
|
60
|
+
if len(t.name) > max_name_len:
|
61
|
+
max_name_len = len(t.name)
|
62
|
+
|
63
|
+
print("No task specified. Available Tasks:")
|
64
|
+
for t in tasks:
|
65
|
+
desc = t.desc
|
66
|
+
if desc is None or t.desc == "":
|
67
|
+
"<no descripion>"
|
68
|
+
print("%s - %s" % (t.name.ljust(max_name_len), desc))
|
69
|
+
else:
|
70
|
+
rundir = os.path.join(pkg._basedir, "rundir")
|
71
|
+
|
72
|
+
builder = TaskGraphBuilder(root_pkg=pkg, rundir=rundir)
|
73
|
+
|
74
|
+
|
75
|
+
if args.all:
|
76
|
+
t = builder.mkTaskGraph(pkg.name + "." + args.task)
|
77
|
+
dep_m = TaskSetRunner(rundir=None).buildDepMap(t)
|
78
|
+
|
79
|
+
order = list(toposort.toposort(dep_m))
|
80
|
+
|
81
|
+
print("Task: %s" % t.name)
|
82
|
+
|
83
|
+
last_s = set()
|
84
|
+
for i,s in enumerate(order):
|
85
|
+
print("-- TaskSet %d --" % (i+1))
|
86
|
+
for t in s:
|
87
|
+
print(" - %s" % t.name)
|
88
|
+
if args.verbose and len(t.params.model_fields.items()):
|
89
|
+
print(" params:")
|
90
|
+
for name,field in t.params.model_fields.items():
|
91
|
+
print(" - %s: %s" % (name, getattr(t.params, name)))
|
92
|
+
if len(t.needs):
|
93
|
+
print(" needs:")
|
94
|
+
for n in t.needs:
|
95
|
+
print(" - %s%s" % (
|
96
|
+
n[0].name,
|
97
|
+
("*" if n[0] in last_s else "")))
|
98
|
+
last_s = s
|
99
|
+
|
100
|
+
pass
|
101
|
+
else:
|
102
|
+
# Show show info about the current task
|
103
|
+
pass
|
104
|
+
|
105
|
+
return 0
|
106
|
+
|
107
|
+
|
dv_flow/mgr/fileset.py
CHANGED
@@ -29,6 +29,7 @@ class FileSet(BaseModel):
|
|
29
29
|
basedir : str
|
30
30
|
name : str = ""
|
31
31
|
src : str = None
|
32
|
+
seq : int = -1
|
32
33
|
files : List[str] = dc.Field(default_factory=list)
|
33
34
|
incdirs: List[str] = dc.Field(default_factory=list)
|
34
35
|
params : Dict[str,str] = dc.Field(default_factory=dict)
|
dv_flow/mgr/fragment_def.py
CHANGED
@@ -34,7 +34,7 @@ class FragmentDef(BaseModel):
|
|
34
34
|
fragments: List[str] = dc.Field(default_factory=list)
|
35
35
|
types : List[TypeDef] = dc.Field(default_factory=list)
|
36
36
|
|
37
|
-
|
37
|
+
_basedir : str = None
|
38
38
|
|
39
39
|
def getTask(self, name : str) -> 'TaskDef':
|
40
40
|
for t in self.tasks:
|
dv_flow/mgr/package.py
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
import dataclasses as dc
|
23
23
|
import logging
|
24
24
|
from typing import Any, ClassVar, Dict
|
25
|
-
from .
|
25
|
+
from .task_node_ctor import TaskNodeCtor
|
26
26
|
|
27
27
|
@dc.dataclass
|
28
28
|
class Package(object):
|
@@ -30,11 +30,11 @@ class Package(object):
|
|
30
30
|
params : Dict[str,Any] = dc.field(default_factory=dict)
|
31
31
|
# Package holds constructors for tasks
|
32
32
|
# - Dict holds the default parameters for the task
|
33
|
-
tasks : Dict[str,
|
33
|
+
tasks : Dict[str,TaskNodeCtor] = dc.field(default_factory=dict)
|
34
34
|
types : Dict[str,Any] = dc.field(default_factory=dict)
|
35
35
|
_log : ClassVar = logging.getLogger("Package")
|
36
36
|
|
37
|
-
def getTaskCtor(self, name : str) ->
|
37
|
+
def getTaskCtor(self, name : str) -> TaskNodeCtor:
|
38
38
|
self._log.debug("-- %s::getTaskCtor: %s" % (self.name, name))
|
39
39
|
if name not in self.tasks.keys():
|
40
40
|
raise Exception("Task %s not present in package %s" % (name, self.name))
|
dv_flow/mgr/package_def.py
CHANGED
@@ -21,7 +21,6 @@
|
|
21
21
|
#****************************************************************************
|
22
22
|
import io
|
23
23
|
import os
|
24
|
-
import json
|
25
24
|
import yaml
|
26
25
|
import importlib
|
27
26
|
import logging
|
@@ -34,10 +33,13 @@ from .fragment_def import FragmentDef
|
|
34
33
|
from .package import Package
|
35
34
|
from .package_import_spec import PackageImportSpec, PackageSpec
|
36
35
|
from .param_def import ParamDef
|
37
|
-
from .
|
38
|
-
from .
|
39
|
-
from .
|
40
|
-
from .
|
36
|
+
from .task_def import TaskDef
|
37
|
+
from .task_node_ctor import TaskNodeCtor
|
38
|
+
from .task_node_ctor_proxy import TaskNodeCtorProxy
|
39
|
+
from .task_node_ctor_task import TaskNodeCtorTask
|
40
|
+
from .task_node_ctor_compound import TaskNodeCtorCompound
|
41
|
+
from .task_node_ctor_compound_proxy import TaskNodeCtorCompoundProxy
|
42
|
+
from .std.task_null import TaskNull
|
41
43
|
from .type_def import TypeDef
|
42
44
|
|
43
45
|
|
@@ -63,15 +65,33 @@ class PackageDef(BaseModel):
|
|
63
65
|
default_factory=list, alias="with",
|
64
66
|
description="List of package parameters to set")
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
+
_fragment_l : List['FragmentDef'] = []
|
69
|
+
_subpkg_m : Dict[str,'PackageDef'] = {}
|
68
70
|
|
69
71
|
# import_m : Dict['PackageSpec','Package'] = dc.Field(default_factory=dict)
|
70
72
|
|
71
|
-
|
73
|
+
_basedir : str = None
|
72
74
|
_log : ClassVar = logging.getLogger("PackageDef")
|
73
75
|
|
76
|
+
@property
|
77
|
+
def fragment_l(self):
|
78
|
+
return self._fragment_l
|
79
|
+
|
80
|
+
@property
|
81
|
+
def subpkg_m(self):
|
82
|
+
return self._subpkg_m
|
83
|
+
|
84
|
+
@property
|
85
|
+
def basedir(self):
|
86
|
+
return self._basedir
|
87
|
+
|
88
|
+
@basedir.setter
|
89
|
+
def basedir(self, v):
|
90
|
+
self._basedir = v
|
91
|
+
|
74
92
|
def __post_init__(self):
|
93
|
+
self._fragment_l = []
|
94
|
+
self._subpkg_m = {}
|
75
95
|
for t in self.tasks:
|
76
96
|
t.fullname = self.name + "." + t.name
|
77
97
|
|
@@ -86,18 +106,18 @@ class PackageDef(BaseModel):
|
|
86
106
|
|
87
107
|
session.push_package(ret, add=True)
|
88
108
|
|
89
|
-
tasks_m : Dict[str,str,
|
109
|
+
tasks_m : Dict[str,str,TaskNodeCtor]= {}
|
90
110
|
|
91
111
|
for task in self.tasks:
|
92
112
|
if task.name in tasks_m.keys():
|
93
113
|
raise Exception("Duplicate task %s" % task.name)
|
94
|
-
tasks_m[task.name] = (task, self.
|
114
|
+
tasks_m[task.name] = (task, self._basedir, ) # We'll add a TaskNodeCtor later
|
95
115
|
|
96
|
-
for frag in self.
|
116
|
+
for frag in self._fragment_l:
|
97
117
|
for task in frag.tasks:
|
98
118
|
if task.name in tasks_m.keys():
|
99
119
|
raise Exception("Duplicate task %s" % task.name)
|
100
|
-
tasks_m[task.name] = (task, frag.
|
120
|
+
tasks_m[task.name] = (task, frag._basedir, ) # We'll add a TaskNodeCtor later
|
101
121
|
|
102
122
|
# Now we have a unified map of the tasks declared in this package
|
103
123
|
for name in list(tasks_m.keys()):
|
@@ -143,10 +163,23 @@ class PackageDef(BaseModel):
|
|
143
163
|
ctor_t = tasks_m[task_name][2]
|
144
164
|
return ctor_t
|
145
165
|
|
146
|
-
def mkTaskCtor(self, session, task, srcdir, tasks_m) ->
|
166
|
+
def mkTaskCtor(self, session, task, srcdir, tasks_m) -> TaskNodeCtor:
|
147
167
|
self._log.debug("--> %s::mkTaskCtor %s (srcdir: %s)" % (self.name, task.name, srcdir))
|
148
|
-
|
149
|
-
|
168
|
+
|
169
|
+
if len(task.tasks) > 0:
|
170
|
+
# Compound task
|
171
|
+
ctor = self._mkCompoundTaskCtor(session, task, srcdir, tasks_m)
|
172
|
+
else:
|
173
|
+
# Leaf task
|
174
|
+
ctor = self._mkLeafTaskCtor(session, task, srcdir, tasks_m)
|
175
|
+
|
176
|
+
return ctor
|
177
|
+
|
178
|
+
|
179
|
+
def _mkLeafTaskCtor(self, session, task, srcdir, tasks_m) -> TaskNodeCtor:
|
180
|
+
self._log.debug("--> _mkLeafTaskCtor")
|
181
|
+
base_ctor_t : TaskNodeCtor = None
|
182
|
+
ctor_t : TaskNodeCtor = None
|
150
183
|
base_params : BaseModel = None
|
151
184
|
callable = None
|
152
185
|
passthrough = task.passthrough
|
@@ -179,14 +212,14 @@ class PackageDef(BaseModel):
|
|
179
212
|
|
180
213
|
try:
|
181
214
|
if modname not in sys.modules:
|
182
|
-
if self.
|
183
|
-
sys.path.append(self.
|
215
|
+
if self._basedir not in sys.path:
|
216
|
+
sys.path.append(self._basedir)
|
184
217
|
mod = importlib.import_module(modname)
|
185
218
|
else:
|
186
219
|
mod = sys.modules[modname]
|
187
220
|
except ModuleNotFoundError as e:
|
188
|
-
raise Exception("Failed to import module %s (
|
189
|
-
modname, self.
|
221
|
+
raise Exception("Failed to import module %s (_basedir=%s): %s" % (
|
222
|
+
modname, self._basedir, str(e)))
|
190
223
|
|
191
224
|
if not hasattr(mod, clsname):
|
192
225
|
raise Exception("Method %s not found in module %s" % (clsname, modname))
|
@@ -227,7 +260,62 @@ class PackageDef(BaseModel):
|
|
227
260
|
|
228
261
|
self._log.debug("<-- %s::mkTaskCtor %s" % (self.name, task.name))
|
229
262
|
return ctor_t
|
230
|
-
|
263
|
+
|
264
|
+
def _mkCompoundTaskCtor(self, session, task, srcdir, tasks_m) -> TaskNodeCtor:
|
265
|
+
self._log.debug("--> _mkCompoundTaskCtor")
|
266
|
+
base_ctor_t : TaskNodeCtor = None
|
267
|
+
ctor_t : TaskNodeCtor = None
|
268
|
+
base_params : BaseModel = None
|
269
|
+
callable = None
|
270
|
+
passthrough = task.passthrough
|
271
|
+
consumes = [] if task.consumes is None else task.consumes.copy()
|
272
|
+
needs = [] if task.needs is None else task.needs.copy()
|
273
|
+
fullname = self.name + "." + task.name
|
274
|
+
|
275
|
+
|
276
|
+
if task.uses is not None:
|
277
|
+
self._log.debug("Uses: %s" % task.uses)
|
278
|
+
base_ctor_t = self.getTaskCtor(session, task.uses, tasks_m)
|
279
|
+
base_params = base_ctor_t.mkTaskParams()
|
280
|
+
|
281
|
+
# Once we have passthrough, we can't turn it off
|
282
|
+
passthrough |= base_ctor_t.passthrough
|
283
|
+
consumes.extend(base_ctor_t.consumes)
|
284
|
+
|
285
|
+
if base_ctor_t is None:
|
286
|
+
self._log.error("Failed to load task ctor %s" % task.uses)
|
287
|
+
|
288
|
+
# Determine if we need to use a new
|
289
|
+
paramT = self._getParamT(session, task, base_params)
|
290
|
+
|
291
|
+
if base_ctor_t is not None:
|
292
|
+
ctor_t = TaskNodeCtorCompoundProxy(
|
293
|
+
name=fullname,
|
294
|
+
srcdir=srcdir,
|
295
|
+
paramT=paramT,
|
296
|
+
passthrough=passthrough,
|
297
|
+
consumes=consumes,
|
298
|
+
needs=needs,
|
299
|
+
task_def=task,
|
300
|
+
uses=base_ctor_t)
|
301
|
+
else:
|
302
|
+
self._log.debug("No 'uses' specified")
|
303
|
+
ctor_t = TaskNodeCtorCompound(
|
304
|
+
name=fullname,
|
305
|
+
srcdir=srcdir,
|
306
|
+
paramT=paramT,
|
307
|
+
passthrough=passthrough,
|
308
|
+
consumes=consumes,
|
309
|
+
needs=needs,
|
310
|
+
task_def=task)
|
311
|
+
|
312
|
+
for t in task.tasks:
|
313
|
+
ctor_t.tasks.append(self.mkTaskCtor(session, t, srcdir, tasks_m))
|
314
|
+
|
315
|
+
|
316
|
+
self._log.debug("<-- %s::mkTaskCtor %s (%d)" % (self.name, task.name, len(ctor_t.tasks)))
|
317
|
+
return ctor_t
|
318
|
+
|
231
319
|
def _getParamT(self, session, task, base_t : BaseModel):
|
232
320
|
self._log.debug("--> _getParamT %s" % task.fullname)
|
233
321
|
# Get the base parameter type (if available)
|
@@ -326,10 +414,10 @@ class PackageDef(BaseModel):
|
|
326
414
|
except Exception as e:
|
327
415
|
PackageDef._log.error("Failed to load package from %s" % root)
|
328
416
|
raise e
|
329
|
-
pkg.
|
417
|
+
pkg._basedir = os.path.dirname(root)
|
330
418
|
|
331
419
|
# for t in pkg.tasks:
|
332
|
-
# t.
|
420
|
+
# t._basedir = os.path.dirname(root)
|
333
421
|
|
334
422
|
if exp_pkg_name is not None:
|
335
423
|
if exp_pkg_name != pkg.name:
|
@@ -347,7 +435,7 @@ class PackageDef(BaseModel):
|
|
347
435
|
PackageDef._loadFragmentSpec(pkg, spec, file_s)
|
348
436
|
|
349
437
|
if len(pkg.imports) > 0:
|
350
|
-
cls._log.info("Loading imported packages (
|
438
|
+
cls._log.info("Loading imported packages (_basedir=%s)" % pkg._basedir)
|
351
439
|
for imp in pkg.imports:
|
352
440
|
if type(imp) == str:
|
353
441
|
imp_path = imp
|
@@ -359,8 +447,8 @@ class PackageDef(BaseModel):
|
|
359
447
|
cls._log.info("Loading imported package %s" % imp_path)
|
360
448
|
|
361
449
|
if not os.path.isabs(imp_path):
|
362
|
-
cls._log.debug("
|
363
|
-
imp_path = os.path.join(pkg.
|
450
|
+
cls._log.debug("_basedir: %s ; imp_path: %s" % (pkg._basedir, imp_path))
|
451
|
+
imp_path = os.path.join(pkg._basedir, imp_path)
|
364
452
|
|
365
453
|
# Search down the tree looking for a flow.dv file
|
366
454
|
if os.path.isdir(imp_path):
|
@@ -389,7 +477,7 @@ class PackageDef(BaseModel):
|
|
389
477
|
|
390
478
|
sub_pkg = PackageDef.load(imp_path)
|
391
479
|
cls._log.info("Loaded imported package %s" % sub_pkg.name)
|
392
|
-
pkg.
|
480
|
+
pkg._subpkg_m[sub_pkg.name] = sub_pkg
|
393
481
|
|
394
482
|
file_s.pop()
|
395
483
|
|
@@ -407,10 +495,10 @@ class PackageDef(BaseModel):
|
|
407
495
|
if "package" not in doc.keys():
|
408
496
|
raise Exception("Missing 'package' key in %s" % root)
|
409
497
|
pkg = PackageDef(**(doc["package"]))
|
410
|
-
pkg.
|
498
|
+
pkg._basedir = None
|
411
499
|
|
412
500
|
# for t in pkg.tasks:
|
413
|
-
# t.
|
501
|
+
# t._basedir = os.path.dirname(root)
|
414
502
|
|
415
503
|
if exp_pkg_name is not None:
|
416
504
|
if exp_pkg_name != pkg.name:
|
@@ -427,10 +515,10 @@ class PackageDef(BaseModel):
|
|
427
515
|
# - File path
|
428
516
|
# - Directory path
|
429
517
|
|
430
|
-
if os.path.isfile(os.path.join(pkg.
|
518
|
+
if os.path.isfile(os.path.join(pkg._basedir, spec)):
|
431
519
|
PackageDef._loadFragmentFile(pkg, spec, file_s)
|
432
|
-
elif os.path.isdir(os.path.join(pkg.
|
433
|
-
PackageDef._loadFragmentDir(pkg, os.path.join(pkg.
|
520
|
+
elif os.path.isdir(os.path.join(pkg._basedir, spec)):
|
521
|
+
PackageDef._loadFragmentDir(pkg, os.path.join(pkg._basedir, spec), file_s)
|
434
522
|
else:
|
435
523
|
raise Exception("Fragment spec %s not found" % spec)
|
436
524
|
|
@@ -454,7 +542,7 @@ class PackageDef(BaseModel):
|
|
454
542
|
if "fragment" in doc.keys():
|
455
543
|
# Merge the package definition
|
456
544
|
frag = FragmentDef(**(doc["fragment"]))
|
457
|
-
frag.
|
458
|
-
pkg.
|
545
|
+
frag._basedir = os.path.dirname(file)
|
546
|
+
pkg._fragment_l.append(frag)
|
459
547
|
else:
|
460
548
|
print("Warning: file %s is not a fragment" % file)
|
dv_flow/mgr/param_def.py
CHANGED
@@ -23,15 +23,20 @@ from typing import Any, List, Union
|
|
23
23
|
from pydantic import BaseModel, Field
|
24
24
|
|
25
25
|
class ListType(BaseModel):
|
26
|
-
item : Union[str, 'ComplexType']
|
26
|
+
# item : Union[str, 'ComplexType']
|
27
|
+
item : Union[str, Any]
|
27
28
|
|
28
29
|
class MapType(BaseModel):
|
29
|
-
key : Union[str, 'ComplexType']
|
30
|
-
item : Union[str, 'ComplexType']
|
30
|
+
# key : Union[str, 'ComplexType']
|
31
|
+
# item : Union[str, 'ComplexType']
|
32
|
+
key : Union[str, Any]
|
33
|
+
item : Union[str, Any]
|
31
34
|
|
32
35
|
class ComplexType(BaseModel):
|
33
36
|
list : Union[ListType, None] = None
|
34
37
|
map : Union[MapType, None] = None
|
38
|
+
# list : Union[Any, None] = None
|
39
|
+
# map : Union[Any, None] = None
|
35
40
|
|
36
41
|
class ParamDef(BaseModel):
|
37
42
|
doc : str = None
|
dv_flow/mgr/std/message.py
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
#* Author:
|
20
20
|
#*
|
21
21
|
#****************************************************************************
|
22
|
-
from dv_flow.mgr import
|
22
|
+
from dv_flow.mgr import TaskDataResult
|
23
23
|
|
24
24
|
async def Message(runner, input) -> TaskDataResult:
|
25
25
|
print("%s: %s" % (input.name, input.params.msg), flush=True)
|