| """Utilities used in the RXN forward/retrosynthesis workers.""" |
| import logging |
| from typing import Optional |
|
|
| from rxn.chemutils.conversion import ( |
| inchi_to_mol, |
| mol_to_inchi, |
| mol_to_smiles, |
| smiles_to_mol, |
| ) |
| from rxn.chemutils.exceptions import InvalidInchi, InvalidSmiles |
|
|
| logger = logging.getLogger(__name__) |
| logger.addHandler(logging.NullHandler()) |
|
|
| RXN_SMILES_SEPARATOR = ">>" |
|
|
|
|
| def standardize_smiles( |
| smiles: str, |
| canonicalize: bool = True, |
| sanitize: bool = True, |
| find_radicals: bool = True, |
| inchify: bool = False, |
| ) -> str: |
| """ |
| Ensure that a SMILES follows a desired standard. |
| |
| It allows canonicalization, sanitization and inchification keeping stereochemistry with isomericSmile=True. |
| It can process multiple molecules separated by ".". |
| Note that inchify set to True will also canonicalize the molecule. |
| |
| Args: |
| smiles (str): SMILES representation of a molecule. |
| canonicalize (bool): canonicalize SMILES. Defaults to True. |
| sanitize (bool): sanitize SMILES. Defaults to True. |
| inchify (bool): inchify the SMILES. Defaults to False. |
| |
| Returns: |
| a SMILES following the desired standard. |
| """ |
| try: |
| molecule = smiles_to_mol(smiles, sanitize=sanitize, find_radicals=find_radicals) |
| except InvalidSmiles: |
| logger.error(f"SMILES parsing failure: {smiles}.") |
| raise |
|
|
| if inchify: |
| try: |
| inchi_string = mol_to_inchi(molecule) |
| except InvalidInchi: |
| logger.error( |
| f"Inchification failure for SMILES: {smiles}. Returning its canonical version." |
| ) |
| return mol_to_smiles(molecule, isomericSmiles=True) |
| else: |
| |
| try: |
| molecule_from_inchi = inchi_to_mol(inchi_string) |
| except InvalidInchi: |
| logger.error( |
| f"De-inchification failure for InChi: {inchi_string}. Returning its canonical version." |
| ) |
| return mol_to_smiles(molecule, isomericSmiles=True) |
| return mol_to_smiles(molecule_from_inchi, canonical=True) |
| if canonicalize: |
| return mol_to_smiles(molecule, isomericSmiles=True) |
| else: |
| return smiles |
|
|
|
|
| def standardize_molecules( |
| molecules: str, |
| canonicalize: bool = True, |
| sanitize: bool = True, |
| inchify: bool = False, |
| fragment_bond: str = "~", |
| ordered_precursors: bool = True, |
| molecule_token_delimiter: Optional[str] = None, |
| is_enzymatic: bool = False, |
| enzyme_separator: str = "|", |
| ) -> str: |
| """ |
| Ensure that a set of molecules represented by a string follows a desired standard. |
| |
| Args: |
| molecules (str): molecules SMILES. Molecules can be separated via a ".". |
| Fragments are supported with a custom `fragment_bond`. |
| canonicalize (bool): canonicalize SMILES. Defaults to True. |
| sanitize (bool): sanitize SMILES. Defaults to True. |
| inchify (bool): inchify the SMILES. Defaults to False. |
| fragment_bond (str): fragment bond. Defaults to '~'. |
| ordered_precursors (bool): order precursors. Defaults to True. |
| molecule_token_delimiter (Optional[str]): delimiter for big molecule tokens. Defaults to None |
| is_enzymatic (bool): the molecules are representing an enzymatic reaction. Defaults to False. |
| enzyme_separator (str): separator for molecules and the enzyme. Defaults to '|'. |
| |
| Returns: |
| standardized molecules. |
| |
| Examples: |
| Standardize multiple molecules: |
| |
| >>> standardize_molecules('CCO.CC') |
| 'CC.CCO' |
| |
| Standardize multiple molecules including fragment information: |
| |
| >>> standardize_molecules('CCO.CC~C') |
| 'CCO.C~CC' |
| """ |
| enzyme = "" |
| if is_enzymatic: |
| splitted_molecules = molecules.split(enzyme_separator) |
| molecules = splitted_molecules[0] |
| if len(splitted_molecules) > 1: |
| enzyme = splitted_molecules[1] |
| enzyme = "{}{}".format(enzyme_separator, enzyme) |
| if molecule_token_delimiter is not None: |
| molecules = molecules.replace(molecule_token_delimiter, "") |
| if fragment_bond in molecules: |
| standardized_molecules_list = [ |
| |
| standardize_smiles( |
| molecule.replace(fragment_bond, "."), |
| canonicalize=canonicalize, |
| sanitize=sanitize, |
| inchify=inchify, |
| ).replace(".", fragment_bond) |
| for molecule in molecules.split(".") |
| ] |
| if ordered_precursors: |
| standardized_molecules_list = sorted(standardized_molecules_list) |
| standardized_molecules = ".".join(standardized_molecules_list) |
| else: |
| if ordered_precursors: |
| |
| standardized_molecules = standardize_smiles( |
| molecules, |
| canonicalize=canonicalize, |
| sanitize=sanitize, |
| inchify=inchify, |
| ) |
| else: |
| standardized_molecules_list = [ |
| standardize_smiles( |
| molecule, |
| canonicalize=canonicalize, |
| sanitize=sanitize, |
| inchify=inchify, |
| ) |
| for molecule in molecules.split(".") |
| ] |
| standardized_molecules = ".".join(standardized_molecules_list) |
| |
| standardized_molecules = "{}{}".format(standardized_molecules, enzyme) |
| return standardized_molecules |
|
|