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

Source Code for Module cinfony.cdk

  1  #-*. coding: utf-8 -*- 
  2  ## Copyright (c) 2008-2011, 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 BSD license 
  7  ##  which is included in the file LICENSE_BSD.txt. 
  8   
  9  """ 
 10  cdk - A Cinfony module for accessing the CDK from CPython and Jython 
 11   
 12  Global variables: 
 13    cdk - the underlying CDK Java library (org.openscience.cdk) 
 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  import sys 
 21  import os 
 22   
 23  if sys.platform[:4] == "java": 
 24      import org.openscience.cdk as cdk 
 25      import java 
 26      import javax 
 27   
 28      #Exceptions are handled differently in jpype and jython. We need to wrap them: 
 29      InvalidSmilesException = cdk.exception.InvalidSmilesException 
 30      CDKException = cdk.exception.CDKException 
 31      NullPointerException = java.lang.NullPointerException 
 32   
 33  else: 
 34      from jpype import * 
 35   
 36      if not isJVMStarted(): 
 37          _jvm = os.environ['JPYPE_JVM'] 
 38          if _jvm[0] == '"': # Remove trailing quotes 
 39              _jvm = _jvm[1:-1] 
 40          _cp = os.environ['CLASSPATH'] 
 41          startJVM(_jvm, "-Djava.class.path=" + _cp) 
 42   
 43      cdk = JPackage("org").openscience.cdk 
 44      try: 
 45          _testmol = cdk.Molecule() 
 46      except TypeError: 
 47          raise ImportError, "The CDK Jar file cannot be found." 
 48   
 49      #Exception wrappers for Jpype 
 50      InvalidSmilesException = JavaException 
 51      CDKException = JavaException 
 52      NullPointerException = JavaException 
53 54 -def _getdescdict():
55 de = cdk.qsar.DescriptorEngine(cdk.qsar.DescriptorEngine.MOLECULAR) 56 descdict = {} 57 for desc in de.getDescriptorInstances(): 58 spec = desc.getSpecification() 59 descclass = de.getDictionaryClass(spec) 60 if "proteinDescriptor" not in descclass: 61 # Using str() for unicode conversion 62 name = str(spec.getSpecificationReference().split("#")[-1]) 63 descdict[name] = desc 64 return descdict
65 66 _descdict = _getdescdict() 67 descs = _descdict.keys() 68 """A list of supported descriptors""" 69 _fingerprinters = {"daylight":cdk.fingerprint.Fingerprinter 70 , "graph":cdk.fingerprint.GraphOnlyFingerprinter 71 , "maccs":cdk.fingerprint.MACCSFingerprinter 72 , "estate":cdk.fingerprint.EStateFingerprinter 73 , "extended":cdk.fingerprint.ExtendedFingerprinter 74 , "hybridization":cdk.fingerprint.HybridizationFingerprinter 75 , "klekota-roth":cdk.fingerprint.KlekotaRothFingerprinter 76 , "pubchem":cdk.fingerprint.PubchemFingerprinter 77 , "substructure":cdk.fingerprint.SubstructureFingerprinter 78 } 79 fps = _fingerprinters.keys() 80 """A list of supported fingerprint types""" 81 _formats = {'smi': "SMILES" , 'sdf': "MDL SDF", 82 'mol2': "MOL2", 'mol': "MDL MOL", 83 "inchi":"InChI", 84 "inchikey":"InChIKey"} 85 _informats = {'sdf': cdk.io.MDLV2000Reader, 'mol': cdk.io.MDLV2000Reader} 86 informats = dict([(_x, _formats[_x]) for _x in ['smi', 'sdf', 'mol', 'inchi']]) 87 """A dictionary of supported input formats""" 88 _outformats = {'mol': cdk.io.MDLV2000Writer, 89 'mol2': cdk.io.Mol2Writer, 90 'sdf': cdk.io.SDFWriter} 91 outformats = dict([(_x, _formats[_x]) for _x in _outformats.keys() + ['smi', 'inchi', 'inchikey']]) 92 """A dictionary of supported output formats""" 93 forcefields = list(cdk.modeling.builder3d.ModelBuilder3D.getInstance().getFfTypes()) 94 """A list of supported forcefields""" 95 96 _isofact = cdk.config.IsotopeFactory.getInstance(cdk.ChemObject().getBuilder()) 97 98 _bondtypes = {1: cdk.CDKConstants.BONDORDER_SINGLE, 99 2: cdk.CDKConstants.BONDORDER_DOUBLE, 100 3: cdk.CDKConstants.BONDORDER_TRIPLE} 101 _revbondtypes = dict([(_y,_x) for (_x,_y) in _bondtypes.iteritems()])
102 103 -def _intvalue(integer):
104 """Paper over some differences between JPype and Jython""" 105 # Jython automagically converts Integer to ints 106 if type(integer) != type(42): # Is it a Python int? 107 integer = integer.intValue() 108 return integer
109
110 -def readfile(format, filename):
111 """Iterate over the molecules in a file. 112 113 Required parameters: 114 format - see the informats variable for a list of available 115 input formats 116 filename 117 118 You can access the first molecule in a file using the next() method 119 of the iterator: 120 mol = readfile("smi", "myfile.smi").next() 121 122 You can make a list of the molecules in a file using: 123 mols = list(readfile("smi", "myfile.smi")) 124 125 You can iterate over the molecules in a file as shown in the 126 following code snippet: 127 >>> atomtotal = 0 128 >>> for mol in readfile("sdf", "head.sdf"): 129 ... atomtotal += len(mol.atoms) 130 ... 131 >>> print atomtotal 132 43 133 """ 134 format = format.lower() 135 if not os.path.isfile(filename): 136 raise IOError, "No such file: '%s'" % filename 137 builder = cdk.DefaultChemObjectBuilder.getInstance() 138 if format=="sdf": 139 return (Molecule(mol) for mol in cdk.io.iterator.IteratingMDLReader( 140 java.io.FileInputStream(java.io.File(filename)), 141 builder) 142 ) 143 elif format=="smi": 144 return (Molecule(mol) for mol in cdk.io.iterator.IteratingSmilesReader( 145 java.io.FileInputStream(java.io.File(filename)), 146 builder 147 )) 148 elif format == 'inchi': 149 inputfile = open(filename, 'rb') 150 return (readstring('inchi', line.rstrip()) for line in inputfile) 151 elif format in informats: 152 reader = _informats[format](java.io.FileInputStream(java.io.File(filename))) 153 chemfile = reader.read(cdk.ChemFile()) 154 manip = cdk.tools.manipulator.ChemFileManipulator 155 return iter(Molecule(manip.getAllAtomContainers(chemfile)[0]),) 156 else: 157 raise ValueError,"%s is not a recognised CDK format" % format
158
159 -def readstring(format, string):
160 """Read in a molecule from a string. 161 162 Required parameters: 163 format - see the informats variable for a list of available 164 input formats 165 string 166 167 Example: 168 >>> input = "C1=CC=CS1" 169 >>> mymol = readstring("smi", input) 170 >>> len(mymol.atoms) 171 5 172 """ 173 format = format.lower() 174 if format=="smi": 175 sp = cdk.smiles.SmilesParser(cdk.DefaultChemObjectBuilder.getInstance()) 176 try: 177 ans = sp.parseSmiles(string) 178 except InvalidSmilesException, ex: 179 if sys.platform[:4] != "java": 180 #Jpype exception 181 ex = ex.message() 182 raise IOError, ex 183 return Molecule(ans) 184 elif format == 'inchi': 185 factory = cdk.inchi.InChIGeneratorFactory.getInstance() 186 intostruct = factory.getInChIToStructure(string,cdk.DefaultChemObjectBuilder.getInstance()) 187 return Molecule(intostruct.getAtomContainer()) 188 elif format in informats: 189 reader = _informats[format](java.io.StringReader(string)) 190 chemfile = reader.read(cdk.ChemFile()) 191 manip = cdk.tools.manipulator.ChemFileManipulator 192 return Molecule(manip.getAllAtomContainers(chemfile)[0]) 193 else: 194 raise ValueError,"%s is not a recognised CDK format" % format
195
196 -class Outputfile(object):
197 """Represent a file to which *output* is to be sent. 198 199 Required parameters: 200 format - see the outformats variable for a list of available 201 output formats 202 filename 203 204 Optional parameters: 205 overwite -- if the output file already exists, should it 206 be overwritten? (default is False) 207 208 Methods: 209 write(molecule) 210 close() 211 """
212 - def __init__(self, format, filename, overwrite=False):
213 self.format = format.lower() 214 self.filename = filename 215 if not overwrite and os.path.isfile(self.filename): 216 raise IOError, "%s already exists. Use 'overwrite=True' to overwrite it." % self.filename 217 if not format in outformats: 218 raise ValueError,"%s is not a recognised CDK format" % format 219 if self.format in ('smi','inchi', 'inchikey'): 220 self._outputfile = open(self.filename, "w") 221 else: 222 self._writer = java.io.FileWriter(java.io.File(self.filename)) 223 self._molwriter = _outformats[self.format](self._writer) 224 self.total = 0 # The total number of molecules written to the file
225
226 - def write(self, molecule):
227 """Write a molecule to the output file. 228 229 Required parameters: 230 molecule 231 """ 232 if not self.filename: 233 raise IOError, "Outputfile instance is closed." 234 if self.format in ('smi','inchi', 'inchikey'): 235 self._outputfile.write("%s\n" % molecule.write(format)) 236 else: 237 self._molwriter.write(molecule.Molecule) 238 self.total += 1
239
240 - def close(self):
241 """Close the Outputfile to further writing.""" 242 self.filename = None 243 if self.format in ('smi','inchi', 'inchikey'): 244 self._outputfile.close() 245 else: 246 self._molwriter.close() 247 self._writer.close()
248
249 -class Molecule(object):
250 """Represent a cdkjpype Molecule. 251 252 Required parameters: 253 Molecule -- a CDK Molecule or any type of cinfony Molecule 254 255 Attributes: 256 atoms, data, exactmass, formula, molwt, title 257 258 Methods: 259 addh(), calcfp(), calcdesc(), draw(), removeh(), write() 260 261 The underlying CDK Molecule can be accessed using the attribute: 262 Molecule 263 """ 264 _cinfony = True 265
266 - def __init__(self, Molecule):
267 268 if hasattr(Molecule, "_cinfony"): 269 a, b = Molecule._exchange 270 if a == 0: 271 mol = readstring("smi", b) 272 else: 273 mol = readstring("sdf", b) 274 Molecule = mol.Molecule 275 276 self.Molecule = Molecule
277 278 @property
279 - def atoms(self): return [Atom(self.Molecule.getAtom(i)) for i in range(self.Molecule.getAtomCount())]
280 @property
281 - def data(self): return MoleculeData(self.Molecule)
282 @property
283 - def formula(self):
284 manip = cdk.tools.manipulator.MolecularFormulaManipulator 285 mf = manip.getMolecularFormula(self.Molecule) 286 return manip.getString(mf) # GetHillString
287 @property
288 - def exactmass(self):
289 clone = Molecule(self.Molecule.clone()) 290 clone.addh() 291 manip = cdk.tools.manipulator.MolecularFormulaManipulator 292 mf = manip.getMolecularFormula(clone.Molecule) 293 return manip.getMajorIsotopeMass(mf)
294 @property
295 - def molwt(self):
296 clone = Molecule(self.Molecule.clone()) 297 clone.addh() 298 atommanip = cdk.tools.manipulator.AtomContainerManipulator 299 return atommanip.getNaturalExactMass(clone.Molecule)
300 - def _gettitle(self): return self.Molecule.getProperty(cdk.CDKConstants.TITLE)
301 - def _settitle(self, val): self.Molecule.setProperty(cdk.CDKConstants.TITLE, val)
302 title = property(_gettitle, _settitle) 303 @property
304 - def _exchange(self):
305 gt = cdk.geometry.GeometryTools 306 if gt.has2DCoordinates(self.Molecule) or gt.has3DCoordinates(self.Molecule): 307 return (1, self.write("mol")) 308 else: 309 return (0, self.write("smi"))
310
311 - def __iter__(self):
312 """Iterate over the Atoms of the Molecule. 313 314 This allows constructions such as the following: 315 for atom in mymol: 316 print atom 317 """ 318 return iter(self.atoms)
319
320 - def __str__(self):
321 return self.write()
322
323 - def addh(self):
324 """Add hydrogens.""" 325 atommanip = cdk.tools.manipulator.AtomContainerManipulator 326 atommanip.convertImplicitToExplicitHydrogens(self.Molecule)
327
328 - def removeh(self):
329 """Remove hydrogens.""" 330 atommanip = cdk.tools.manipulator.AtomContainerManipulator 331 self.Molecule = atommanip.removeHydrogens(self.Molecule)
332
333 - def write(self, format="smi", filename=None, overwrite=False):
334 """Write the molecule to a file or return a string. 335 336 Optional parameters: 337 format -- see the informats variable for a list of available 338 output formats (default is "smi") 339 filename -- default is None 340 overwite -- if the output file already exists, should it 341 be overwritten? (default is False) 342 343 If a filename is specified, the result is written to a file. 344 Otherwise, a string is returned containing the result. 345 346 To write multiple molecules to the same file you should use 347 the Outputfile class. 348 """ 349 format = format.lower() 350 if format not in outformats: 351 raise ValueError,"%s is not a recognised CDK format" % format 352 353 if filename is not None and not overwrite and os.path.isfile(filename): 354 raise IOError, "%s already exists. Use 'overwrite=True' to overwrite it." % filename 355 356 if format == "smi": 357 sg = cdk.smiles.SmilesGenerator() 358 # Set flag or else c1ccccc1 will be written as C1CCCCC1 359 sg.setUseAromaticityFlag(True) 360 smiles = sg.createSMILES(self.Molecule) 361 if filename: 362 output = open(filename, "w") 363 print >> output, smiles 364 output.close() 365 return 366 else: 367 return smiles 368 elif format in ('inchi', 'inchikey'): 369 factory = cdk.inchi.InChIGeneratorFactory.getInstance() 370 gen = factory.getInChIGenerator(self.Molecule) 371 if format == 'inchi': 372 return gen.getInchi() 373 else: 374 return gen.getInchiKey() 375 376 else: 377 if filename is None: 378 writer = java.io.StringWriter() 379 else: 380 writer = java.io.FileWriter(java.io.File(filename)) 381 molwriter = _outformats[format](writer) 382 molwriter.write(self.Molecule) 383 molwriter.close() 384 writer.close() 385 if filename == None: 386 return str(writer.toString())
387
388 - def calcfp(self, fp="daylight"):
389 """Calculate a molecular fingerprint. 390 391 Optional parameters: 392 fptype -- the fingerprint type (default is "daylight"). See the 393 fps variable for a list of of available fingerprint 394 types. 395 """ 396 fp = fp.lower() 397 if fp in _fingerprinters: 398 fingerprinter = _fingerprinters[fp]() 399 else: 400 raise ValueError, "%s is not a recognised CDK Fingerprint type" % fp 401 return Fingerprint(fingerprinter.getFingerprint(self.Molecule))
402
403 - def calcdesc(self, descnames=[]):
404 """Calculate descriptor values. 405 406 Optional parameter: 407 descnames -- a list of names of descriptors 408 409 If descnames is not specified, all available descriptors are 410 calculated. See the descs variable for a list of available 411 descriptors. 412 """ 413 if not descnames: 414 descnames = descs 415 ans = {} 416 for descname in descnames: 417 try: 418 desc = _descdict[descname] 419 except KeyError: 420 raise ValueError, "%s is not a recognised CDK descriptor type" % descname 421 try: 422 value = desc.calculate(self.Molecule).getValue() 423 if hasattr(value, "get"): # Instead of array 424 for i in range(value.length()): 425 ans[descname + ".%d" % i] = value.get(i) 426 elif hasattr(value, "doubleValue"): 427 ans[descname] = value.doubleValue() 428 else: 429 ans[descname] = _intvalue(value) 430 except CDKException, ex: 431 # Can happen if molecule has no 3D coordinates 432 pass 433 except NullPointerException, ex: 434 # Happens with moment of inertia descriptor 435 pass 436 return ans
437
438 - def draw(self, show=True, filename=None, update=False, 439 usecoords=False):
440 """Create a 2D depiction of the molecule. 441 442 There is no option to display or write an image file of 443 the depiction. For this, you should use the CDK from 444 Jython or else the depiction engine of one of the other 445 toolkits. 446 447 When using jpype, arguments will be ignored: calling this function is 448 equivalent to calling the draw() method of one of the other Cinfony 449 modules with parameters: 450 show=False, filename=None, update=True, usecoords=False 451 """ 452 if sys.platform[:4] != "java": 453 show=False 454 filename=None 455 update=True 456 usecoords=False 457 458 mol = Molecule(self.Molecule.clone()) 459 cdk.aromaticity.CDKHueckelAromaticityDetector.detectAromaticity(mol.Molecule) 460 461 if not usecoords: 462 # Do the SDG 463 sdg = cdk.layout.StructureDiagramGenerator() 464 sdg.setMolecule(mol.Molecule) 465 sdg.generateCoordinates() 466 mol = Molecule(sdg.getMolecule()) 467 if update: 468 for atom, newatom in zip(self.atoms, mol.atoms): 469 coords = newatom.Atom.getPoint2d() 470 atom.Atom.setPoint3d(javax.vecmath.Point3d( 471 coords.x, coords.y, 0.0)) 472 else: 473 if self.atoms[0].Atom.getPoint2d() is None: 474 # Use the 3D coords to set the 2D coords 475 for atom, newatom in zip(self.atoms, mol.atoms): 476 coords = atom.Atom.getPoint3d() 477 newatom.Atom.setPoint2d(javax.vecmath.Point2d( 478 coords.x, coords.y)) 479 480 if sys.platform[:4] != "java": 481 #We are done in jpype 482 return 483 mol.removeh() 484 canvas = _Canvas(mol.Molecule) 485 486 if filename: 487 canvas.writetofile(filename) 488 if show: 489 canvas.popup() 490 else: 491 canvas.frame.dispose()
492 493 if sys.platform[:4] == "java":
494 - class _Canvas(javax.swing.JPanel):
495 """ 496 Class used by Molecule.draw() in jython 497 """
498 - def __init__(self, mol):
499 self.mol = mol 500 501 self.frame = javax.swing.JFrame() 502 generators = [] 503 generators.append(cdk.renderer.generators.BasicSceneGenerator()) 504 generators.append(cdk.renderer.generators.BasicBondGenerator()) 505 generators.append(cdk.renderer.generators.RingGenerator()) 506 generators.append(cdk.renderer.generators.BasicAtomGenerator()) 507 self.renderer = cdk.renderer.AtomContainerRenderer(generators, 508 cdk.renderer.font.AWTFontManager()) 509 510 drawArea = java.awt.Rectangle(300, 300) 511 self.renderer.setup(mol, drawArea) 512 image = java.awt.image.BufferedImage(300, 300, 513 java.awt.image.BufferedImage.TYPE_INT_RGB) 514 screenSize = java.awt.Dimension(300, 300) 515 self.setPreferredSize(screenSize) 516 self.setBackground(java.awt.Color.WHITE) 517 self.frame.getContentPane().add(self) 518 self.frame.pack() 519 self.frame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE)
520
521 - def paint(self, g):
522 javax.swing.JPanel.paint(self, g) 523 self.renderer.paint(self.mol, cdk.renderer.visitor.AWTDrawVisitor(g), 524 java.awt.Rectangle(300, 300), True);
525
526 - def popup(self):
527 self.frame.visible = True
528
529 - def writetofile(self, filename):
530 img = self.createImage(300, 300) 531 g2 = img.getGraphics() # Graphics2D 532 g2.setColor(java.awt.Color.WHITE) 533 g2.fillRect(0, 0, 300, 300) 534 self.paint(g2) 535 javax.imageio.ImageIO.write(img, "png", java.io.File(filename))
536
537 -class Fingerprint(object):
538 """A Molecular Fingerprint. 539 540 Required parameters: 541 fingerprint -- a vector calculated by one of the fingerprint methods 542 543 Attributes: 544 fp -- the underlying fingerprint object 545 bits -- a list of bits set in the Fingerprint 546 547 Methods: 548 The "|" operator can be used to calculate the Tanimoto coeff. For example, 549 given two Fingerprints 'a', and 'b', the Tanimoto coefficient is given by: 550 tanimoto = a | b 551 """
552 - def __init__(self, fingerprint):
553 self.fp = fingerprint
554 - def __or__(self, other):
555 return cdk.similarity.Tanimoto.calculate(self.fp, other.fp)
556 - def __getattr__(self, attr):
557 if attr == "bits": 558 # Create a bits attribute on-the-fly 559 bits = [] 560 idx = self.fp.nextSetBit(0) 561 while idx >= 0: 562 bits.append(idx) 563 idx = self.fp.nextSetBit(idx + 1) 564 return bits 565 else: 566 raise AttributeError, "Fingerprint has no attribute %s" % attr
567 - def __str__(self):
568 return self.fp.toString()
569
570 -class Atom(object):
571 """Represent a cdkjpype Atom. 572 573 Required parameters: 574 Atom -- a CDK Atom 575 576 Attributes: 577 atomicnum, coords, formalcharge 578 579 The original CDK Atom can be accessed using the attribute: 580 Atom 581 """ 582
583 - def __init__(self, Atom):
584 self.Atom = Atom
585 586 @property
587 - def atomicnum(self):
588 _isofact.configure(self.Atom) 589 return _intvalue(self.Atom.getAtomicNumber())
590 @property
591 - def coords(self):
592 coords = self.Atom.point3d 593 if not coords: 594 coords = self.Atom.point2d 595 if not coords: 596 return (0., 0., 0.) 597 else: 598 return (coords.x, coords.y, coords.z)
599 @property
600 - def formalcharge(self):
601 _isofact.configure(self.Atom) 602 return _intvalue(self.Atom.getFormalCharge())
603
604 - def __str__(self):
605 c = self.coords 606 return "Atom: %d (%.2f %.2f %.2f)" % (self.atomicnum, c[0], c[1], c[2])
607
608 -class Smarts(object):
609 """A Smarts Pattern Matcher 610 611 Required parameters: 612 smartspattern 613 614 Methods: 615 findall() 616 617 Example: 618 >>> mol = readstring("smi","CCN(CC)CC") # triethylamine 619 >>> smarts = Smarts("[#6][#6]") # Matches an ethyl group 620 >>> print smarts.findall(mol) 621 [(1, 2), (4, 5), (6, 7)] 622 """
623 - def __init__(self, smartspattern):
624 """Initialise with a SMARTS pattern.""" 625 self.smarts = cdk.smiles.smarts.SMARTSQueryTool(smartspattern)
626
627 - def findall(self, molecule):
628 """Find all matches of the SMARTS pattern to a particular molecule. 629 630 Required parameters: 631 molecule 632 """ 633 match = self.smarts.matches(molecule.Molecule) 634 return list(self.smarts.getUniqueMatchingAtoms())
635
636 -class MoleculeData(object):
637 """Store molecule data in a dictionary-type object 638 639 Required parameters: 640 Molecule -- a CDK Molecule 641 642 Methods and accessor methods are like those of a dictionary except 643 that the data is retrieved on-the-fly from the underlying Molecule. 644 645 Example: 646 >>> mol = readfile("sdf", 'head.sdf').next() 647 >>> data = mol.data 648 >>> print data 649 {'Comment': 'CORINA 2.61 0041 25.10.2001', 'NSC': '1'} 650 >>> print len(data), data.keys(), data.has_key("NSC") 651 2 ['Comment', 'NSC'] True 652 >>> print data['Comment'] 653 CORINA 2.61 0041 25.10.2001 654 >>> data['Comment'] = 'This is a new comment' 655 >>> for k,v in data.iteritems(): 656 ... print k, "-->", v 657 Comment --> This is a new comment 658 NSC --> 1 659 >>> del data['NSC'] 660 >>> print len(data), data.keys(), data.has_key("NSC") 661 1 ['Comment'] False 662 """
663 - def __init__(self, Molecule):
664 self._mol = Molecule
665 - def _data(self):
666 return self._mol.getProperties()
667 - def _testforkey(self, key):
668 if not key in self: 669 raise KeyError, "'%s'" % key
670 - def keys(self):
671 return list(self._data().keySet())
672 - def values(self):
673 return list(self._data().values())
674 - def items(self):
675 return [(k, self[k]) for k in self._data().keySet()]
676 - def __iter__(self):
677 return iter(self.keys())
678 - def iteritems(self):
679 return iter(self.items())
680 - def __len__(self):
681 return len(self._data())
682 - def __contains__(self, key):
683 return key in self._data()
684 - def __delitem__(self, key):
685 self._testforkey(key) 686 self._mol.removeProperty(key)
687 - def clear(self):
688 for key in self: 689 del self[key]
690 - def has_key(self, key):
691 return key in self
692 - def update(self, dictionary):
693 for k, v in dictionary.iteritems(): 694 self[k] = v
695 - def __getitem__(self, key):
696 self._testforkey(key) 697 return self._mol.getProperty(key)
698 - def __setitem__(self, key, value):
699 self._mol.setProperty(key, str(value))
700 - def __repr__(self):
701 return dict(self.iteritems()).__repr__()
702 703 if __name__=="__main__": #pragma: no cover 704 mol = readstring("smi", "CC(=O)Cl") 705 mol.title = "Noel" 706 mol.draw() 707 708 for mol in readfile("sdf", "head.sdf"): 709 pass 710