def copy_mol_props(source: Chem.rdchem.Mol, destination: Chem.rdchem.Mol): """Copy properties from one source molecule to another destination molecule. Args: source: a molecule to copy from. destination: a molecule to copy to. """ props = source.GetPropsAsDict() dm.set_mol_props(destination, props)
def test_sdf_props_and_conformer_preserved(tmp_path): sdf_path = tmp_path / "test.sdf" # Generate an SDF file props = dict(test_int=588, test_str="hello") smiles = "CC1(C2C(C3C(C(=O)C(=C(C3(C(=O)C2=C(C4=C1C=CC=C4O)O)O)O)C(=O)N)N(C)C)O)O" mol = dm.to_mol(smiles) mol = dm.set_mol_props(mol, props) mol = dm.conformers.generate(mol, n_confs=1) pos = mol.GetConformer().GetPositions() dm.to_sdf(mol, sdf_path) # Read sdf file mols = dm.read_sdf(sdf_path) mol = mols[0] # Check properties assert mol.GetPropsAsDict() == props # Check conformer conf = mol.GetConformer() assert mol.GetNumConformers() == 1 assert conf.Is3D() np.testing.assert_almost_equal(conf.GetPositions(), pos, decimal=4)
def test_copy_mol_props(): source = dm.to_mol("CCC") destination = dm.to_mol("CC") props = {} props["bool"] = True props["number"] = 55 props["float"] = 5.555 props["string"] = "hello" props["something_else"] = type(int) dm.set_mol_props(source, props) dm.copy_mol_props(source, destination) assert destination.GetPropsAsDict() == source.GetPropsAsDict()
def test_set_mol_props(): mol = dm.to_mol("CCC") props = {} props["number"] = 55 props["float"] = 5.555 props["string"] = "hello" props["something_else"] = type(int) dm.set_mol_props(mol, props) mol_props = mol.GetPropsAsDict() assert mol_props["number"] == props["number"] assert mol_props["float"] == props["float"] assert mol_props["string"] == props["string"] assert mol_props["something_else"] == str(props["something_else"])
def _row_to_mol(row): props = row.to_dict() if mol_column is not None: mol = props[mol_column] else: if conserve_smiles: smiles = props[smiles_column] else: # If a SMILES column is used to create the molecule then it is removed from the # properties. smiles = props.pop(smiles_column) mol = dm.to_mol(smiles) if mol is None: return None dm.set_mol_props(mol, props) return mol
def test_sanitize_mol_keep_props_and_conformers(): # Generate a mol with props and a conformer props = dict(test_int=588, test_str="hello") smiles = "CCC[N+](=O)[O-]" mol = dm.to_mol(smiles) mol = dm.set_mol_props(mol, props) mol = dm.conformers.generate(mol, n_confs=1) pos = mol.GetConformer().GetPositions() # Sanitize sane_mol = dm.sanitize_mol(mol) # Check properties assert sane_mol.GetPropsAsDict() == props # Check conformer conf = sane_mol.GetConformer() assert sane_mol.GetNumConformers() == 1 assert conf.Is3D() np.testing.assert_almost_equal(conf.GetPositions(), pos, decimal=4)
def sanitize_mol( mol: Chem.rdchem.Mol, charge_neutral: bool = False, sanifix: bool = True, verbose: bool = True, add_hs: bool = False, ) -> Optional[Chem.rdchem.Mol]: """An augmented version of RDKit `sanitize=True`. It uses a mol-SMILES-mol conversion to catch potential aromaticity errors and try to fix aromatic nitrogen (using the popular sanifix4 script). Optionally, it can neutralize the charge of the molecule. Note #1: Only the first conformer (if present) will be preserved and a warning will be displayed if more than one conformer is detected. Note #2: The molecule's properties will be preserved but the atom's properties will be lost. Args: mol: a molecule. charge_neutral: whether charge neutralization should be applied. sanifix: whether to run the sanifix from James Davidson (sanifix4.py) that try to adjust aromatic nitrogens. verbose: Whether displaying a warning about multiple conformers. add_hs: Add hydrogens to the returned molecule. Useful when the input molecule already contains hydrogens. Returns: mol: a molecule. """ if mol is None: return mol # Extract properties. original_mol = copy_mol(mol) properties = original_mol.GetPropsAsDict() if charge_neutral: mol = to_neutral(mol) if sanifix: mol = _sanifix4.sanifix(mol) if mol is not None: # Detect multiple conformers if verbose and mol.GetNumConformers() > 1: logger.warning( f"The molecule contains multiple conformers. Only the first one will be preserved." ) # Try catch to avoid occasional aromaticity errors try: # `cxsmiles` is used here to preserve the first conformer. mol = to_mol(dm.to_smiles(mol, cxsmiles=True), sanitize=True, add_hs=add_hs) # type: ignore except Exception: mol = None if mol is not None: # Insert back properties. mol = dm.set_mol_props(mol, properties) return mol