Mercurial > repos > fubar2 > toolfactory_gtn
view toolfactory/ToolFactory_tester.xml @ 0:f288fab71d8b draft default tip
Uploaded
author | fubar2 |
---|---|
date | Mon, 26 Apr 2021 04:18:54 +0000 |
parents | |
children |
line wrap: on
line source
<tool name="toolfactory_tester" id="toolfactory_tester" version="1"> <!--Source in git at: https://github.com/fubar2/toolfactory--> <!--Created by admin@galaxy.org at 23/04/2021 10:25:58 using the Galaxy Tool Factory.--> <description>Test an untested tool and update it</description> <requirements> <requirement type="package" version="2.30.2">git</requirement> <requirement type="package" version="0.74.3">planemo</requirement> </requirements> <stdio> <exit_code range="1:" level="fatal"/> </stdio> <version_command><![CDATA[echo "1"]]></version_command> <command><![CDATA[ python $runme --in_tool_archive $in_tool_archive --new_tested_tool_archive $new_tested_tool_archive --galaxy_root "$galaxyroot" > $tf_archive_tester_log; ]]></command> <configfiles> <configfile name="runme"><![CDATA[#raw # see https://github.com/fubar2/toolfactory # # copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 # # all rights reserved # Licensed under the LGPL # suggestions for improvement and bug fixes welcome at # https://github.com/fubar2/toolfactory # # July 2020: BCC was fun and I feel like rip van winkle after 5 years. # Decided to # 1. Fix the toolfactory so it works - done for simplest case # 2. Fix planemo so the toolfactory function works # 3. Rewrite bits using galaxyxml functions where that makes sense - done import argparse import copy import os import subprocess import shutil import sys import tarfile import tempfile import time import xml.etree.ElementTree as ET myversion = "V2.2 April 2021" verbose = True debug = True toolFactoryURL = "https://github.com/fubar2/toolfactory" def timenow(): """return current time as a string""" return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) class ToolTester(): # requires highly insecure docker settings - like write to tool_conf.xml and to tools ! # if in a container possibly not so courageous. # Fine on your own laptop but security red flag for most production instances # uncompress passed tar, run planemo and rebuild a new tarball with tests def __init__(self, args=None, in_tool_archive='/galaxy-central/tools/newtool/newtool_toolshed.gz', new_tool_archive=None): self.args = args self.new_tool_archive = new_tool_archive assert tarfile.is_tarfile(in_tool_archive) # this is not going to go well with arbitrary names. tff = tarfile.open(in_tool_archive, "r:*") flist = tff.getnames() ourdir = os.path.commonpath(flist) # eg pyrevpos self.tool_name = ourdir ourxmls = [x for x in flist if x.lower().endswith('.xml') and os.path.split(x)[0] == ourdir] # planemo_test/planemo_test.xml assert len(ourxmls) > 0 self.ourxmls = ourxmls # [os.path.join(tool_path,x) for x in ourxmls] res = tff.extractall() self.update_tests(ourdir) tff.close() self.tooloutdir = "./tfout" self.repdir = "./TF_run_report" self.testdir = os.path.join(self.tooloutdir, "test-data") if not os.path.exists(self.tooloutdir): os.mkdir(self.tooloutdir) if not os.path.exists(self.testdir): os.mkdir(self.testdir) if not os.path.exists(self.repdir): os.mkdir(self.repdir) self.makeTool() self.moveRunOutputs() self.makeToolTar() def call_planemo(self,xmlpath,ourdir): penv = os.environ #penv['HOME'] = os.path.join(self.args.galaxy_root,'planemo') #penv["GALAXY_VIRTUAL_ENV"] = os.path.join(penv['HOME'],'.planemo','gx_venv_3.9') penv["PIP_CACHE_DIR"] = os.path.join(self.args.galaxy_root,'pipcache') toolfile = os.path.split(xmlpath)[1] tool_name = self.tool_name tool_test_output = f"{tool_name}_planemo_test_report.html" cll = [ "planemo", "test", "--biocontainers", "--test_output", os.path.abspath(tool_test_output), "--galaxy_root", self.args.galaxy_root, "--update_test_data", os.path.abspath(xmlpath), ] print(cll) p = subprocess.run( cll, #capture_output=True, encoding='utf8', env = penv, shell=False, ) return p def makeTool(self): """write xmls and input samples into place""" for xreal in self.ourxmls: x = os.path.split(xreal)[1] xout = os.path.join(self.tooloutdir,x) shutil.copyfile(xreal, xout) # for p in self.infiles: # 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): """move outputs into test-data and prepare the tarball""" excludeme = "_planemo_test_report.html" def exclude_function(tarinfo): filename = tarinfo.name return None if filename.endswith(excludeme) else tarinfo newtar = 'new_%s_toolshed.gz' % self.tool_name ttf = tarfile.open(newtar, "w:gz") ttf.add(name=self.tool_name, arcname=self.tool_name, filter=exclude_function) ttf.close() shutil.copyfile(newtar, self.new_tool_archive) def moveRunOutputs(self): """need to move planemo or run outputs into toolfactory collection""" with os.scandir(self.tooloutdir) as outs: for entry in outs: if not entry.is_file(): 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.tooloutdir, entry.name) shutil.copyfile(src, dest) with os.scandir('.') as outs: for entry in outs: if not entry.is_file(): continue if "." in entry.name: _, ext = os.path.splitext(entry.name) 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 =entry.name shutil.copyfile(src, dest) if True or 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 update_tests(self,ourdir): for xmlf in self.ourxmls: capture = self.call_planemo(xmlf,ourdir) #sys.stderr.write('%s, stdout=%s, stderr=%s' % (xmlf, capture.stdout, capture.stdout)) #print('%s, stdout=%s, stderr=%s' % (capture.stdout, capture.stdout,xmlf)) def main(): """ This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml """ parser = argparse.ArgumentParser() a = parser.add_argument a("--in_tool_archive", default=None) a("--new_tested_tool_archive", default=None) a("--galaxy_root", default="/home/ross/gal21/") args = parser.parse_args() print('Hello from',os.getcwd()) tt = ToolTester(args=args, in_tool_archive=args.in_tool_archive, new_tool_archive=args.new_tested_tool_archive) if __name__ == "__main__": main() #end raw]]></configfile> </configfiles> <inputs> <param name="new_tool_name" value="" type="hidden"/> <param name="in_tool_archive" type="data" optional="false" label="Select a no_test tarfile to test and update for a toolshed" help="" format="toolshed.gz" multiple="false"/> <param name="galaxyroot" type="text" value="/home/ross/gal21" label="Galaxy root for planemo to use - MUST be made available in the Galaxy job runner configuration" help=""/> </inputs> <outputs> <data name="new_tested_tool_archive" format="toolshed.gz" label="${in_tool_archive.name.split('_')[0]}_tested_toolshed.gz" hidden="false"/> <data name="tf_archive_tester_log" format="txt" label="${in_tool_archive.name}_test_log" hidden="false"/> <collection name="TF_run_report" type="list" label="${in_tool_archive.name} test Run reports"> <discover_datasets pattern="__name_and_ext__" directory="TF_run_report" visible="false"/> </collection> </outputs> <tests> <test> <output name="new_tested_tool_archive" value="new_tested_tool_archive_sample" compare="sim_size" delta_frac="0.5"/> <output name="tf_archive_tester_log" value="tf_archive_tester_log_sample" compare="sim_size" delta_frac="0.1"/> <param name="in_tool_archive" value="in_tool_archive_sample"/> <param name="galaxyroot" value="/home/ross/gal21"/> <output_collection name="TF_run_report"/> </test> </tests> <help><![CDATA[ **What it Does** ------ Script:: import argparse import copy import os import subprocess import shutil import sys import tarfile import tempfile import time import xml.etree.ElementTree as ET myversion = "V2.2 April 2021" verbose = True debug = True toolFactoryURL = "https://github.com/fubar2/toolfactory" def timenow(): """return current time as a string""" return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) class ToolTester(): # requires highly insecure docker settings - like write to tool_conf.xml and to tools ! # if in a container possibly not so courageous. # Fine on your own laptop but security red flag for most production instances # uncompress passed tar, run planemo and rebuild a new tarball with tests def __init__(self, args=None, in_tool_archive='/galaxy-central/tools/newtool/newtool_toolshed.gz', new_tool_archive=None): self.args = args self.new_tool_archive = new_tool_archive assert tarfile.is_tarfile(in_tool_archive) # this is not going to go well with arbitrary names. tff = tarfile.open(in_tool_archive, "r:*") flist = tff.getnames() ourdir = os.path.commonpath(flist) # eg pyrevpos self.tool_name = ourdir ourxmls = [x for x in flist if x.lower().endswith('.xml') and os.path.split(x)[0] == ourdir] # planemo_test/planemo_test.xml assert len(ourxmls) > 0 self.ourxmls = ourxmls # [os.path.join(tool_path,x) for x in ourxmls] res = tff.extractall() self.update_tests(ourdir) tff.close() self.tooloutdir = "./tfout" self.repdir = "./TF_run_report" self.testdir = os.path.join(self.tooloutdir, "test-data") if not os.path.exists(self.tooloutdir): os.mkdir(self.tooloutdir) if not os.path.exists(self.testdir): os.mkdir(self.testdir) if not os.path.exists(self.repdir): os.mkdir(self.repdir) self.makeTool() self.moveRunOutputs() self.makeToolTar() def call_planemo(self,xmlpath,ourdir): penv = os.environ penv['HOME'] = '/home/ross/galaxy-release_21.01' toolfile = os.path.split(xmlpath)[1] tool_name = self.tool_name tool_test_output = f"{tool_name}_planemo_test_report.html" cll = [ "planemo", "test", "--test_output", os.path.abspath(tool_test_output), "--galaxy_root", self.args.galaxy_root, "--update_test_data", os.path.abspath(xmlpath), ] print(cll) p = subprocess.run( cll, capture_output=True, encoding='utf8', env = penv, shell=False, ) return p def makeTool(self): """write xmls and input samples into place""" for xreal in self.ourxmls: x = os.path.split(xreal)[1] xout = os.path.join(self.tooloutdir,x) shutil.copyfile(xreal, xout) # for p in self.infiles: # 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): """move outputs into test-data and prepare the tarball""" excludeme = "_planemo_test_report.html" def exclude_function(tarinfo): filename = tarinfo.name return None if filename.endswith(excludeme) else tarinfo newtar = 'new_%s_toolshed.gz' % self.tool_name ttf = tarfile.open(newtar, "w:gz") ttf.add(name=self.tooloutdir, arcname=self.tool_name, filter=exclude_function) ttf.close() shutil.copyfile(newtar, self.new_tool_archive) def moveRunOutputs(self): """need to move planemo or run outputs into toolfactory collection""" with os.scandir(self.tooloutdir) as outs: for entry in outs: if not entry.is_file(): 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.tooloutdir, entry.name) shutil.copyfile(src, dest) with os.scandir('.') as outs: for entry in outs: if not entry.is_file(): continue if "." in entry.name: _, ext = os.path.splitext(entry.name) 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 =entry.name shutil.copyfile(src, dest) if True or 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 update_tests(self,ourdir): for xmlf in self.ourxmls: capture = self.call_planemo(xmlf,ourdir) #sys.stderr.write('%s, stdout=%s, stderr=%s' % (xmlf, capture.stdout, capture.stdout)) print('%s, stdout=%s, stderr=%s' % (capture.stdout, capture.stdout,xmlf)) def main(): """ This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml """ parser = argparse.ArgumentParser() a = parser.add_argument a("--in_tool_archive", default=None) a("--new_tested_tool_archive", default=None) a("--galaxy_root", default="/home/ross/gal21/") args = parser.parse_args() print('Hello from',os.getcwd()) tt = ToolTester(args=args, in_tool_archive=args.in_tool_archive, new_tool_archive=args.new_tested_tool_archive) if __name__ == "__main__": main() ]]></help> <citations> <citation type="doi">10.1093/bioinformatics/bts573</citation> </citations> </tool>