Package weblogolib :: Module _cgi

Source Code for Module weblogolib._cgi

  1  #!/usr/bin/env python 
  2   
  3  #  Copyright (c) 2003-2004 The Regents of the University of California. 
  4  #  Copyright (c) 2005 Gavin E. Crooks 
  5  #  Copyright (c) 2006, The Regents of the University of California, through  
  6  #  Lawrence Berkeley National Laboratory (subject to receipt of any required 
  7  #  approvals from the U.S. Dept. of Energy).  All rights reserved. 
  8   
  9  #  This software is distributed under the new BSD Open Source License. 
 10  #  <http://www.opensource.org/licenses/bsd-license.html> 
 11  # 
 12  #  Redistribution and use in source and binary forms, with or without  
 13  #  modification, are permitted provided that the following conditions are met:  
 14  # 
 15  #  (1) Redistributions of source code must retain the above copyright notice,  
 16  #  this list of conditions and the following disclaimer.  
 17  # 
 18  #  (2) Redistributions in binary form must reproduce the above copyright  
 19  #  notice, this list of conditions and the following disclaimer in the  
 20  #  documentation and or other materials provided with the distribution.  
 21  # 
 22  #  (3) Neither the name of the University of California, Lawrence Berkeley  
 23  #  National Laboratory, U.S. Dept. of Energy nor the names of its contributors  
 24  #  may be used to endorse or promote products derived from this software  
 25  #  without specific prior written permission.  
 26  # 
 27  #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
 28  #  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
 29  #  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
 30  #  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE  
 31  #  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
 32  #  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  
 33  #  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  
 34  #  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  
 35  #  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
 36  #  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
 37  #  POSSIBILITY OF SUCH DAMAGE.  
 38   
 39  import sys 
 40  import cgi as cgilib 
 41  import cgitb; cgitb.enable() 
 42   
 43  #print "Content-Type: text/html\n\n" 
 44  #print "HELLO WORLD" 
 45  #print __name__ 
 46   
 47  from StringIO import StringIO 
 48  from color import * 
 49  from colorscheme import ColorScheme, ColorGroup 
 50   
 51  import weblogolib 
 52  from corebio.utils import * 
 53  from corebio._future import Template 
 54   
 55   
 56  # TODO: Check units 
 57   
 58  # TODO: In WebLogo2: why slash create.cgi? I think this was a workaround 
 59  # for some browser quirk 
 60  #<form method="post" action="/create.cgi" enctype="multipart/form-data"> 
 61       
62 -def resource_string(resource, basefilename) :
63 import os 64 fn = os.path.join(os.path.dirname(basefilename), resource) 65 return open( fn ).read()
66 67 mime_type = { 68 'eps': 'application/postscript', 69 'pdf': 'application/pdf', 70 'png': 'image/png', 71 'png_print': 'image/png', 72 'txt' : 'text/plain', 73 'jpeg' : 'image/jpeg', 74 } 75 76 extension = { 77 'eps': 'eps', 78 'pdf': 'pdf', 79 'png': 'png', 80 'png_print': 'png', 81 'txt' : 'txt', 82 'jpeg' : 'png' 83 } 84 85 86 alphabets = { 87 'alphabet_auto': None, 88 'alphabet_protein': weblogolib.unambiguous_protein_alphabet, 89 'alphabet_rna': weblogolib.unambiguous_rna_alphabet, 90 'alphabet_dna': weblogolib.unambiguous_dna_alphabet} 91 92 color_schemes = {} 93 for k in weblogolib.std_color_schemes.keys(): 94 color_schemes[ 'color_'+k.replace(' ', '_')] = weblogolib.std_color_schemes[k] 95 96 97 composition = {'comp_none' : 'none', 98 'comp_auto' : 'auto', 99 'comp_equiprobable':'equiprobable', 100 'comp_CG': 'percentCG', 101 'comp_Celegans' : 'C. elegans', 102 'comp_Dmelanogaster' : 'D. melanogaster', 103 'comp_Ecoli' : 'E. coli', 104 'comp_Hsapiens': 'H. sapiens', 105 'comp_Mmusculus' : 'M. musculus', 106 'comp_Scerevisiae': 'S. cerevisiae' 107 } 108
109 -class Field(object) :
110 """ A representation of an HTML form field."""
111 - def __init__(self, name, default=None, conversion= None, options=None, errmsg="Illegal value.") :
112 self.name = name 113 self.default = default 114 self.value = default 115 self.conversion = conversion 116 self.options = options 117 self.errmsg = errmsg
118
119 - def get_value(self) :
120 if self.options : 121 if not self.value in self.options : 122 raise ValueError, (self.name, self.errmsg) 123 124 if self.conversion : 125 try : 126 return self.conversion(self.value) 127 except ValueError, e : 128 raise ValueError, (self.name, self.errmsg) 129 else: 130 return self.value
131 132
133 -def string_or_none(value) :
134 if value is None or value == 'auto': 135 return None 136 return str(value)
137
138 -def truth(value) :
139 if value== "true" : return True 140 return bool(value)
141
142 -def int_or_none(value) :
143 if value =='' or value is None or value == 'auto': 144 return None 145 return int(value)
146
147 -def float_or_none(value) :
148 if value =='' or value is None or value == 'auto': 149 return None 150 return float(value)
151 152
153 -def main(htdocs_directory = None) :
154 155 logooptions = weblogolib.LogoOptions() 156 157 # A list of form fields. 158 # The default for checkbox values must be False (irrespective of 159 # the default in logooptions) since a checked checkbox returns 'true' 160 # but an unchecked checkbox returns nothing. 161 controls = [ 162 Field( 'sequences', ''), 163 Field( 'format', 'png', weblogolib.formatters.get , 164 options=['png_print', 'png', 'jpeg', 'eps', 'pdf', 'txt'] , 165 errmsg="Unknown format option."), 166 Field( 'stacks_per_line', logooptions.stacks_per_line , int, 167 errmsg='Invalid number of stacks per line.'), 168 Field( 'size','medium', weblogolib.std_sizes.get, 169 options=['small', 'medium', 'large'], errmsg='Invalid logo size.'), 170 Field( 'alphabet','alphabet_auto', alphabets.get, 171 options=['alphabet_auto', 'alphabet_protein', 'alphabet_dna', 172 'alphabet_rna'], 173 errmsg="Unknown sequence type."), 174 Field( 'unit_name', 'bits', 175 options=[ 'probability', 'bits', 'nats', 'kT', 'kJ/mol', 176 'kcal/mol']), 177 Field( 'first_index', 1, int_or_none), 178 Field( 'logo_start', '', int_or_none), 179 Field( 'logo_end', '', int_or_none), 180 Field( 'composition', 'comp_auto', composition.get, 181 options=['comp_none','comp_auto','comp_equiprobable','comp_CG', 182 'comp_Celegans','comp_Dmelanogaster','comp_Ecoli', 183 'comp_Hsapiens','comp_Mmusculus','comp_Scerevisiae'], 184 errmsg= "Illegal sequence composition."), 185 Field( 'percentCG', '', float_or_none, errmsg="Invalid CG percentage."), 186 Field( 'show_errorbars', False , truth), 187 Field( 'logo_title', logooptions.logo_title ), 188 Field( 'logo_label', logooptions.logo_label ), 189 Field( 'show_xaxis', False, truth), 190 Field( 'xaxis_label', logooptions.xaxis_label ), 191 Field( 'show_yaxis', False, truth), 192 Field( 'yaxis_label', logooptions.yaxis_label, string_or_none ), 193 Field( 'yaxis_scale', logooptions.yaxis_scale , float_or_none, 194 errmsg="The yaxis scale must be a positive number." ), 195 Field( 'yaxis_tic_interval', logooptions.yaxis_tic_interval , 196 float_or_none), 197 Field( 'show_ends', False, truth), 198 Field( 'show_fineprint', False , truth), 199 Field( 'color_scheme', 'color_auto', color_schemes.get, 200 options=color_schemes.keys() , 201 errmsg = 'Unknown color scheme'), 202 Field( 'color0', ''), 203 Field( 'symbols0', ''), 204 Field( 'desc0', ''), 205 Field( 'color1', ''), 206 Field( 'symbols1', ''), 207 Field( 'desc1', ''), 208 Field( 'color2', ''), 209 Field( 'symbols2', ''), 210 Field( 'desc2', ''), 211 Field( 'color3', ''), 212 Field( 'symbols3', ''), 213 Field( 'desc3', ''), 214 Field( 'color4', ''), 215 Field( 'symbols4', ''), 216 Field( 'desc4', ''), 217 Field( 'ignore_lower_case', False, truth), 218 Field( 'scale_width', False, truth), 219 ] 220 221 form = {} 222 for c in controls : 223 form[c.name] = c 224 225 226 form_values = cgilib.FieldStorage() 227 228 # Send default form? 229 if len(form_values) ==0 or form_values.has_key("cmd_reset"): 230 # Load default truth values now. 231 form['show_errorbars'].value = logooptions.show_errorbars 232 form['show_xaxis'].value = logooptions.show_xaxis 233 form['show_yaxis'].value = logooptions.show_yaxis 234 form['show_ends'].value = logooptions.show_ends 235 form['show_fineprint'].value = logooptions.show_fineprint 236 form['scale_width'].value = logooptions.scale_width 237 238 send_form(controls, htdocs_directory = htdocs_directory) 239 return 240 241 # Get form content 242 for c in controls : 243 c.value = form_values.getfirst( c.name, c.default) 244 245 246 options_from_form = ['format', 'stacks_per_line', 'size', 247 'alphabet', 'unit_name', 'first_index', 'logo_start','logo_end', 248 'composition', 249 'show_errorbars', 'logo_title', 'logo_label', 'show_xaxis', 250 'xaxis_label', 251 'show_yaxis', 'yaxis_label', 'yaxis_scale', 'yaxis_tic_interval', 252 'show_ends', 'show_fineprint', 'scale_width'] 253 254 errors = [] 255 for optname in options_from_form : 256 try : 257 value = form[optname].get_value() 258 if value!=None : setattr(logooptions, optname, value) 259 except ValueError, err : 260 errors.append(err.args) 261 262 263 # Construct custom color scheme 264 custom = ColorScheme() 265 for i in range(0,5) : 266 color = form["color%d"%i].get_value() 267 symbols = form["symbols%d"%i].get_value() 268 desc = form["desc%d"%i].get_value() 269 270 if color : 271 try : 272 custom.groups.append(weblogolib.ColorGroup(symbols, color, desc)) 273 except ValueError, e : 274 errors.append( ('color%d'%i, "Invalid color: %s" % color) ) 275 276 if form["color_scheme"].value == 'color_custom' : 277 logooptions.color_scheme = custom 278 else : 279 try : 280 logooptions.color_scheme = form["color_scheme"].get_value() 281 except ValueError, err : 282 errors.append(err.args) 283 284 sequences = None 285 286 # FIXME: Ugly fix: Must check that sequence_file key exists 287 # FIXME: Sending malformed or missing form keys should not cause a crash 288 # sequences_file = form["sequences_file"] 289 if form_values.has_key("sequences_file") : 290 sequences = form_values.getvalue("sequences_file") 291 assert type(sequences) == str 292 293 if not sequences or len(sequences) ==0: 294 sequences = form["sequences"].get_value() 295 296 if not sequences or len(sequences) ==0: 297 errors.append( ("sequences", "Please enter a multiple-sequence alignment in the box above, or select a file to upload.")) 298 299 300 301 # If we have uncovered errors or we want the chance to edit the logo 302 # ("cmd_edit" command from examples page) then we return the form now. 303 # We do not proceed to the time consuming logo creation step unless 304 # required by a 'create' or 'validate' command, and no errors have been 305 # found yet. 306 if form_values.has_key("cmd_edit") or errors : 307 send_form(controls, errors, htdocs_directory) 308 return 309 310 311 # We write the logo into a local buffer so that we can catch and 312 # handle any errors. Once the "Content-Type:" header has been sent 313 # we can't send any useful feedback 314 logo = StringIO() 315 try : 316 comp = form["composition"].get_value() 317 percentCG = form["percentCG"].get_value() 318 ignore_lower_case = form_values.has_key("ignore_lower_case") 319 seqs = weblogolib.read_seq_data(StringIO( sequences), 320 alphabet=logooptions.alphabet, 321 ignore_lower_case=ignore_lower_case 322 ) 323 if comp=='percentCG': comp = str(percentCG/100) 324 prior = weblogolib.parse_prior(comp, seqs.alphabet) 325 data = weblogolib.LogoData.from_seqs(seqs, prior) 326 logoformat = weblogolib.LogoFormat(data, logooptions) 327 format = form["format"].value 328 weblogolib.formatters[format](data, logoformat, logo) 329 except ValueError, err : 330 errors.append( err.args ) 331 except IOError, err : 332 errors.append( err.args) 333 except RuntimeError, err : 334 errors.append( err.args ) 335 336 if form_values.has_key("cmd_validate") or errors : 337 send_form(controls, errors, htdocs_directory) 338 return 339 340 341 # 342 # RETURN LOGO OVER HTTP 343 # 344 345 print "Content-Type:", mime_type[format] 346 # Content-Disposition: inline Open logo in browser window 347 # Content-Disposition: attachment Download logo 348 if form_values.has_key("download") : 349 print 'Content-Disposition: attachment; ' \ 350 'filename="logo.%s"' % extension[format] 351 else : 352 print 'Content-Disposition: inline; ' \ 353 'filename="logo.%s"' % extension[format] 354 355 356 # Seperate header from data 357 print 358 359 # Finally, and at last, send the logo. 360 print logo.getvalue()
361 362
363 -def send_form(controls, errors=[], htdocs_directory=None) :
364 if htdocs_directory is None : 365 htdocs_directory = os.path.join( 366 os.path.dirname(__file__, "htdocs") ) 367 368 subsitutions = {} 369 subsitutions["version"] = weblogolib.release_description 370 371 for c in controls : 372 if c.options : 373 for opt in c.options : 374 subsitutions[opt.replace('/','_')] = '' 375 subsitutions[c.value.replace('/','_')] = 'selected' 376 else : 377 value = c.value 378 if value == None : value = 'auto' 379 if value=='true': 380 subsitutions[c.name] = 'checked' 381 elif type(value)==bool : 382 if value : 383 subsitutions[c.name] = 'checked' 384 else : 385 subsitutions[c.name] = '' 386 else : 387 subsitutions[c.name] = str(value) 388 subsitutions[c.name+'_err'] = '' 389 390 if errors : 391 print >>sys.stderr, errors 392 error_message = [] 393 for e in errors : 394 if type(e) is str : 395 msg = e 396 elif len(e)==2: 397 subsitutions[e[0]+"_err"] = "class='error'" 398 msg = e[1] 399 else : 400 msg = e[0] 401 402 403 error_message += "ERROR: " 404 error_message += msg 405 error_message += ' <br />' 406 407 error_message += \ 408 "<input style='float:right; font-size:small' type='submit' name='cmd_validate' value='Clear Error' /> " 409 subsitutions["error_message"] = ''.join(error_message) 410 else : 411 subsitutions["error_message"] = "" 412 413 414 template = resource_string("create_html_template.html", htdocs_directory) 415 html = Template(template).safe_substitute(subsitutions) #FIXME 416 417 print "Content-Type: text/html\n\n" 418 print html
419 420 # DEBUG 421 # keys = subsitutions.keys() 422 # keys.sort() 423 # for k in keys : 424 # print k,"=", subsitutions[k], " <br />" 425 426 #for k in controls : 427 # print k.name,"=", k.get_value(), " <br />" 428 429 430 431 if __name__=="__main__" : 432 main() 433