graph2cwl 0.0.1__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.
- graph2cwl-0.0.1/PKG-INFO +96 -0
- graph2cwl-0.0.1/README.md +88 -0
- graph2cwl-0.0.1/pyproject.toml +8 -0
- graph2cwl-0.0.1/setup.cfg +4 -0
- graph2cwl-0.0.1/src/graph2cwl/__init__.py +1 -0
- graph2cwl-0.0.1/src/graph2cwl/creator.py +264 -0
- graph2cwl-0.0.1/src/graph2cwl.egg-info/PKG-INFO +96 -0
- graph2cwl-0.0.1/src/graph2cwl.egg-info/SOURCES.txt +9 -0
- graph2cwl-0.0.1/src/graph2cwl.egg-info/dependency_links.txt +1 -0
- graph2cwl-0.0.1/src/graph2cwl.egg-info/requires.txt +1 -0
- graph2cwl-0.0.1/src/graph2cwl.egg-info/top_level.txt +1 -0
graph2cwl-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: graph2cwl
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Helper to generate cwl workflows
|
|
5
|
+
Requires-Python: >=3.13
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: cwl-utils>=0.40
|
|
8
|
+
|
|
9
|
+
# graph2cwl
|
|
10
|
+
|
|
11
|
+
Python module that interfaces with cwl-utils in order to generate cwl files.
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install graph2cwl
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Here is a code snippet :
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from graph2cwl import WorkflowCreator
|
|
23
|
+
|
|
24
|
+
wf = WorkflowCreator(id="wf")
|
|
25
|
+
wf.add_step(id="step_1", run="./my_file.py")
|
|
26
|
+
wf.add_step(id="step_2", run="./my_file_2.py")
|
|
27
|
+
wf.add_dependency("step_1", "step_2", dep_name="step_1_out")
|
|
28
|
+
wf.add_workflow_input("input_1")
|
|
29
|
+
wf.add_workflow_output("output", outputSource="step_1/step_1_out")
|
|
30
|
+
wf.add_dependency("input_1", "step_2")
|
|
31
|
+
wf.add_dependency("input_1", "step_1")
|
|
32
|
+
|
|
33
|
+
wf.to_yaml("wf.yaml")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This creates the following valid cwl:
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
id: w
|
|
40
|
+
class: Workflow
|
|
41
|
+
inputs:
|
|
42
|
+
- id: input_1
|
|
43
|
+
type: File
|
|
44
|
+
outputs:
|
|
45
|
+
- id: output
|
|
46
|
+
outputSource: step_1/step_1_out
|
|
47
|
+
type: File
|
|
48
|
+
cwlVersion: v1.2
|
|
49
|
+
steps:
|
|
50
|
+
- id: step_1
|
|
51
|
+
in:
|
|
52
|
+
- id: xehsftvk
|
|
53
|
+
source: input_1
|
|
54
|
+
out:
|
|
55
|
+
- step_1_out
|
|
56
|
+
run: my_file.py
|
|
57
|
+
- id: step_2
|
|
58
|
+
in:
|
|
59
|
+
- id: fwfmzpkk
|
|
60
|
+
source: step_1/step_1_out
|
|
61
|
+
- id: ellhmrzg
|
|
62
|
+
source: input_1
|
|
63
|
+
out: []
|
|
64
|
+
run: my_file_2.py
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
which can be visualized (see [cwl2nx](https://github.com/mariusgarenaux/cwl2nx)):
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
• w/input_1
|
|
71
|
+
├─• w/step_1
|
|
72
|
+
│ ╰─• w/step_1/step_1_out
|
|
73
|
+
│ ├─• w/output
|
|
74
|
+
╰───┴─• w/step_2
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Advanced usage
|
|
78
|
+
|
|
79
|
+
To embed the cwl with additionnal information, you must follow the cwl specification, implemented in cwl-utils. For example, to insert additional informations to a step, you can add the `hints` argument, or the `extension_field` one :
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from graph2cwl import WorkflowCreator
|
|
83
|
+
|
|
84
|
+
wf = WorkflowCreator(id="w")
|
|
85
|
+
wf.add_step(id="step_1", run="./my_file.py", hints={"hint1": "value1"})
|
|
86
|
+
wf.add_step(id="step_2", run="./my_file_2.py")
|
|
87
|
+
wf.add_dependency("step_1", "step_2", dep_name="step_1_out")
|
|
88
|
+
wf.add_workflow_input("input_1", extension_fields={"additional_field": "het"})
|
|
89
|
+
wf.add_workflow_output("output", outputSource="step_1/step_1_out")
|
|
90
|
+
wf.add_dependency("input_1", "step_2")
|
|
91
|
+
wf.add_dependency("input_1", "step_1")
|
|
92
|
+
|
|
93
|
+
wf.to_yaml("wf2.yaml")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
See : https://cwl-utils.readthedocs.io/en/latest/autoapi/cwl_utils/parser/cwl_v1_2/index.html#cwl_utils.parser.cwl_v1_2.WorkflowStep for the list of supported arguments.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# graph2cwl
|
|
2
|
+
|
|
3
|
+
Python module that interfaces with cwl-utils in order to generate cwl files.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install graph2cwl
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Here is a code snippet :
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from graph2cwl import WorkflowCreator
|
|
15
|
+
|
|
16
|
+
wf = WorkflowCreator(id="wf")
|
|
17
|
+
wf.add_step(id="step_1", run="./my_file.py")
|
|
18
|
+
wf.add_step(id="step_2", run="./my_file_2.py")
|
|
19
|
+
wf.add_dependency("step_1", "step_2", dep_name="step_1_out")
|
|
20
|
+
wf.add_workflow_input("input_1")
|
|
21
|
+
wf.add_workflow_output("output", outputSource="step_1/step_1_out")
|
|
22
|
+
wf.add_dependency("input_1", "step_2")
|
|
23
|
+
wf.add_dependency("input_1", "step_1")
|
|
24
|
+
|
|
25
|
+
wf.to_yaml("wf.yaml")
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This creates the following valid cwl:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
id: w
|
|
32
|
+
class: Workflow
|
|
33
|
+
inputs:
|
|
34
|
+
- id: input_1
|
|
35
|
+
type: File
|
|
36
|
+
outputs:
|
|
37
|
+
- id: output
|
|
38
|
+
outputSource: step_1/step_1_out
|
|
39
|
+
type: File
|
|
40
|
+
cwlVersion: v1.2
|
|
41
|
+
steps:
|
|
42
|
+
- id: step_1
|
|
43
|
+
in:
|
|
44
|
+
- id: xehsftvk
|
|
45
|
+
source: input_1
|
|
46
|
+
out:
|
|
47
|
+
- step_1_out
|
|
48
|
+
run: my_file.py
|
|
49
|
+
- id: step_2
|
|
50
|
+
in:
|
|
51
|
+
- id: fwfmzpkk
|
|
52
|
+
source: step_1/step_1_out
|
|
53
|
+
- id: ellhmrzg
|
|
54
|
+
source: input_1
|
|
55
|
+
out: []
|
|
56
|
+
run: my_file_2.py
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
which can be visualized (see [cwl2nx](https://github.com/mariusgarenaux/cwl2nx)):
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
• w/input_1
|
|
63
|
+
├─• w/step_1
|
|
64
|
+
│ ╰─• w/step_1/step_1_out
|
|
65
|
+
│ ├─• w/output
|
|
66
|
+
╰───┴─• w/step_2
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Advanced usage
|
|
70
|
+
|
|
71
|
+
To embed the cwl with additionnal information, you must follow the cwl specification, implemented in cwl-utils. For example, to insert additional informations to a step, you can add the `hints` argument, or the `extension_field` one :
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from graph2cwl import WorkflowCreator
|
|
75
|
+
|
|
76
|
+
wf = WorkflowCreator(id="w")
|
|
77
|
+
wf.add_step(id="step_1", run="./my_file.py", hints={"hint1": "value1"})
|
|
78
|
+
wf.add_step(id="step_2", run="./my_file_2.py")
|
|
79
|
+
wf.add_dependency("step_1", "step_2", dep_name="step_1_out")
|
|
80
|
+
wf.add_workflow_input("input_1", extension_fields={"additional_field": "het"})
|
|
81
|
+
wf.add_workflow_output("output", outputSource="step_1/step_1_out")
|
|
82
|
+
wf.add_dependency("input_1", "step_2")
|
|
83
|
+
wf.add_dependency("input_1", "step_1")
|
|
84
|
+
|
|
85
|
+
wf.to_yaml("wf2.yaml")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
See : https://cwl-utils.readthedocs.io/en/latest/autoapi/cwl_utils/parser/cwl_v1_2/index.html#cwl_utils.parser.cwl_v1_2.WorkflowStep for the list of supported arguments.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .creator import WorkflowCreator, WorkflowStepCreator
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Base python dependencies
|
|
2
|
+
from typing import Literal, Optional, Any, Type
|
|
3
|
+
import random
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
# Externel dependencies
|
|
7
|
+
from ruamel.yaml import YAML
|
|
8
|
+
from cwl_utils.parser import cwl_v1_0, cwl_v1_1, cwl_v1_2
|
|
9
|
+
|
|
10
|
+
CWLVersion = Literal["v1.0", "v1.1", "v1.2"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def random_name():
|
|
14
|
+
return "".join(
|
|
15
|
+
random.choice(re.escape("abcdefghijklmnopqrstuvwxyz")) for _ in range(8)
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class WorkflowStepCreator:
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
WorkflowStep: (
|
|
23
|
+
Type[cwl_v1_0.WorkflowStep]
|
|
24
|
+
| Type[cwl_v1_1.WorkflowStep]
|
|
25
|
+
| Type[cwl_v1_2.WorkflowStep]
|
|
26
|
+
),
|
|
27
|
+
id: str,
|
|
28
|
+
kwargs: Optional[dict[str, Any]] = None,
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Buffer class of cwl_utils WorkflowStep; that stores the initialization arguments
|
|
32
|
+
while the dependencies between task are created.
|
|
33
|
+
"""
|
|
34
|
+
self.WorkflowStep = WorkflowStep
|
|
35
|
+
self.id = id
|
|
36
|
+
if kwargs is None:
|
|
37
|
+
kwargs = {}
|
|
38
|
+
self.kwargs = kwargs
|
|
39
|
+
|
|
40
|
+
if self.kwargs.get("out", None) is None:
|
|
41
|
+
self.kwargs["out"] = []
|
|
42
|
+
|
|
43
|
+
if self.kwargs.get("in_", None) is None:
|
|
44
|
+
self.kwargs["in_"] = []
|
|
45
|
+
|
|
46
|
+
def create_cwl_utils_obj(
|
|
47
|
+
self,
|
|
48
|
+
) -> cwl_v1_0.WorkflowStep | cwl_v1_1.WorkflowStep | cwl_v1_2.WorkflowStep:
|
|
49
|
+
return self.WorkflowStep(id=self.id, **self.kwargs)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class WorkflowCreator:
|
|
53
|
+
"""
|
|
54
|
+
Helper class that allows to create cwl files, only from the steps.
|
|
55
|
+
It deals with WorkflowStepInput, WorkflowStepOutput so that
|
|
56
|
+
the end user does not have to use them.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(self, cwl_version: CWLVersion = "v1.2", id: Optional[str] = None):
|
|
60
|
+
if cwl_version not in ["v1.0", "v1.1", "v1.2"]:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
f"Unexpected cwl version : `{cwl_version}`. Expected one among `v1.0`, `v1.1`, `v1.2`."
|
|
63
|
+
)
|
|
64
|
+
match cwl_version:
|
|
65
|
+
case "v1.0":
|
|
66
|
+
self.cwl_module = cwl_v1_0
|
|
67
|
+
case "v1.1":
|
|
68
|
+
self.cwl_module = cwl_v1_1
|
|
69
|
+
case "v1.2":
|
|
70
|
+
self.cwl_module = cwl_v1_2
|
|
71
|
+
|
|
72
|
+
self.cwl_version = cwl_version
|
|
73
|
+
self.id = id
|
|
74
|
+
self.WorkflowStep = self.cwl_module.WorkflowStep
|
|
75
|
+
self.WorkflowOutputParameter = self.cwl_module.WorkflowOutputParameter
|
|
76
|
+
if hasattr(self.cwl_module, "WorkflowInputParameter"):
|
|
77
|
+
self.WorkflowInputParameter = (
|
|
78
|
+
self.cwl_module.WorkflowInputParameter # pyright: ignore
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
self.WorkflowStepInput = self.cwl_module.WorkflowStepInput
|
|
82
|
+
self.WorkflowStepOutput = self.cwl_module.WorkflowStepOutput
|
|
83
|
+
self.Workflow = self.cwl_module.Workflow
|
|
84
|
+
|
|
85
|
+
self.all_step_creators: dict[str, WorkflowStepCreator] = {}
|
|
86
|
+
self.all_workflow_inputs: dict[str, Any] = {}
|
|
87
|
+
self.all_workflow_outputs: dict[str, Any] = {}
|
|
88
|
+
|
|
89
|
+
def add_step(
|
|
90
|
+
self,
|
|
91
|
+
id: str,
|
|
92
|
+
**kwargs,
|
|
93
|
+
) -> WorkflowStepCreator:
|
|
94
|
+
"""
|
|
95
|
+
Adds a step to the workflow creator.
|
|
96
|
+
|
|
97
|
+
Parameters :
|
|
98
|
+
---
|
|
99
|
+
- id (str): the name of the step
|
|
100
|
+
- **kwargs : any named arguments (different of the one above)
|
|
101
|
+
that will be given to cwl_utils.parser.cwl_<version>.WorkflowStep creator.
|
|
102
|
+
"""
|
|
103
|
+
new_step = WorkflowStepCreator(self.WorkflowStep, id=id, kwargs=kwargs)
|
|
104
|
+
self.all_step_creators[id] = new_step
|
|
105
|
+
return new_step
|
|
106
|
+
|
|
107
|
+
def _add_dependency_from_input_param_to_step(
|
|
108
|
+
self, from_input: str, to_step: str, dep_name: Optional[str] = None
|
|
109
|
+
):
|
|
110
|
+
if from_input not in self.all_workflow_inputs:
|
|
111
|
+
raise KeyError(
|
|
112
|
+
f"No workflow input parameter was found with id `{from_input}`. Available inputs are : {self.all_workflow_inputs}"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if to_step not in self.all_step_creators:
|
|
116
|
+
raise KeyError(
|
|
117
|
+
f"Could not find any step of the workflow with id `{to_step}`"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
end_step = self.all_step_creators[to_step]
|
|
121
|
+
|
|
122
|
+
dep_name = random_name() if dep_name is None else dep_name
|
|
123
|
+
|
|
124
|
+
# creates output of start step
|
|
125
|
+
|
|
126
|
+
# creates input parameter for the end step
|
|
127
|
+
step_input = self.WorkflowStepInput(dep_name, source=from_input)
|
|
128
|
+
end_step.kwargs["in_"].append(step_input)
|
|
129
|
+
|
|
130
|
+
def _add_dependency_from_step_to_step(
|
|
131
|
+
self,
|
|
132
|
+
from_step: str,
|
|
133
|
+
to_step: str,
|
|
134
|
+
dep_name: Optional[str] = None,
|
|
135
|
+
):
|
|
136
|
+
"""
|
|
137
|
+
Creates a dependency between the step with id `from_step` and
|
|
138
|
+
the one with if `to_step`.
|
|
139
|
+
"""
|
|
140
|
+
if from_step not in self.all_step_creators:
|
|
141
|
+
raise KeyError(
|
|
142
|
+
f"Could not find any step of the workflow with id `{from_step}`"
|
|
143
|
+
)
|
|
144
|
+
if to_step not in self.all_step_creators:
|
|
145
|
+
raise KeyError(
|
|
146
|
+
f"Could not find any step of the workflow with id `{to_step}`"
|
|
147
|
+
)
|
|
148
|
+
start_step = self.all_step_creators[from_step]
|
|
149
|
+
end_step = self.all_step_creators[to_step]
|
|
150
|
+
|
|
151
|
+
dep_name = random_name() if dep_name is None else dep_name
|
|
152
|
+
|
|
153
|
+
# creates output of start step
|
|
154
|
+
start_step.kwargs["out"].append(dep_name)
|
|
155
|
+
|
|
156
|
+
# creates input parameter for the end step
|
|
157
|
+
step_input = self.WorkflowStepInput(
|
|
158
|
+
random_name(), source=f"{start_step.id}/{dep_name}"
|
|
159
|
+
)
|
|
160
|
+
end_step.kwargs["in_"].append(step_input)
|
|
161
|
+
|
|
162
|
+
def add_dependency(
|
|
163
|
+
self, from_elem: str, to_step: str, dep_name: Optional[str] = None
|
|
164
|
+
):
|
|
165
|
+
"""
|
|
166
|
+
Creates a dependency between either :
|
|
167
|
+
- a workflow input parameter and a step
|
|
168
|
+
- two steps of the workflow
|
|
169
|
+
|
|
170
|
+
Parameters :
|
|
171
|
+
---
|
|
172
|
+
- from_elem (str): either an id of a input parameter of the workflow,
|
|
173
|
+
or the id of a step. The method first seek for a matching step.
|
|
174
|
+
- to_step (str): the id of the end step
|
|
175
|
+
- dep_name (Optional[str] = None): the name of the dependency
|
|
176
|
+
"""
|
|
177
|
+
if from_elem not in self.all_step_creators:
|
|
178
|
+
if from_elem in self.all_workflow_inputs:
|
|
179
|
+
self._add_dependency_from_input_param_to_step(
|
|
180
|
+
from_elem, to_step, dep_name
|
|
181
|
+
)
|
|
182
|
+
return
|
|
183
|
+
else:
|
|
184
|
+
raise ValueError(
|
|
185
|
+
f"Could not find any object of the workflow with id `{from_elem}`"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
self._add_dependency_from_step_to_step(from_elem, to_step, dep_name)
|
|
189
|
+
|
|
190
|
+
def add_workflow_input(self, id: str, **kwargs):
|
|
191
|
+
"""
|
|
192
|
+
Adds an input to the workflow with id. Any keyword argument can be given,
|
|
193
|
+
it will be forwarded to cwl_utils WorkflowInputParameter constructor.
|
|
194
|
+
"""
|
|
195
|
+
if "type_" not in kwargs:
|
|
196
|
+
kwargs["type_"] = "File"
|
|
197
|
+
|
|
198
|
+
self.all_workflow_inputs[id] = self.WorkflowInputParameter(id=id, **kwargs)
|
|
199
|
+
|
|
200
|
+
def add_workflow_output(self, id: str, **kwargs):
|
|
201
|
+
"""
|
|
202
|
+
Adds an output to the workflow with id. Any keyword argument can be given,
|
|
203
|
+
it will be forwarded to cwl_utils WorkflowInputParameter constructor.
|
|
204
|
+
|
|
205
|
+
Parameters :
|
|
206
|
+
---
|
|
207
|
+
- id (str) : the id of the Workflow Output Parameter
|
|
208
|
+
"""
|
|
209
|
+
if "type_" not in kwargs:
|
|
210
|
+
kwargs["type_"] = "File"
|
|
211
|
+
|
|
212
|
+
self.all_workflow_outputs[id] = self.WorkflowOutputParameter(id=id, **kwargs)
|
|
213
|
+
|
|
214
|
+
def build(self, **kwargs):
|
|
215
|
+
"""
|
|
216
|
+
Creates the cwl_utils Workflow Object
|
|
217
|
+
"""
|
|
218
|
+
all_cwl_steps = []
|
|
219
|
+
for each_step_id, each_step in self.all_step_creators.items():
|
|
220
|
+
try:
|
|
221
|
+
cwl_step = each_step.create_cwl_utils_obj()
|
|
222
|
+
except Exception as e:
|
|
223
|
+
raise Exception(
|
|
224
|
+
f"Could not create the step with id {each_step_id}"
|
|
225
|
+
) from e
|
|
226
|
+
else:
|
|
227
|
+
all_cwl_steps.append(cwl_step)
|
|
228
|
+
|
|
229
|
+
return self.Workflow(
|
|
230
|
+
id=self.id,
|
|
231
|
+
inputs=list(self.all_workflow_inputs.values()),
|
|
232
|
+
outputs=list(self.all_workflow_outputs.values()),
|
|
233
|
+
steps=all_cwl_steps,
|
|
234
|
+
cwlVersion=self.cwl_version,
|
|
235
|
+
**kwargs,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
def to_dict(self, **kwargs) -> dict:
|
|
239
|
+
"""
|
|
240
|
+
Shortcut that calls self.create; followed by cwl_utils save method.
|
|
241
|
+
Returns a YAML/JSON friendly python dictionnary
|
|
242
|
+
"""
|
|
243
|
+
return self.build().save(**kwargs)
|
|
244
|
+
|
|
245
|
+
def to_yaml(self, file_name: str, **kwargs):
|
|
246
|
+
"""
|
|
247
|
+
Build the cwl and save it to a yaml file located at `file_name`
|
|
248
|
+
"""
|
|
249
|
+
yaml = YAML()
|
|
250
|
+
with open(file_name, "wt") as f:
|
|
251
|
+
yaml.dump(self.to_dict(**kwargs), f)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
if __name__ == "__main__":
|
|
255
|
+
wf = WorkflowCreator(id="w")
|
|
256
|
+
wf.add_step(id="step_1", run="./my_file.py")
|
|
257
|
+
wf.add_step(id="step_2", run="./my_file_2.py")
|
|
258
|
+
wf.add_dependency("step_1", "step_2", dep_name="step_1_out")
|
|
259
|
+
wf.add_workflow_input("input_1")
|
|
260
|
+
wf.add_workflow_output("output", outputSource="step_1/step_1_out")
|
|
261
|
+
wf.add_dependency("input_1", "step_2")
|
|
262
|
+
wf.add_dependency("input_1", "step_1")
|
|
263
|
+
|
|
264
|
+
print(wf.to_dict())
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: graph2cwl
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Helper to generate cwl workflows
|
|
5
|
+
Requires-Python: >=3.13
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: cwl-utils>=0.40
|
|
8
|
+
|
|
9
|
+
# graph2cwl
|
|
10
|
+
|
|
11
|
+
Python module that interfaces with cwl-utils in order to generate cwl files.
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install graph2cwl
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Here is a code snippet :
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from graph2cwl import WorkflowCreator
|
|
23
|
+
|
|
24
|
+
wf = WorkflowCreator(id="wf")
|
|
25
|
+
wf.add_step(id="step_1", run="./my_file.py")
|
|
26
|
+
wf.add_step(id="step_2", run="./my_file_2.py")
|
|
27
|
+
wf.add_dependency("step_1", "step_2", dep_name="step_1_out")
|
|
28
|
+
wf.add_workflow_input("input_1")
|
|
29
|
+
wf.add_workflow_output("output", outputSource="step_1/step_1_out")
|
|
30
|
+
wf.add_dependency("input_1", "step_2")
|
|
31
|
+
wf.add_dependency("input_1", "step_1")
|
|
32
|
+
|
|
33
|
+
wf.to_yaml("wf.yaml")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This creates the following valid cwl:
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
id: w
|
|
40
|
+
class: Workflow
|
|
41
|
+
inputs:
|
|
42
|
+
- id: input_1
|
|
43
|
+
type: File
|
|
44
|
+
outputs:
|
|
45
|
+
- id: output
|
|
46
|
+
outputSource: step_1/step_1_out
|
|
47
|
+
type: File
|
|
48
|
+
cwlVersion: v1.2
|
|
49
|
+
steps:
|
|
50
|
+
- id: step_1
|
|
51
|
+
in:
|
|
52
|
+
- id: xehsftvk
|
|
53
|
+
source: input_1
|
|
54
|
+
out:
|
|
55
|
+
- step_1_out
|
|
56
|
+
run: my_file.py
|
|
57
|
+
- id: step_2
|
|
58
|
+
in:
|
|
59
|
+
- id: fwfmzpkk
|
|
60
|
+
source: step_1/step_1_out
|
|
61
|
+
- id: ellhmrzg
|
|
62
|
+
source: input_1
|
|
63
|
+
out: []
|
|
64
|
+
run: my_file_2.py
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
which can be visualized (see [cwl2nx](https://github.com/mariusgarenaux/cwl2nx)):
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
• w/input_1
|
|
71
|
+
├─• w/step_1
|
|
72
|
+
│ ╰─• w/step_1/step_1_out
|
|
73
|
+
│ ├─• w/output
|
|
74
|
+
╰───┴─• w/step_2
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Advanced usage
|
|
78
|
+
|
|
79
|
+
To embed the cwl with additionnal information, you must follow the cwl specification, implemented in cwl-utils. For example, to insert additional informations to a step, you can add the `hints` argument, or the `extension_field` one :
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from graph2cwl import WorkflowCreator
|
|
83
|
+
|
|
84
|
+
wf = WorkflowCreator(id="w")
|
|
85
|
+
wf.add_step(id="step_1", run="./my_file.py", hints={"hint1": "value1"})
|
|
86
|
+
wf.add_step(id="step_2", run="./my_file_2.py")
|
|
87
|
+
wf.add_dependency("step_1", "step_2", dep_name="step_1_out")
|
|
88
|
+
wf.add_workflow_input("input_1", extension_fields={"additional_field": "het"})
|
|
89
|
+
wf.add_workflow_output("output", outputSource="step_1/step_1_out")
|
|
90
|
+
wf.add_dependency("input_1", "step_2")
|
|
91
|
+
wf.add_dependency("input_1", "step_1")
|
|
92
|
+
|
|
93
|
+
wf.to_yaml("wf2.yaml")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
See : https://cwl-utils.readthedocs.io/en/latest/autoapi/cwl_utils/parser/cwl_v1_2/index.html#cwl_utils.parser.cwl_v1_2.WorkflowStep for the list of supported arguments.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/graph2cwl/__init__.py
|
|
4
|
+
src/graph2cwl/creator.py
|
|
5
|
+
src/graph2cwl.egg-info/PKG-INFO
|
|
6
|
+
src/graph2cwl.egg-info/SOURCES.txt
|
|
7
|
+
src/graph2cwl.egg-info/dependency_links.txt
|
|
8
|
+
src/graph2cwl.egg-info/requires.txt
|
|
9
|
+
src/graph2cwl.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cwl-utils>=0.40
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
graph2cwl
|