B
    3Rc)                 @   s   d dl Z d dlZd dlmZ d dlmZ d dlmZmZ d dl	m
Z
mZ G dd dZdd	 Zd
d Zdd ZG dd deZdddZedkre  dS )    N)
namedtuple)closing)ChemRDConfig)SDMolSupplierSmilesMolSupplierc               @   s   e Zd ZdZdZdZdS )InputFormatsmartsmolZsmilesN)__name__
__module____qualname__SMARTSMOLSMILES r   r   5lib/python3.7/site-packages/rdkit/Chem/SaltRemover.pyr   *   s   r   c             C   sP   t d}|  dd } | rL|| }t|d }|dkrHt| |S dS )zI
    Converts given line into a molecule using 'Chem.MolFromSmarts'.
    z[\t ]+z//r   N)recompilestripsplitr   ZMolFromSmarts
ValueError)lineZ
whitespacer	   saltr   r   r   _smartsFromSmartsLine0   s    

r   c          	   c   s8   t | &}x|D ]}t|}|r|V  qW W dQ R X dS )z:
    Yields extracted SMARTS salts from given stream.
    N)r   r   )streamlinesr   r	   r   r   r   _getSmartsSaltsFromStreamA   s
    

r   c             C   s   t t| dS )z7
    Extracts SMARTS salts from given file object.
    r)r   open)filenamer   r   r   _getSmartsSaltsFromFileL   s    r!   c               @   s^   e Zd ZejejdZdde	j
fddZdd Zdd	d
ZdddZdddZdddZdS )SaltRemoverz	Salts.txtNc             C   s(   |r
|| _ || _d | _|| _|   d S )N)defnFilenamedefnDatasalts
defnFormat_initPatterns)selfr#   r$   r&   r   r   r   __init__V   s    zSaltRemover.__init__c          	   C   s  | j rddlm} || j }t|p g | _xb|D ]Z}|r2| jtjkrPt|}n | jtj	krht
|}ntd|dkrt|| j| q2W W dQ R X nv| jtjkrdd t| jD | _nR| jtjkrdd t| jD | _n.| jtj	kr
dd t| jD | _ntddS )	a~  

        >>> remover = SaltRemover()
        >>> len(remover.salts)>0
        True

        Default input format is SMARTS
        >>> remover = SaltRemover(defnData="[Cl,Br]")
        >>> len(remover.salts)
        1

        >>> remover = SaltRemover(defnData="[Na+]\nCC(=O)O", defnFormat=InputFormat.SMILES)
        >>> len(remover.salts)
        2

        >>> from rdkit import RDLogger
        >>> RDLogger.DisableLog('rdApp.error')
        >>> remover = SaltRemover(defnData="[Cl,fail]")
        Traceback (most recent call last):
          ...
        ValueError: [Cl,fail]

        >>> RDLogger.EnableLog('rdApp.error')
        r   )StringIOz Unsupported format for supplier.Nc             S   s   g | ]}|qS r   r   ).0r
   r   r   r   
<listcomp>   s    z-SaltRemover._initPatterns.<locals>.<listcomp>c             S   s   g | ]}|qS r   r   )r+   r
   r   r   r   r,      s    c             S   s   g | ]}|qS r   r   )r+   r
   r   r   r   r,      s    )r$   ior*   r   r%   r&   r   r   r   r   r   ZMolFromSmilesr   appendr!   r#   r   r   r   )r(   r*   ZinFr   r   r   r   r   r'   ^   s,    



zSaltRemover._initPatternsFTc             C   s   |  |||}|jS )a  

        >>> remover = SaltRemover(defnData="[Cl,Br]")
        >>> len(remover.salts)
        1

        >>> mol = Chem.MolFromSmiles('CN(C)C.Cl')
        >>> res = remover.StripMol(mol)
        >>> res is not None
        True
        >>> res.GetNumAtoms()
        4

        Notice that all salts are removed:

        >>> mol = Chem.MolFromSmiles('CN(C)C.Cl.Cl.Br')
        >>> res = remover.StripMol(mol)
        >>> res.GetNumAtoms()
        4

        Matching (e.g. "salt-like") atoms in the molecule are unchanged:

        >>> mol = Chem.MolFromSmiles('CN(Br)Cl')
        >>> res = remover.StripMol(mol)
        >>> res.GetNumAtoms()
        4

        >>> mol = Chem.MolFromSmiles('CN(Br)Cl.Cl')
        >>> res = remover.StripMol(mol)
        >>> res.GetNumAtoms()
        4

        Charged salts are handled reasonably:

        >>> mol = Chem.MolFromSmiles('C[NH+](C)(C).[Cl-]')
        >>> res = remover.StripMol(mol)
        >>> res.GetNumAtoms()
        4


        Watch out for this case (everything removed):

        >>> remover = SaltRemover()
        >>> len(remover.salts)>1
        True
        >>> mol = Chem.MolFromSmiles('CC(=O)O.[Na]')
        >>> res = remover.StripMol(mol)
        >>> res.GetNumAtoms()
        0

        dontRemoveEverything helps with this by leaving the last salt:

        >>> res = remover.StripMol(mol,dontRemoveEverything=True)
        >>> res.GetNumAtoms()
        4

        but in cases where the last salts are the same, it can't choose
        between them, so it returns all of them:

        >>> mol = Chem.MolFromSmiles('Cl.Cl')
        >>> res = remover.StripMol(mol,dontRemoveEverything=True)
        >>> res.GetNumAtoms()
        2

        )	_StripMolr
   )r(   r
   dontRemoveEverythingsanitizeZstrippedMolr   r   r   StripMol   s    BzSaltRemover.StripMolc             C   s   |  ||S )aL  
        Strips given molecule and returns it, with the fragments which have been deleted.

        >>> remover = SaltRemover(defnData="[Cl,Br]")
        >>> len(remover.salts)
        1

        >>> mol = Chem.MolFromSmiles('CN(C)C.Cl.Br')
        >>> res, deleted = remover.StripMolWithDeleted(mol)
        >>> Chem.MolToSmiles(res)
        'CN(C)C'
        >>> [Chem.MolToSmarts(m) for m in deleted]
        ['[Cl,Br]']

        >>> mol = Chem.MolFromSmiles('CN(C)C.Cl')
        >>> res, deleted = remover.StripMolWithDeleted(mol)
        >>> res.GetNumAtoms()
        4
        >>> len(deleted)
        1
        >>> deleted[0].GetNumAtoms()
        1
        >>> Chem.MolToSmarts(deleted[0])
        '[Cl,Br]'

        Multiple occurrences of 'Cl' and without tuple destructuring
        
        >>> mol = Chem.MolFromSmiles('CN(C)C.Cl.Cl')
        >>> tup = remover.StripMolWithDeleted(mol)

        >>> tup.mol.GetNumAtoms()
        4
        >>> len(tup.deleted)
        1
        >>> tup.deleted[0].GetNumAtoms()
        1
        >>> Chem.MolToSmarts(deleted[0])
        '[Cl,Br]'
        )r/   )r(   r
   r0   r   r   r   StripMolWithDeleted   s    (zSaltRemover.StripMolWithDeletedc       
      C   s   dd }t dddg}g }|r:tt|dkr:|||S d}| }xT| jD ]J}	|||	|}|| krN| }d}||	 |rNtt|dkrNP qNW |r|r| d	krt| |||S )
Nc             S   s   |   }|s| S | }t||d}|r6|r:|  dkr:|S |}xD|  r||  kr|  }t||d}|r||  dkr|P |}q@W |S )NTr   )GetNumAtomsr   ZDeleteSubstructs)mr   ZnotEverythingZnAtsZrestr   r   r   _applyPattern  s    z,SaltRemover._StripMol.<locals>._applyPatternStrippedMolr
   deleted   FTr   )r   lenr   ZGetMolFragsr4   r%   r.   ZSanitizeMol)
r(   r
   r0   r1   r7   r8   r9   ZmodifiedZnatomsr   r   r   r   r/      s$    


zSaltRemover._StripMolc             C   s   | j ||dS )aN  

        >>> remover = SaltRemover(defnData="[Cl,Br]")
        >>> len(remover.salts)
        1
        >>> Chem.MolToSmarts(remover.salts[0])
        '[Cl,Br]'

        >>> mol = Chem.MolFromSmiles('CN(C)C.Cl')
        >>> res = remover(mol)
        >>> res is not None
        True
        >>> res.GetNumAtoms()
        4

        )r0   )r2   )r(   r
   r0   r   r   r   __call__&  s    zSaltRemover.__call__)FT)F)FT)F)r   r   r   ospathjoinr   Z	RDDataDirr#   r   r   r)   r'   r2   r3   r/   r<   r   r   r   r   r"   S   s   3
E
*
&r"   c             C   s2   dd l }dd l}|j|j| d\}}|| d S )Nr   )Zoptionflagsverbose)sysdoctestZtestmodELLIPSISexit)r@   rA   rB   Zfailed_r   r   r   _runDoctests>  s    rF   __main__)N)r=   r   collectionsr   
contextlibr   Zrdkitr   r   Zrdkit.Chem.rdmolfilesr   r   r   r   r   r!   objectr"   rF   r   r   r   r   r   <module>!   s    l
