comparison transposetest/transposetest.py @ 0:bf814ef1c04d draft default tip

testing
author fubar
date Thu, 21 Mar 2013 21:14:49 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:bf814ef1c04d
1 # transposetest.py - a self annotated version of rgToolFactory.py generated by running rgToolFactory.py
2 # to make a new Galaxy tool called transposetest
3 # User admin@here.now at 22/03/2013 01:13:57
4 # rgToolFactory.py
5 # see https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home
6 #
7 # copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012
8 #
9 # all rights reserved
10 # Licensed under the LGPL
11 # suggestions for improvement and bug fixes welcome at https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home
12 #
13 # January 2013
14 # problem pointed out by Carlos Borroto
15 # added escaping for <>$ - thought I did that ages ago...
16 #
17 # August 11 2012
18 # changed to use shell=False and cl as a sequence
19
20 # This is a Galaxy tool factory for simple scripts in python, R or whatever ails ye.
21 # It also serves as the wrapper for the new tool.
22 #
23 # you paste and run your script
24 # Only works for simple scripts that read one input from the history.
25 # Optionally can write one new history dataset,
26 # and optionally collect any number of outputs into links on an autogenerated HTML page.
27
28 # DO NOT install on a public or important site - please.
29
30 # installed generated tools are fine if the script is safe.
31 # They just run normally and their user cannot do anything unusually insecure
32 # but please, practice safe toolshed.
33 # Read the fucking code before you install any tool
34 # especially this one
35
36 # After you get the script working on some test data, you can
37 # optionally generate a toolshed compatible gzip file
38 # containing your script safely wrapped as an ordinary Galaxy script in your local toolshed for
39 # safe and largely automated installation in a production Galaxy.
40
41 # If you opt for an HTML output, you get all the script outputs arranged
42 # as a single Html history item - all output files are linked, thumbnails for all the pdfs.
43 # Ugly but really inexpensive.
44 #
45 # Patches appreciated please.
46 #
47 #
48 # long route to June 2012 product
49 # Behold the awesome power of Galaxy and the toolshed with the tool factory to bind them
50 # derived from an integrated script model
51 # called rgBaseScriptWrapper.py
52 # Note to the unwary:
53 # This tool allows arbitrary scripting on your Galaxy as the Galaxy user
54 # There is nothing stopping a malicious user doing whatever they choose
55 # Extremely dangerous!!
56 # Totally insecure. So, trusted users only
57 #
58 # preferred model is a developer using their throw away workstation instance - ie a private site.
59 # no real risk. The universe_wsgi.ini admin_users string is checked - only admin users are permitted to run this tool.
60 #
61
62 import sys
63 import shutil
64 import subprocess
65 import os
66 import time
67 import tempfile
68 import optparse
69 import tarfile
70 import re
71 import shutil
72 import math
73
74 progname = os.path.split(sys.argv[0])[1]
75 myversion = 'V000.2 June 2012'
76 verbose = False
77 debug = False
78 toolFactoryURL = 'https://bitbucket.org/fubar/galaxytoolfactory'
79
80 def timenow():
81 """return current time as a string
82 """
83 return time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(time.time()))
84
85 cheetah_escape_table = {
86 "$": "\$"
87 }
88
89 cheetah_unescape_table = {
90 "\$": "$"
91 }
92
93 def html_escape(t):
94 """Unescape \$ first in case already done
95 cheetah barfs if any $ without \
96 xml parsing is controlled with <![CDATA[...]]>
97 """
98 text = t
99 for k in cheetah_unescape_table.keys():
100 text = text.replace(k,cheetah_unescape_table[k])
101 for k in cheetah_escape_table.keys():
102 text = text.replace(k,cheetah_escape_table[k])
103 return text
104
105
106 class ScriptRunner:
107 """class is a wrapper for an arbitrary script
108 """
109
110 def __init__(self,opts=None,treatbashSpecial=True):
111 """
112 cleanup inputs, setup some outputs
113
114 """
115 self.treatbashSpecial = treatbashSpecial
116 if opts.output_dir: # simplify for the tool tarball
117 os.chdir(opts.output_dir)
118 self.thumbformat = 'jpg'
119 self.opts = opts
120 self.toolname = re.sub('[^a-zA-Z0-9_]+', '', opts.tool_name) # a sanitizer now does this but..
121 self.toolid = self.toolname
122 self.myname = sys.argv[0] # get our name because we write ourselves out as a tool later
123 self.pyfile = self.myname # crude but efficient - the cruft won't hurt much
124 self.xmlfile = '%s.xml' % self.toolname
125 s = open(self.opts.script_path,'r').readlines()
126 s = [x.rstrip() for x in s] # remove pesky dos line endings if needed
127 self.script = '\n'.join(s)
128 fhandle,self.sfile = tempfile.mkstemp(prefix=self.toolname,suffix=".%s" % (opts.interpreter))
129 tscript = open(self.sfile,'w') # use self.sfile as script source for Popen
130 tscript.write(self.script)
131 tscript.close()
132 self.escapedS = [html_escape(x) for x in s] # for restructured text in help
133 self.escapedScript = '\n'.join(self.escapedS)
134 self.indentedScript = '\n'.join([' %s' % x for x in s]) # for restructured text in help
135 if opts.output_dir: # may not want these complexities
136 self.tlog = os.path.join(opts.output_dir,"%s_runner.log" % self.toolname)
137 art = '%s.%s' % (self.toolname,opts.interpreter)
138 artpath = os.path.join(self.opts.output_dir,art) # need full path
139 artifact = open(artpath,'w') # use self.sfile as script source for Popen
140 artifact.write(self.script)
141 artifact.close()
142 self.cl = []
143 self.html = []
144 a = self.cl.append
145 a(opts.interpreter)
146 if self.treatbashSpecial and opts.interpreter in ['bash','sh']:
147 a(self.sfile)
148 else:
149 a('-') # stdin
150 a(opts.input_tab)
151 a(opts.output_tab)
152 self.outFormats = 'tabular' # TODO make this an option at tool generation time
153 self.inputFormats = 'tabular' # TODO make this an option at tool generation time
154 self.test1Input = '%s_test1_input.xls' % self.toolname
155 self.test1Output = '%s_test1_output.xls' % self.toolname
156 self.test1HTML = '%s_test1_output.html' % self.toolname
157
158 def makeXML(self):
159 """
160 Create a Galaxy xml tool wrapper for the new script as a string to write out
161 fixme - use templating or something less fugly than this example of what we produce
162
163 <tool id="reverse" name="reverse" version="0.01">
164 <description>a tabular file</description>
165 <command interpreter="python">
166 reverse.py --script_path "$runMe" --interpreter "python"
167 --tool_name "reverse" --input_tab "$input1" --output_tab "$tab_file"
168 </command>
169 <inputs>
170 <param name="input1" type="data" format="tabular" label="Select a suitable input file from your history"/><param name="job_name" type="text" label="Supply a name for the outputs to remind you what they contain" value="reverse"/>
171
172 </inputs>
173 <outputs>
174 <data format="tabular" name="tab_file" label="${job_name}"/>
175
176 </outputs>
177 <help>
178
179 **What it Does**
180
181 Reverse the columns in a tabular file
182
183 </help>
184 <configfiles>
185 <configfile name="runMe">
186
187 # reverse order of columns in a tabular file
188 import sys
189 inp = sys.argv[1]
190 outp = sys.argv[2]
191 i = open(inp,'r')
192 o = open(outp,'w')
193 for row in i:
194 rs = row.rstrip().split('\t')
195 rs.reverse()
196 o.write('\t'.join(rs))
197 o.write('\n')
198 i.close()
199 o.close()
200
201
202 </configfile>
203 </configfiles>
204 </tool>
205
206 """
207 newXML="""<tool id="%(toolid)s" name="%(toolname)s" version="%(tool_version)s">
208 %(tooldesc)s
209 %(command)s
210 <inputs>
211 %(inputs)s
212 </inputs>
213 <outputs>
214 %(outputs)s
215 </outputs>
216 <configfiles>
217 <configfile name="runMe">
218 <![CDATA[
219 %(script)s
220 ]]>
221 </configfile>
222 </configfiles>
223 %(tooltests)s
224 <help>
225 <![CDATA[
226 %(help)s
227 ]]>
228
229 </help>
230 </tool>"""
231 # needs a dict with toolname, toolid, interpreter, scriptname, command, inputs as a multi line string ready to write, outputs ditto, help ditto
232
233 newCommand="""<command interpreter="python">
234 %(toolname)s.py --script_path "$runMe" --interpreter "%(interpreter)s"
235 --tool_name "%(toolname)s" %(command_inputs)s %(command_outputs)s
236 </command>""" # may NOT be an input or htmlout
237 tooltestsTabOnly = """<tests><test>
238 <param name="input1" value="%(test1Input)s" ftype="tabular"/>
239 <param name="job_name" value="test1"/>
240 <param name="runMe" value="$runMe"/>
241 <output name="tab_file" file="%(test1Output)s" ftype="tabular"/>
242 </test></tests>"""
243 tooltestsHTMLOnly = """<tests><test>
244 <param name="input1" value="%(test1Input)s" ftype="tabular"/>
245 <param name="job_name" value="test1"/>
246 <param name="runMe" value="$runMe"/>
247 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="5"/>
248 </test></tests>"""
249 tooltestsBoth = """<tests><test>
250 <param name="input1" value="%(test1Input)s" ftype="tabular"/>
251 <param name="job_name" value="test1"/>
252 <param name="runMe" value="$runMe"/>
253 <output name="tab_file" file="%(test1Output)s" ftype="tabular" />
254 <output name="html_file" file="%(test1HTML)s" ftype="html" lines_diff="10"/>
255 </test></tests>"""
256 xdict = {}
257 xdict['tool_version'] = self.opts.tool_version
258 xdict['test1Input'] = self.test1Input
259 xdict['test1HTML'] = self.test1HTML
260 xdict['test1Output'] = self.test1Output
261 if self.opts.make_HTML and self.opts.output_tab <> 'None':
262 xdict['tooltests'] = tooltestsBoth % xdict
263 elif self.opts.make_HTML:
264 xdict['tooltests'] = tooltestsHTMLOnly % xdict
265 else:
266 xdict['tooltests'] = tooltestsTabOnly % xdict
267 xdict['script'] = self.escapedScript
268 # configfile is least painful way to embed script to avoid external dependencies
269 # but requires escaping of <, > and $ to avoid Mako parsing
270 if self.opts.help_text:
271 xdict['help'] = open(self.opts.help_text,'r').read()
272 else:
273 xdict['help'] = 'Please ask the tool author for help as none was supplied at tool generation\n'
274 coda = ['**Script**','Pressing execute will run the following code over your input file and generate some outputs in your history::\n']
275 coda.append(self.indentedScript)
276 coda.append('\n\n')
277 coda.append('**Attribution** This Galaxy tool was created by %s at %s\nusing the Galaxy Tool Factory.' % (self.opts.user_email,timenow()))
278 coda.append('See %s for details of that project' % (toolFactoryURL))
279 coda.append('Please cite: Creating re-usable tools from scripts: The Galaxy Tool Factory. Ross Lazarus; Antony Kaspi; Mark Ziemann; The Galaxy Team. ')
280 coda.append('Bioinformatics 2012; doi: 10.1093/bioinformatics/bts573')
281 xdict['help'] = '%s\n\n%s\n\n' % (xdict['help'],'\n'.join(coda))
282 if self.opts.tool_desc:
283 xdict['tooldesc'] = '<description>%s</description>' % self.opts.tool_desc
284 else:
285 xdict['tooldesc'] = ''
286 xdict['command_outputs'] = ''
287 xdict['outputs'] = ''
288 if self.opts.input_tab <> 'None':
289 xdict['command_inputs'] = '--input_tab "$input1" ' # the space may matter a lot if we append something
290 xdict['inputs'] = '<param name="input1" type="data" format="%s" label="Select a suitable input file from your history"/> \n' % self.inputFormats
291 else:
292 xdict['command_inputs'] = '' # assume no input - eg a random data generator
293 xdict['inputs'] = ''
294 xdict['inputs'] += '<param name="job_name" type="text" label="Supply a name for the outputs to remind you what they contain" value="%s"/> \n' % self.toolname
295 xdict['toolname'] = self.toolname
296 xdict['toolid'] = self.toolid
297 xdict['interpreter'] = self.opts.interpreter
298 xdict['scriptname'] = self.sfile
299 if self.opts.make_HTML:
300 xdict['command_outputs'] += ' --output_dir "$html_file.files_path" --output_html "$html_file" --make_HTML "yes" '
301 xdict['outputs'] += ' <data format="html" name="html_file" label="${job_name}.html"/>\n'
302 if self.opts.output_tab <> 'None':
303 xdict['command_outputs'] += ' --output_tab "$tab_file"'
304 xdict['outputs'] += ' <data format="%s" name="tab_file" label="${job_name}"/>\n' % self.outFormats
305 xdict['command'] = newCommand % xdict
306 xmls = newXML % xdict
307 xf = open(self.xmlfile,'w')
308 xf.write(xmls)
309 xf.write('\n')
310 xf.close()
311 # ready for the tarball
312
313
314 def makeTooltar(self):
315 """
316 a tool is a gz tarball with eg
317 /toolname/tool.xml /toolname/tool.py /toolname/test-data/test1_in.foo ...
318 """
319 retval = self.run()
320 if retval:
321 print >> sys.stderr,'## Run failed. Cannot build yet. Please fix and retry'
322 sys.exit(1)
323 self.makeXML()
324 tdir = self.toolname
325 os.mkdir(tdir)
326 if self.opts.input_tab <> 'None': # no reproducible test otherwise? TODO: maybe..
327 testdir = os.path.join(tdir,'test-data')
328 os.mkdir(testdir) # make tests directory
329 shutil.copyfile(self.opts.input_tab,os.path.join(testdir,self.test1Input))
330 if self.opts.output_tab <> 'None':
331 shutil.copyfile(self.opts.output_tab,os.path.join(testdir,self.test1Output))
332 if self.opts.make_HTML:
333 shutil.copyfile(self.opts.output_html,os.path.join(testdir,self.test1HTML))
334 if self.opts.output_dir:
335 shutil.copyfile(self.tlog,os.path.join(testdir,'test1_out.log'))
336 op = '%s.py' % self.toolname # new name
337 outpiname = os.path.join(tdir,op) # path for the tool tarball
338 pyin = os.path.basename(self.pyfile) # our name - we rewrite ourselves (TM)
339 notes = ['# %s - a self annotated version of %s generated by running %s\n' % (op,pyin,pyin),]
340 notes.append('# to make a new Galaxy tool called %s\n' % self.toolname)
341 notes.append('# User %s at %s\n' % (self.opts.user_email,timenow()))
342 pi = open(self.pyfile,'r').readlines() # our code becomes new tool wrapper (!) - first Galaxy worm
343 notes += pi
344 outpi = open(outpiname,'w')
345 outpi.write(''.join(notes))
346 outpi.write('\n')
347 outpi.close()
348 stname = os.path.join(tdir,self.sfile)
349 if not os.path.exists(stname):
350 shutil.copyfile(self.sfile, stname)
351 xtname = os.path.join(tdir,self.xmlfile)
352 if not os.path.exists(xtname):
353 shutil.copyfile(self.xmlfile,xtname)
354 tarpath = "%s.gz" % self.toolname
355 tar = tarfile.open(tarpath, "w:gz")
356 tar.add(tdir,arcname=self.toolname)
357 tar.close()
358 shutil.copyfile(tarpath,self.opts.new_tool)
359 shutil.rmtree(tdir)
360 ## TODO: replace with optional direct upload to local toolshed?
361 return retval
362
363 def compressPDF(self,inpdf=None,thumbformat='png'):
364 """need absolute path to pdf
365 """
366 assert os.path.isfile(inpdf), "## Input %s supplied to %s compressPDF not found" % (inpdf,self.myName)
367 hf,hlog = tempfile.mkstemp(suffix="%s.log" % self.toolname)
368 sto = open(hlog,'w')
369 outpdf = '%s_compressed' % inpdf
370 cl = ["gs", "-sDEVICE=pdfwrite", "-dNOPAUSE", "-dBATCH", "-sOutputFile=%s" % outpdf,inpdf]
371 x = subprocess.Popen(cl,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
372 retval1 = x.wait()
373 if retval1 == 0:
374 os.unlink(inpdf)
375 shutil.move(outpdf,inpdf)
376 outpng = '%s.%s' % (os.path.splitext(inpdf)[0],thumbformat)
377 cl2 = ['convert', inpdf, outpng]
378 x = subprocess.Popen(cl2,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
379 retval2 = x.wait()
380 sto.close()
381 retval = retval1 or retval2
382 return retval
383
384
385 def getfSize(self,fpath,outpath):
386 """
387 format a nice file size string
388 """
389 size = ''
390 fp = os.path.join(outpath,fpath)
391 if os.path.isfile(fp):
392 size = '0 B'
393 n = float(os.path.getsize(fp))
394 if n > 2**20:
395 size = '%1.1f MB' % (n/2**20)
396 elif n > 2**10:
397 size = '%1.1f KB)' % (n/2**10)
398 elif n > 0:
399 size = '%d B' % (int(n))
400 return size
401
402 def makeHtml(self):
403 """ Create an HTML file content to list all the artifacts found in the output_dir
404 """
405
406 galhtmlprefix = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
407 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
408 <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
409 <meta name="generator" content="Galaxy %s tool output - see http://g2.trac.bx.psu.edu/" />
410 <title></title>
411 <link rel="stylesheet" href="/static/style/base.css" type="text/css" />
412 </head>
413 <body>
414 <div class="toolFormBody">
415 """
416 galhtmlattr = """<hr/><div class="infomessage">This tool (%s) was generated by the <a href="https://bitbucket.org/fubar/galaxytoolfactory/overview">Galaxy Tool Factory</a></div><br/>"""
417 galhtmlpostfix = """</div></body></html>\n"""
418
419 flist = os.listdir(self.opts.output_dir)
420 flist = [x for x in flist if x <> 'Rplots.pdf']
421 flist.sort()
422 html = []
423 html.append(galhtmlprefix % progname)
424 html.append('<div class="infomessage">Galaxy Tool "%s" run at %s</div><br/>' % (self.toolname,timenow()))
425 fhtml = []
426 if len(flist) > 0:
427 pdflist = []
428 npdf = len([x for x in flist if os.path.splitext(x)[-1].lower() == '.pdf'])
429 nacross = 1
430 if npdf > 0:
431 nacross = int(round(math.log(npdf,2)))
432 nacross = max(1,nacross)
433 width = min(400,int(1200/nacross))
434 for rownum,fname in enumerate(flist):
435 dname,e = os.path.splitext(fname)
436 sfsize = self.getfSize(fname,self.opts.output_dir)
437 if e.lower() == '.pdf' : # compress and make a thumbnail
438 thumb = '%s.%s' % (dname,self.thumbformat)
439 pdff = os.path.join(self.opts.output_dir,fname)
440 retval = self.compressPDF(inpdf=pdff,thumbformat=self.thumbformat)
441 if retval == 0:
442 pdflist.append((fname,thumb))
443 if (rownum+1) % 2 == 0:
444 fhtml.append('<tr class="odd_row"><td><a href="%s">%s</a></td><td>%s</td></tr>' % (fname,fname,sfsize))
445 else:
446 fhtml.append('<tr><td><a href="%s">%s</a></td><td>%s</td></tr>' % (fname,fname,sfsize))
447 ntogo = nacross # counter for table row padding with empty cells
448 if len(pdflist) > 0:
449 html.append('<div><table class="simple" cellpadding="2" cellspacing="2">\n<tr>')
450 for i,paths in enumerate(pdflist):
451 fname,thumb = paths
452 s= """<td><a href="%s"><img src="%s" title="Click to download a PDF of %s" hspace="5" width="%d"
453 alt="Image called %s"/></a></td>\n""" % (fname,thumb,fname,width,fname)
454 if ((i+1) % nacross == 0):
455 s += '</tr>\n'
456 ntogo = 0
457 if i < (npdf - 1): # more to come
458 s += '<tr>'
459 ntogo = nacross
460 else:
461 ntogo -= 1
462 html.append(s)
463 if html[-1].strip().endswith('</tr>'):
464 html.append('</table></div>\n')
465 else:
466 if ntogo > 0: # pad
467 html.append('<td>&nbsp;</td>'*ntogo)
468 html.append('</tr></table></div>\n')
469 if len(fhtml) > 0:
470 fhtml.insert(0,'<div><table class="colored" cellpadding="3" cellspacing="3"><tr><th>Output File Name (click to view)</th><th>Size</th></tr>\n')
471 fhtml.append('</table></div><br/>')
472 html += fhtml # add all non-pdf files to the end of the display
473 else:
474 html.append('<div class="warningmessagelarge">### Error - %s returned no files - please confirm that parameters are sane</div>' % self.opts.interpreter)
475 rlog = open(self.tlog,'r').readlines()
476 rlog = [x for x in rlog if x.strip() > '']
477 if len(rlog) > 1:
478 html.append('<div class="toolFormTitle">%s log</div><pre>\n' % self.opts.interpreter)
479 html += rlog
480 html.append('</pre>\n')
481 html.append(galhtmlattr % (self.toolname))
482 html.append(galhtmlpostfix)
483 htmlf = file(self.opts.output_html,'w')
484 htmlf.write('\n'.join(html))
485 htmlf.write('\n')
486 htmlf.close()
487 self.html = html
488
489
490 def run(self):
491 """
492 scripts must be small enough not to fill the pipe!
493 """
494 if self.treatbashSpecial and self.opts.interpreter in ['bash','sh']:
495 retval = self.runBash()
496 else:
497 if self.opts.output_dir:
498 sto = open(self.tlog,'w')
499 sto.write('## Toolfactory generated command line = %s\n' % ' '.join(self.cl))
500 sto.flush()
501 p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,stdin=subprocess.PIPE,cwd=self.opts.output_dir)
502 else:
503 p = subprocess.Popen(self.cl,shell=False,stdin=subprocess.PIPE)
504 p.stdin.write(self.script)
505 p.stdin.close()
506 retval = p.wait()
507 if self.opts.output_dir:
508 sto.close()
509 if self.opts.make_HTML:
510 self.makeHtml()
511 return retval
512
513 def runBash(self):
514 """
515 cannot use - for bash so use self.sfile
516 """
517 if self.opts.output_dir:
518 s = '## Toolfactory generated command line = %s\n' % ' '.join(self.cl)
519 sto = open(self.tlog,'w')
520 sto.write(s)
521 sto.flush()
522 p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
523 else:
524 p = subprocess.Popen(self.cl,shell=False)
525 retval = p.wait()
526 if self.opts.output_dir:
527 sto.close()
528 if self.opts.make_HTML:
529 self.makeHtml()
530 return retval
531
532
533 def main():
534 u = """
535 This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml as:
536 <command interpreter="python">rgBaseScriptWrapper.py --script_path "$scriptPath" --tool_name "foo" --interpreter "Rscript"
537 </command>
538 """
539 op = optparse.OptionParser()
540 a = op.add_option
541 a('--script_path',default=None)
542 a('--tool_name',default=None)
543 a('--interpreter',default=None)
544 a('--output_dir',default=None)
545 a('--output_html',default=None)
546 a('--input_tab',default="None")
547 a('--output_tab',default="None")
548 a('--user_email',default='Unknown')
549 a('--bad_user',default=None)
550 a('--make_Tool',default=None)
551 a('--make_HTML',default=None)
552 a('--help_text',default=None)
553 a('--tool_desc',default=None)
554 a('--new_tool',default=None)
555 a('--tool_version',default=None)
556 opts, args = op.parse_args()
557 assert not opts.bad_user,'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to admin_users in universe_wsgi.ini' % (opts.bad_user,opts.bad_user)
558 assert opts.tool_name,'## Tool Factory expects a tool name - eg --tool_name=DESeq'
559 assert opts.interpreter,'## Tool Factory wrapper expects an interpreter - eg --interpreter=Rscript'
560 assert os.path.isfile(opts.script_path),'## Tool Factory wrapper expects a script path - eg --script_path=foo.R'
561 if opts.output_dir:
562 try:
563 os.makedirs(opts.output_dir)
564 except:
565 pass
566 r = ScriptRunner(opts)
567 if opts.make_Tool:
568 retcode = r.makeTooltar()
569 else:
570 retcode = r.run()
571 os.unlink(r.sfile)
572 if retcode:
573 sys.exit(retcode) # indicate failure to job runner
574
575
576 if __name__ == "__main__":
577 main()
578
579
580