Package cinfony :: Module webel
[frames] | no frames]

Source Code for Module cinfony.webel

  1  ## Copyright (c) 2009-2011, Noel O'Boyle 
  2  ## All rights reserved. 
  3  ## 
  4  ##  This file is part of Cinfony. 
  5  ##  The contents are covered by the terms of the BSD license 
  6  ##  which is included in the file LICENSE_BSD.txt. 
  7   
  8  """ 
  9  webel - A Cinfony module that runs entirely on web services 
 10   
 11  webel can be used from all of CPython, Jython and IronPython.  
 12   
 13  Global variables: 
 14    informats - a dictionary of supported input formats 
 15    outformats - a dictionary of supported output formats 
 16    fps - a list of supported fingerprint types 
 17  """ 
 18   
 19  import re 
 20  import os 
 21  import urllib2 
 22  import StringIO 
 23   
 24  try: 
 25      import Tkinter as tk 
 26      import Image as PIL 
 27      import ImageTk as piltk 
 28  except ImportError: 
 29      tk = None 
 30   
 31  informats = {"smi":"SMILES", "inchikey":"InChIKey", "inchi":"InChI", 
 32               "name":"Common name"} 
 33  """A dictionary of supported input formats""" 
 34  outformats = {"smi":"SMILES", "cdxml":"ChemDraw XML", "inchi":"InChI", 
 35                "sdf":"Symyx SDF", "names":"Common names", "inchikey":"InChIKey", 
 36                "alc":"Alchemy", "cerius":"MSI Cerius II", "charmm":"CHARMM", 
 37                "cif":"Crystallographic Information File", 
 38                "cml":"Chemical Markup Language", "ctx":"Gasteiger Clear Text", 
 39                "gjf":"Gaussian job file", "gromacs":"GROMACS", 
 40                "hyperchem":"HyperChem", "jme":"Java Molecule Editor", 
 41                "maestro":"Schrodinger MacroModel", 
 42                "mol":"Symyx mol", "mol2":"Tripos Sybyl MOL2", 
 43                "mrv":"ChemAxon MRV", "pdb":"Protein Data Bank", 
 44                "sdf3000":"Symyx SDF3000", "sln":"Sybl line notation", 
 45                "xyz":"XYZ", "iupac":"IUPAC name"} 
 46  """A dictionary of supported output formats""" 
 47   
 48  fps = ["std", "maccs", "estate"] 
 49  """A list of supported fingerprint types""" 
50 51 # The following function is taken from urllib.py in the IronPython dist 52 -def _quo(text, safe="/"):
53 always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' 54 'abcdefghijklmnopqrstuvwxyz' 55 '0123456789' '_.-') 56 _safemaps = {} 57 cachekey = (safe, always_safe) 58 try: 59 safe_map = _safemaps[cachekey] 60 except KeyError: 61 safe += always_safe 62 safe_map = {} 63 for i in range(256): 64 c = chr(i) 65 safe_map[c] = (c in safe) and c or ('%%%02X' % i) 66 _safemaps[cachekey] = safe_map 67 res = map(safe_map.__getitem__, text) 68 return ''.join(res)
69
70 -def _makeserver(serverurl):
71 """Curry the name of the server""" 72 def server(*urlcomponents): 73 url = "%s/" % serverurl + "/".join(urlcomponents) 74 resp = urllib2.urlopen(url) 75 return resp.read()
76 return server 77 78 rajweb = _makeserver("http://ws1.bmc.uu.se:8182/cdk") 79 nci = _makeserver("http://cactus.nci.nih.gov/chemical/structure") 80 81 _descs = None # Cache the list of descriptors
82 -def getdescs():
83 """Return a list of supported descriptor types""" 84 global _descs 85 if not _descs: 86 response = rajweb("descriptors").rstrip() 87 _descs = [x.split(".")[-1] for x in response.split("\n")] 88 return _descs
89
90 -def readstring(format, string):
91 """Read in a molecule from a string. 92 93 Required parameters: 94 format - see the informats variable for a list of available 95 input formats 96 string 97 98 Note: For InChIKeys a list of molecules is returned. 99 100 Example: 101 >>> input = "C1=CC=CS1" 102 >>> mymol = readstring("smi", input) 103 """ 104 format = format.lower() 105 if not format in informats: 106 raise ValueError("%s is not a recognised Webel format" % format) 107 108 if format != "smi": 109 smiles = nci(_quo(string), "smiles").rstrip() 110 else: 111 smiles = string 112 if format == "inchikey": 113 return [Molecule(smile) for smile in smiles.split("\n")] 114 else: 115 mol = Molecule(smiles) 116 if format == "name": 117 mol.title = string 118 return mol
119
120 -class Outputfile(object):
121 """Represent a file to which *output* is to be sent. 122 123 Although it's possible to write a single molecule to a file by 124 calling the write() method of a molecule, if multiple molecules 125 are to be written to the same file you should use the Outputfile 126 class. 127 128 Required parameters: 129 format - see the outformats variable for a list of available 130 output formats 131 filename 132 133 Optional parameters: 134 overwrite -- if the output file already exists, should it 135 be overwritten? (default is False) 136 137 Methods: 138 write(molecule) 139 close() 140 """
141 - def __init__(self, format, filename, overwrite=False):
142 self.format = format.lower() 143 self.filename = filename 144 if not overwrite and os.path.isfile(self.filename): 145 raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % self.filename) 146 if not format in outformats: 147 raise ValueError("%s is not a recognised Webel format" % format) 148 self.file = open(filename, "w")
149
150 - def write(self, molecule):
151 """Write a molecule to the output file. 152 153 Required parameters: 154 molecule 155 """ 156 if self.file.closed: 157 raise IOError("Outputfile instance is closed.") 158 output = molecule.write(self.format) 159 print >> self.file, output
160
161 - def close(self):
162 """Close the Outputfile to further writing.""" 163 self.file.close()
164
165 -class Molecule(object):
166 """Represent a Webel Molecule. 167 168 Required parameter: 169 smiles -- a SMILES string or any type of cinfony Molecule 170 171 Attributes: 172 formula, molwt, title 173 174 Methods: 175 calcfp(), calcdesc(), draw(), write() 176 177 The underlying SMILES string can be accessed using the attribute: 178 smiles 179 """ 180 _cinfony = True 181
182 - def __init__(self, smiles):
183 184 if hasattr(smiles, "_cinfony"): 185 a, b = smiles._exchange 186 if a == 0: 187 smiles = b 188 else: 189 # Must convert to SMILES 190 smiles = smiles.write("smi").split()[0] 191 192 self.smiles = smiles 193 self.title = ""
194 195 @property
196 - def formula(self): return rajweb("mf", _quo(self.smiles))
197 @property
198 - def molwt(self): return float(rajweb("mw", _quo(self.smiles)))
199 @property
200 - def _exchange(self):
201 return (0, self.smiles)
202
203 - def calcdesc(self, descnames=[]):
204 """Calculate descriptor values. 205 206 Optional parameter: 207 descnames -- a list of names of descriptors 208 209 If descnames is not specified, all available descriptors are 210 calculated. See the descs variable for a list of available 211 descriptors. 212 """ 213 if not descnames: 214 descnames = getdescs() 215 else: 216 for descname in descnames: 217 if descname not in getdescs(): 218 raise ValueError("%s is not a recognised Webel descriptor type" % descname) 219 ans = {} 220 p = re.compile("""Descriptor parent="(\w*)" name="([\w\-\+\d]*)" value="([\d\.]*)""") 221 for descname in descnames: 222 longname = "org.openscience.cdk.qsar.descriptors.molecular." + descname 223 response = rajweb("descriptor", longname, _quo(self.smiles)) 224 for match in p.findall(response): 225 if match[2]: 226 ans["%s_%s" % (match[0], match[1])] = float(match[2]) 227 return ans
228
229 - def calcfp(self, fptype="std"):
230 """Calculate a molecular fingerprint. 231 232 Optional parameters: 233 fptype -- the fingerprint type (default is "std"). See the 234 fps variable for a list of of available fingerprint 235 types. 236 """ 237 fptype = fptype.lower() 238 if fptype not in fps: 239 raise ValueError("%s is not a recognised Webel Fingerprint type" % fptype) 240 fp = rajweb("fingerprint/%s/%s" % (fptype, _quo(self.smiles))).rstrip() 241 return Fingerprint(fp)
242
243 - def write(self, format="smi", filename=None, overwrite=False):
244 """Write the molecule to a file or return a string. 245 246 Optional parameters: 247 format -- see the informats variable for a list of available 248 output formats (default is "smi") 249 filename -- default is None 250 overwite -- if the output file already exists, should it 251 be overwritten? (default is False) 252 253 If a filename is specified, the result is written to a file. 254 Otherwise, a string is returned containing the result. 255 256 To write multiple molecules to the same file you should use 257 the Outputfile class. 258 """ 259 format = format.lower() 260 if not format in outformats: 261 raise ValueError("%s is not a recognised Webel format" % format) 262 if format == "smi": 263 output = self.smiles 264 elif format == "names": 265 try: 266 output = nci(_quo(self.smiles), "%s" % format).rstrip().split("\n") 267 except urllib2.URLError, e: 268 if e.code == 404: 269 output = [] 270 elif format in ['inchi', 'inchikey']: 271 format = "std" + format 272 output = nci(_quo(self.smiles), "%s" % format).rstrip() 273 elif format == 'iupac': 274 format = format + "_name" 275 try: 276 output = nci(_quo(self.smiles), "%s" % format).rstrip() 277 except urllib2.URLError, e: 278 if e.code == 404: 279 output = "" 280 else: 281 output = nci(_quo(self.smiles), "file?format=%s" % format).rstrip() 282 283 if filename: 284 if not overwrite and os.path.isfile(filename): 285 raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % filename) 286 outputfile = open(filename, "w") 287 print >> outputfile, output 288 outputfile.close() 289 else: 290 return output
291
292 - def __str__(self):
293 return self.write()
294
295 - def draw(self, show=True, filename=None):
296 """Create a 2D depiction of the molecule. 297 298 Optional parameters: 299 show -- display on screen (default is True) 300 filename -- write to file (default is None) 301 302 Tkinter and Python Imaging Library are required for 303 image display. 304 """ 305 imagedata = nci(_quo(self.smiles), "image") 306 if filename: 307 print >> open(filename, "wb"), imagedata 308 if show: 309 if not tk: 310 errormessage = ("Tkinter or Python Imaging " 311 "Library not found, but is required for image " 312 "display. See installation instructions for " 313 "more information.") 314 raise ImportError, errormessage 315 root = tk.Tk() 316 root.title(self.smiles) 317 frame = tk.Frame(root, colormap="new", visual='truecolor').pack() 318 image = PIL.open(StringIO.StringIO(imagedata)) 319 imagedata = piltk.PhotoImage(image) 320 label = tk.Label(frame, image=imagedata).pack() 321 quitbutton = tk.Button(root, text="Close", command=root.destroy).pack(fill=tk.X) 322 root.mainloop()
323
324 -class Fingerprint(object):
325 """A Molecular Fingerprint. 326 327 Required parameters: 328 fingerprint -- a string of 0's and 1's representing a binary fingerprint 329 330 Attributes: 331 fp -- the underlying fingerprint object 332 bits -- a list of bits set in the Fingerprint 333 334 Methods: 335 The "|" operator can be used to calculate the Tanimoto coeff. For example, 336 given two Fingerprints 'a', and 'b', the Tanimoto coefficient is given by: 337 tanimoto = a | b 338 """
339 - def __init__(self, fingerprint):
340 self.fp = fingerprint
341 - def __or__(self, other):
342 mybits = set(self.bits) 343 otherbits = set(other.bits) 344 return len(mybits&otherbits) / float(len(mybits|otherbits))
345 @property
346 - def bits(self):
347 return [i for i,x in enumerate(self.fp) if x=="1"]
348 - def __str__(self):
349 return self.fp
350
351 -class Smarts(object):
352 """A Smarts Pattern Matcher 353 354 Required parameters: 355 smartspattern 356 357 Methods: 358 match(molecule) 359 360 Example: 361 >>> mol = readstring("smi","CCN(CC)CC") # triethylamine 362 >>> smarts = Smarts("[#6][#6]") # Matches an ethyl group 363 >>> smarts.match(mol) 364 True 365 """
366 - def __init__(self, smartspattern):
367 """Initialise with a SMARTS pattern.""" 368 self.pat = smartspattern
369 - def match(self, molecule):
370 """Does a SMARTS pattern match a particular molecule? 371 372 Required parameters: 373 molecule 374 """ 375 resp = rajweb("substruct", _quo(molecule.smiles), _quo(self.pat)).rstrip() 376 return resp == "true"
377 378 if __name__=="__main__": #pragma: no cover 379 import doctest 380 doctest.run_docstring_examples(rajweb, globals()) 381