Package rdkit :: Package Chem :: Module Recap
[hide private]
[frames] | no frames]

Source Code for Module rdkit.Chem.Recap

  1  #  $Id$ 
  2  # 
  3  #  Copyright (c) 2007, Novartis Institutes for BioMedical Research Inc. 
  4  #  All rights reserved. 
  5  #  
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions are 
  8  # met:  
  9  # 
 10  #     * Redistributions of source code must retain the above copyright  
 11  #       notice, this list of conditions and the following disclaimer. 
 12  #     * Redistributions in binary form must reproduce the above 
 13  #       copyright notice, this list of conditions and the following  
 14  #       disclaimer in the documentation and/or other materials provided  
 15  #       with the distribution. 
 16  #     * Neither the name of Novartis Institutes for BioMedical Research Inc.  
 17  #       nor the names of its contributors may be used to endorse or promote  
 18  #       products derived from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 23  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 24  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 25  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 26  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 27  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 28  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 29  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 30  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 31  # 
 32  """ Implementation of the RECAP algorithm from Lewell et al. JCICS *38* 511-522 (1998) 
 33   
 34  The published algorithm is implemented more or less without 
 35  modification. The results are returned as a hierarchy of nodes instead 
 36  of just as a set of fragments. The hope is that this will allow a bit 
 37  more flexibility in working with the results. 
 38   
 39  For example: 
 40  >>> m = Chem.MolFromSmiles('C1CC1Oc1ccccc1-c1ncc(OC)cc1') 
 41  >>> res = Recap.RecapDecompose(m) 
 42  >>> res 
 43  <Chem.Recap.RecapHierarchyNode object at 0x00CDB5D0> 
 44  >>> res.children.keys() 
 45  ['[*]C1CC1', '[*]c1ccccc1-c1ncc(OC)cc1', '[*]c1ccc(OC)cn1', '[*]c1ccccc1OC1CC1'] 
 46  >>> res.GetAllChildren().keys() 
 47  ['[*]c1ccccc1[*]', '[*]C1CC1', '[*]c1ccccc1-c1ncc(OC)cc1', '[*]c1ccc(OC)cn1', '[*]c1ccccc1OC1CC1'] 
 48   
 49   
 50  To get the standard set of RECAP results, use GetLeaves(): 
 51  >>> leaves=res.GetLeaves() 
 52  >>> leaves.keys() 
 53  ['[*]c1ccccc1[*]', '[*]c1ccc(OC)cn1', '[*]C1CC1'] 
 54  >>> leaf = leaves['[*]C1CC1'] 
 55  >>> leaf.mol 
 56  <Chem.rdchem.Mol object at 0x00CBE0F0> 
 57   
 58   
 59  """ 
 60  import sys 
 61  import weakref 
 62  from rdkit import Chem 
 63  from rdkit.Chem import rdChemReactions as Reactions 
 64  from rdkit.six import iterkeys, iteritems, next 
 65   
 66  # These are the definitions that will be applied to fragment molecules: 
 67  reactionDefs = ( 
 68    "[#7;+0;D2,D3:1]!@C(!@=O)!@[#7;+0;D2,D3:2]>>[*][#7:1].[#7:2][*]", # urea 
 69   
 70    "[C;!$(C([#7])[#7]):1](=!@[O:2])!@[#7;+0;!D1:3]>>[*][C:1]=[O:2].[*][#7:3]", # amide 
 71   
 72    "[C:1](=!@[O:2])!@[O;+0:3]>>[*][C:1]=[O:2].[O:3][*]", # ester 
 73   
 74    "[N;!D1;+0;!$(N-C=[#7,#8,#15,#16])](-!@[*:1])-!@[*:2]>>[*][*:1].[*:2][*]", # amines 
 75    #"[N;!D1](!@[*:1])!@[*:2]>>[*][*:1].[*:2][*]", # amines 
 76   
 77    # again: what about aromatics? 
 78    "[#7;R;D3;+0:1]-!@[*:2]>>[*][#7:1].[*:2][*]", # cyclic amines 
 79   
 80    "[#6:1]-!@[O;+0]-!@[#6:2]>>[#6:1][*].[*][#6:2]", # ether 
 81   
 82    "[C:1]=!@[C:2]>>[C:1][*].[*][C:2]", # olefin 
 83   
 84    "[n;+0:1]-!@[C:2]>>[n:1][*].[C:2][*]", # aromatic nitrogen - aliphatic carbon 
 85   
 86    "[O:3]=[C:4]-@[N;+0:1]-!@[C:2]>>[O:3]=[C:4]-[N:1][*].[C:2][*]", # lactam nitrogen - aliphatic carbon 
 87   
 88    "[c:1]-!@[c:2]>>[c:1][*].[*][c:2]", # aromatic carbon - aromatic carbon 
 89   
 90    "[n;+0:1]-!@[c:2]>>[n:1][*].[*][c:2]", # aromatic nitrogen - aromatic carbon *NOTE* this is not part of the standard recap set. 
 91   
 92    "[#7;+0;D2,D3:1]-!@[S:2](=[O:3])=[O:4]>>[#7:1][*].[*][S:2](=[O:3])=[O:4]", # sulphonamide 
 93    ) 
 94   
 95  reactions = tuple([Reactions.ReactionFromSmarts(x) for x in reactionDefs]) 
 96   
 97   
98 -class RecapHierarchyNode(object):
99 """ This class is used to hold the Recap hiearchy 100 """ 101 mol=None 102 children=None 103 parents=None 104 smiles = None
105 - def __init__(self,mol):
106 self.mol=mol 107 self.children = {} 108 self.parents = {}
109
110 - def GetAllChildren(self):
111 " returns a dictionary, keyed by SMILES, of children " 112 res = {} 113 for smi,child in iteritems(self.children): 114 res[smi] = child 115 child._gacRecurse(res,terminalOnly=False) 116 return res
117
118 - def GetLeaves(self):
119 " returns a dictionary, keyed by SMILES, of leaf (terminal) nodes " 120 res = {} 121 for smi,child in iteritems(self.children): 122 if not len(child.children): 123 res[smi] = child 124 else: 125 child._gacRecurse(res,terminalOnly=True) 126 return res
127
128 - def getUltimateParents(self):
129 """ returns all the nodes in the hierarchy tree that contain this 130 node as a child 131 """ 132 if not self.parents: 133 res = [self] 134 else: 135 res = [] 136 for p in self.parents.values(): 137 for uP in p.getUltimateParents(): 138 if uP not in res: 139 res.append(uP) 140 return res
141
142 - def _gacRecurse(self,res,terminalOnly=False):
143 for smi,child in iteritems(self.children): 144 if not terminalOnly or not len(child.children): 145 res[smi] = child 146 child._gacRecurse(res,terminalOnly=terminalOnly)
147
148 - def __del__(self):
149 self.children={} 150 self.parent={} 151 self.mol=None
152 153
154 -def RecapDecompose(mol,allNodes=None,minFragmentSize=0,onlyUseReactions=None):
155 """ returns the recap decomposition for a molecule """ 156 mSmi = Chem.MolToSmiles(mol,1) 157 158 if allNodes is None: 159 allNodes={} 160 if mSmi in allNodes: 161 return allNodes[mSmi] 162 163 res = RecapHierarchyNode(mol) 164 res.smiles =mSmi 165 activePool={mSmi:res} 166 allNodes[mSmi]=res 167 while activePool: 168 nSmi = next(iterkeys(activePool)) 169 node = activePool.pop(nSmi) 170 if not node.mol: continue 171 for rxnIdx,reaction in enumerate(reactions): 172 if onlyUseReactions and rxnIdx not in onlyUseReactions: 173 continue 174 #print ' .',nSmi 175 #print ' !!!!',rxnIdx,nSmi,reactionDefs[rxnIdx] 176 ps = reaction.RunReactants((node.mol,)) 177 #print ' ',len(ps) 178 if ps: 179 for prodSeq in ps: 180 seqOk=True 181 # we want to disqualify small fragments, so sort the product sequence by size 182 # and then look for "forbidden" fragments 183 tSeq = [(prod.GetNumAtoms(onlyExplicit=True),idx) for idx,prod in enumerate(prodSeq)] 184 tSeq.sort() 185 ts=[(x,prodSeq[y]) for x,y in tSeq] 186 prodSeq=ts 187 for nats,prod in prodSeq: 188 try: 189 Chem.SanitizeMol(prod) 190 except Exception: 191 continue 192 pSmi = Chem.MolToSmiles(prod,1) 193 if minFragmentSize>0: 194 nDummies = pSmi.count('*') 195 if nats-nDummies<minFragmentSize: 196 seqOk=False 197 break 198 # don't forget after replacing dummy atoms to remove any empty 199 # branches: 200 elif pSmi.replace('[*]','').replace('()','') in ('','C','CC','CCC'): 201 seqOk=False 202 break 203 prod.pSmi = pSmi 204 if seqOk: 205 for nats,prod in prodSeq: 206 pSmi = prod.pSmi 207 #print '\t',nats,pSmi 208 if not pSmi in allNodes: 209 pNode = RecapHierarchyNode(prod) 210 pNode.smiles=pSmi 211 pNode.parents[nSmi]=weakref.proxy(node) 212 node.children[pSmi]=pNode 213 activePool[pSmi] = pNode 214 allNodes[pSmi]=pNode 215 else: 216 pNode=allNodes[pSmi] 217 pNode.parents[nSmi]=weakref.proxy(node) 218 node.children[pSmi]=pNode 219 #print ' >>an:',allNodes.keys() 220 return res
221 222 223 # ------- ------- ------- ------- ------- ------- ------- ------- 224 # Begin testing code 225 if __name__=='__main__': 226 import unittest
227 - class TestCase(unittest.TestCase):
228 - def test1(self):
229 m = Chem.MolFromSmiles('C1CC1Oc1ccccc1-c1ncc(OC)cc1') 230 res = RecapDecompose(m) 231 self.assertTrue(res) 232 self.assertTrue(len(res.children.keys())==4) 233 self.assertTrue(len(res.GetAllChildren().keys())==5) 234 self.assertTrue(len(res.GetLeaves().keys())==3)
235 - def test2(self):
236 m = Chem.MolFromSmiles('CCCOCCC') 237 res = RecapDecompose(m) 238 self.assertTrue(res) 239 self.assertTrue(res.children=={})
240 - def test3(self):
241 allNodes={} 242 m = Chem.MolFromSmiles('c1ccccc1-c1ncccc1') 243 res = RecapDecompose(m,allNodes=allNodes) 244 self.assertTrue(res) 245 self.assertTrue(len(res.children.keys())==2) 246 self.assertTrue(len(allNodes.keys())==3) 247 248 m = Chem.MolFromSmiles('COc1ccccc1-c1ncccc1') 249 res = RecapDecompose(m,allNodes=allNodes) 250 self.assertTrue(res) 251 self.assertTrue(len(res.children.keys())==2) 252 # we get two more nodes from that: 253 self.assertTrue(len(allNodes.keys())==5) 254 self.assertTrue('[*]c1ccccc1OC' in allNodes) 255 self.assertTrue('[*]c1ccccc1' in allNodes) 256 257 m = Chem.MolFromSmiles('C1CC1Oc1ccccc1-c1ncccc1') 258 res = RecapDecompose(m,allNodes=allNodes) 259 self.assertTrue(res) 260 self.assertTrue(len(res.children.keys())==4) 261 self.assertTrue(len(allNodes.keys())==10)
262
263 - def testSFNetIssue1801871(self):
264 m = Chem.MolFromSmiles('c1ccccc1OC(Oc1ccccc1)Oc1ccccc1') 265 res = RecapDecompose(m) 266 self.assertTrue(res) 267 self.assertTrue(len(res.GetLeaves())==2) 268 ks = res.GetLeaves().keys() 269 self.assertFalse('[*]C([*])[*]' in ks) 270 self.assertTrue('[*]c1ccccc1' in ks) 271 self.assertTrue('[*]C([*])Oc1ccccc1' in ks)
272
273 - def testSFNetIssue1804418(self):
274 m = Chem.MolFromSmiles('C1CCCCN1CCCC') 275 res = RecapDecompose(m) 276 self.assertTrue(res) 277 self.assertTrue(len(res.GetLeaves())==2) 278 ks = res.GetLeaves().keys() 279 self.assertTrue('[*]N1CCCCC1' in ks) 280 self.assertTrue('[*]CCCC' in ks)
281
282 - def testMinFragmentSize(self):
283 m = Chem.MolFromSmiles('CCCOCCC') 284 res = RecapDecompose(m) 285 self.assertTrue(res) 286 self.assertTrue(res.children=={}) 287 res = RecapDecompose(m,minFragmentSize=3) 288 self.assertTrue(res) 289 self.assertTrue(len(res.GetLeaves())==1) 290 ks = res.GetLeaves().keys() 291 self.assertTrue('[*]CCC' in ks) 292 293 m = Chem.MolFromSmiles('CCCOCC') 294 res = RecapDecompose(m,minFragmentSize=3) 295 self.assertTrue(res) 296 self.assertTrue(res.children=={}) 297 298 m = Chem.MolFromSmiles('CCCOCCOC') 299 res = RecapDecompose(m,minFragmentSize=2) 300 self.assertTrue(res) 301 self.assertTrue(len(res.GetLeaves())==2) 302 ks = res.GetLeaves().keys() 303 self.assertTrue('[*]CCC' in ks) 304 ks = res.GetLeaves().keys() 305 self.assertTrue('[*]CCOC' in ks)
306
307 - def testAmideRxn(self):
308 m = Chem.MolFromSmiles('C1CC1C(=O)NC1OC1') 309 res = RecapDecompose(m,onlyUseReactions=[1]) 310 self.assertTrue(res) 311 self.assertTrue(len(res.GetLeaves())==2) 312 ks = res.GetLeaves().keys() 313 self.assertTrue('[*]C(=O)C1CC1' in ks) 314 self.assertTrue('[*]NC1CO1' in ks) 315 316 m = Chem.MolFromSmiles('C1CC1C(=O)N(C)C1OC1') 317 res = RecapDecompose(m,onlyUseReactions=[1]) 318 self.assertTrue(res) 319 self.assertTrue(len(res.GetLeaves())==2) 320 ks = res.GetLeaves().keys() 321 self.assertTrue('[*]C(=O)C1CC1' in ks) 322 self.assertTrue('[*]N(C)C1CO1' in ks) 323 324 m = Chem.MolFromSmiles('C1CC1C(=O)n1cccc1') 325 res = RecapDecompose(m,onlyUseReactions=[1]) 326 self.assertTrue(res) 327 self.assertTrue(len(res.GetLeaves())==2) 328 ks = res.GetLeaves().keys() 329 self.assertTrue('[*]C(=O)C1CC1' in ks) 330 self.assertTrue('[*]n1cccc1' in ks) 331 332 m = Chem.MolFromSmiles('C1CC1C(=O)CC1OC1') 333 res = RecapDecompose(m,onlyUseReactions=[1]) 334 self.assertTrue(res) 335 self.assertTrue(len(res.GetLeaves())==0) 336 337 m = Chem.MolFromSmiles('C1CCC(=O)NC1') 338 res = RecapDecompose(m,onlyUseReactions=[1]) 339 self.assertTrue(res) 340 self.assertTrue(len(res.GetLeaves())==0) 341 342 m = Chem.MolFromSmiles('CC(=O)NC') 343 res = RecapDecompose(m,onlyUseReactions=[1]) 344 self.assertTrue(res) 345 self.assertTrue(len(res.GetLeaves())==2) 346 ks = res.GetLeaves().keys() 347 348 m = Chem.MolFromSmiles('CC(=O)N') 349 res = RecapDecompose(m,onlyUseReactions=[1]) 350 self.assertTrue(res) 351 self.assertTrue(len(res.GetLeaves())==0) 352 353 m = Chem.MolFromSmiles('C(=O)NCCNC(=O)CC') 354 res = RecapDecompose(m,onlyUseReactions=[1]) 355 self.assertTrue(res) 356 self.assertTrue(len(res.children)==4) 357 self.assertTrue(len(res.GetLeaves())==3)
358
359 - def testEsterRxn(self):
360 m = Chem.MolFromSmiles('C1CC1C(=O)OC1OC1') 361 res = RecapDecompose(m,onlyUseReactions=[2]) 362 self.assertTrue(res) 363 self.assertTrue(len(res.GetLeaves())==2) 364 ks = res.GetLeaves().keys() 365 self.assertTrue('[*]C(=O)C1CC1' in ks) 366 self.assertTrue('[*]OC1CO1' in ks) 367 368 m = Chem.MolFromSmiles('C1CC1C(=O)CC1OC1') 369 res = RecapDecompose(m,onlyUseReactions=[2]) 370 self.assertTrue(res) 371 self.assertTrue(len(res.GetLeaves())==0) 372 373 m = Chem.MolFromSmiles('C1CCC(=O)OC1') 374 res = RecapDecompose(m,onlyUseReactions=[2]) 375 self.assertTrue(res) 376 self.assertTrue(len(res.GetLeaves())==0)
377
378 - def testUreaRxn(self):
379 m = Chem.MolFromSmiles('C1CC1NC(=O)NC1OC1') 380 res = RecapDecompose(m,onlyUseReactions=[0]) 381 self.assertTrue(res) 382 self.assertTrue(len(res.GetLeaves())==2) 383 ks = res.GetLeaves().keys() 384 self.assertTrue('[*]NC1CC1' in ks) 385 self.assertTrue('[*]NC1CO1' in ks) 386 387 m = Chem.MolFromSmiles('C1CC1NC(=O)N(C)C1OC1') 388 res = RecapDecompose(m,onlyUseReactions=[0]) 389 self.assertTrue(res) 390 self.assertTrue(len(res.GetLeaves())==2) 391 ks = res.GetLeaves().keys() 392 self.assertTrue('[*]NC1CC1' in ks) 393 self.assertTrue('[*]N(C)C1CO1' in ks) 394 395 m = Chem.MolFromSmiles('C1CCNC(=O)NC1C') 396 res = RecapDecompose(m,onlyUseReactions=[0]) 397 self.assertTrue(res) 398 self.assertTrue(len(res.GetLeaves())==0) 399 400 m = Chem.MolFromSmiles('c1cccn1C(=O)NC1OC1') 401 res = RecapDecompose(m,onlyUseReactions=[0]) 402 self.assertTrue(res) 403 self.assertTrue(len(res.GetLeaves())==2) 404 ks = res.GetLeaves().keys() 405 self.assertTrue('[*]n1cccc1' in ks) 406 self.assertTrue('[*]NC1CO1' in ks) 407 408 m = Chem.MolFromSmiles('c1cccn1C(=O)n1c(C)ccc1') 409 res = RecapDecompose(m,onlyUseReactions=[0]) 410 self.assertTrue(res) 411 self.assertTrue(len(res.GetLeaves())==2) 412 ks = res.GetLeaves().keys() 413 self.assertTrue('[*]n1cccc1C' in ks)
414
415 - def testAmineRxn(self):
416 m = Chem.MolFromSmiles('C1CC1N(C1NC1)C1OC1') 417 res = RecapDecompose(m) 418 self.assertTrue(res) 419 self.assertTrue(len(res.GetLeaves())==3) 420 ks = res.GetLeaves().keys() 421 self.assertTrue('[*]C1CC1' in ks) 422 self.assertTrue('[*]C1CO1' in ks) 423 self.assertTrue('[*]C1CN1' in ks) 424 425 m = Chem.MolFromSmiles('c1ccccc1N(C1NC1)C1OC1') 426 res = RecapDecompose(m) 427 self.assertTrue(res) 428 self.assertTrue(len(res.GetLeaves())==3) 429 ks = res.GetLeaves().keys() 430 self.assertTrue('[*]c1ccccc1' in ks) 431 self.assertTrue('[*]C1CO1' in ks) 432 self.assertTrue('[*]C1CN1' in ks) 433 434 m = Chem.MolFromSmiles('c1ccccc1N(c1ncccc1)C1OC1') 435 res = RecapDecompose(m) 436 self.assertTrue(res) 437 self.assertTrue(len(res.GetLeaves())==3) 438 ks = res.GetLeaves().keys() 439 self.assertTrue('[*]c1ccccc1' in ks) 440 self.assertTrue('[*]c1ccccn1' in ks) 441 self.assertTrue('[*]C1CO1' in ks) 442 443 m = Chem.MolFromSmiles('c1ccccc1N(c1ncccc1)c1ccco1') 444 res = RecapDecompose(m) 445 self.assertTrue(res) 446 self.assertTrue(len(res.GetLeaves())==3) 447 ks = res.GetLeaves().keys() 448 self.assertTrue('[*]c1ccccc1' in ks) 449 self.assertTrue('[*]c1ccccn1' in ks) 450 self.assertTrue('[*]c1ccco1' in ks) 451 452 m = Chem.MolFromSmiles('C1CCCCN1C1CC1') 453 res = RecapDecompose(m) 454 self.assertTrue(res) 455 self.assertTrue(len(res.GetLeaves())==2) 456 ks = res.GetLeaves().keys() 457 self.assertTrue('[*]N1CCCCC1' in ks) 458 self.assertTrue('[*]C1CC1' in ks) 459 460 m = Chem.MolFromSmiles('C1CCC2N1CC2') 461 res = RecapDecompose(m) 462 self.assertTrue(res) 463 self.assertTrue(len(res.GetLeaves())==0)
464
465 - def testEtherRxn(self):
466 m = Chem.MolFromSmiles('C1CC1OC1OC1') 467 res = RecapDecompose(m) 468 self.assertTrue(res) 469 self.assertTrue(len(res.GetLeaves())==2) 470 ks = res.GetLeaves().keys() 471 self.assertTrue('[*]C1CC1' in ks) 472 self.assertTrue('[*]C1CO1' in ks) 473 474 m = Chem.MolFromSmiles('C1CCCCO1') 475 res = RecapDecompose(m) 476 self.assertTrue(res) 477 self.assertTrue(len(res.GetLeaves())==0) 478 479 m = Chem.MolFromSmiles('c1ccccc1OC1OC1') 480 res = RecapDecompose(m) 481 self.assertTrue(res) 482 self.assertTrue(len(res.GetLeaves())==2) 483 ks = res.GetLeaves().keys() 484 self.assertTrue('[*]c1ccccc1' in ks) 485 self.assertTrue('[*]C1CO1' in ks) 486 487 m = Chem.MolFromSmiles('c1ccccc1Oc1ncccc1') 488 res = RecapDecompose(m) 489 self.assertTrue(res) 490 self.assertTrue(len(res.GetLeaves())==2) 491 ks = res.GetLeaves().keys() 492 self.assertTrue('[*]c1ccccc1' in ks) 493 self.assertTrue('[*]c1ccccn1' in ks)
494
495 - def testOlefinRxn(self):
496 m = Chem.MolFromSmiles('ClC=CBr') 497 res = RecapDecompose(m) 498 self.assertTrue(res) 499 self.assertTrue(len(res.GetLeaves())==2) 500 ks = res.GetLeaves().keys() 501 self.assertTrue('[*]CCl' in ks) 502 self.assertTrue('[*]CBr' in ks) 503 504 m = Chem.MolFromSmiles('C1CC=CC1') 505 res = RecapDecompose(m) 506 self.assertTrue(res) 507 self.assertTrue(len(res.GetLeaves())==0)
508
509 - def testAromNAliphCRxn(self):
510 m = Chem.MolFromSmiles('c1cccn1CCCC') 511 res = RecapDecompose(m) 512 self.assertTrue(res) 513 self.assertTrue(len(res.GetLeaves())==2) 514 ks = res.GetLeaves().keys() 515 self.assertTrue('[*]n1cccc1' in ks) 516 self.assertTrue('[*]CCCC' in ks) 517 518 m = Chem.MolFromSmiles('c1ccc2n1CCCC2') 519 res = RecapDecompose(m) 520 self.assertTrue(res) 521 self.assertTrue(len(res.GetLeaves())==0)
522
523 - def testLactamNAliphCRxn(self):
524 m = Chem.MolFromSmiles('C1CC(=O)N1CCCC') 525 res = RecapDecompose(m,onlyUseReactions=[8]) 526 self.assertTrue(res) 527 self.assertTrue(len(res.GetLeaves())==2) 528 ks = res.GetLeaves().keys() 529 self.assertTrue('[*]N1CCC1=O' in ks) 530 self.assertTrue('[*]CCCC' in ks) 531 532 m = Chem.MolFromSmiles('O=C1CC2N1CCCC2') 533 res = RecapDecompose(m) 534 self.assertTrue(res) 535 self.assertTrue(len(res.GetLeaves())==0)
536
537 - def testAromCAromCRxn(self):
538 m = Chem.MolFromSmiles('c1ccccc1c1ncccc1') 539 res = RecapDecompose(m) 540 self.assertTrue(res) 541 self.assertTrue(len(res.GetLeaves())==2) 542 ks = res.GetLeaves().keys() 543 self.assertTrue('[*]c1ccccc1' in ks) 544 self.assertTrue('[*]c1ccccn1' in ks) 545 546 m = Chem.MolFromSmiles('c1ccccc1C1CC1') 547 res = RecapDecompose(m) 548 self.assertTrue(res) 549 self.assertTrue(len(res.GetLeaves())==0)
550
551 - def testAromNAromCRxn(self):
552 m = Chem.MolFromSmiles('c1cccn1c1ccccc1') 553 res = RecapDecompose(m) 554 self.assertTrue(res) 555 self.assertTrue(len(res.GetLeaves())==2) 556 ks = res.GetLeaves().keys() 557 self.assertTrue('[*]n1cccc1' in ks) 558 self.assertTrue('[*]c1ccccc1' in ks)
559
560 - def testSulfonamideRxn(self):
561 m = Chem.MolFromSmiles('CCCNS(=O)(=O)CC') 562 res = RecapDecompose(m) 563 self.assertTrue(res) 564 self.assertTrue(len(res.GetLeaves())==2) 565 ks = res.GetLeaves().keys() 566 self.assertTrue('[*]NCCC' in ks) 567 self.assertTrue('[*]S(=O)(=O)CC' in ks) 568 569 m = Chem.MolFromSmiles('c1cccn1S(=O)(=O)CC') 570 res = RecapDecompose(m) 571 self.assertTrue(res) 572 self.assertTrue(len(res.GetLeaves())==2) 573 ks = res.GetLeaves().keys() 574 self.assertTrue('[*]n1cccc1' in ks) 575 self.assertTrue('[*]S(=O)(=O)CC' in ks) 576 577 m = Chem.MolFromSmiles('C1CNS(=O)(=O)CC1') 578 res = RecapDecompose(m) 579 self.assertTrue(res) 580 self.assertTrue(len(res.GetLeaves())==0)
581
582 - def testSFNetIssue1881803(self):
583 m = Chem.MolFromSmiles('c1ccccc1n1cccc1') 584 res = RecapDecompose(m) 585 self.assertTrue(res) 586 self.assertTrue(len(res.GetLeaves())==2) 587 m = Chem.MolFromSmiles('c1ccccc1[n+]1ccccc1') 588 res = RecapDecompose(m) 589 self.assertTrue(res) 590 self.assertTrue(len(res.GetLeaves())==0) 591 592 m = Chem.MolFromSmiles('C1CC1NC(=O)CC') 593 res = RecapDecompose(m) 594 self.assertTrue(res) 595 self.assertTrue(len(res.GetLeaves())==2) 596 m = Chem.MolFromSmiles('C1CC1[NH+]C(=O)CC') 597 res = RecapDecompose(m) 598 self.assertTrue(res) 599 self.assertTrue(len(res.GetLeaves())==0) 600 601 m = Chem.MolFromSmiles('C1CC1NC(=O)NC1CCC1') 602 res = RecapDecompose(m) 603 self.assertTrue(res) 604 self.assertTrue(len(res.GetLeaves())==2) 605 m = Chem.MolFromSmiles('C1CC1[NH+]C(=O)[NH+]C1CCC1') 606 res = RecapDecompose(m) 607 self.assertTrue(res) 608 self.assertTrue(len(res.GetLeaves())==0)
609 610 unittest.main() 611