Source code for molsystem.inchi

# -*- coding: utf-8 -*-

"""Functions for handling InChI"""

import logging
import requests

try:
    from openbabel import openbabel as OB
except ModuleNotFoundError:
    print(
        "Please install openbabel using conda:\n"
        "     conda install -c conda-forge openbabel"
    )
    raise
try:
    from rdkit import Chem
    from rdkit.Chem import AllChem
except ModuleNotFoundError:
    print("Please install RDKit using conda:\n     conda install -c conda-forge rdkit")
    raise

logger = logging.getLogger(__name__)


[docs] class InChIMixin: """A mixin for handling InChI.""" @property def inchi(self): """Return the InChI string for this object.""" return self.to_inchi() @property def inchikey(self): """Return the InChIKey string for this object.""" return self.to_inchi(key=True)
[docs] def to_inchi(self, key=False, openbabel=False): """Create the InChI string from the system. Parameters ---------- key : bool = False Whether to create the InChIKey openbabel : bool = False Whether to use OpenBabel rather than default of RDkit Returns ------- str The InChI string, or (InChI, name) if the rname is requested """ logger.info("to_inchi") if openbabel: obConversion = OB.OBConversion() if key: obConversion.SetOutFormat("inchikey") else: obConversion.SetOutFormat("inchi") mol = self.to_OBMol() inchi = obConversion.WriteString(mol) else: mol = self.to_RDKMol() if key: inchi = Chem.inchi.MolToInchiKey(mol) else: inchi = Chem.inchi.MolToInchi(mol) logger.info(f"inchi = '{inchi}'") return inchi.strip()
[docs] def from_inchi(self, inchi, name=None, reorient=True, openbabel=True): """Create the system from a InChI string. Parameters ---------- inchi : str The InChI string name : str = None The name of the molecule reorient : bool = True Whether to reorient to the standard orientation openbabel : bool = False Whether to use Openbabel rather than default of RDKit Returns ------- None """ save = self.name if openbabel: obConversion = OB.OBConversion() obConversion.SetInAndOutFormats("inchi", "mdl") mol = OB.OBMol() obConversion.ReadString(mol, inchi) # Add hydrogens mol.AddHydrogens() # Get coordinates for a 3-D structure builder = OB.OBBuilder() builder.Build(mol) self.from_OBMol(mol) else: raise NotImplementedError("RDKit from InChI doesn't seem to work!") mol = Chem.MolFromInchi( inchi, sanitize=False, removeHs=False, treatWarningAsError=True ) mol = Chem.AddHs(mol) AllChem.EmbedMolecule(mol) self.from_RDKMol(mol) # Rotate to standard orientation rdkMol = self.to_RDKMol() rdkConf = rdkMol.GetConformers()[0] Chem.rdMolTransforms.CanonicalizeConformer(rdkConf) self.from_RDKMol(rdkMol) if name is not None: self.name = name else: self.name = save
[docs] def from_inchikey(self, inchikey, name=None, reorient=True): """Create the system from an InChIKey string. Parameters ---------- inchikey : str The InChIKey string name : str = None The name of the molecule reorient : bool = True Whether to reorient to the standard orientation Returns ------- None """ inchi = self._get_inchi(inchikey) self.from_inchi(inchi, reorient=reorient)
def _get_inchi(self, inchikey): """Get the InChI from PubChem given the InChIKey.""" url = ( f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/inchikey/{inchikey}" "/property/InChI/JSON" ) r = requests.get(url) result = r.json() if "Fault" in result: raise RuntimeError(f"InChIKey '{inchikey}' not found in PubChem.") inchi = set() for properties in result["PropertyTable"]["Properties"]: if "InChI" in properties: inchi.add(properties["InChI"]) if len(inchi) == 1: return inchi.pop() else: return [*inchi]