Skip to content

Commit f5a3fd9

Browse files
tetronmr-c
andauthored
Fix string interpolation and backslash escaping to match 1.2 spec. (#1309)
* Fix string interpolation and backslash escaping to match 1.2 spec. * Adjust escaping behavior based on version. * Add tests for each escaping behavior of interpolate. * refresh cwl v1.2.0-dev4 schema Co-authored-by: Michael R. Crusoe <[email protected]>
1 parent 00eaa76 commit f5a3fd9

File tree

112 files changed

+67467
-19
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+67467
-19
lines changed

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ include cwltool/schemas/v1.2.0-dev3/*.yml
3333
include cwltool/schemas/v1.2.0-dev3/*.md
3434
include cwltool/schemas/v1.2.0-dev3/salad/schema_salad/metaschema/*.yml
3535
include cwltool/schemas/v1.2.0-dev3/salad/schema_salad/metaschema/*.md
36+
include cwltool/schemas/v1.2.0-dev4/*.yml
37+
include cwltool/schemas/v1.2.0-dev4/*.md
38+
include cwltool/schemas/v1.2.0-dev4/salad/schema_salad/metaschema/*.yml
39+
include cwltool/schemas/v1.2.0-dev4/salad/schema_salad/metaschema/*.md
3640
include cwltool/cwlNodeEngine.js
3741
include cwltool/cwlNodeEngineJSConsole.js
3842
include cwltool/cwlNodeEngineWithContext.js

cwltool/builder.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ def __init__(
173173
outdir: str,
174174
tmpdir: str,
175175
stagedir: str,
176+
cwlVersion: str,
176177
) -> None:
177178
"""Initialize this Builder."""
178179
self.job = job
@@ -204,6 +205,8 @@ def __init__(
204205
self.tmpdir = tmpdir
205206
self.stagedir = stagedir
206207

208+
self.cwlVersion = cwlVersion
209+
207210
self.pathmapper = None # type: Optional[PathMapper]
208211
self.prov_obj = None # type: Optional[ProvenanceProfile]
209212
self.find_default_container = None # type: Optional[Callable[[], str]]
@@ -630,4 +633,5 @@ def do_eval(
630633
js_console=self.js_console,
631634
force_docker_pull=self.force_docker_pull,
632635
strip_whitespace=strip_whitespace,
636+
cwlVersion=self.cwlVersion,
633637
)

cwltool/command_line_tool.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,10 @@ def make_job_runner(self, runtimeContext: RuntimeContext) -> Type[JobBase]:
368368
if runtimeContext.find_default_container is not None:
369369
default_container = runtimeContext.find_default_container(self)
370370
if default_container is not None:
371-
dockerReq = {"class": "DockerRequirement", "dockerPull": default_container}
371+
dockerReq = {
372+
"class": "DockerRequirement",
373+
"dockerPull": default_container,
374+
}
372375
if mpiRequired:
373376
self.hints.insert(0, dockerReq)
374377
dockerRequired = False
@@ -389,29 +392,33 @@ def make_job_runner(self, runtimeContext: RuntimeContext) -> Type[JobBase]:
389392

390393
if dockerReq is not None and runtimeContext.use_container:
391394
if mpiReq is not None:
392-
_logger.warning(
393-
"MPIRequirement with containers is a beta feature"
394-
)
395+
_logger.warning("MPIRequirement with containers is a beta feature")
395396
if runtimeContext.singularity:
396397
return SingularityCommandLineJob
397398
elif runtimeContext.user_space_docker_cmd:
398399
return UDockerCommandLineJob
399400
if mpiReq is not None:
400401
if mpiRequired:
401402
if dockerRequired:
402-
raise UnsupportedRequirement("No support for Docker and MPIRequirement both being required")
403+
raise UnsupportedRequirement(
404+
"No support for Docker and MPIRequirement both being required"
405+
)
403406
else:
404407
_logger.warning(
405408
"MPI has been required while Docker is hinted, discarding Docker hint(s)"
406409
)
407-
self.hints = [h for h in self.hints if h["class"] != "DockerRequirement"]
410+
self.hints = [
411+
h for h in self.hints if h["class"] != "DockerRequirement"
412+
]
408413
return CommandLineJob
409414
else:
410415
if dockerRequired:
411416
_logger.warning(
412417
"Docker has been required while MPI is hinted, discarding MPI hint(s)"
413418
)
414-
self.hints = [h for h in self.hints if h["class"] != MPIRequirementName]
419+
self.hints = [
420+
h for h in self.hints if h["class"] != MPIRequirementName
421+
]
415422
else:
416423
raise UnsupportedRequirement(
417424
"Both Docker and MPI have been hinted - don't know what to do"
@@ -873,12 +880,16 @@ def register_reader(f: CWLObjectType) -> None:
873880
if mpi is not None:
874881
np = cast( # From the schema for MPIRequirement.processes
875882
Union[int, str],
876-
mpi.get('processes', runtimeContext.mpi_config.default_nproc)
883+
mpi.get("processes", runtimeContext.mpi_config.default_nproc),
877884
)
878885
if isinstance(np, str):
879886
tmp = builder.do_eval(np)
880887
if not isinstance(tmp, int):
881-
raise TypeError("{} needs 'processes' to evaluate to an int, got {}".format(MPIRequirementName, type(np)))
888+
raise TypeError(
889+
"{} needs 'processes' to evaluate to an int, got {}".format(
890+
MPIRequirementName, type(np)
891+
)
892+
)
882893
np = tmp
883894
j.mpi_procs = np
884895
yield j

cwltool/expression.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
cast,
1616
)
1717

18+
import json
1819
from schema_salad.utils import json_dumps
1920

2021
from .errors import WorkflowException
@@ -90,6 +91,7 @@ def scanner(scan: str) -> Optional[Tuple[int, int]]:
9091
stack.append(BRACE)
9192
else:
9293
stack.pop()
94+
i -= 1
9395
elif state == PAREN:
9496
if c == "(":
9597
stack.append(PAREN)
@@ -124,14 +126,13 @@ def scanner(scan: str) -> Optional[Tuple[int, int]]:
124126
stack.append(BACKSLASH)
125127
i += 1
126128

127-
if len(stack) > 1:
129+
if len(stack) > 1 and not (len(stack) == 2 and stack[1] in (BACKSLASH, DOLLAR)):
128130
raise SubstitutionError(
129-
"Substitution error, unfinished block starting at position {}: {}".format(
130-
start, scan[start:]
131+
"Substitution error, unfinished block starting at position {}: '{}' stack was {}".format(
132+
start, scan[start:], stack
131133
)
132134
)
133-
else:
134-
return None
135+
return None
135136

136137

137138
def next_seg(
@@ -279,6 +280,7 @@ def interpolate(
279280
debug: bool = False,
280281
js_console: bool = False,
281282
strip_whitespace: bool = True,
283+
escaping_behavior: int = 2,
282284
) -> Optional[CWLOutputType]:
283285
if strip_whitespace:
284286
scan = scan.strip()
@@ -302,11 +304,30 @@ def interpolate(
302304
return e
303305
leaf = json_dumps(e, sort_keys=True)
304306
if leaf[0] == '"':
305-
leaf = leaf[1:-1]
307+
leaf = json.loads(leaf)
306308
parts.append(leaf)
307309
elif scan[w[0]] == "\\":
308-
e = scan[w[1] - 1]
309-
parts.append(e)
310+
if escaping_behavior == 1:
311+
# Old behavior. Just skip the next character.
312+
e = scan[w[1] - 1]
313+
parts.append(e)
314+
elif escaping_behavior == 2:
315+
# Backslash quoting requires a three character lookahead.
316+
e = scan[w[0] : w[1] + 1]
317+
if e in ("\\$(", "\\${"):
318+
# Suppress start of a parameter reference, drop the
319+
# backslash.
320+
parts.append(e[1:])
321+
w = (w[0], w[1] + 1)
322+
elif e[1] == "\\":
323+
# Double backslash, becomes a single backslash
324+
parts.append("\\")
325+
else:
326+
# Some other text, add it as-is (including the
327+
# backslash) and resume scanning.
328+
parts.append(e[:2])
329+
else:
330+
raise Exception("Unknown escaping behavior %s" % escaping_behavior)
310331

311332
scan = scan[w[1] :]
312333
w = scanner(scan)
@@ -331,6 +352,7 @@ def do_eval(
331352
debug: bool = False,
332353
js_console: bool = False,
333354
strip_whitespace: bool = True,
355+
cwlVersion: str = "",
334356
) -> Optional[CWLOutputType]:
335357

336358
runtime = cast(MutableMapping[str, Union[int, str, None]], copy.deepcopy(resources))
@@ -362,6 +384,17 @@ def do_eval(
362384
debug=debug,
363385
js_console=js_console,
364386
strip_whitespace=strip_whitespace,
387+
escaping_behavior=1
388+
if cwlVersion
389+
in (
390+
"v1.0",
391+
"v1.1.0-dev1",
392+
"v1.1",
393+
"v1.2.0-dev1",
394+
"v1.2.0-dev2",
395+
"v1.2.0-dev3",
396+
)
397+
else 2,
365398
)
366399

367400
except Exception as e:

cwltool/process.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,9 @@ def inc(d): # type: (List[int]) -> None
864864
runtime_context.stagedir or tempfile.mkdtemp()
865865
)
866866

867+
cwl_version = cast(str, self.metadata.get(
868+
"http://commonwl.org/cwltool#original_cwlVersion", None
869+
))
867870
builder = Builder(
868871
job,
869872
files,
@@ -886,6 +889,7 @@ def inc(d): # type: (List[int]) -> None
886889
outdir,
887890
tmpdir,
888891
stagedir,
892+
cwl_version,
889893
)
890894

891895
bindings.extend(

cwltool/schemas/v1.2.0-dev4/CITATION

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
To cite the Common Workflow Language standard in a publication, please use:
2+
3+
Amstutz, Peter; Crusoe, Michael R; Tijanić, Nebojša; Chapman, Brad;
4+
Chilton, John; Heuer, Michael; Kartashov, Andrey; Kern, John; Leehr, Dan;
5+
Ménager, Hervé; Nedeljkovich, Maya; Scales, Matt; Soiland-Reyes, Stian;
6+
Stojanovic, Luka (2016): Common Workflow Language, v1.0. Specification,
7+
Common Workflow Language working group. https://w3id.org/cwl/v1.0/
8+
https://doi.org/10.6084/m9.figshare.3115156.v2
9+
10+
@data{cwl,
11+
doi = {10.6084/m9.figshare.3115156.v2},
12+
url = {https://doi.org/10.6084/m9.figshare.3115156.v2},
13+
author = {Peter Amstutz; Michael R. Crusoe; Nebojša Tijanić; Brad Chapman;
14+
John Chilton; Michael Heuer; Andrey Kartashov; John Kern; Dan Leehr;
15+
Hervé Ménager; Maya Nedeljkovich; Matt Scales; Stian Soiland-Reyes;
16+
Luka Stojanovic
17+
},
18+
publisher = {Figshare},
19+
institution = {Common Workflow Language working group},
20+
title = {Common Workflow Language, v1.0},
21+
year = {2016}
22+
}
23+
24+
# Are you editing this file?
25+
# Synchronize any changes made with
26+
# README.md
27+
# and
28+
# https://github.com/common-workflow-language/user_guide/blob/gh-pages/CITATION
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
CWL Code of Conduct
2+
===================
3+
4+
The CWL Project is dedicated to providing a harassment-free experience for
5+
everyone. We do not tolerate harassment of participants in any form.
6+
7+
This code of conduct applies to all CWL Project spaces both online and off: the
8+
Google Group, the Gitter chat room, the Google Hangouts chats, and any other
9+
CWL spaces. Anyone who violates this code of conduct may be sanctioned or
10+
expelled from these spaces at the discretion of the CWL Leadership Team.
11+
12+
Some CWL Project spaces may have additional rules in place, which will be
13+
made clearly available to participants. Participants are responsible for
14+
knowing and abiding by these rules.
15+
16+
Harassment includes, but is not limited to:
17+
18+
- Offensive comments related to gender, gender identity and expression, sexual
19+
orientation, disability, mental illness, neuro(a)typicality, physical
20+
appearance, body size, age, race, or religion.
21+
- Unwelcome comments regarding a person’s lifestyle choices and practices,
22+
including those related to food, health, parenting, drugs, and employment.
23+
- Deliberate misgendering or use of [dead](https://www.quora.com/What-is-deadnaming/answer/Nancy-C-Walker)
24+
or rejected names.
25+
- Gratuitous or off-topic sexual images or behaviour in spaces where they’re not
26+
appropriate.
27+
- Physical contact and simulated physical contact (eg, textual descriptions like
28+
\*hug\*” or “\*backrub\*”) without consent or after a request to stop.
29+
- Threats of violence.
30+
- Incitement of violence towards any individual, including encouraging a person
31+
to commit suicide or to engage in self-harm.
32+
- Deliberate intimidation.
33+
- Stalking or following.
34+
- Harassing photography or recording, including logging online activity for
35+
harassment purposes.
36+
- Sustained disruption of discussion.
37+
- Unwelcome sexual attention.
38+
- Pattern of inappropriate social contact, such as requesting/assuming
39+
inappropriate levels of intimacy with others
40+
- Continued one-on-one communication after requests to cease.
41+
- Deliberate “outing” of any aspect of a person’s identity without their consent
42+
except as necessary to protect vulnerable people from intentional abuse.
43+
- Publication of non-harassing private communication.
44+
45+
The CWL Project prioritizes marginalized people’s safety over privileged
46+
people’s comfort. The CWL Leadeship Team will not act on complaints regarding:
47+
48+
- ‘Reverse’ -isms, including ‘reverse racism,’ ‘reverse sexism,’ and ‘cisphobia’
49+
- Reasonable communication of boundaries, such as “leave me alone,” “go away,” or
50+
“I’m not discussing this with you.”
51+
- Communicating in a [tone](http://geekfeminism.wikia.com/wiki/Tone_argument)
52+
you don’t find congenial
53+
54+
Reporting
55+
---------
56+
57+
If you are being harassed by a member of the CWL Project, notice that someone
58+
else is being harassed, or have any other concerns, please contact the CWL
59+
Leadership Team at [email protected]. If person who is harassing
60+
you is on the team, they will recuse themselves from handling your incident. We
61+
will respond as promptly as we can.
62+
63+
This code of conduct applies to CWL Project spaces, but if you are being
64+
harassed by a member of CWL Project outside our spaces, we still want to
65+
know about it. We will take all good-faith reports of harassment by CWL Project
66+
members, especially the CWL Leadership Team, seriously. This includes harassment
67+
outside our spaces and harassment that took place at any point in time. The
68+
abuse team reserves the right to exclude people from the CWL Project based on
69+
their past behavior, including behavior outside CWL Project spaces and
70+
behavior towards people who are not in the CWL Project.
71+
72+
In order to protect volunteers from abuse and burnout, we reserve the right to
73+
reject any report we believe to have been made in bad faith. Reports intended
74+
to silence legitimate criticism may be deleted without response.
75+
76+
We will respect confidentiality requests for the purpose of protecting victims
77+
of abuse. At our discretion, we may publicly name a person about whom we’ve
78+
received harassment complaints, or privately warn third parties about them, if
79+
we believe that doing so will increase the safety of CWL Project members or
80+
the general public. We will not name harassment victims without their
81+
affirmative consent.
82+
83+
Consequences
84+
------------
85+
86+
Participants asked to stop any harassing behavior are expected to comply
87+
immediately.
88+
89+
If a participant engages in harassing behavior, the CWL Leadership Team may
90+
take any action they deem appropriate, up to and including expulsion from all
91+
CWL Project spaces and identification of the participant as a harasser to other
92+
CWL Project members or the general public.
93+
94+
This anti-harassment policy is based on the [example policy from the Geek
95+
Feminism wiki](http://geekfeminism.wikia.com/wiki/Community_anti-harassment/Policy),
96+
created by the Geek Feminism community.
97+
98+
CWL Leadership Team
99+
-------------------
100+
101+
As a stop gap measure until a more formal governance structure is adopted, the
102+
following individuals make up the leadership of the CWL Project: Peter Amstutz,
103+
John Chilton, Michael R. Crusoe, and Nebojša Tijanić.
104+
105+
To report an issue with anyone on the team you can escalate to Ward Vandewege
106+
(Curoverse) [email protected], Anton Nekrutenko (Galaxy)
107+
anton AT bx DOT psu DOT edu, C. Titus Brown (UC Davis) [email protected], or
108+
Brandi Davis-Dusenbery (Seven Bridges Genomics) [email protected].

0 commit comments

Comments
 (0)