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

Source Code for Module rdkit.Chem.Recap

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