comparison toolfactory/rgToolFactory2.py @ 126:def0f754ee1b draft

Uploaded
author fubar
date Fri, 26 Mar 2021 09:29:58 +0000
parents f267ed4a3026
children 98c8a76b3638
comparison
equal deleted inserted replaced
125:2dbb412af425 126:def0f754ee1b
14 # 2. Fix planemo so the toolfactory function works 14 # 2. Fix planemo so the toolfactory function works
15 # 3. Rewrite bits using galaxyxml functions where that makes sense - done 15 # 3. Rewrite bits using galaxyxml functions where that makes sense - done
16 16
17 import argparse 17 import argparse
18 import copy 18 import copy
19 import json
19 import logging 20 import logging
20 import os 21 import os
21 import re 22 import re
22 import shutil 23 import shutil
23 import subprocess 24 import subprocess
34 35
35 import lxml 36 import lxml
36 37
37 import yaml 38 import yaml
38 39
39 myversion = "V2.1 July 2020" 40
41 myversion = "V2.2 February 2021"
40 verbose = True 42 verbose = True
41 debug = True 43 debug = True
42 toolFactoryURL = "https://github.com/fubar2/toolfactory" 44 toolFactoryURL = "https://github.com/fubar2/toolfactory"
43 ourdelim = "~~~"
44
45 # --input_files="$intab.input_files~~~$intab.input_CL~~~
46 # $intab.input_formats# ~~~$intab.input_label
47 # ~~~$intab.input_help"
48 IPATHPOS = 0
49 ICLPOS = 1
50 IFMTPOS = 2
51 ILABPOS = 3
52 IHELPOS = 4
53 IOCLPOS = 5
54
55 # --output_files "$otab.history_name~~~$otab.history_format~~~
56 # $otab.history_CL~~~$otab.history_test"
57 ONAMEPOS = 0
58 OFMTPOS = 1
59 OCLPOS = 2
60 OTESTPOS = 3
61 OOCLPOS = 4
62
63
64 # --additional_parameters="$i.param_name~~~$i.param_value~~~
65 # $i.param_label~~~$i.param_help~~~$i.param_type
66 # ~~~$i.CL~~~i$.param_CLoverride"
67 ANAMEPOS = 0
68 AVALPOS = 1
69 ALABPOS = 2
70 AHELPPOS = 3
71 ATYPEPOS = 4
72 ACLPOS = 5
73 AOVERPOS = 6
74 AOCLPOS = 7
75
76
77 foo = len(lxml.__version__) 45 foo = len(lxml.__version__)
78 # fug you, flake8. Say my name! 46 # fug you, flake8. Say my name!
79 FAKEEXE = "~~~REMOVE~~~ME~~~" 47 FAKEEXE = "~~~REMOVE~~~ME~~~"
80 # need this until a PR/version bump to fix galaxyxml prepending the exe even 48 # need this until a PR/version bump to fix galaxyxml prepending the exe even
81 # with override. 49 # with override.
84 def timenow(): 52 def timenow():
85 """return current time as a string""" 53 """return current time as a string"""
86 return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) 54 return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time()))
87 55
88 56
89 def quote_non_numeric(s):
90 """return a prequoted string for non-numerics
91 useful for perl and Rscript parameter passing?
92 """
93 try:
94 _ = float(s)
95 return s
96 except ValueError:
97 return '"%s"' % s
98
99
100 html_escape_table = {
101 "&": "&",
102 ">": ">",
103 "<": "&lt;",
104 "#": "&#35;",
105 "$": "&#36;",
106 }
107 cheetah_escape_table = {"$": "\\$", "#": "\\#"} 57 cheetah_escape_table = {"$": "\\$", "#": "\\#"}
108
109
110 def html_escape(text):
111 """Produce entities within text."""
112 return "".join([html_escape_table.get(c, c) for c in text])
113 58
114 59
115 def cheetah_escape(text): 60 def cheetah_escape(text):
116 """Produce entities within text.""" 61 """Produce entities within text."""
117 return "".join([cheetah_escape_table.get(c, c) for c in text]) 62 return "".join([cheetah_escape_table.get(c, c) for c in text])
139 """ 84 """
140 prepare command line cl for running the tool here 85 prepare command line cl for running the tool here
141 and prepare elements needed for galaxyxml tool generation 86 and prepare elements needed for galaxyxml tool generation
142 """ 87 """
143 self.ourcwd = os.getcwd() 88 self.ourcwd = os.getcwd()
144 self.ourenv = copy.deepcopy(os.environ) 89 self.collections = []
145 self.infiles = [x.split(ourdelim) for x in args.input_files] 90 if len(args.collection) > 0:
146 self.outfiles = [x.split(ourdelim) for x in args.output_files] 91 try:
147 self.addpar = [x.split(ourdelim) for x in args.additional_parameters] 92 self.collections = [
93 json.loads(x) for x in args.collection if len(x.strip()) > 1
94 ]
95 except Exception:
96 print(
97 f"--collections parameter {str(args.collection)} is malformed - should be a dictionary"
98 )
99 try:
100 self.infiles = [
101 json.loads(x) for x in args.input_files if len(x.strip()) > 1
102 ]
103 except Exception:
104 print(
105 f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary"
106 )
107 try:
108 self.outfiles = [
109 json.loads(x) for x in args.output_files if len(x.strip()) > 1
110 ]
111 except Exception:
112 print(
113 f"--output_files parameter {args.output_files} is malformed - should be a dictionary"
114 )
115 try:
116 self.addpar = [
117 json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1
118 ]
119 except Exception:
120 print(
121 f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary"
122 )
123 try:
124 self.selpar = [
125 json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1
126 ]
127 except Exception:
128 print(
129 f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary"
130 )
148 self.args = args 131 self.args = args
149 self.cleanuppar() 132 self.cleanuppar()
150 self.lastclredirect = None 133 self.lastclredirect = None
151 self.lastxclredirect = None 134 self.lastxclredirect = None
152 self.cl = [] 135 self.cl = []
153 self.xmlcl = [] 136 self.xmlcl = []
154 self.is_positional = self.args.parampass == "positional" 137 self.is_positional = self.args.parampass == "positional"
155 if self.args.sysexe: 138 if self.args.sysexe:
156 self.executeme = self.args.sysexe 139 if ' ' in self.args.sysexe:
140 self.executeme = self.args.sysexe.split(' ')
141 else:
142 self.executeme = [self.args.sysexe, ]
157 else: 143 else:
158 if self.args.packages: 144 if self.args.packages:
159 self.executeme = self.args.packages.split(",")[0].split(":")[0].strip() 145 self.executeme = [self.args.packages.split(",")[0].split(":")[0].strip(), ]
160 else: 146 else:
161 self.executeme = None 147 self.executeme = None
162 aCL = self.cl.append 148 aCL = self.cl.append
163 aXCL = self.xmlcl.append 149 aXCL = self.xmlcl.append
164 assert args.parampass in [ 150 assert args.parampass in [
173 self.tool_id, 159 self.tool_id,
174 self.args.tool_version, 160 self.args.tool_version,
175 self.args.tool_desc, 161 self.args.tool_desc,
176 FAKEEXE, 162 FAKEEXE,
177 ) 163 )
178 self.newtarpath = "toolfactory_%s.tgz" % self.tool_name 164 self.newtarpath = "%s_toolshed.gz" % self.tool_name
179 self.tooloutdir = "./tfout" 165 self.tooloutdir = "./tfout"
180 self.repdir = "./TF_run_report_tempdir" 166 self.repdir = "./TF_run_report_tempdir"
181 self.testdir = os.path.join(self.tooloutdir, "test-data") 167 self.testdir = os.path.join(self.tooloutdir, "test-data")
182 if not os.path.exists(self.tooloutdir): 168 if not os.path.exists(self.tooloutdir):
183 os.mkdir(self.tooloutdir) 169 os.mkdir(self.tooloutdir)
198 if self.args.test_override: 184 if self.args.test_override:
199 stos = open(self.args.test_override, "r").readlines() 185 stos = open(self.args.test_override, "r").readlines()
200 self.test_override = [x.rstrip() for x in stos] 186 self.test_override = [x.rstrip() for x in stos]
201 else: 187 else:
202 self.test_override = None 188 self.test_override = None
203 if self.args.cl_prefix: # DIY CL start 189 if self.args.script_path:
190 for ex in self.executeme:
191 aCL(ex)
192 aXCL(ex)
193 aCL(self.sfile)
194 aXCL("$runme")
195 else:
196 aCL(self.executeme[0])
197 aXCL(self.executeme[0])
198 self.elog = os.path.join(self.repdir, "%s_error_log.txt" % self.tool_name)
199 self.tlog = os.path.join(self.repdir, "%s_runner_log.txt" % self.tool_name)
200 if self.args.parampass == "0":
201 self.clsimple()
202 else:
203 if self.args.parampass == "positional":
204 self.prepclpos()
205 self.clpositional()
206 else:
207 self.prepargp()
208 self.clargparse()
209 if self.args.cl_prefix: # DIY CL end - misnamed!
204 clp = self.args.cl_prefix.split(" ") 210 clp = self.args.cl_prefix.split(" ")
205 for c in clp: 211 for c in clp:
206 aCL(c) 212 aCL(c)
207 aXCL(c) 213 aXCL(c)
208 else: 214
209 if self.args.script_path: 215 def clsimple(self):
210 aCL(self.executeme) 216 """no parameters - uses < and > for i/o"""
211 aCL(self.sfile) 217 aCL = self.cl.append
212 aXCL(self.executeme) 218 aXCL = self.xmlcl.append
213 aXCL("$runme") 219 if len(self.infiles) > 0:
214 else: 220 aCL("<")
215 aCL(self.executeme) 221 aCL(self.infiles[0]["infilename"])
216 aXCL(self.executeme) 222 aXCL("<")
217 self.elog = os.path.join(self.repdir, "%s_error_log.txt" % self.tool_name) 223 aXCL("$%s" % self.infiles[0]["infilename"])
218 self.tlog = os.path.join(self.repdir, "%s_runner_log.txt" % self.tool_name) 224 if len(self.outfiles) > 0:
219 225 aCL(">")
220 if self.args.parampass == "0": 226 aCL(self.outfiles[0]["name"])
221 self.clsimple() 227 aXCL(">")
222 else: 228 aXCL("$%s" % self.outfiles[0]["name"])
223 clsuffix = [] 229
224 xclsuffix = [] 230 def prepargp(self):
225 for i, p in enumerate(self.infiles): 231 clsuffix = []
226 if p[IOCLPOS].upper() == "STDIN": 232 xclsuffix = []
227 appendme = [ 233 for i, p in enumerate(self.infiles):
228 p[ICLPOS], 234 if p["origCL"].strip().upper() == "STDIN":
229 p[ICLPOS], 235 appendme = [
230 p[IPATHPOS], 236 p["infilename"],
231 "< %s" % p[IPATHPOS], 237 p["infilename"],
232 ] 238 "< %s" % p["infilename"],
233 xappendme = [ 239 ]
234 p[ICLPOS], 240 xappendme = [
235 p[ICLPOS], 241 p["infilename"],
236 p[IPATHPOS], 242 p["infilename"],
237 "< $%s" % p[ICLPOS], 243 "< $%s" % p["infilename"],
238 ] 244 ]
239 else: 245 else:
240 appendme = [p[IOCLPOS], p[ICLPOS], p[IPATHPOS], ""] 246 appendme = [p["CL"], p["CL"], ""]
241 xappendme = [p[IOCLPOS], p[ICLPOS], "$%s" % p[ICLPOS], ""] 247 xappendme = [p["CL"], "$%s" % p["CL"], ""]
242 clsuffix.append(appendme) 248 clsuffix.append(appendme)
243 xclsuffix.append(xappendme) 249 xclsuffix.append(xappendme)
244 for i, p in enumerate(self.outfiles): 250 for i, p in enumerate(self.outfiles):
245 if p[OOCLPOS] == "STDOUT": 251 if p["origCL"].strip().upper() == "STDOUT":
246 self.lastclredirect = [">", p[ONAMEPOS]] 252 self.lastclredirect = [">", p["name"]]
247 self.lastxclredirect = [">", "$%s" % p[OCLPOS]] 253 self.lastxclredirect = [">", "$%s" % p["name"]]
248 else: 254 else:
249 clsuffix.append([p[OCLPOS], p[ONAMEPOS], p[ONAMEPOS], ""]) 255 clsuffix.append([p["name"], p["name"], ""])
250 xclsuffix.append([p[OCLPOS], p[ONAMEPOS], "$%s" % p[ONAMEPOS], ""]) 256 xclsuffix.append([p["name"], "$%s" % p["name"], ""])
251 for p in self.addpar: 257 for p in self.addpar:
252 clsuffix.append([p[AOCLPOS], p[ACLPOS], p[AVALPOS], p[AOVERPOS]]) 258 clsuffix.append([p["CL"], p["name"], p["override"]])
253 xclsuffix.append( 259 xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
254 [p[AOCLPOS], p[ACLPOS], '"$%s"' % p[ANAMEPOS], p[AOVERPOS]] 260 for p in self.selpar:
255 ) 261 clsuffix.append([p["CL"], p["name"], p["override"]])
256 clsuffix.sort() 262 xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
257 xclsuffix.sort() 263 clsuffix.sort()
258 self.xclsuffix = xclsuffix 264 xclsuffix.sort()
259 self.clsuffix = clsuffix 265 self.xclsuffix = xclsuffix
260 if self.args.parampass == "positional": 266 self.clsuffix = clsuffix
261 self.clpositional() 267
262 else: 268 def prepclpos(self):
263 self.clargparse() 269 clsuffix = []
270 xclsuffix = []
271 for i, p in enumerate(self.infiles):
272 if p["origCL"].strip().upper() == "STDIN":
273 appendme = [
274 "999",
275 p["infilename"],
276 "< $%s" % p["infilename"],
277 ]
278 xappendme = [
279 "999",
280 p["infilename"],
281 "< $%s" % p["infilename"],
282 ]
283 else:
284 appendme = [p["CL"], p["infilename"], ""]
285 xappendme = [p["CL"], "$%s" % p["infilename"], ""]
286 clsuffix.append(appendme)
287 xclsuffix.append(xappendme)
288 for i, p in enumerate(self.outfiles):
289 if p["origCL"].strip().upper() == "STDOUT":
290 self.lastclredirect = [">", p["name"]]
291 self.lastxclredirect = [">", "$%s" % p["name"]]
292 else:
293 clsuffix.append([p["CL"], p["name"], ""])
294 xclsuffix.append([p["CL"], "$%s" % p["name"], ""])
295 for p in self.addpar:
296 clsuffix.append([p["CL"], p["name"], p["override"]])
297 xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
298 for p in self.selpar:
299 clsuffix.append([p["CL"], p["name"], p["override"]])
300 xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
301 clsuffix.sort()
302 xclsuffix.sort()
303 self.xclsuffix = xclsuffix
304 self.clsuffix = clsuffix
264 305
265 def prepScript(self): 306 def prepScript(self):
266 rx = open(self.args.script_path, "r").readlines() 307 rx = open(self.args.script_path, "r").readlines()
267 rx = [x.rstrip() for x in rx] 308 rx = [x.rstrip() for x in rx]
268 rxcheck = [x.strip() for x in rx if x.strip() > ""] 309 rxcheck = [x.strip() for x in rx if x.strip() > ""]
269 assert len(rxcheck) > 0, "Supplied script is empty. Cannot run" 310 assert len(rxcheck) > 0, "Supplied script is empty. Cannot run"
270 self.script = "\n".join(rx) 311 self.script = "\n".join(rx)
271 fhandle, self.sfile = tempfile.mkstemp( 312 fhandle, self.sfile = tempfile.mkstemp(
272 prefix=self.tool_name, suffix="_%s" % (self.executeme) 313 prefix=self.tool_name, suffix="_%s" % (self.executeme[0])
273 ) 314 )
274 tscript = open(self.sfile, "w") 315 tscript = open(self.sfile, "w")
275 tscript.write(self.script) 316 tscript.write(self.script)
276 tscript.close() 317 tscript.close()
277 self.escapedScript = [cheetah_escape(x) for x in rx] 318 self.escapedScript = [cheetah_escape(x) for x in rx]
278 self.spacedScript = [f" {x}" for x in rx if x.strip() > ""] 319 self.spacedScript = [f" {x}" for x in rx if x.strip() > ""]
279 art = "%s.%s" % (self.tool_name, self.executeme) 320 art = "%s.%s" % (self.tool_name, self.executeme[0])
280 artifact = open(art, "wb") 321 artifact = open(art, "wb")
281 artifact.write(bytes("\n".join(self.escapedScript), "utf8")) 322 artifact.write(bytes("\n".join(self.escapedScript), "utf8"))
282 artifact.close() 323 artifact.close()
283 324
284 def cleanuppar(self): 325 def cleanuppar(self):
285 """ positional parameters are complicated by their numeric ordinal""" 326 """ positional parameters are complicated by their numeric ordinal"""
286 if self.args.parampass == "positional": 327 if self.args.parampass == "positional":
287 for i, p in enumerate(self.infiles): 328 for i, p in enumerate(self.infiles):
288 assert ( 329 assert (
289 p[ICLPOS].isdigit() or p[ICLPOS].strip().upper() == "STDIN" 330 p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN"
290 ), "Positional parameters must be ordinal integers - got %s for %s" % ( 331 ), "Positional parameters must be ordinal integers - got %s for %s" % (
291 p[ICLPOS], 332 p["CL"],
292 p[ILABPOS], 333 p["label"],
293 ) 334 )
294 for i, p in enumerate(self.outfiles): 335 for i, p in enumerate(self.outfiles):
295 assert ( 336 assert (
296 p[OCLPOS].isdigit() or p[OCLPOS].strip().upper() == "STDOUT" 337 p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT"
297 ), "Positional parameters must be ordinal integers - got %s for %s" % ( 338 ), "Positional parameters must be ordinal integers - got %s for %s" % (
298 p[OCLPOS], 339 p["CL"],
299 p[ONAMEPOS], 340 p["name"],
300 ) 341 )
301 for i, p in enumerate(self.addpar): 342 for i, p in enumerate(self.addpar):
302 assert p[ 343 assert p[
303 ACLPOS 344 "CL"
304 ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % ( 345 ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % (
305 p[ACLPOS], 346 p["CL"],
306 p[ANAMEPOS], 347 p["name"],
307 ) 348 )
308 for i, p in enumerate(self.infiles): 349 for i, p in enumerate(self.infiles):
309 infp = copy.copy(p) 350 infp = copy.copy(p)
310 icl = infp[ICLPOS] 351 infp["origCL"] = infp["CL"]
311 infp.append(icl) 352 if self.args.parampass in ["positional", "0"]:
312 if ( 353 infp["infilename"] = infp["label"].replace(" ", "_")
313 infp[ICLPOS].isdigit() 354 else:
314 or self.args.parampass == "0" 355 infp["infilename"] = infp["CL"]
315 or infp[ICLPOS].strip().upper() == "STDOUT"
316 ):
317 scl = "input%d" % (i + 1)
318 infp[ICLPOS] = scl
319 self.infiles[i] = infp 356 self.infiles[i] = infp
320 for i, p in enumerate(self.outfiles): 357 for i, p in enumerate(self.outfiles):
321 p.append(p[OCLPOS]) # keep copy 358 p["origCL"] = p["CL"] # keep copy
322 if (p[OOCLPOS].isdigit() and self.args.parampass != "positional") or p[
323 OOCLPOS
324 ].strip().upper() == "STDOUT":
325 scl = p[ONAMEPOS]
326 p[OCLPOS] = scl
327 self.outfiles[i] = p 359 self.outfiles[i] = p
328 for i, p in enumerate(self.addpar): 360 for i, p in enumerate(self.addpar):
329 p.append(p[ACLPOS]) 361 p["origCL"] = p["CL"]
330 if p[ACLPOS].isdigit():
331 scl = "param%s" % p[ACLPOS]
332 p[ACLPOS] = scl
333 self.addpar[i] = p 362 self.addpar[i] = p
334
335 def clsimple(self):
336 """no parameters - uses < and > for i/o"""
337 aCL = self.cl.append
338 aXCL = self.xmlcl.append
339
340 if len(self.infiles) > 0:
341 aCL("<")
342 aCL(self.infiles[0][IPATHPOS])
343 aXCL("<")
344 aXCL("$%s" % self.infiles[0][ICLPOS])
345 if len(self.outfiles) > 0:
346 aCL(">")
347 aCL(self.outfiles[0][OCLPOS])
348 aXCL(">")
349 aXCL("$%s" % self.outfiles[0][ONAMEPOS])
350 363
351 def clpositional(self): 364 def clpositional(self):
352 # inputs in order then params 365 # inputs in order then params
353 aCL = self.cl.append 366 aCL = self.cl.append
354 for (o_v, k, v, koverride) in self.clsuffix: 367 for (k, v, koverride) in self.clsuffix:
355 if " " in v: 368 if " " in v:
356 aCL("%s" % v) 369 aCL("%s" % v)
357 else: 370 else:
358 aCL(v) 371 aCL(v)
359 aXCL = self.xmlcl.append 372 aXCL = self.xmlcl.append
360 for (o_v, k, v, koverride) in self.xclsuffix: 373 for (k, v, koverride) in self.xclsuffix:
361 aXCL(v) 374 aXCL(v)
362 if self.lastxclredirect: 375 if self.lastxclredirect:
363 aXCL(self.lastxclredirect[0]) 376 aXCL(self.lastxclredirect[0])
364 aXCL(self.lastxclredirect[1]) 377 aXCL(self.lastxclredirect[1])
365 378
367 """argparse style""" 380 """argparse style"""
368 aCL = self.cl.append 381 aCL = self.cl.append
369 aXCL = self.xmlcl.append 382 aXCL = self.xmlcl.append
370 # inputs then params in argparse named form 383 # inputs then params in argparse named form
371 384
372 for (o_v, k, v, koverride) in self.xclsuffix: 385 for (k, v, koverride) in self.xclsuffix:
373 if koverride > "": 386 if koverride > "":
374 k = koverride 387 k = koverride
375 elif len(k.strip()) == 1: 388 elif len(k.strip()) == 1:
376 k = "-%s" % k 389 k = "-%s" % k
377 else: 390 else:
378 k = "--%s" % k 391 k = "--%s" % k
379 aXCL(k) 392 aXCL(k)
380 aXCL(v) 393 aXCL(v)
381 for (o_v, k, v, koverride) in self.clsuffix: 394 for (k, v, koverride) in self.clsuffix:
382 if koverride > "": 395 if koverride > "":
383 k = koverride 396 k = koverride
384 elif len(k.strip()) == 1: 397 elif len(k.strip()) == 1:
385 k = "-%s" % k 398 k = "-%s" % k
386 else: 399 else:
398 return ndash 411 return ndash
399 412
400 def doXMLparam(self): 413 def doXMLparam(self):
401 """flake8 made me do this...""" 414 """flake8 made me do this..."""
402 for p in self.outfiles: 415 for p in self.outfiles:
403 # --output_files "$otab.history_name~~~$otab.history_format~~~$otab.history_CL~~~$otab.history_test" 416 newname = p["name"]
404 newname, newfmt, newcl, test, oldcl = p 417 newfmt = p["format"]
418 newcl = p["CL"]
419 test = p["test"]
420 oldcl = p["origCL"]
405 test = test.strip() 421 test = test.strip()
406 ndash = self.getNdash(newcl) 422 ndash = self.getNdash(newcl)
407 aparm = gxtp.OutputData( 423 aparm = gxtp.OutputData(
408 name=newname, format=newfmt, num_dashes=ndash, label=newname 424 name=newname, format=newfmt, num_dashes=ndash, label=newname
409 ) 425 )
444 value="%s_sample" % newname, 460 value="%s_sample" % newname,
445 compare=c, 461 compare=c,
446 delta=delta, 462 delta=delta,
447 delta_frac=delta_frac, 463 delta_frac=delta_frac,
448 ) 464 )
465 else:
466 c = test
467 tp = gxtp.TestOutput(
468 name=newname,
469 value="%s_sample" % newname,
470 compare=c,
471 )
449 self.testparam.append(tp) 472 self.testparam.append(tp)
450 for p in self.infiles: 473 for p in self.infiles:
451 newname = p[ICLPOS] 474 newname = p["infilename"]
452 newfmt = p[IFMTPOS] 475 newfmt = p["format"]
453 ndash = self.getNdash(newname) 476 ndash = self.getNdash(newname)
454 if not len(p[ILABPOS]) > 0: 477 if not len(p["label"]) > 0:
455 alab = p[ICLPOS] 478 alab = p["CL"]
456 else: 479 else:
457 alab = p[ILABPOS] 480 alab = p["label"]
458 aninput = gxtp.DataParam( 481 aninput = gxtp.DataParam(
459 newname, 482 newname,
460 optional=False, 483 optional=False,
461 label=alab, 484 label=alab,
462 help=p[IHELPOS], 485 help=p["help"],
463 format=newfmt, 486 format=newfmt,
464 multiple=False, 487 multiple=False,
465 num_dashes=ndash, 488 num_dashes=ndash,
466 ) 489 )
467 aninput.positional = self.is_positional 490 aninput.positional = self.is_positional
491 if self.is_positional:
492 if p["origCL"].upper() == "STDIN":
493 aparm.positional = 9999998
494 aparm.command_line_override = "> $%s" % newname
495 else:
496 aparm.positional = int(p["origCL"])
497 aparm.command_line_override = "$%s" % newname
468 self.tinputs.append(aninput) 498 self.tinputs.append(aninput)
469 tparm = gxtp.TestParam(name=newname, value="%s_sample" % newname) 499 tparm = gxtp.TestParam(name=newname, value="%s_sample" % newname)
470 self.testparam.append(tparm) 500 self.testparam.append(tparm)
471 for p in self.addpar: 501 for p in self.addpar:
472 ( 502 newname = p["name"]
473 newname, 503 newval = p["value"]
474 newval, 504 newlabel = p["label"]
475 newlabel, 505 newhelp = p["help"]
476 newhelp, 506 newtype = p["type"]
477 newtype, 507 newcl = p["CL"]
478 newcl, 508 oldcl = p["origCL"]
479 override,
480 oldcl,
481 ) = p
482 if not len(newlabel) > 0: 509 if not len(newlabel) > 0:
483 newlabel = newname 510 newlabel = newname
484 ndash = self.getNdash(newname) 511 ndash = self.getNdash(newname)
485 if newtype == "text": 512 if newtype == "text":
486 aparm = gxtp.TextParam( 513 aparm = gxtp.TextParam(
504 label=newname, 531 label=newname,
505 help=newhelp, 532 help=newhelp,
506 value=newval, 533 value=newval,
507 num_dashes=ndash, 534 num_dashes=ndash,
508 ) 535 )
536 elif newtype == "boolean":
537 aparm = gxtp.BooleanParam(
538 newname,
539 label=newname,
540 help=newhelp,
541 value=newval,
542 num_dashes=ndash,
543 )
509 else: 544 else:
510 raise ValueError( 545 raise ValueError(
511 'Unrecognised parameter type "%s" for\ 546 'Unrecognised parameter type "%s" for\
512 additional parameter %s in makeXML' 547 additional parameter %s in makeXML'
513 % (newtype, newname) 548 % (newtype, newname)
516 if self.is_positional: 551 if self.is_positional:
517 aparm.positional = int(oldcl) 552 aparm.positional = int(oldcl)
518 self.tinputs.append(aparm) 553 self.tinputs.append(aparm)
519 tparm = gxtp.TestParam(newname, value=newval) 554 tparm = gxtp.TestParam(newname, value=newval)
520 self.testparam.append(tparm) 555 self.testparam.append(tparm)
556 for p in self.selpar:
557 newname = p["name"]
558 newval = p["value"]
559 newlabel = p["label"]
560 newhelp = p["help"]
561 newtype = p["type"]
562 newcl = p["CL"]
563 if not len(newlabel) > 0:
564 newlabel = newname
565 ndash = self.getNdash(newname)
566 if newtype == "selecttext":
567 newtext = p["texts"]
568 aparm = gxtp.SelectParam(
569 newname,
570 label=newlabel,
571 help=newhelp,
572 num_dashes=ndash,
573 )
574 for i in range(len(newval)):
575 anopt = gxtp.SelectOption(
576 value=newval[i],
577 text=newtext[i],
578 )
579 aparm.append(anopt)
580 aparm.positional = self.is_positional
581 if self.is_positional:
582 aparm.positional = int(newcl)
583 self.tinputs.append(aparm)
584 tparm = gxtp.TestParam(newname, value=newval)
585 self.testparam.append(tparm)
586 else:
587 raise ValueError(
588 'Unrecognised parameter type "%s" for\
589 selecttext parameter %s in makeXML'
590 % (newtype, newname)
591 )
592 for p in self.collections:
593 newkind = p["kind"]
594 newname = p["name"]
595 newlabel = p["label"]
596 newdisc = p["discover"]
597 collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind)
598 disc = gxtp.DiscoverDatasets(
599 pattern=newdisc, directory=f"{newname}", visible="false"
600 )
601 collect.append(disc)
602 self.toutputs.append(collect)
603 tparm = gxtp.TestOutput(newname, ftype="pdf")
604 self.testparam.append(tparm)
521 605
522 def doNoXMLparam(self): 606 def doNoXMLparam(self):
523 """filter style package - stdin to stdout""" 607 """filter style package - stdin to stdout"""
524 if len(self.infiles) > 0: 608 if len(self.infiles) > 0:
525 alab = self.infiles[0][ILABPOS] 609 alab = self.infiles[0]["label"]
526 if len(alab) == 0: 610 if len(alab) == 0:
527 alab = self.infiles[0][ICLPOS] 611 alab = self.infiles[0]["infilename"]
528 max1s = ( 612 max1s = (
529 "Maximum one input if parampass is 0 but multiple input files supplied - %s" 613 "Maximum one input if parampass is 0 but multiple input files supplied - %s"
530 % str(self.infiles) 614 % str(self.infiles)
531 ) 615 )
532 assert len(self.infiles) == 1, max1s 616 assert len(self.infiles) == 1, max1s
533 newname = self.infiles[0][ICLPOS] 617 newname = self.infiles[0]["infilename"]
534 aninput = gxtp.DataParam( 618 aninput = gxtp.DataParam(
535 newname, 619 newname,
536 optional=False, 620 optional=False,
537 label=alab, 621 label=alab,
538 help=self.infiles[0][IHELPOS], 622 help=self.infiles[0]["help"],
539 format=self.infiles[0][IFMTPOS], 623 format=self.infiles[0]["format"],
540 multiple=False, 624 multiple=False,
541 num_dashes=0, 625 num_dashes=0,
542 ) 626 )
543 aninput.command_line_override = "< $%s" % newname 627 aninput.command_line_override = "< $%s" % newname
544 aninput.positional = self.is_positional 628 aninput.positional = True
545 self.tinputs.append(aninput) 629 self.tinputs.append(aninput)
546 tp = gxtp.TestParam(name=newname, value="%s_sample" % newname) 630 tp = gxtp.TestParam(name=newname, value="%s_sample" % newname)
547 self.testparam.append(tp) 631 self.testparam.append(tp)
548 if len(self.outfiles) > 0: 632 if len(self.outfiles) > 0:
549 newname = self.outfiles[0][OCLPOS] 633 newname = self.outfiles[0]["name"]
550 newfmt = self.outfiles[0][OFMTPOS] 634 newfmt = self.outfiles[0]["format"]
551 anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0) 635 anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0)
552 anout.command_line_override = "> $%s" % newname 636 anout.command_line_override = "> $%s" % newname
553 anout.positional = self.is_positional 637 anout.positional = self.is_positional
554 self.toutputs.append(anout) 638 self.toutputs.append(anout)
555 tp = gxtp.TestOutput( 639 tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname)
556 name=newname, value="%s_sample" % newname
557 )
558 self.testparam.append(tp) 640 self.testparam.append(tp)
559 641
560 def makeXML(self): 642 def makeXML(self):
561 """ 643 """
562 Create a Galaxy xml tool wrapper for the new script 644 Create a Galaxy xml tool wrapper for the new script
637 if ( 719 if (
638 self.test_override 720 self.test_override
639 ): # cannot do this inside galaxyxml as it expects lxml objects for tests 721 ): # cannot do this inside galaxyxml as it expects lxml objects for tests
640 part1 = exml.split("<tests>")[0] 722 part1 = exml.split("<tests>")[0]
641 part2 = exml.split("</tests>")[1] 723 part2 = exml.split("</tests>")[1]
642 fixed = "%s\n%s\n%s" % (part1, self.test_override, part2) 724 fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2)
643 exml = fixed 725 exml = fixed
644 # exml = exml.replace('range="1:"', 'range="1000:"') 726 # exml = exml.replace('range="1:"', 'range="1000:"')
645 xf = open("%s.xml" % self.tool_name, "w") 727 xf = open("%s.xml" % self.tool_name, "w")
646 xf.write(exml) 728 xf.write(exml)
647 xf.write("\n") 729 xf.write("\n")
672 sto.write( 754 sto.write(
673 "## Executing Toolfactory generated command line = %s\n" % scl 755 "## Executing Toolfactory generated command line = %s\n" % scl
674 ) 756 )
675 sto.flush() 757 sto.flush()
676 subp = subprocess.run( 758 subp = subprocess.run(
677 self.cl, env=self.ourenv, shell=False, stdout=sto, stderr=ste 759 self.cl, shell=False, stdout=sto, stderr=ste
678 ) 760 )
679 sto.close() 761 sto.close()
680 ste.close() 762 ste.close()
681 retval = subp.returncode 763 retval = subp.returncode
682 else: # work around special case - stdin and write to stdout 764 else: # work around special case - stdin and write to stdout
683 if len(self.infiles) > 0: 765 if len(self.infiles) > 0:
684 sti = open(self.infiles[0][IPATHPOS], "rb") 766 sti = open(self.infiles[0]["name"], "rb")
685 else: 767 else:
686 sti = sys.stdin 768 sti = sys.stdin
687 if len(self.outfiles) > 0: 769 if len(self.outfiles) > 0:
688 sto = open(self.outfiles[0][ONAMEPOS], "wb") 770 sto = open(self.outfiles[0]["name"], "wb")
689 else: 771 else:
690 sto = sys.stdout 772 sto = sys.stdout
691 subp = subprocess.run( 773 subp = subprocess.run(
692 self.cl, env=self.ourenv, shell=False, stdout=sto, stdin=sti 774 self.cl, shell=False, stdout=sto, stdin=sti
693 ) 775 )
694 sto.write("## Executing Toolfactory generated command line = %s\n" % scl) 776 sto.write("## Executing Toolfactory generated command line = %s\n" % scl)
695 retval = subp.returncode 777 retval = subp.returncode
696 sto.close() 778 sto.close()
697 sti.close() 779 sti.close()
783 "ToolFactory", 865 "ToolFactory",
784 ] 866 ]
785 tout.write("running\n%s\n" % " ".join(cll)) 867 tout.write("running\n%s\n" % " ".join(cll))
786 subp = subprocess.run( 868 subp = subprocess.run(
787 cll, 869 cll,
788 env=self.ourenv,
789 cwd=self.ourcwd, 870 cwd=self.ourcwd,
790 shell=False, 871 shell=False,
791 stderr=tout, 872 stderr=tout,
792 stdout=tout, 873 stdout=tout,
793 ) 874 )
813 yaml.dump(odict, yamlf, allow_unicode=True) 894 yaml.dump(odict, yamlf, allow_unicode=True)
814 yamlf.close() 895 yamlf.close()
815 896
816 def makeTool(self): 897 def makeTool(self):
817 """write xmls and input samples into place""" 898 """write xmls and input samples into place"""
818 self.makeXML() 899 if self.args.parampass == 0:
900 self.doNoXMLparam()
901 else:
902 self.makeXML()
819 if self.args.script_path: 903 if self.args.script_path:
820 stname = os.path.join(self.tooloutdir, "%s" % (self.sfile)) 904 stname = os.path.join(self.tooloutdir, self.sfile)
821 if not os.path.exists(stname): 905 if not os.path.exists(stname):
822 shutil.copyfile(self.sfile, stname) 906 shutil.copyfile(self.sfile, stname)
823 xreal = "%s.xml" % self.tool_name 907 xreal = "%s.xml" % self.tool_name
824 xout = os.path.join(self.tooloutdir, xreal) 908 xout = os.path.join(self.tooloutdir, xreal)
825 shutil.copyfile(xreal, xout) 909 shutil.copyfile(xreal, xout)
826 for p in self.infiles: 910 for p in self.infiles:
827 pth = p[IPATHPOS] 911 pth = p["name"]
828 dest = os.path.join(self.testdir, "%s_sample" % p[ICLPOS]) 912 dest = os.path.join(self.testdir, "%s_sample" % p["infilename"])
829 shutil.copyfile(pth, dest) 913 shutil.copyfile(pth, dest)
830 914 dest = os.path.join(self.repdir, "%s_sample" % p["infilename"])
831 def makeToolTar(self): 915 shutil.copyfile(pth, dest)
916
917 def makeToolTar(self, report_fail=False):
832 """move outputs into test-data and prepare the tarball""" 918 """move outputs into test-data and prepare the tarball"""
833 excludeme = "_planemo_test_report.html" 919 excludeme = "_planemo_test_report.html"
834 920
835 def exclude_function(tarinfo): 921 def exclude_function(tarinfo):
836 filename = tarinfo.name 922 filename = tarinfo.name
839 if os.path.exists(self.tlog): 925 if os.path.exists(self.tlog):
840 tout = open(self.tlog, "a") 926 tout = open(self.tlog, "a")
841 else: 927 else:
842 tout = open(self.tlog, "w") 928 tout = open(self.tlog, "w")
843 for p in self.outfiles: 929 for p in self.outfiles:
844 oname = p[ONAMEPOS] 930 oname = p["name"]
845 tdest = os.path.join(self.testdir, "%s_sample" % oname) 931 tdest = os.path.join(self.testdir, "%s_sample" % oname)
932 src = os.path.join(self.testdir, oname)
846 if not os.path.isfile(tdest): 933 if not os.path.isfile(tdest):
847 src = os.path.join(self.testdir, oname)
848 if os.path.isfile(src): 934 if os.path.isfile(src):
849 shutil.copyfile(src, tdest) 935 shutil.copyfile(src, tdest)
850 dest = os.path.join(self.repdir, "%s.sample" % (oname)) 936 dest = os.path.join(self.repdir, "%s.sample" % (oname))
851 shutil.copyfile(src, dest) 937 shutil.copyfile(src, dest)
852 else: 938 else:
853 tout.write( 939 if report_fail:
854 "###Output file %s not found in testdir %s. This is normal during the first Planemo run that generates test outputs" 940 tout.write(
855 % (tdest, self.testdir) 941 "###Tool may have failed - output file %s not found in testdir after planemo run %s."
856 ) 942 % (tdest, self.testdir)
943 )
857 tf = tarfile.open(self.newtarpath, "w:gz") 944 tf = tarfile.open(self.newtarpath, "w:gz")
858 tf.add( 945 tf.add(
859 name=self.tooloutdir, 946 name=self.tooloutdir,
860 arcname=self.tool_name, 947 arcname=self.tool_name,
861 filter=exclude_function, 948 filter=exclude_function,
868 with os.scandir(self.tooloutdir) as outs: 955 with os.scandir(self.tooloutdir) as outs:
869 for entry in outs: 956 for entry in outs:
870 if not entry.is_file(): 957 if not entry.is_file():
871 continue 958 continue
872 if "." in entry.name: 959 if "." in entry.name:
873 nayme, ext = os.path.splitext(entry.name) 960 _, ext = os.path.splitext(entry.name)
874 if ext in [".yml", ".xml", ".json", ".yaml"]: 961 if ext in [".tgz", ".json"]:
875 ext = f"{ext}.txt" 962 continue
963 if ext in [".yml", ".xml", ".yaml"]:
964 newname = f"{entry.name.replace('.','_')}.txt"
965 else:
966 newname = entry.name
876 else: 967 else:
877 ext = ".txt" 968 newname = f"{entry.name}.txt"
878 ofn = "%s%s" % (entry.name.replace(".", "_"), ext) 969 dest = os.path.join(self.repdir, newname)
879 dest = os.path.join(self.repdir, ofn)
880 src = os.path.join(self.tooloutdir, entry.name) 970 src = os.path.join(self.tooloutdir, entry.name)
881 shutil.copyfile(src, dest) 971 shutil.copyfile(src, dest)
882 with os.scandir(self.testdir) as outs: 972 if self.args.include_tests:
883 for entry in outs: 973 with os.scandir(self.testdir) as outs:
884 if ( 974 for entry in outs:
885 (not entry.is_file()) 975 if (not entry.is_file()) or entry.name.endswith(
886 or entry.name.endswith("_sample") 976 "_planemo_test_report.html"
887 or entry.name.endswith("_planemo_test_report.html") 977 ):
888 ): 978 continue
889 continue 979 if "." in entry.name:
890 if "." in entry.name: 980 _, ext = os.path.splitext(entry.name)
891 nayme, ext = os.path.splitext(entry.name) 981 if ext in [".tgz", ".json"]:
892 else: 982 continue
893 ext = ".txt" 983 if ext in [".yml", ".xml", ".yaml"]:
894 newname = f"{entry.name}{ext}" 984 newname = f"{entry.name.replace('.','_')}.txt"
895 dest = os.path.join(self.repdir, newname) 985 else:
896 src = os.path.join(self.testdir, entry.name) 986 newname = entry.name
897 shutil.copyfile(src, dest) 987 else:
898 988 newname = f"{entry.name}.txt"
899 def planemo_test(self, genoutputs=True): 989 dest = os.path.join(self.repdir, newname)
990 src = os.path.join(self.testdir, entry.name)
991 shutil.copyfile(src, dest)
992
993
994 def planemo_test_once(self):
900 """planemo is a requirement so is available for testing but needs a 995 """planemo is a requirement so is available for testing but needs a
901 different call if in the biocontainer - see above 996 different call if in the biocontainer - see above
902 and for generating test outputs if command or test overrides are 997 and for generating test outputs if command or test overrides are
903 supplied test outputs are sent to repdir for display 998 supplied test outputs are sent to repdir for display
904 """ 999 """
908 ) 1003 )
909 if os.path.exists(self.tlog): 1004 if os.path.exists(self.tlog):
910 tout = open(self.tlog, "a") 1005 tout = open(self.tlog, "a")
911 else: 1006 else:
912 tout = open(self.tlog, "w") 1007 tout = open(self.tlog, "w")
913 if genoutputs: 1008 cll = [
914 dummy, tfile = tempfile.mkstemp() 1009 "planemo",
915 cll = [ 1010 "test",
916 "planemo", 1011 "--conda_auto_init",
917 "test", 1012 "--test_data",
918 "--test_data", 1013 os.path.abspath(self.testdir),
919 os.path.abspath(self.testdir), 1014 "--test_output",
920 "--test_output", 1015 os.path.abspath(tool_test_path),
921 os.path.abspath(tool_test_path), 1016 "--galaxy_root",
922 "--skip_venv", 1017 self.args.galaxy_root,
923 "--galaxy_root", 1018 "--update_test_data",
924 self.args.galaxy_root, 1019 os.path.abspath(xreal),
925 "--update_test_data", 1020 ]
926 os.path.abspath(xreal), 1021 p = subprocess.run(
927 ] 1022 cll,
928 p = subprocess.run( 1023 shell=False,
929 cll, 1024 cwd=self.tooloutdir,
930 env=self.ourenv, 1025 stderr=tout,
931 shell=False, 1026 stdout=tout,
932 cwd=self.tooloutdir, 1027 )
933 stderr=dummy,
934 stdout=dummy,
935 )
936
937 else:
938 cll = [
939 "planemo",
940 "test",
941 "--test_data",
942 os.path.abspath(self.testdir),
943 "--test_output",
944 os.path.abspath(tool_test_path),
945 "--skip_venv",
946 "--galaxy_root",
947 self.args.galaxy_root,
948 os.path.abspath(xreal),
949 ]
950 p = subprocess.run(
951 cll,
952 shell=False,
953 env=self.ourenv,
954 cwd=self.tooloutdir,
955 stderr=tout,
956 stdout=tout,
957 )
958 tout.close() 1028 tout.close()
959 return p.returncode 1029 return p.returncode
960 1030
961 1031
962 def main(): 1032 def main():
984 a("--tool_version", default=None) 1054 a("--tool_version", default=None)
985 a("--citations", default=None) 1055 a("--citations", default=None)
986 a("--command_override", default=None) 1056 a("--command_override", default=None)
987 a("--test_override", default=None) 1057 a("--test_override", default=None)
988 a("--additional_parameters", action="append", default=[]) 1058 a("--additional_parameters", action="append", default=[])
1059 a("--selecttext_parameters", action="append", default=[])
989 a("--edit_additional_parameters", action="store_true", default=False) 1060 a("--edit_additional_parameters", action="store_true", default=False)
990 a("--parampass", default="positional") 1061 a("--parampass", default="positional")
991 a("--tfout", default="./tfout") 1062 a("--tfout", default="./tfout")
992 a("--new_tool", default="new_tool") 1063 a("--new_tool", default="new_tool")
993 a("--galaxy_url", default="http://localhost:8080") 1064 a("--galaxy_url", default="http://localhost:8080")
996 # localhost != 127.0.0.1 so validation fails 1067 # localhost != 127.0.0.1 so validation fails
997 a("--toolshed_api_key", default="fakekey") 1068 a("--toolshed_api_key", default="fakekey")
998 a("--galaxy_api_key", default="fakekey") 1069 a("--galaxy_api_key", default="fakekey")
999 a("--galaxy_root", default="/galaxy-central") 1070 a("--galaxy_root", default="/galaxy-central")
1000 a("--galaxy_venv", default="/galaxy_venv") 1071 a("--galaxy_venv", default="/galaxy_venv")
1072 a("--collection", action="append", default=[])
1073 a("--include_tests", default=False, action="store_true")
1001 args = parser.parse_args() 1074 args = parser.parse_args()
1002 assert not args.bad_user, ( 1075 assert not args.bad_user, (
1003 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \ 1076 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \
1004 admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file' 1077 admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file'
1005 % (args.bad_user, args.bad_user) 1078 % (args.bad_user, args.bad_user)
1007 assert args.tool_name, "## Tool Factory expects a tool name - eg --tool_name=DESeq" 1080 assert args.tool_name, "## Tool Factory expects a tool name - eg --tool_name=DESeq"
1008 assert ( 1081 assert (
1009 args.sysexe or args.packages 1082 args.sysexe or args.packages
1010 ), "## Tool Factory wrapper expects an interpreter \ 1083 ), "## Tool Factory wrapper expects an interpreter \
1011 or an executable package in --sysexe or --packages" 1084 or an executable package in --sysexe or --packages"
1012 args.input_files = [x.replace('"', "").replace("'", "") for x in args.input_files]
1013 # remove quotes we need to deal with spaces in CL params
1014 for i, x in enumerate(args.additional_parameters):
1015 args.additional_parameters[i] = args.additional_parameters[i].replace('"', "")
1016 r = ScriptRunner(args) 1085 r = ScriptRunner(args)
1017 r.writeShedyml() 1086 r.writeShedyml()
1018 r.makeTool() 1087 r.makeTool()
1019 if args.make_Tool == "generate": 1088 if args.make_Tool == "generate":
1020 retcode = r.run() 1089 r.run()
1021 r.moveRunOutputs() 1090 r.moveRunOutputs()
1022 r.makeToolTar() 1091 r.makeToolTar()
1023 else: 1092 else:
1024 retcode = r.planemo_test(genoutputs=True) # this fails :( - see PR 1093 # r.planemo_test(genoutputs=True) # this fails :( - see PR
1094 # r.moveRunOutputs()
1095 # r.makeToolTar(report_fail=False)
1096 r.planemo_test_once()
1025 r.moveRunOutputs() 1097 r.moveRunOutputs()
1026 r.makeToolTar() 1098 r.makeToolTar(report_fail=True)
1027 retcode = r.planemo_test(genoutputs=False)
1028 r.moveRunOutputs()
1029 r.makeToolTar()
1030 print(f"second planemo_test returned {retcode}")
1031 if args.make_Tool == "gentestinstall": 1099 if args.make_Tool == "gentestinstall":
1032 r.shedLoad() 1100 r.shedLoad()
1033 r.eph_galaxy_load() 1101 r.eph_galaxy_load()
1034 1102
1035 1103