comparison env/lib/python3.9/site-packages/cwltool/update.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 import copy
2 from functools import partial
3 from typing import (
4 Callable,
5 Dict,
6 MutableMapping,
7 MutableSequence,
8 Optional,
9 Tuple,
10 Union,
11 cast,
12 )
13
14 from ruamel.yaml.comments import CommentedMap, CommentedSeq
15 from schema_salad.exceptions import ValidationException
16 from schema_salad.ref_resolver import Loader
17 from schema_salad.sourceline import SourceLine
18
19 from .loghandler import _logger
20 from .utils import CWLObjectType, CWLOutputType, aslist, visit_class, visit_field
21
22
23 def v1_1to1_2(
24 doc: CommentedMap, loader: Loader, baseuri: str
25 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
26 """Public updater for v1.1 to v1.2."""
27 doc = copy.deepcopy(doc)
28
29 upd = doc
30 if isinstance(upd, MutableMapping) and "$graph" in upd:
31 upd = cast(CommentedMap, upd["$graph"])
32 for proc in aslist(upd):
33 if "cwlVersion" in proc:
34 del proc["cwlVersion"]
35
36 return doc, "v1.2"
37
38
39 def v1_0to1_1(
40 doc: CommentedMap, loader: Loader, baseuri: str
41 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
42 """Public updater for v1.0 to v1.1."""
43 doc = copy.deepcopy(doc)
44
45 rewrite = {
46 "http://commonwl.org/cwltool#WorkReuse": "WorkReuse",
47 "http://arvados.org/cwl#ReuseRequirement": "WorkReuse",
48 "http://commonwl.org/cwltool#TimeLimit": "ToolTimeLimit",
49 "http://commonwl.org/cwltool#NetworkAccess": "NetworkAccess",
50 "http://commonwl.org/cwltool#InplaceUpdateRequirement": "InplaceUpdateRequirement",
51 "http://commonwl.org/cwltool#LoadListingRequirement": "LoadListingRequirement",
52 }
53
54 def rewrite_requirements(t: CWLObjectType) -> None:
55 if "requirements" in t:
56 for r in cast(MutableSequence[CWLObjectType], t["requirements"]):
57 if isinstance(r, MutableMapping):
58 cls = cast(str, r["class"])
59 if cls in rewrite:
60 r["class"] = rewrite[cls]
61 else:
62 raise ValidationException(
63 "requirements entries must be dictionaries: {} {}.".format(
64 type(r), r
65 )
66 )
67 if "hints" in t:
68 for r in cast(MutableSequence[CWLObjectType], t["hints"]):
69 if isinstance(r, MutableMapping):
70 cls = cast(str, r["class"])
71 if cls in rewrite:
72 r["class"] = rewrite[cls]
73 else:
74 raise ValidationException(
75 "hints entries must be dictionaries: {} {}.".format(type(r), r)
76 )
77 if "steps" in t:
78 for s in cast(MutableSequence[CWLObjectType], t["steps"]):
79 if isinstance(s, MutableMapping):
80 rewrite_requirements(s)
81 else:
82 raise ValidationException(
83 "steps entries must be dictionaries: {} {}.".format(type(s), s)
84 )
85
86 def update_secondaryFiles(t, top=False):
87 # type: (CWLOutputType, bool) -> Union[MutableSequence[MutableMapping[str, str]], MutableMapping[str, str]]
88 if isinstance(t, CommentedSeq):
89 new_seq = copy.deepcopy(t)
90 for index, entry in enumerate(t):
91 new_seq[index] = update_secondaryFiles(entry)
92 return new_seq
93 elif isinstance(t, MutableSequence):
94 return CommentedSeq(
95 [update_secondaryFiles(cast(CWLOutputType, p)) for p in t]
96 )
97 elif isinstance(t, MutableMapping):
98 return cast(MutableMapping[str, str], t)
99 elif top:
100 return CommentedSeq([CommentedMap([("pattern", t)])])
101 else:
102 return CommentedMap([("pattern", t)])
103
104 def fix_inputBinding(t: CWLObjectType) -> None:
105 for i in cast(MutableSequence[CWLObjectType], t["inputs"]):
106 if "inputBinding" in i:
107 ib = cast(CWLObjectType, i["inputBinding"])
108 for k in list(ib.keys()):
109 if k != "loadContents":
110 _logger.warning(
111 SourceLine(ib, k).makeError(
112 "Will ignore field '{}' which is not valid in {} "
113 "inputBinding".format(k, t["class"])
114 )
115 )
116 del ib[k]
117
118 visit_class(doc, ("CommandLineTool", "Workflow"), rewrite_requirements)
119 visit_class(doc, ("ExpressionTool", "Workflow"), fix_inputBinding)
120 visit_field(doc, "secondaryFiles", partial(update_secondaryFiles, top=True))
121
122 upd = doc
123 if isinstance(upd, MutableMapping) and "$graph" in upd:
124 upd = cast(CommentedMap, upd["$graph"])
125 for proc in aslist(upd):
126 proc.setdefault("hints", CommentedSeq())
127 proc["hints"].insert(
128 0, CommentedMap([("class", "NetworkAccess"), ("networkAccess", True)])
129 )
130 proc["hints"].insert(
131 0,
132 CommentedMap(
133 [("class", "LoadListingRequirement"), ("loadListing", "deep_listing")]
134 ),
135 )
136 if "cwlVersion" in proc:
137 del proc["cwlVersion"]
138
139 return (doc, "v1.1")
140
141
142 def v1_1_0dev1to1_1(
143 doc: CommentedMap, loader: Loader, baseuri: str
144 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
145 """Public updater for v1.1.0-dev1 to v1.1."""
146 return (doc, "v1.1")
147
148
149 def v1_2_0dev1todev2(
150 doc: CommentedMap, loader: Loader, baseuri: str
151 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
152 """Public updater for v1.2.0-dev1 to v1.2.0-dev2."""
153 return (doc, "v1.2.0-dev2")
154
155
156 def v1_2_0dev2todev3(
157 doc: CommentedMap, loader: Loader, baseuri: str
158 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
159 """Public updater for v1.2.0-dev2 to v1.2.0-dev3."""
160 doc = copy.deepcopy(doc)
161
162 def update_pickvalue(t: CWLObjectType) -> None:
163 for step in cast(MutableSequence[CWLObjectType], t["steps"]):
164 for inp in cast(MutableSequence[CWLObjectType], step["in"]):
165 if "pickValue" in inp:
166 if inp["pickValue"] == "only_non_null":
167 inp["pickValue"] = "the_only_non_null"
168
169 visit_class(doc, "Workflow", update_pickvalue)
170 upd = doc
171 if isinstance(upd, MutableMapping) and "$graph" in upd:
172 upd = cast(CommentedMap, upd["$graph"])
173 for proc in aslist(upd):
174 if "cwlVersion" in proc:
175 del proc["cwlVersion"]
176 return (doc, "v1.2.0-dev3")
177
178
179 def v1_2_0dev3todev4(
180 doc: CommentedMap, loader: Loader, baseuri: str
181 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
182 """Public updater for v1.2.0-dev3 to v1.2.0-dev4."""
183 return (doc, "v1.2.0-dev4")
184
185
186 def v1_2_0dev4todev5(
187 doc: CommentedMap, loader: Loader, baseuri: str
188 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
189 """Public updater for v1.2.0-dev4 to v1.2.0-dev5."""
190 return (doc, "v1.2.0-dev5")
191
192
193 def v1_2_0dev5to1_2(
194 doc: CommentedMap, loader: Loader, baseuri: str
195 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
196 """Public updater for v1.2.0-dev5 to v1.2."""
197 return (doc, "v1.2")
198
199
200 ORDERED_VERSIONS = [
201 "v1.0",
202 "v1.1.0-dev1",
203 "v1.1",
204 "v1.2.0-dev1",
205 "v1.2.0-dev2",
206 "v1.2.0-dev3",
207 "v1.2.0-dev4",
208 "v1.2.0-dev5",
209 "v1.2",
210 ]
211
212 UPDATES = {
213 "v1.0": v1_0to1_1,
214 "v1.1": v1_1to1_2,
215 "v1.2": None,
216 } # type: Dict[str, Optional[Callable[[CommentedMap, Loader, str], Tuple[CommentedMap, str]]]]
217
218 DEVUPDATES = {
219 "v1.1.0-dev1": v1_1_0dev1to1_1,
220 "v1.2.0-dev1": v1_2_0dev1todev2,
221 "v1.2.0-dev2": v1_2_0dev2todev3,
222 "v1.2.0-dev3": v1_2_0dev3todev4,
223 "v1.2.0-dev4": v1_2_0dev4todev5,
224 "v1.2.0-dev5": v1_2_0dev5to1_2,
225 } # type: Dict[str, Optional[Callable[[CommentedMap, Loader, str], Tuple[CommentedMap, str]]]]
226
227
228 ALLUPDATES = UPDATES.copy()
229 ALLUPDATES.update(DEVUPDATES)
230
231 INTERNAL_VERSION = "v1.2"
232
233 ORIGINAL_CWLVERSION = "http://commonwl.org/cwltool#original_cwlVersion"
234
235
236 def identity(
237 doc: CommentedMap, loader: Loader, baseuri: str
238 ) -> Tuple[CommentedMap, str]: # pylint: disable=unused-argument
239 """Do-nothing, CWL document upgrade function."""
240 return (doc, cast(str, doc["cwlVersion"]))
241
242
243 def checkversion(
244 doc: Union[CommentedSeq, CommentedMap],
245 metadata: CommentedMap,
246 enable_dev: bool,
247 ) -> Tuple[CommentedMap, str]:
248 """Check the validity of the version of the give CWL document.
249
250 Returns the document and the validated version string.
251 """
252 cdoc = None # type: Optional[CommentedMap]
253 if isinstance(doc, CommentedSeq):
254 if not isinstance(metadata, CommentedMap):
255 raise Exception("Expected metadata to be CommentedMap")
256 lc = metadata.lc
257 metadata = copy.deepcopy(metadata)
258 metadata.lc.data = copy.copy(lc.data)
259 metadata.lc.filename = lc.filename
260 metadata["$graph"] = doc
261 cdoc = metadata
262 elif isinstance(doc, CommentedMap):
263 cdoc = doc
264 else:
265 raise Exception("Expected CommentedMap or CommentedSeq")
266
267 version = metadata["cwlVersion"]
268 cdoc["cwlVersion"] = version
269
270 updated_from = metadata.get(ORIGINAL_CWLVERSION) or cdoc.get(ORIGINAL_CWLVERSION)
271
272 if updated_from:
273 if version != INTERNAL_VERSION:
274 raise ValidationException(
275 "original_cwlVersion is set (%s) but cwlVersion is '%s', expected '%s' "
276 % (updated_from, version, INTERNAL_VERSION)
277 )
278 elif version not in UPDATES:
279 if version in DEVUPDATES:
280 if enable_dev:
281 pass
282 else:
283 keys = list(UPDATES.keys())
284 keys.sort()
285 raise ValidationException(
286 "Version '%s' is a development or deprecated version.\n "
287 "Update your document to a stable version (%s) or use "
288 "--enable-dev to enable support for development and "
289 "deprecated versions." % (version, ", ".join(keys))
290 )
291 else:
292 raise ValidationException("Unrecognized version %s" % version)
293
294 return (cdoc, version)
295
296
297 def update(
298 doc: Union[CommentedSeq, CommentedMap],
299 loader: Loader,
300 baseuri: str,
301 enable_dev: bool,
302 metadata: CommentedMap,
303 update_to: Optional[str] = None,
304 ) -> CommentedMap:
305 """Update a CWL document to 'update_to' (if provided) or INTERNAL_VERSION."""
306 if update_to is None:
307 update_to = INTERNAL_VERSION
308
309 (cdoc, version) = checkversion(doc, metadata, enable_dev)
310 originalversion = copy.copy(version)
311
312 nextupdate = (
313 identity
314 ) # type: Optional[Callable[[CommentedMap, Loader, str], Tuple[CommentedMap, str]]]
315
316 while version != update_to and nextupdate:
317 (cdoc, version) = nextupdate(cdoc, loader, baseuri)
318 nextupdate = ALLUPDATES[version]
319
320 cdoc["cwlVersion"] = version
321 metadata["cwlVersion"] = version
322 metadata["http://commonwl.org/cwltool#original_cwlVersion"] = originalversion
323 cdoc["http://commonwl.org/cwltool#original_cwlVersion"] = originalversion
324
325 return cdoc