Skip to content

Commit 9f3b9e7

Browse files
authored
abstract operation (#1255)
* Update to schema with Operation defined * Accept and check for abstract operations * Since we only support Python 3 now, can lift the pytest pin.
1 parent d32d569 commit 9f3b9e7

17 files changed

+246
-41
lines changed

cwltool/checker.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,7 @@ def check_all_types(src_dict, sinks, sourceField, param_to_step):
397397
return validation
398398

399399

400-
def is_conditional_step(param_to_step: Dict[str, Dict[str, Any]],
401-
parm_id: str) -> bool:
400+
def is_conditional_step(param_to_step: Dict[str, Dict[str, Any]], parm_id: str) -> bool:
402401
source_step = param_to_step.get(parm_id)
403402
if source_step is not None:
404403
if source_step.get("when") is not None:

cwltool/command_line_tool.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,17 @@ def job(
162162
yield job
163163

164164

165+
class AbstractOperation(Process):
166+
def job(
167+
self,
168+
job_order, # type: Mapping[str, str]
169+
output_callbacks, # type: Callable[[Any, Any], Any]
170+
runtimeContext, # type: RuntimeContext
171+
):
172+
# type: (...) -> Generator[ExpressionTool.ExpressionJob, None, None]
173+
raise WorkflowException("Abstract operation cannot be executed.")
174+
175+
165176
def remove_path(f): # type: (Dict[str, Any]) -> None
166177
if "path" in f:
167178
del f["path"]

cwltool/docker.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,18 +224,16 @@ def append_volume(runtime, source, target, writable=False):
224224
# type: (List[str], str, str, bool) -> None
225225
"""Add binding arguments to the runtime list."""
226226
options = [
227-
'type=bind',
228-
'source=' + source,
229-
'target=' + target,
227+
"type=bind",
228+
"source=" + source,
229+
"target=" + target,
230230
]
231231
if not writable:
232-
options.append('readonly')
232+
options.append("readonly")
233233
output = StringIO()
234234
csv.writer(output).writerow(options)
235235
mount_arg = output.getvalue().strip()
236-
runtime.append(
237-
"--mount={}".format(mount_arg)
238-
)
236+
runtime.append("--mount={}".format(mount_arg))
239237
# Unlike "--volume", "--mount" will fail if the volume doesn't already exist.
240238
if not os.path.exists(source):
241239
os.mkdir(source)

cwltool/executors.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,22 @@
77
import threading
88
from abc import ABCMeta, abstractmethod
99
from threading import Lock
10-
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Union
10+
from typing import (
11+
Any,
12+
Dict,
13+
Iterable,
14+
List,
15+
Optional,
16+
Set,
17+
Tuple,
18+
Union,
19+
MutableMapping,
20+
)
1121

1222
import psutil
1323

1424
from schema_salad.validate import ValidationException
25+
from schema_salad.sourceline import SourceLine
1526

1627
from .command_line_tool import CallbackJob
1728
from .context import RuntimeContext, getdefault
@@ -68,6 +79,14 @@ def execute(
6879
if not runtime_context.basedir:
6980
raise WorkflowException("Must provide 'basedir' in runtimeContext")
7081

82+
def check_for_abstract_op(tool: MutableMapping[str, Any]) -> None:
83+
if tool["class"] == "Operation":
84+
raise SourceLine(tool, "class", WorkflowException).makeError(
85+
"Workflow has unrunnable abstract Operation"
86+
)
87+
88+
process.visit(check_for_abstract_op)
89+
7190
finaloutdir = None # Type: Optional[str]
7291
original_outdir = runtime_context.outdir
7392
if isinstance(original_outdir, str):

cwltool/main.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,10 @@ def main(
782782
input_required: bool = True,
783783
) -> int:
784784
if not stdout: # force UTF-8 even if the console is configured differently
785-
if hasattr(sys.stdout, "encoding") and sys.stdout.encoding != "UTF-8":
785+
if hasattr(sys.stdout, "encoding") and sys.stdout.encoding.upper() not in (
786+
"UTF-8",
787+
"UTF8",
788+
):
786789
if hasattr(sys.stdout, "detach"):
787790
stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
788791
else:

cwltool/process.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def filter(self, record): # type: (logging.LogRecord) -> bool
119119
"CommandLineTool.yml",
120120
"CommonWorkflowLanguage.yml",
121121
"Process.yml",
122+
"Operation.yml",
122123
"concepts.md",
123124
"contrib.md",
124125
"intro.md",
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
saladVersion: v1.1
2+
$base: "https://w3id.org/cwl/cwl#"
3+
4+
$namespaces:
5+
cwl: "https://w3id.org/cwl/cwl#"
6+
7+
$graph:
8+
9+
- name: OperationInputParameter
10+
type: record
11+
extends: InputParameter
12+
docParent: "#Operation"
13+
doc: |
14+
Describe an input parameter of an operation.
15+
fields:
16+
- name: type
17+
type:
18+
- CWLType
19+
- InputRecordSchema
20+
- InputEnumSchema
21+
- InputArraySchema
22+
- string
23+
- type: array
24+
items:
25+
- CWLType
26+
- InputRecordSchema
27+
- InputEnumSchema
28+
- InputArraySchema
29+
- string
30+
jsonldPredicate:
31+
"_id": "sld:type"
32+
"_type": "@vocab"
33+
refScope: 2
34+
typeDSL: True
35+
doc: |
36+
Specify valid types of data that may be assigned to this parameter.
37+
38+
- name: OperationOutputParameter
39+
type: record
40+
extends: OutputParameter
41+
docParent: "#Operation"
42+
doc: |
43+
Describe an output parameter of an operation.
44+
fields:
45+
- name: type
46+
type:
47+
- CWLType
48+
- OutputRecordSchema
49+
- OutputEnumSchema
50+
- OutputArraySchema
51+
- string
52+
- type: array
53+
items:
54+
- CWLType
55+
- OutputRecordSchema
56+
- OutputEnumSchema
57+
- OutputArraySchema
58+
- string
59+
jsonldPredicate:
60+
"_id": "sld:type"
61+
"_type": "@vocab"
62+
refScope: 2
63+
typeDSL: True
64+
doc: |
65+
Specify valid types of data that may be assigned to this parameter.
66+
67+
- type: record
68+
name: Operation
69+
extends: Process
70+
documentRoot: true
71+
specialize:
72+
- specializeFrom: InputParameter
73+
specializeTo: OperationInputParameter
74+
- specializeFrom: OutputParameter
75+
specializeTo: OperationOutputParameter
76+
doc: |
77+
This record describes an abstract operation. It is a potential
78+
step of a workflow that has not yet been bound to a concrete
79+
implementation. It specifies an input and output signature, but
80+
does not provide enough information to be executed. An
81+
implementation (or other tooling) may provide a means of binding
82+
an Operation to a concrete process (such as Workflow,
83+
CommandLineTool, or ExpressionTool) with a compatible signature.
84+
85+
fields:
86+
- name: class
87+
jsonldPredicate:
88+
"_id": "@type"
89+
"_type": "@vocab"
90+
type: string

cwltool/schemas/v1.2.0-dev1/Workflow.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ $graph:
2424
- |
2525
# Abstract
2626
27-
One way to define a workflow is: an analysis task represented by a
28-
directed graph describing a sequence of operations that transform an
29-
input data set to output. This specification defines the Common Workflow
30-
Language (CWL) Workflow description, a vendor-neutral standard for
31-
representing workflows intended to be portable across a variety of
32-
computing platforms.
27+
This specification defines the Common Workflow Language (CWL)
28+
Workflow description, a vendor-neutral standard for representing
29+
analysis tasks where a sequence of operations are described
30+
using a directed graph of operations to transform input to
31+
output. CWL is portable across a variety of computing
32+
platforms.
3333
3434
- {$include: intro.md}
3535

@@ -734,3 +734,5 @@ $graph:
734734
jsonldPredicate:
735735
"_id": "@type"
736736
"_type": "@vocab"
737+
738+
- {$import: Operation.yml}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
- |
2+
## Domain Specific Language for secondary files
3+
4+
Fields may be tagged `secondaryFilesDSL: true` in `jsonldPredicate`. If so, the field is expanded using the
5+
following micro-DSL for secondary files:
6+
7+
* If the value is a string, it is transformed to an object with two fields `pattern` and `required`
8+
* By default, the value of `required` is `null` (this indicates default behavior, which may be based on the context)
9+
* If the value ends with a question mark `?` the question mark is
10+
stripped off and the value of the field `required` is set to `False`
11+
* The remaining value is assigned to the field `pattern`
12+
13+
### Type DSL example
14+
15+
Given the following schema:
16+
17+
```
18+
- $include: sfdsl_res_schema.yml
19+
- |
20+
```
21+
22+
Process the following example:
23+
24+
```
25+
- $include: sfdsl_res_src.yml
26+
- |
27+
```
28+
29+
This becomes:
30+
31+
```
32+
- $include: sfdsl_res_proc.yml
33+
- |
34+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[
2+
{
3+
"secondaryFiles": {
4+
"pattern": ".bai",
5+
"required": null
6+
},
7+
{
8+
"secondaryFiles": {
9+
"pattern": ".bai",
10+
"required": false
11+
},
12+
{
13+
"secondaryFiles": {
14+
"pattern": ".bai?"
15+
},
16+
{
17+
"secondaryFiles": {
18+
"pattern": ".bai?",
19+
"required": true
20+
},
21+
]

0 commit comments

Comments
 (0)