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

Source Code for Module cinfony.pybel

  1  #-*. coding: utf-8 -*- 
  2  ## Copyright (c) 2008-2012, Noel O'Boyle; 2012, Adrià Cereto-Massagué 
  3  ## All rights reserved. 
  4  ## 
  5  ##  This file is part of Cinfony. 
  6  ##  The contents are covered by the terms of the GPL v2 license 
  7  ##  which is included in the file LICENSE_GPLv2.txt. 
  8   
  9  """ 
 10  pybel - A Cinfony module for accessing Open Babel 
 11   
 12  Global variables: 
 13    ob - the underlying SWIG bindings for Open Babel 
 14    informats - a dictionary of supported input formats 
 15    outformats - a dictionary of supported output formats 
 16    descs - a list of supported descriptors 
 17    fps - a list of supported fingerprint types 
 18    forcefields - a list of supported forcefields 
 19  """ 
 20   
 21  import sys 
 22  import math 
 23  import os.path 
 24  import tempfile 
 25   
 26  if sys.platform[:4] == "java": 
 27      import org.openbabel as ob 
 28      import java.lang.System 
 29      java.lang.System.loadLibrary("openbabel_java") 
 30      _obfuncs = ob.openbabel_java 
 31      _obconsts = ob.openbabel_javaConstants 
 32      import javax 
 33  elif sys.platform[:3] == "cli": 
 34      import System 
 35      import clr 
 36      clr.AddReference('System.Windows.Forms') 
 37      clr.AddReference('System.Drawing') 
 38        
 39      from System.Windows.Forms import ( 
 40          Application, DockStyle, Form, PictureBox, PictureBoxSizeMode 
 41          ) 
 42      from System.Drawing import Image, Size 
 43   
 44      _obdotnet = os.environ["OBDOTNET"] 
 45      if _obdotnet[0] == '"': # Remove trailing quotes 
 46          _obdotnet = _obdotnet[1:-1] 
 47      clr.AddReferenceToFileAndPath(os.path.join(_obdotnet, "OBDotNet.dll")) 
 48      import OpenBabel as ob 
 49      _obfuncs = ob.openbabel_csharp 
 50      _obconsts = ob.openbabel_csharp 
 51  else: 
 52      import openbabel as ob 
 53      _obfuncs = _obconsts = ob 
 54      try: 
 55          import Tkinter as tk 
 56          import Image as PIL 
 57          import ImageTk as piltk 
 58      except ImportError: #pragma: no cover 
 59          tk = None 
60 61 -def _formatstodict(list):
62 if sys.platform[:4] == "java": 63 list = [list.get(i) for i in range(list.size())] 64 broken = [x.replace("[Read-only]", "").replace("[Write-only]","").split(" -- ") for x in list] 65 broken = [(x,y.strip()) for x,y in broken] 66 return dict(broken)
67 _obconv = ob.OBConversion() 68 _builder = ob.OBBuilder() 69 informats = _formatstodict(_obconv.GetSupportedInputFormat()) 70 """A dictionary of supported input formats""" 71 outformats = _formatstodict(_obconv.GetSupportedOutputFormat()) 72 """A dictionary of supported output formats"""
73 74 -def _getplugins(findplugin, names):
75 plugins = dict([(x, findplugin(x)) for x in names if findplugin(x)]) 76 return plugins
77 -def _getpluginnames(ptype):
78 if sys.platform[:4] == "cli": 79 plugins = ob.VectorString() 80 else: 81 plugins = ob.vectorString() 82 ob.OBPlugin.ListAsVector(ptype, None, plugins) 83 if sys.platform[:4] == "java": 84 plugins = [plugins.get(i) for i in range(plugins.size())] 85 return [x.split()[0] for x in plugins]
86 87 descs = _getpluginnames("descriptors") 88 """A list of supported descriptors""" 89 _descdict = _getplugins(ob.OBDescriptor.FindType, descs) 90 fps = [_x.lower() for _x in _getpluginnames("fingerprints")] 91 """A list of supported fingerprint types""" 92 _fingerprinters = _getplugins(ob.OBFingerprint.FindFingerprint, fps) 93 forcefields = [_x.lower() for _x in _getpluginnames("forcefields")] 94 """A list of supported forcefields""" 95 _forcefields = _getplugins(ob.OBForceField.FindType, forcefields) 96 operations = _getpluginnames("ops") 97 """A list of supported operations""" 98 _operations = _getplugins(ob.OBOp.FindType, operations)
99 100 -def readfile(format, filename, opt=None):
101 """Iterate over the molecules in a file. 102 103 Required parameters: 104 format - see the informats variable for a list of available 105 input formats 106 filename 107 108 Optional parameters: 109 opt - a dictionary of format-specific options 110 For format options with no parameters, specify the 111 value as None. 112 113 You can access the first molecule in a file using the next() method 114 of the iterator (or the next() keyword in Python 3): 115 mol = readfile("smi", "myfile.smi").next() # Python 2 116 mol = next(readfile("smi", "myfile.smi")) # Python 3 117 118 You can make a list of the molecules in a file using: 119 mols = list(readfile("smi", "myfile.smi")) 120 121 You can iterate over the molecules in a file as shown in the 122 following code snippet: 123 >>> atomtotal = 0 124 >>> for mol in readfile("sdf", "head.sdf"): 125 ... atomtotal += len(mol.atoms) 126 ... 127 >>> print atomtotal 128 43 129 """ 130 if opt == None: 131 opt = {} 132 obconversion = ob.OBConversion() 133 formatok = obconversion.SetInFormat(format) 134 for k, v in opt.items(): 135 if v == None: 136 obconversion.AddOption(k, obconversion.INOPTIONS) 137 else: 138 obconversion.AddOption(k, obconversion.INOPTIONS, str(v)) 139 if not formatok: 140 raise ValueError("%s is not a recognised Open Babel format" % format) 141 if not os.path.isfile(filename): 142 raise IOError("No such file: '%s'" % filename) 143 def filereader(): 144 obmol = ob.OBMol() 145 notatend = obconversion.ReadFile(obmol,filename) 146 while notatend: 147 yield Molecule(obmol) 148 obmol = ob.OBMol() 149 notatend = obconversion.Read(obmol)
150 return filereader() 151
152 -def readstring(format, string, opt=None):
153 """Read in a molecule from a string. 154 155 Required parameters: 156 format - see the informats variable for a list of available 157 input formats 158 string 159 160 Optional parameters: 161 opt - a dictionary of format-specific options 162 For format options with no parameters, specify the 163 value as None. 164 165 Example: 166 >>> input = "C1=CC=CS1" 167 >>> mymol = readstring("smi", input) 168 >>> len(mymol.atoms) 169 5 170 """ 171 if opt == None: 172 opt = {} 173 174 obmol = ob.OBMol() 175 obconversion = ob.OBConversion() 176 177 formatok = obconversion.SetInFormat(format) 178 if not formatok: 179 raise ValueError("%s is not a recognised Open Babel format" % format) 180 for k, v in opt.items(): 181 if v == None: 182 obconversion.AddOption(k, obconversion.INOPTIONS) 183 else: 184 obconversion.AddOption(k, obconversion.INOPTIONS, str(v)) 185 186 success = obconversion.ReadString(obmol, string) 187 if not success: 188 raise IOError("Failed to convert '%s' to format '%s'" % ( 189 string, format)) 190 return Molecule(obmol)
191
192 -class Outputfile(object):
193 """Represent a file to which *output* is to be sent. 194 195 Although it's possible to write a single molecule to a file by 196 calling the write() method of a molecule, if multiple molecules 197 are to be written to the same file you should use the Outputfile 198 class. 199 200 Required parameters: 201 format - see the outformats variable for a list of available 202 output formats 203 filename 204 205 Optional parameters: 206 overwrite -- if the output file already exists, should it 207 be overwritten? (default is False) 208 opt -- a dictionary of format-specific options 209 For format options with no parameters, specify the 210 value as None. 211 212 Methods: 213 write(molecule) 214 close() 215 """
216 - def __init__(self, format, filename, overwrite=False, opt=None):
217 if opt == None: 218 opt = {} 219 self.format = format 220 self.filename = filename 221 if not overwrite and os.path.isfile(self.filename): 222 raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % self.filename) 223 224 self.obConversion = ob.OBConversion() 225 formatok = self.obConversion.SetOutFormat(self.format) 226 if not formatok: 227 raise ValueError("%s is not a recognised Open Babel format" % format) 228 229 for k, v in opt.items(): 230 if v == None: 231 self.obConversion.AddOption(k, self.obConversion.OUTOPTIONS) 232 else: 233 self.obConversion.AddOption(k, self.obConversion.OUTOPTIONS, str(v)) 234 self.total = 0 # The total number of molecules written to the file
235
236 - def write(self, molecule):
237 """Write a molecule to the output file. 238 239 Required parameters: 240 molecule 241 """ 242 if not self.filename: 243 raise IOError("Outputfile instance is closed.") 244 245 if self.total==0: 246 self.obConversion.WriteFile(molecule.OBMol, self.filename) 247 else: 248 self.obConversion.Write(molecule.OBMol) 249 self.total += 1
250
251 - def close(self):
252 """Close the Outputfile to further writing.""" 253 self.obConversion.CloseOutFile() 254 self.filename = None
255
256 -class Molecule(object):
257 """Represent a Pybel Molecule. 258 259 Required parameter: 260 OBMol -- an Open Babel OBMol or any type of cinfony Molecule 261 262 Attributes: 263 atoms, charge, conformers, data, dim, energy, exactmass, formula, 264 molwt, spin, sssr, title, unitcell. 265 (refer to the Open Babel library documentation for more info). 266 267 Methods: 268 addh(), calcfp(), calcdesc(), draw(), localopt(), make3D(), removeh(), 269 write() 270 271 The underlying Open Babel molecule can be accessed using the attribute: 272 OBMol 273 """ 274 _cinfony = True 275
276 - def __init__(self, OBMol):
277 278 if hasattr(OBMol, "_cinfony"): 279 a, b = OBMol._exchange 280 if a == 0: 281 mol = readstring("smi", b) 282 else: 283 mol = readstring("mol", b) 284 OBMol = mol.OBMol 285 286 self.OBMol = OBMol
287 288 @property
289 - def atoms(self):
290 return [ Atom(self.OBMol.GetAtom(i+1)) for i in range(self.OBMol.NumAtoms()) ]
291 @property
292 - def charge(self): return self.OBMol.GetTotalCharge()
293 @property
294 - def conformers(self): return self.OBMol.GetConformers()
295 @property
296 - def data(self): return MoleculeData(self.OBMol)
297 @property
298 - def dim(self): return self.OBMol.GetDimension()
299 @property
300 - def energy(self): return self.OBMol.GetEnergy()
301 @property
302 - def exactmass(self): return self.OBMol.GetExactMass()
303 @property
304 - def formula(self): return self.OBMol.GetFormula()
305 @property
306 - def molwt(self): return self.OBMol.GetMolWt()
307 @property
308 - def spin(self): return self.OBMol.GetTotalSpinMultiplicity()
309 @property
310 - def sssr(self): return self.OBMol.GetSSSR()
311 - def _gettitle(self): return self.OBMol.GetTitle()
312 - def _settitle(self, val): self.OBMol.SetTitle(val)
313 title = property(_gettitle, _settitle) 314 @property
315 - def unitcell(self):
316 unitcell_index = _obconsts.UnitCell 317 if sys.platform[:3] == "cli": 318 unitcell_index = System.UInt32(unitcell_index) 319 unitcell = self.OBMol.GetData(unitcell_index) 320 if unitcell: 321 if sys.platform[:3] != "cli": 322 return _obfuncs.toUnitCell(unitcell) 323 else: 324 return unitcell.Downcast[ob.OBUnitCell]() 325 else: 326 raise AttributeError("Molecule has no attribute 'unitcell'")
327 @property
328 - def _exchange(self):
329 if self.OBMol.HasNonZeroCoords(): 330 return (1, self.write("mol")) 331 else: 332 return (0, self.write("can").split()[0])
333
334 - def __iter__(self):
335 """Iterate over the Atoms of the Molecule. 336 337 This allows constructions such as the following: 338 for atom in mymol: 339 print atom 340 """ 341 return iter(self.atoms)
342
343 - def calcdesc(self, descnames=[]):
344 """Calculate descriptor values. 345 346 Optional parameter: 347 descnames -- a list of names of descriptors 348 349 If descnames is not specified, all available descriptors are 350 calculated. See the descs variable for a list of available 351 descriptors. 352 """ 353 if not descnames: 354 descnames = descs 355 ans = {} 356 for descname in descnames: 357 try: 358 desc = _descdict[descname] 359 except KeyError: 360 raise ValueError("%s is not a recognised Open Babel descriptor type" % descname) 361 ans[descname] = desc.Predict(self.OBMol) 362 return ans
363
364 - def calcfp(self, fptype="FP2"):
365 """Calculate a molecular fingerprint. 366 367 Optional parameters: 368 fptype -- the fingerprint type (default is "FP2"). See the 369 fps variable for a list of of available fingerprint 370 types. 371 """ 372 if sys.platform[:3] == "cli": 373 fp = ob.VectorUInt() 374 else: 375 fp = ob.vectorUnsignedInt() 376 fptype = fptype.lower() 377 try: 378 fingerprinter = _fingerprinters[fptype] 379 except KeyError: 380 raise ValueError("%s is not a recognised Open Babel Fingerprint type" % fptype) 381 fingerprinter.GetFingerprint(self.OBMol, fp) 382 return Fingerprint(fp)
383
384 - def write(self, format="smi", filename=None, overwrite=False, opt=None):
385 """Write the molecule to a file or return a string. 386 387 Optional parameters: 388 format -- see the informats variable for a list of available 389 output formats (default is "smi") 390 filename -- default is None 391 overwite -- if the output file already exists, should it 392 be overwritten? (default is False) 393 opt -- a dictionary of format specific options 394 For format options with no parameters, specify the 395 value as None. 396 397 If a filename is specified, the result is written to a file. 398 Otherwise, a string is returned containing the result. 399 400 To write multiple molecules to the same file you should use 401 the Outputfile class. 402 """ 403 if opt == None: 404 opt = {} 405 obconversion = ob.OBConversion() 406 formatok = obconversion.SetOutFormat(format) 407 if not formatok: 408 raise ValueError("%s is not a recognised Open Babel format" % format) 409 for k, v in opt.items(): 410 if v == None: 411 obconversion.AddOption(k, obconversion.OUTOPTIONS) 412 else: 413 obconversion.AddOption(k, obconversion.OUTOPTIONS, str(v)) 414 415 if filename: 416 if not overwrite and os.path.isfile(filename): 417 raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % filename) 418 obconversion.WriteFile(self.OBMol,filename) 419 obconversion.CloseOutFile() 420 else: 421 return obconversion.WriteString(self.OBMol)
422
423 - def localopt(self, forcefield="mmff94", steps=500):
424 """Locally optimize the coordinates. 425 426 Optional parameters: 427 forcefield -- default is "mmff94". See the forcefields variable 428 for a list of available forcefields. 429 steps -- default is 500 430 431 If the molecule does not have any coordinates, make3D() is 432 called before the optimization. Note that the molecule needs 433 to have explicit hydrogens. If not, call addh(). 434 """ 435 forcefield = forcefield.lower() 436 if self.dim != 3: 437 self.make3D(forcefield) 438 ff = _forcefields[forcefield] 439 success = ff.Setup(self.OBMol) 440 if not success: 441 return 442 ff.SteepestDescent(steps) 443 ff.GetCoordinates(self.OBMol)
444 445 ## def globalopt(self, forcefield="MMFF94", steps=1000): 446 ## if not (self.OBMol.Has2D() or self.OBMol.Has3D()): 447 ## self.make3D() 448 ## self.localopt(forcefield, 250) 449 ## ff = _forcefields[forcefield] 450 ## numrots = self.OBMol.NumRotors() 451 ## if numrots > 0: 452 ## ff.WeightedRotorSearch(numrots, int(math.log(numrots + 1) * steps)) 453 ## ff.GetCoordinates(self.OBMol) 454
455 - def make3D(self, forcefield = "mmff94", steps = 50):
456 """Generate 3D coordinates. 457 458 Optional parameters: 459 forcefield -- default is "mmff94". See the forcefields variable 460 for a list of available forcefields. 461 steps -- default is 50 462 463 Once coordinates are generated, hydrogens are added and a quick 464 local optimization is carried out with 50 steps and the 465 MMFF94 forcefield. Call localopt() if you want 466 to improve the coordinates further. 467 """ 468 forcefield = forcefield.lower() 469 _builder.Build(self.OBMol) 470 self.addh() 471 self.localopt(forcefield, steps)
472
473 - def addh(self):
474 """Add hydrogens.""" 475 self.OBMol.AddHydrogens()
476
477 - def removeh(self):
478 """Remove hydrogens.""" 479 self.OBMol.DeleteHydrogens()
480
481 - def __str__(self):
482 return self.write()
483
484 - def draw(self, show=True, filename=None, update=False, usecoords=False):
485 """Create a 2D depiction of the molecule. 486 487 Optional parameters: 488 show -- display on screen (default is True) 489 filename -- write to file (default is None) 490 update -- update the coordinates of the atoms to those 491 determined by the structure diagram generator 492 (default is False) 493 usecoords -- don't calculate 2D coordinates, just use 494 the current coordinates (default is False) 495 496 Tkinter and Python Imaging Library are required for image display. 497 """ 498 obconversion = ob.OBConversion() 499 formatok = obconversion.SetOutFormat("_png2") 500 if not formatok: 501 errormessage = ("PNG depiction support not found. You should compile " 502 "Open Babel with support for Cairo. See installation " 503 "instructions for more information.") 504 raise ImportError(errormessage) 505 506 # Need to copy to avoid removing hydrogens from self 507 workingmol = Molecule(ob.OBMol(self.OBMol)) 508 workingmol.removeh() 509 510 if not usecoords: 511 _operations['gen2D'].Do(workingmol.OBMol) 512 if update == True: 513 if workingmol.OBMol.NumAtoms() != self.OBMol.NumAtoms(): 514 errormessage = ("It is not possible to update the original molecule " 515 "with the calculated coordinates, as the original " 516 "molecule contains explicit hydrogens for which no " 517 "coordinates have been calculated.") 518 raise RuntimeError(errormessage) 519 else: 520 for i in range(workingmol.OBMol.NumAtoms()): 521 self.OBMol.GetAtom(i + 1).SetVector(workingmol.OBMol.GetAtom(i + 1).GetVector()) 522 523 if filename: 524 filedes = None 525 else: 526 if sys.platform[:3] == "cli" and show: 527 errormessage = ("It is only possible to show the molecule if you " 528 "provide a filename. The reason for this is that I kept " 529 "having problems when using temporary files.") 530 raise RuntimeError(errormessage) 531 532 filedes, filename = tempfile.mkstemp() 533 534 workingmol.write("_png2", filename=filename, overwrite=True) 535 536 if show: 537 if sys.platform[:4] == "java": 538 image = javax.imageio.ImageIO.read(java.io.File(filename)) 539 frame = javax.swing.JFrame(visible=1) 540 frame.getContentPane().add(javax.swing.JLabel(javax.swing.ImageIcon(image))) 541 frame.setSize(300,300) 542 frame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE) 543 frame.show() 544 elif sys.platform[:3] == "cli": 545 form = _MyForm() 546 form.setup(filename, self.title) 547 Application.Run(form) 548 else: 549 if not tk: 550 errormessage = ("Tkinter or Python Imaging " 551 "Library not found, but is required for image " 552 "display. See installation instructions for " 553 "more information.") 554 raise ImportError(errormessage) 555 root = tk.Tk() 556 root.title((hasattr(self, "title") and self.title) 557 or self.__str__().rstrip()) 558 frame = tk.Frame(root, colormap="new", visual='truecolor').pack() 559 image = PIL.open(filename) 560 imagedata = piltk.PhotoImage(image) 561 label = tk.Label(frame, image=imagedata).pack() 562 quitbutton = tk.Button(root, text="Close", command=root.destroy).pack(fill=tk.X) 563 root.mainloop() 564 if filedes: 565 os.close(filedes) 566 os.remove(filename)
567
568 -class Atom(object):
569 """Represent a Pybel atom. 570 571 Required parameter: 572 OBAtom -- an Open Babel OBAtom 573 574 Attributes: 575 atomicmass, atomicnum, cidx, coords, coordidx, exactmass, 576 formalcharge, heavyvalence, heterovalence, hyb, idx, 577 implicitvalence, isotope, partialcharge, spin, type, 578 valence, vector. 579 580 (refer to the Open Babel library documentation for more info). 581 582 The original Open Babel atom can be accessed using the attribute: 583 OBAtom 584 """ 585
586 - def __init__(self, OBAtom):
587 self.OBAtom = OBAtom
588 589 @property
590 - def coords(self):
591 return (self.OBAtom.GetX(), self.OBAtom.GetY(), self.OBAtom.GetZ())
592 @property
593 - def atomicmass(self): return self.OBAtom.GetAtomicMass()
594 @property
595 - def atomicnum(self): return self.OBAtom.GetAtomicNum()
596 @property
597 - def cidx(self): return self.OBAtom.GetCIdx()
598 @property
599 - def coordidx(self): return self.OBAtom.GetCoordinateIdx()
600 @property
601 - def exactmass(self): return self.OBAtom.GetExactMass()
602 @property
603 - def formalcharge(self): return self.OBAtom.GetFormalCharge()
604 @property
605 - def heavyvalence(self): return self.OBAtom.GetHvyValence()
606 @property
607 - def heterovalence(self): return self.OBAtom.GetHeteroValence()
608 @property
609 - def hyb(self): return self.OBAtom.GetHyb()
610 @property
611 - def idx(self): return self.OBAtom.GetIdx()
612 @property
613 - def implicitvalence(self): return self.OBAtom.GetImplicitValence()
614 @property
615 - def isotope(self): return self.OBAtom.GetIsotope()
616 @property
617 - def partialcharge(self): return self.OBAtom.GetPartialCharge()
618 @property
619 - def spin(self): return self.OBAtom.GetSpinMultiplicity()
620 @property
621 - def type(self): return self.OBAtom.GetType()
622 @property
623 - def valence(self): return self.OBAtom.GetValence()
624 @property
625 - def vector(self): return self.OBAtom.GetVector()
626
627 - def __str__(self):
628 c = self.coords 629 return "Atom: %d (%.2f %.2f %.2f)" % (self.atomicnum, c[0], c[1], c[2])
630
631 -def _findbits(fp, bitsperint):
632 """Find which bits are set in a list/vector. 633 634 This function is used by the Fingerprint class. 635 636 >>> _findbits([13, 71], 8) 637 [1, 3, 4, 9, 10, 11, 15] 638 """ 639 ans = [] 640 start = 1 641 if sys.platform[:4] == "java": 642 fp = [fp.get(i) for i in range(fp.size())] 643 for x in fp: 644 i = start 645 while x > 0: 646 if x % 2: 647 ans.append(i) 648 x >>= 1 649 i += 1 650 start += bitsperint 651 return ans
652
653 -class Fingerprint(object):
654 """A Molecular Fingerprint. 655 656 Required parameters: 657 fingerprint -- a vector calculated by OBFingerprint.FindFingerprint() 658 659 Attributes: 660 fp -- the underlying fingerprint object 661 bits -- a list of bits set in the Fingerprint 662 663 Methods: 664 The "|" operator can be used to calculate the Tanimoto coeff. For example, 665 given two Fingerprints 'a', and 'b', the Tanimoto coefficient is given by: 666 tanimoto = a | b 667 """
668 - def __init__(self, fingerprint):
669 self.fp = fingerprint
670 - def __or__(self, other):
671 return ob.OBFingerprint.Tanimoto(self.fp, other.fp)
672 @property
673 - def bits(self):
674 return _findbits(self.fp, ob.OBFingerprint.Getbitsperint())
675 - def __str__(self):
676 fp = self.fp 677 if sys.platform[:4] == "java": 678 fp = [self.fp.get(i) for i in range(self.fp.size())] 679 return ", ".join([str(x) for x in fp])
680
681 -class Smarts(object):
682 """A Smarts Pattern Matcher 683 684 Required parameters: 685 smartspattern 686 687 Methods: 688 findall(molecule) 689 690 Example: 691 >>> mol = readstring("smi","CCN(CC)CC") # triethylamine 692 >>> smarts = Smarts("[#6][#6]") # Matches an ethyl group 693 >>> print smarts.findall(mol) 694 [(1, 2), (4, 5), (6, 7)] 695 696 The numbers returned are the indices (starting from 1) of the atoms 697 that match the SMARTS pattern. In this case, there are three matches 698 for each of the three ethyl groups in the molecule. 699 """
700 - def __init__(self,smartspattern):
701 """Initialise with a SMARTS pattern.""" 702 self.obsmarts = ob.OBSmartsPattern() 703 success = self.obsmarts.Init(smartspattern) 704 if not success: 705 raise IOError("Invalid SMARTS pattern")
706 - def findall(self,molecule):
707 """Find all matches of the SMARTS pattern to a particular molecule. 708 709 Required parameters: 710 molecule 711 """ 712 self.obsmarts.Match(molecule.OBMol) 713 vector = self.obsmarts.GetUMapList() 714 if sys.platform[:4] == "java": 715 vector = [vector.get(i) for i in range(vector.size())] 716 return list(vector)
717
718 -class MoleculeData(object):
719 """Store molecule data in a dictionary-type object 720 721 Required parameters: 722 obmol -- an Open Babel OBMol 723 724 Methods and accessor methods are like those of a dictionary except 725 that the data is retrieved on-the-fly from the underlying OBMol. 726 727 Example: 728 >>> mol = readfile("sdf", 'head.sdf').next() # Python 2 729 >>> # mol = next(readfile("sdf", 'head.sdf')) # Python 3 730 >>> data = mol.data 731 >>> print data 732 {'Comment': 'CORINA 2.61 0041 25.10.2001', 'NSC': '1'} 733 >>> print len(data), data.keys(), data.has_key("NSC") 734 2 ['Comment', 'NSC'] True 735 >>> print data['Comment'] 736 CORINA 2.61 0041 25.10.2001 737 >>> data['Comment'] = 'This is a new comment' 738 >>> for k,v in data.items(): 739 ... print k, "-->", v 740 Comment --> This is a new comment 741 NSC --> 1 742 >>> del data['NSC'] 743 >>> print len(data), data.keys(), data.has_key("NSC") 744 1 ['Comment'] False 745 """
746 - def __init__(self, obmol):
747 self._mol = obmol
748 - def _data(self):
749 data = self._mol.GetData() 750 if sys.platform[:4] == "java": 751 data = [data.get(i) for i in range(data.size())] 752 answer = [x for x in data if 753 x.GetDataType()==_obconsts.PairData or 754 x.GetDataType()==_obconsts.CommentData] 755 if sys.platform[:3] != "cli": 756 answer = [_obfuncs.toPairData(x) for x in answer] 757 return answer
758 - def _testforkey(self, key):
759 if not key in self: 760 raise KeyError("'%s'" % key)
761 - def keys(self):
762 return [x.GetAttribute() for x in self._data()]
763 - def values(self):
764 return [x.GetValue() for x in self._data()]
765 - def items(self):
766 return iter(zip(self.keys(), self.values()))
767 - def __iter__(self):
768 return iter(self.keys())
769 - def iteritems(self): # Can remove for Python 3
770 return self.items()
771 - def __len__(self):
772 return len(self._data())
773 - def __contains__(self, key):
774 return self._mol.HasData(key)
775 - def __delitem__(self, key):
776 self._testforkey(key) 777 self._mol.DeleteData(self._mol.GetData(key))
778 - def clear(self):
779 for key in self: 780 del self[key]
781 - def has_key(self, key):
782 return key in self
783 - def update(self, dictionary):
784 for k, v in dictionary.items(): 785 self[k] = v
786 - def __getitem__(self, key):
787 self._testforkey(key) 788 answer = self._mol.GetData(key) 789 if sys.platform[:3] != "cli": 790 answer = _obfuncs.toPairData(answer) 791 return answer.GetValue()
792 - def __setitem__(self, key, value):
793 if key in self: 794 if sys.platform[:3] != "cli": 795 pairdata = _obfuncs.toPairData(self._mol.GetData(key)) 796 else: 797 pairdata = self._mol.GetData(key).Downcast[ob.OBPairData]() 798 pairdata.SetValue(str(value)) 799 else: 800 pairdata = ob.OBPairData() 801 pairdata.SetAttribute(key) 802 pairdata.SetValue(str(value)) 803 self._mol.CloneData(pairdata)
804 - def __repr__(self):
805 return dict(self.items()).__repr__()
806 807 if sys.platform[:3] == "cli":
808 - class _MyForm(Form):
809 - def __init__(self):
810 Form.__init__(self)
811
812 - def setup(self, filename, title):
813 # adjust the form's client area size to the picture 814 self.ClientSize = Size(300, 300) 815 self.Text = title 816 817 self.filename = filename 818 self.image = Image.FromFile(self.filename) 819 pictureBox = PictureBox() 820 # this will fit the image to the form 821 pictureBox.SizeMode = PictureBoxSizeMode.StretchImage 822 pictureBox.Image = self.image 823 # fit the picture box to the frame 824 pictureBox.Dock = DockStyle.Fill 825 826 self.Controls.Add(pictureBox) 827 self.Show()
828 829 if __name__=="__main__": #pragma: no cover 830 import doctest 831 doctest.testmod(verbose=True) 832