# HG changeset patch # User fubar # Date 1616750998 0 # Node ID def0f754ee1b963bb40d24f34f4bf289b0c59bc5 # Parent 2dbb412af425c2abdc9395888782977dc93739a4 Uploaded diff -r 2dbb412af425 -r def0f754ee1b toolfactory/rgToolFactory2.py --- a/toolfactory/rgToolFactory2.py Fri Mar 26 09:27:55 2021 +0000 +++ b/toolfactory/rgToolFactory2.py Fri Mar 26 09:29:58 2021 +0000 @@ -16,6 +16,7 @@ import argparse import copy +import json import logging import os import re @@ -36,44 +37,11 @@ import yaml -myversion = "V2.1 July 2020" + +myversion = "V2.2 February 2021" verbose = True debug = True toolFactoryURL = "https://github.com/fubar2/toolfactory" -ourdelim = "~~~" - -# --input_files="$intab.input_files~~~$intab.input_CL~~~ -# $intab.input_formats# ~~~$intab.input_label -# ~~~$intab.input_help" -IPATHPOS = 0 -ICLPOS = 1 -IFMTPOS = 2 -ILABPOS = 3 -IHELPOS = 4 -IOCLPOS = 5 - -# --output_files "$otab.history_name~~~$otab.history_format~~~ -# $otab.history_CL~~~$otab.history_test" -ONAMEPOS = 0 -OFMTPOS = 1 -OCLPOS = 2 -OTESTPOS = 3 -OOCLPOS = 4 - - -# --additional_parameters="$i.param_name~~~$i.param_value~~~ -# $i.param_label~~~$i.param_help~~~$i.param_type -# ~~~$i.CL~~~i$.param_CLoverride" -ANAMEPOS = 0 -AVALPOS = 1 -ALABPOS = 2 -AHELPPOS = 3 -ATYPEPOS = 4 -ACLPOS = 5 -AOVERPOS = 6 -AOCLPOS = 7 - - foo = len(lxml.__version__) # fug you, flake8. Say my name! FAKEEXE = "~~~REMOVE~~~ME~~~" @@ -86,32 +54,9 @@ return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) -def quote_non_numeric(s): - """return a prequoted string for non-numerics - useful for perl and Rscript parameter passing? - """ - try: - _ = float(s) - return s - except ValueError: - return '"%s"' % s - - -html_escape_table = { - "&": "&", - ">": ">", - "<": "<", - "#": "#", - "$": "$", -} cheetah_escape_table = {"$": "\\$", "#": "\\#"} -def html_escape(text): - """Produce entities within text.""" - return "".join([html_escape_table.get(c, c) for c in text]) - - def cheetah_escape(text): """Produce entities within text.""" return "".join([cheetah_escape_table.get(c, c) for c in text]) @@ -141,10 +86,48 @@ and prepare elements needed for galaxyxml tool generation """ self.ourcwd = os.getcwd() - self.ourenv = copy.deepcopy(os.environ) - self.infiles = [x.split(ourdelim) for x in args.input_files] - self.outfiles = [x.split(ourdelim) for x in args.output_files] - self.addpar = [x.split(ourdelim) for x in args.additional_parameters] + self.collections = [] + if len(args.collection) > 0: + try: + self.collections = [ + json.loads(x) for x in args.collection if len(x.strip()) > 1 + ] + except Exception: + print( + f"--collections parameter {str(args.collection)} is malformed - should be a dictionary" + ) + try: + self.infiles = [ + json.loads(x) for x in args.input_files if len(x.strip()) > 1 + ] + except Exception: + print( + f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary" + ) + try: + self.outfiles = [ + json.loads(x) for x in args.output_files if len(x.strip()) > 1 + ] + except Exception: + print( + f"--output_files parameter {args.output_files} is malformed - should be a dictionary" + ) + try: + self.addpar = [ + json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1 + ] + except Exception: + print( + f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary" + ) + try: + self.selpar = [ + json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1 + ] + except Exception: + print( + f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary" + ) self.args = args self.cleanuppar() self.lastclredirect = None @@ -153,10 +136,13 @@ self.xmlcl = [] self.is_positional = self.args.parampass == "positional" if self.args.sysexe: - self.executeme = self.args.sysexe + if ' ' in self.args.sysexe: + self.executeme = self.args.sysexe.split(' ') + else: + self.executeme = [self.args.sysexe, ] else: if self.args.packages: - self.executeme = self.args.packages.split(",")[0].split(":")[0].strip() + self.executeme = [self.args.packages.split(",")[0].split(":")[0].strip(), ] else: self.executeme = None aCL = self.cl.append @@ -175,7 +161,7 @@ self.args.tool_desc, FAKEEXE, ) - self.newtarpath = "toolfactory_%s.tgz" % self.tool_name + self.newtarpath = "%s_toolshed.gz" % self.tool_name self.tooloutdir = "./tfout" self.repdir = "./TF_run_report_tempdir" self.testdir = os.path.join(self.tooloutdir, "test-data") @@ -200,67 +186,122 @@ self.test_override = [x.rstrip() for x in stos] else: self.test_override = None - if self.args.cl_prefix: # DIY CL start + if self.args.script_path: + for ex in self.executeme: + aCL(ex) + aXCL(ex) + aCL(self.sfile) + aXCL("$runme") + else: + aCL(self.executeme[0]) + aXCL(self.executeme[0]) + self.elog = os.path.join(self.repdir, "%s_error_log.txt" % self.tool_name) + self.tlog = os.path.join(self.repdir, "%s_runner_log.txt" % self.tool_name) + if self.args.parampass == "0": + self.clsimple() + else: + if self.args.parampass == "positional": + self.prepclpos() + self.clpositional() + else: + self.prepargp() + self.clargparse() + if self.args.cl_prefix: # DIY CL end - misnamed! clp = self.args.cl_prefix.split(" ") for c in clp: aCL(c) aXCL(c) - else: - if self.args.script_path: - aCL(self.executeme) - aCL(self.sfile) - aXCL(self.executeme) - aXCL("$runme") - else: - aCL(self.executeme) - aXCL(self.executeme) - self.elog = os.path.join(self.repdir, "%s_error_log.txt" % self.tool_name) - self.tlog = os.path.join(self.repdir, "%s_runner_log.txt" % self.tool_name) + + def clsimple(self): + """no parameters - uses < and > for i/o""" + aCL = self.cl.append + aXCL = self.xmlcl.append + if len(self.infiles) > 0: + aCL("<") + aCL(self.infiles[0]["infilename"]) + aXCL("<") + aXCL("$%s" % self.infiles[0]["infilename"]) + if len(self.outfiles) > 0: + aCL(">") + aCL(self.outfiles[0]["name"]) + aXCL(">") + aXCL("$%s" % self.outfiles[0]["name"]) - if self.args.parampass == "0": - self.clsimple() - else: - clsuffix = [] - xclsuffix = [] - for i, p in enumerate(self.infiles): - if p[IOCLPOS].upper() == "STDIN": - appendme = [ - p[ICLPOS], - p[ICLPOS], - p[IPATHPOS], - "< %s" % p[IPATHPOS], - ] - xappendme = [ - p[ICLPOS], - p[ICLPOS], - p[IPATHPOS], - "< $%s" % p[ICLPOS], - ] - else: - appendme = [p[IOCLPOS], p[ICLPOS], p[IPATHPOS], ""] - xappendme = [p[IOCLPOS], p[ICLPOS], "$%s" % p[ICLPOS], ""] - clsuffix.append(appendme) - xclsuffix.append(xappendme) - for i, p in enumerate(self.outfiles): - if p[OOCLPOS] == "STDOUT": - self.lastclredirect = [">", p[ONAMEPOS]] - self.lastxclredirect = [">", "$%s" % p[OCLPOS]] - else: - clsuffix.append([p[OCLPOS], p[ONAMEPOS], p[ONAMEPOS], ""]) - xclsuffix.append([p[OCLPOS], p[ONAMEPOS], "$%s" % p[ONAMEPOS], ""]) - for p in self.addpar: - clsuffix.append([p[AOCLPOS], p[ACLPOS], p[AVALPOS], p[AOVERPOS]]) - xclsuffix.append( - [p[AOCLPOS], p[ACLPOS], '"$%s"' % p[ANAMEPOS], p[AOVERPOS]] - ) - clsuffix.sort() - xclsuffix.sort() - self.xclsuffix = xclsuffix - self.clsuffix = clsuffix - if self.args.parampass == "positional": - self.clpositional() + def prepargp(self): + clsuffix = [] + xclsuffix = [] + for i, p in enumerate(self.infiles): + if p["origCL"].strip().upper() == "STDIN": + appendme = [ + p["infilename"], + p["infilename"], + "< %s" % p["infilename"], + ] + xappendme = [ + p["infilename"], + p["infilename"], + "< $%s" % p["infilename"], + ] + else: + appendme = [p["CL"], p["CL"], ""] + xappendme = [p["CL"], "$%s" % p["CL"], ""] + clsuffix.append(appendme) + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastclredirect = [">", p["name"]] + self.lastxclredirect = [">", "$%s" % p["name"]] else: - self.clargparse() + clsuffix.append([p["name"], p["name"], ""]) + xclsuffix.append([p["name"], "$%s" % p["name"], ""]) + for p in self.addpar: + clsuffix.append([p["CL"], p["name"], p["override"]]) + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + for p in self.selpar: + clsuffix.append([p["CL"], p["name"], p["override"]]) + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + clsuffix.sort() + xclsuffix.sort() + self.xclsuffix = xclsuffix + self.clsuffix = clsuffix + + def prepclpos(self): + clsuffix = [] + xclsuffix = [] + for i, p in enumerate(self.infiles): + if p["origCL"].strip().upper() == "STDIN": + appendme = [ + "999", + p["infilename"], + "< $%s" % p["infilename"], + ] + xappendme = [ + "999", + p["infilename"], + "< $%s" % p["infilename"], + ] + else: + appendme = [p["CL"], p["infilename"], ""] + xappendme = [p["CL"], "$%s" % p["infilename"], ""] + clsuffix.append(appendme) + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastclredirect = [">", p["name"]] + self.lastxclredirect = [">", "$%s" % p["name"]] + else: + clsuffix.append([p["CL"], p["name"], ""]) + xclsuffix.append([p["CL"], "$%s" % p["name"], ""]) + for p in self.addpar: + clsuffix.append([p["CL"], p["name"], p["override"]]) + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + for p in self.selpar: + clsuffix.append([p["CL"], p["name"], p["override"]]) + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + clsuffix.sort() + xclsuffix.sort() + self.xclsuffix = xclsuffix + self.clsuffix = clsuffix def prepScript(self): rx = open(self.args.script_path, "r").readlines() @@ -269,14 +310,14 @@ assert len(rxcheck) > 0, "Supplied script is empty. Cannot run" self.script = "\n".join(rx) fhandle, self.sfile = tempfile.mkstemp( - prefix=self.tool_name, suffix="_%s" % (self.executeme) + prefix=self.tool_name, suffix="_%s" % (self.executeme[0]) ) tscript = open(self.sfile, "w") tscript.write(self.script) tscript.close() self.escapedScript = [cheetah_escape(x) for x in rx] self.spacedScript = [f" {x}" for x in rx if x.strip() > ""] - art = "%s.%s" % (self.tool_name, self.executeme) + art = "%s.%s" % (self.tool_name, self.executeme[0]) artifact = open(art, "wb") artifact.write(bytes("\n".join(self.escapedScript), "utf8")) artifact.close() @@ -286,78 +327,50 @@ if self.args.parampass == "positional": for i, p in enumerate(self.infiles): assert ( - p[ICLPOS].isdigit() or p[ICLPOS].strip().upper() == "STDIN" + p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN" ), "Positional parameters must be ordinal integers - got %s for %s" % ( - p[ICLPOS], - p[ILABPOS], + p["CL"], + p["label"], ) for i, p in enumerate(self.outfiles): assert ( - p[OCLPOS].isdigit() or p[OCLPOS].strip().upper() == "STDOUT" + p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT" ), "Positional parameters must be ordinal integers - got %s for %s" % ( - p[OCLPOS], - p[ONAMEPOS], + p["CL"], + p["name"], ) for i, p in enumerate(self.addpar): assert p[ - ACLPOS + "CL" ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % ( - p[ACLPOS], - p[ANAMEPOS], + p["CL"], + p["name"], ) for i, p in enumerate(self.infiles): infp = copy.copy(p) - icl = infp[ICLPOS] - infp.append(icl) - if ( - infp[ICLPOS].isdigit() - or self.args.parampass == "0" - or infp[ICLPOS].strip().upper() == "STDOUT" - ): - scl = "input%d" % (i + 1) - infp[ICLPOS] = scl + infp["origCL"] = infp["CL"] + if self.args.parampass in ["positional", "0"]: + infp["infilename"] = infp["label"].replace(" ", "_") + else: + infp["infilename"] = infp["CL"] self.infiles[i] = infp for i, p in enumerate(self.outfiles): - p.append(p[OCLPOS]) # keep copy - if (p[OOCLPOS].isdigit() and self.args.parampass != "positional") or p[ - OOCLPOS - ].strip().upper() == "STDOUT": - scl = p[ONAMEPOS] - p[OCLPOS] = scl + p["origCL"] = p["CL"] # keep copy self.outfiles[i] = p for i, p in enumerate(self.addpar): - p.append(p[ACLPOS]) - if p[ACLPOS].isdigit(): - scl = "param%s" % p[ACLPOS] - p[ACLPOS] = scl + p["origCL"] = p["CL"] self.addpar[i] = p - def clsimple(self): - """no parameters - uses < and > for i/o""" - aCL = self.cl.append - aXCL = self.xmlcl.append - - if len(self.infiles) > 0: - aCL("<") - aCL(self.infiles[0][IPATHPOS]) - aXCL("<") - aXCL("$%s" % self.infiles[0][ICLPOS]) - if len(self.outfiles) > 0: - aCL(">") - aCL(self.outfiles[0][OCLPOS]) - aXCL(">") - aXCL("$%s" % self.outfiles[0][ONAMEPOS]) - def clpositional(self): # inputs in order then params aCL = self.cl.append - for (o_v, k, v, koverride) in self.clsuffix: + for (k, v, koverride) in self.clsuffix: if " " in v: aCL("%s" % v) else: aCL(v) aXCL = self.xmlcl.append - for (o_v, k, v, koverride) in self.xclsuffix: + for (k, v, koverride) in self.xclsuffix: aXCL(v) if self.lastxclredirect: aXCL(self.lastxclredirect[0]) @@ -369,7 +382,7 @@ aXCL = self.xmlcl.append # inputs then params in argparse named form - for (o_v, k, v, koverride) in self.xclsuffix: + for (k, v, koverride) in self.xclsuffix: if koverride > "": k = koverride elif len(k.strip()) == 1: @@ -378,7 +391,7 @@ k = "--%s" % k aXCL(k) aXCL(v) - for (o_v, k, v, koverride) in self.clsuffix: + for (k, v, koverride) in self.clsuffix: if koverride > "": k = koverride elif len(k.strip()) == 1: @@ -400,8 +413,11 @@ def doXMLparam(self): """flake8 made me do this...""" for p in self.outfiles: - # --output_files "$otab.history_name~~~$otab.history_format~~~$otab.history_CL~~~$otab.history_test" - newname, newfmt, newcl, test, oldcl = p + newname = p["name"] + newfmt = p["format"] + newcl = p["CL"] + test = p["test"] + oldcl = p["origCL"] test = test.strip() ndash = self.getNdash(newcl) aparm = gxtp.OutputData( @@ -446,39 +462,50 @@ delta=delta, delta_frac=delta_frac, ) + else: + c = test + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + ) self.testparam.append(tp) for p in self.infiles: - newname = p[ICLPOS] - newfmt = p[IFMTPOS] + newname = p["infilename"] + newfmt = p["format"] ndash = self.getNdash(newname) - if not len(p[ILABPOS]) > 0: - alab = p[ICLPOS] + if not len(p["label"]) > 0: + alab = p["CL"] else: - alab = p[ILABPOS] + alab = p["label"] aninput = gxtp.DataParam( newname, optional=False, label=alab, - help=p[IHELPOS], + help=p["help"], format=newfmt, multiple=False, num_dashes=ndash, ) aninput.positional = self.is_positional + if self.is_positional: + if p["origCL"].upper() == "STDIN": + aparm.positional = 9999998 + aparm.command_line_override = "> $%s" % newname + else: + aparm.positional = int(p["origCL"]) + aparm.command_line_override = "$%s" % newname self.tinputs.append(aninput) tparm = gxtp.TestParam(name=newname, value="%s_sample" % newname) self.testparam.append(tparm) for p in self.addpar: - ( - newname, - newval, - newlabel, - newhelp, - newtype, - newcl, - override, - oldcl, - ) = p + newname = p["name"] + newval = p["value"] + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newcl = p["CL"] + oldcl = p["origCL"] if not len(newlabel) > 0: newlabel = newname ndash = self.getNdash(newname) @@ -506,6 +533,14 @@ value=newval, num_dashes=ndash, ) + elif newtype == "boolean": + aparm = gxtp.BooleanParam( + newname, + label=newname, + help=newhelp, + value=newval, + num_dashes=ndash, + ) else: raise ValueError( 'Unrecognised parameter type "%s" for\ @@ -518,43 +553,90 @@ self.tinputs.append(aparm) tparm = gxtp.TestParam(newname, value=newval) self.testparam.append(tparm) + for p in self.selpar: + newname = p["name"] + newval = p["value"] + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newcl = p["CL"] + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "selecttext": + newtext = p["texts"] + aparm = gxtp.SelectParam( + newname, + label=newlabel, + help=newhelp, + num_dashes=ndash, + ) + for i in range(len(newval)): + anopt = gxtp.SelectOption( + value=newval[i], + text=newtext[i], + ) + aparm.append(anopt) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(newcl) + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval) + self.testparam.append(tparm) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for\ + selecttext parameter %s in makeXML' + % (newtype, newname) + ) + for p in self.collections: + newkind = p["kind"] + newname = p["name"] + newlabel = p["label"] + newdisc = p["discover"] + collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind) + disc = gxtp.DiscoverDatasets( + pattern=newdisc, directory=f"{newname}", visible="false" + ) + collect.append(disc) + self.toutputs.append(collect) + tparm = gxtp.TestOutput(newname, ftype="pdf") + self.testparam.append(tparm) def doNoXMLparam(self): """filter style package - stdin to stdout""" if len(self.infiles) > 0: - alab = self.infiles[0][ILABPOS] + alab = self.infiles[0]["label"] if len(alab) == 0: - alab = self.infiles[0][ICLPOS] + alab = self.infiles[0]["infilename"] max1s = ( "Maximum one input if parampass is 0 but multiple input files supplied - %s" % str(self.infiles) ) assert len(self.infiles) == 1, max1s - newname = self.infiles[0][ICLPOS] + newname = self.infiles[0]["infilename"] aninput = gxtp.DataParam( newname, optional=False, label=alab, - help=self.infiles[0][IHELPOS], - format=self.infiles[0][IFMTPOS], + help=self.infiles[0]["help"], + format=self.infiles[0]["format"], multiple=False, num_dashes=0, ) aninput.command_line_override = "< $%s" % newname - aninput.positional = self.is_positional + aninput.positional = True self.tinputs.append(aninput) tp = gxtp.TestParam(name=newname, value="%s_sample" % newname) self.testparam.append(tp) if len(self.outfiles) > 0: - newname = self.outfiles[0][OCLPOS] - newfmt = self.outfiles[0][OFMTPOS] + newname = self.outfiles[0]["name"] + newfmt = self.outfiles[0]["format"] anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0) anout.command_line_override = "> $%s" % newname anout.positional = self.is_positional self.toutputs.append(anout) - tp = gxtp.TestOutput( - name=newname, value="%s_sample" % newname - ) + tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname) self.testparam.append(tp) def makeXML(self): @@ -639,7 +721,7 @@ ): # cannot do this inside galaxyxml as it expects lxml objects for tests part1 = exml.split("")[0] part2 = exml.split("")[1] - fixed = "%s\n%s\n%s" % (part1, self.test_override, part2) + fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2) exml = fixed # exml = exml.replace('range="1:"', 'range="1000:"') xf = open("%s.xml" % self.tool_name, "w") @@ -674,22 +756,22 @@ ) sto.flush() subp = subprocess.run( - self.cl, env=self.ourenv, shell=False, stdout=sto, stderr=ste + self.cl, shell=False, stdout=sto, stderr=ste ) sto.close() ste.close() retval = subp.returncode else: # work around special case - stdin and write to stdout if len(self.infiles) > 0: - sti = open(self.infiles[0][IPATHPOS], "rb") + sti = open(self.infiles[0]["name"], "rb") else: sti = sys.stdin if len(self.outfiles) > 0: - sto = open(self.outfiles[0][ONAMEPOS], "wb") + sto = open(self.outfiles[0]["name"], "wb") else: sto = sys.stdout subp = subprocess.run( - self.cl, env=self.ourenv, shell=False, stdout=sto, stdin=sti + self.cl, shell=False, stdout=sto, stdin=sti ) sto.write("## Executing Toolfactory generated command line = %s\n" % scl) retval = subp.returncode @@ -785,7 +867,6 @@ tout.write("running\n%s\n" % " ".join(cll)) subp = subprocess.run( cll, - env=self.ourenv, cwd=self.ourcwd, shell=False, stderr=tout, @@ -815,20 +896,25 @@ def makeTool(self): """write xmls and input samples into place""" - self.makeXML() + if self.args.parampass == 0: + self.doNoXMLparam() + else: + self.makeXML() if self.args.script_path: - stname = os.path.join(self.tooloutdir, "%s" % (self.sfile)) + stname = os.path.join(self.tooloutdir, self.sfile) if not os.path.exists(stname): shutil.copyfile(self.sfile, stname) xreal = "%s.xml" % self.tool_name xout = os.path.join(self.tooloutdir, xreal) shutil.copyfile(xreal, xout) for p in self.infiles: - pth = p[IPATHPOS] - dest = os.path.join(self.testdir, "%s_sample" % p[ICLPOS]) + pth = p["name"] + dest = os.path.join(self.testdir, "%s_sample" % p["infilename"]) + shutil.copyfile(pth, dest) + dest = os.path.join(self.repdir, "%s_sample" % p["infilename"]) shutil.copyfile(pth, dest) - def makeToolTar(self): + def makeToolTar(self, report_fail=False): """move outputs into test-data and prepare the tarball""" excludeme = "_planemo_test_report.html" @@ -841,19 +927,20 @@ else: tout = open(self.tlog, "w") for p in self.outfiles: - oname = p[ONAMEPOS] + oname = p["name"] tdest = os.path.join(self.testdir, "%s_sample" % oname) + src = os.path.join(self.testdir, oname) if not os.path.isfile(tdest): - src = os.path.join(self.testdir, oname) if os.path.isfile(src): shutil.copyfile(src, tdest) dest = os.path.join(self.repdir, "%s.sample" % (oname)) shutil.copyfile(src, dest) else: - tout.write( - "###Output file %s not found in testdir %s. This is normal during the first Planemo run that generates test outputs" - % (tdest, self.testdir) - ) + if report_fail: + tout.write( + "###Tool may have failed - output file %s not found in testdir after planemo run %s." + % (tdest, self.testdir) + ) tf = tarfile.open(self.newtarpath, "w:gz") tf.add( name=self.tooloutdir, @@ -870,33 +957,41 @@ if not entry.is_file(): continue if "." in entry.name: - nayme, ext = os.path.splitext(entry.name) - if ext in [".yml", ".xml", ".json", ".yaml"]: - ext = f"{ext}.txt" + _, ext = os.path.splitext(entry.name) + if ext in [".tgz", ".json"]: + continue + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name else: - ext = ".txt" - ofn = "%s%s" % (entry.name.replace(".", "_"), ext) - dest = os.path.join(self.repdir, ofn) + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) src = os.path.join(self.tooloutdir, entry.name) shutil.copyfile(src, dest) - with os.scandir(self.testdir) as outs: - for entry in outs: - if ( - (not entry.is_file()) - or entry.name.endswith("_sample") - or entry.name.endswith("_planemo_test_report.html") - ): - continue - if "." in entry.name: - nayme, ext = os.path.splitext(entry.name) - else: - ext = ".txt" - newname = f"{entry.name}{ext}" - dest = os.path.join(self.repdir, newname) - src = os.path.join(self.testdir, entry.name) - shutil.copyfile(src, dest) + if self.args.include_tests: + with os.scandir(self.testdir) as outs: + for entry in outs: + if (not entry.is_file()) or entry.name.endswith( + "_planemo_test_report.html" + ): + continue + if "." in entry.name: + _, ext = os.path.splitext(entry.name) + if ext in [".tgz", ".json"]: + continue + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name + else: + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) + src = os.path.join(self.testdir, entry.name) + shutil.copyfile(src, dest) - def planemo_test(self, genoutputs=True): + + def planemo_test_once(self): """planemo is a requirement so is available for testing but needs a different call if in the biocontainer - see above and for generating test outputs if command or test overrides are @@ -910,51 +1005,26 @@ tout = open(self.tlog, "a") else: tout = open(self.tlog, "w") - if genoutputs: - dummy, tfile = tempfile.mkstemp() - cll = [ - "planemo", - "test", - "--test_data", - os.path.abspath(self.testdir), - "--test_output", - os.path.abspath(tool_test_path), - "--skip_venv", - "--galaxy_root", - self.args.galaxy_root, - "--update_test_data", - os.path.abspath(xreal), - ] - p = subprocess.run( - cll, - env=self.ourenv, - shell=False, - cwd=self.tooloutdir, - stderr=dummy, - stdout=dummy, - ) - - else: - cll = [ - "planemo", - "test", - "--test_data", - os.path.abspath(self.testdir), - "--test_output", - os.path.abspath(tool_test_path), - "--skip_venv", - "--galaxy_root", - self.args.galaxy_root, - os.path.abspath(xreal), - ] - p = subprocess.run( - cll, - shell=False, - env=self.ourenv, - cwd=self.tooloutdir, - stderr=tout, - stdout=tout, - ) + cll = [ + "planemo", + "test", + "--conda_auto_init", + "--test_data", + os.path.abspath(self.testdir), + "--test_output", + os.path.abspath(tool_test_path), + "--galaxy_root", + self.args.galaxy_root, + "--update_test_data", + os.path.abspath(xreal), + ] + p = subprocess.run( + cll, + shell=False, + cwd=self.tooloutdir, + stderr=tout, + stdout=tout, + ) tout.close() return p.returncode @@ -986,6 +1056,7 @@ a("--command_override", default=None) a("--test_override", default=None) a("--additional_parameters", action="append", default=[]) + a("--selecttext_parameters", action="append", default=[]) a("--edit_additional_parameters", action="store_true", default=False) a("--parampass", default="positional") a("--tfout", default="./tfout") @@ -998,6 +1069,8 @@ a("--galaxy_api_key", default="fakekey") a("--galaxy_root", default="/galaxy-central") a("--galaxy_venv", default="/galaxy_venv") + a("--collection", action="append", default=[]) + a("--include_tests", default=False, action="store_true") args = parser.parse_args() assert not args.bad_user, ( 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \ @@ -1009,25 +1082,20 @@ args.sysexe or args.packages ), "## Tool Factory wrapper expects an interpreter \ or an executable package in --sysexe or --packages" - args.input_files = [x.replace('"', "").replace("'", "") for x in args.input_files] - # remove quotes we need to deal with spaces in CL params - for i, x in enumerate(args.additional_parameters): - args.additional_parameters[i] = args.additional_parameters[i].replace('"', "") r = ScriptRunner(args) r.writeShedyml() r.makeTool() if args.make_Tool == "generate": - retcode = r.run() + r.run() r.moveRunOutputs() r.makeToolTar() else: - retcode = r.planemo_test(genoutputs=True) # this fails :( - see PR + # r.planemo_test(genoutputs=True) # this fails :( - see PR + # r.moveRunOutputs() + # r.makeToolTar(report_fail=False) + r.planemo_test_once() r.moveRunOutputs() - r.makeToolTar() - retcode = r.planemo_test(genoutputs=False) - r.moveRunOutputs() - r.makeToolTar() - print(f"second planemo_test returned {retcode}") + r.makeToolTar(report_fail=True) if args.make_Tool == "gentestinstall": r.shedLoad() r.eph_galaxy_load() diff -r 2dbb412af425 -r def0f754ee1b toolfactory/rgToolFactory2.xml --- a/toolfactory/rgToolFactory2.xml Fri Mar 26 09:27:55 2021 +0000 +++ b/toolfactory/rgToolFactory2.xml Fri Mar 26 09:29:58 2021 +0000 @@ -1,6 +1,32 @@ Scripts into tools v2.0 + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10,8 +36,7 @@ value="**What it Does**" help="Supply user documentation to appear on the new tool form as reStructured text - http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html" > - - + @@ -29,8 +54,7 @@ - - + @@ -40,9 +64,9 @@
- - @@ -50,32 +74,23 @@ - - - - - + - - - - - + + - + - + + + + + + + + + + + + + + + + + +
@@ -98,8 +133,7 @@ - - @@ -107,35 +141,37 @@ + - - - - - - - - - + + + + + - - - - - + + + + + + + + + + + + + + + + + - - - - - + - @@ -146,7 +182,7 @@ galaxyxml bioblend ephemeris - planemo + planemo + help="Use =[ver] or :[ver] for specific version - 'bwa=0.17.0'. Default is latest. Will be used every time the tool is (re)run. Only Conda is currently supported" /> - - - - - + help="Scripts are interpreted by the executable named here. For conda r-base, 'Rscript --vanilla' or for conda planemo, 'planemo test' for example"> - - + @@ -302,8 +358,8 @@ - + @@ -318,16 +374,14 @@ - - + - - + @@ -339,7 +393,7 @@ help="Installation in this Galaxy is optional" > - + @@ -359,32 +413,28 @@ - - + - - + - - + - - + @@ -395,7 +445,7 @@ - + makeMode['make_Tool'] != "runonly" @@ -413,7 +463,7 @@ - + @@ -512,6 +562,27 @@ o.write('\n') o.close() +R script to draw some plots - use a collection. + +:: + + + \# note this script takes NO input because it generates random data + dir.create('plots') + for (i in 1:10) { + foo = runif(100) + bar = rnorm(100) + bar = foo + 0.05*bar + pdf(paste('plots/yet',i,"anotherplot.pdf",sep='_')) + plot(foo,bar,main=paste("Foo by Bar plot \#",i),col="maroon", pch=3,cex=0.6) + dev.off() + foo = data.frame(a=runif(100),b=runif(100),c=runif(100),d=runif(100),e=runif(100),f=runif(100)) + bar = as.matrix(foo) + pdf(paste('plots/yet',i,"anotherheatmap.pdf",sep='_')) + heatmap(bar,main='Random Heatmap') + dev.off() + } + Paper_ @@ -524,7 +595,7 @@ .. _LGPL: http://www.gnu.org/copyleft/lesser.html .. _GTF: https://github.com/fubar2/toolfactory -.. _Paper: http://bioinformatics.oxfordjournals.org/cgi/reprint/bts573 +.. _Paper: https://academic.oup.com/bioinformatics/article/28/23/3139/192853