Expose a couple of additional functions to Python (#7444)

This commit is contained in:
Greg Landrum
2024-05-17 04:47:30 +02:00
committed by GitHub
parent a9b7881b8b
commit db952786b6
3 changed files with 114 additions and 42 deletions

View File

@@ -1,6 +1,5 @@
//
// Copyright (C) 2001-2021 Greg Landrum and Rational Discovery LLC
// Copyright (c) 2014, Novartis Institutes for BioMedical Research Inc.
// Copyright (C) 2001-2024 Greg Landrum and other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
@@ -9,8 +8,8 @@
// of the RDKit source tree.
//
#include <RDGeneral/export.h>
#ifndef _RD_MOL_OPS_H_
#define _RD_MOL_OPS_H_
#ifndef RD_MOL_OPS_H
#define RD_MOL_OPS_H
#include <vector>
#include <map>
@@ -952,10 +951,13 @@ class Hybridizations {
std::vector<int> d_hybridizations;
};
//! removes bogus chirality markers (those on non-sp3 centers):
//! removes bogus chirality markers (e.g. tetrahedral flags on non-sp3 centers):
RDKIT_GRAPHMOL_EXPORT void cleanupChirality(RWMol &mol);
//! \overload
RDKIT_GRAPHMOL_EXPORT void cleanupAtropisomers(RWMol &);
//! removes bogus atropisomeric markers (e.g. those without sp2 begin and end
//! atoms):
RDKIT_GRAPHMOL_EXPORT void cleanupAtropisomers(RWMol &mol,
Hybridizations &hybridizations);

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2003-2022 Greg Landrum and other RDKit contributors
// Copyright (C) 2003-2024 Greg Landrum and other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
@@ -471,6 +471,16 @@ void setHybridizationMol(ROMol &mol) {
MolOps::setHybridization(wmol);
}
void cleanupChiralityMol(ROMol &mol) {
auto &rwmol = static_cast<RWMol &>(mol);
MolOps::cleanupChirality(rwmol);
}
void cleanupAtropisomersMol(ROMol &mol) {
auto &rwmol = static_cast<RWMol &>(mol);
MolOps::cleanupAtropisomers(rwmol);
}
VECT_INT_VECT getSymmSSSR(ROMol &mol, bool includeDativeBonds) {
VECT_INT_VECT rings;
MolOps::symmetrizeSSSR(mol, rings, includeDativeBonds);
@@ -970,23 +980,24 @@ ROMol *molzipHelper(python::object &pmols, const MolzipParams &p) {
}
ROMol *rgroupRowZipHelper(python::dict row, const MolzipParams &p) {
std::map<std::string, ROMOL_SPTR> rgroup_row;
std::map<std::string, ROMOL_SPTR> rgroup_row;
python::list items = row.items();
for(size_t i = 0; i < (size_t) python::len(items); ++i) {
for (size_t i = 0; i < (size_t)python::len(items); ++i) {
python::object key = items[i][0];
python::object value = items[i][1];
python::extract<std::string> rgroup_key(key);
python::extract<ROMOL_SPTR> mol(value);
if(rgroup_key.check() && mol.check()) {
if (rgroup_key.check() && mol.check()) {
rgroup_row[rgroup_key] = mol;
} else {
// raise value error
throw ValueErrorException("Unable to retrieve rgroup key and molecule from dictionary");
throw ValueErrorException(
"Unable to retrieve rgroup key and molecule from dictionary");
}
}
return molzip(rgroup_row, p).release();
}
}
python::tuple hasQueryHsHelper(const ROMol &m) {
python::list res;
@@ -1094,7 +1105,7 @@ struct molops_wrapper {
(python::arg("mol"), python::arg("conformer")),
docString.c_str());
docString =
"\n\
"DEPRECATED\n\
- mol: the molecule to be modified\n\
- confId: Conformer to use for the coordinates\n\
\n";
@@ -1379,11 +1390,11 @@ struct molops_wrapper {
docString =
"Check to see if the molecule has query Hs, this is normally used on query molecules\n\
such as thos returned from MolFromSmarts\n\
such as those returned from MolFromSmarts\n\
Example: \n\
(hasQueryHs, hasUnmergableQueryHs) = HasQueryHs(mol)\n\
(hasQueryHs, hasUnmergeableQueryHs) = HasQueryHs(mol)\n\
\n\
if hasUnmergableQueryHs, these query hs cannot be removed by calling\n\
if hasUnmergeableQueryHs, these query hs cannot be removed by calling\n\
MergeQueryHs";
python::def("HasQueryHs", hasQueryHsHelper, python::arg("mol"),
docString.c_str());
@@ -1688,17 +1699,45 @@ to the terminal dummy atoms.\n\
docString.c_str());
// ------------------------------------------------------------------------
docString =
"cleans up certain common bad functionalities in the molecule\n\
\n\
ARGUMENTS:\n\
\n\
- mol: the molecule to use\n\
\n\
NOTES:\n\
\n\
- The molecule is modified in place.\n\
\n";
R"DOC(cleans up certain common bad functionalities in the molecule
ARGUMENTS:
- mol: the molecule to use
NOTES:
- The molecule is modified in place.
)DOC";
python::def("Cleanup", cleanupMol, (python::arg("mol")), docString.c_str());
// ------------------------------------------------------------------------
docString =
R"DOC(removes bogus chirality markers (e.g. tetrahedral flags on non-sp3 centers)
ARGUMENTS:
- mol: the molecule to use
NOTES:
- The molecule is modified in place.
)DOC";
python::def("CleanupChirality", cleanupChiralityMol, (python::arg("mol")),
docString.c_str());
// ------------------------------------------------------------------------
docString =
R"DOC(removes bogus atropisomeric markers (e.g. those without sp2 begin and end atoms)
ARGUMENTS:
- mol: the molecule to use
NOTES:
- The molecule is modified in place.
)DOC";
python::def("CleanupAtropisomers", cleanupAtropisomersMol,
(python::arg("mol")), docString.c_str());
// ------------------------------------------------------------------------
docString =
@@ -2837,23 +2876,24 @@ must be the core",
python::return_value_policy<python::manage_new_object>());
docString =
"zip an RGroupRow together to recreate the original molecule. This correctly handles\n"
"broken cycles that can occur in decompositions.\n"
" example:\n\n"
" >>> from rdkit import Chem\n"
" >>> from rdkit.Chem import rdRGroupDecomposition as rgd\n"
" >>> core = Chem.MolFromSmiles('CO')\n"
" >>> mols = [Chem.MolFromSmiles('C1NNO1')]\n"
" >>> rgroups, unmatched = rgd.RGroupDecompose(core, mols)\n"
" >>> for rgroup in rgroups:\n"
" ... mol = rgd.molzip(rgroup)\n"
"\n";
python::def("molzip",
(ROMol * (*)(python::dict, const MolzipParams &)) & rgroupRowZipHelper,
(python::arg("row"), python::arg("params") = MolzipParams()),
docString.c_str(),
python::return_value_policy<python::manage_new_object>());
"zip an RGroupRow together to recreate the original molecule. This correctly handles\n"
"broken cycles that can occur in decompositions.\n"
" example:\n\n"
" >>> from rdkit import Chem\n"
" >>> from rdkit.Chem import rdRGroupDecomposition as rgd\n"
" >>> core = Chem.MolFromSmiles('CO')\n"
" >>> mols = [Chem.MolFromSmiles('C1NNO1')]\n"
" >>> rgroups, unmatched = rgd.RGroupDecompose(core, mols)\n"
" >>> for rgroup in rgroups:\n"
" ... mol = rgd.molzip(rgroup)\n"
"\n";
python::def(
"molzip",
(ROMol * (*)(python::dict, const MolzipParams &)) & rgroupRowZipHelper,
(python::arg("row"), python::arg("params") = MolzipParams()),
docString.c_str(),
python::return_value_policy<python::manage_new_object>());
// ------------------------------------------------------------------------
docString =
"Adds a recursive query to an atom\n\
@@ -3126,6 +3166,15 @@ A note on the flags controlling which atoms/bonds are modified:
)DOC");
python::def("_TestSetProps", testSetProps, python::arg("mol"));
python::def("NeedsHs", MolOps::needsHs, (python::arg("mol")),
"returns whether or not the molecule needs to have Hs added");
python::def(
"CountAtomElec", MolOps::countAtomElec, (python::arg("atom")),
"returns the number of electrons available on an atom to donate for aromaticity");
python::def(
"AtomHasConjugatedBond", MolOps::atomHasConjugatedBond,
(python::arg("atom")),
"returns whether or not the atom is involved in a conjugated bond");
}
};
} // namespace RDKit

View File

@@ -8110,6 +8110,27 @@ M END
self.assertEqual(fusedBonds.count(1), 2)
self.assertEqual(fusedBonds.count(2), 3)
def testNeedsHs(self):
m = Chem.MolFromSmiles("CO")
self.failUnless(Chem.NeedsHs(m))
mh = Chem.AddHs(m)
self.failIf(Chem.NeedsHs(mh))
nm = Chem.RWMol(mh)
nm.RemoveAtom(3)
self.failUnless(Chem.NeedsHs(m))
def testCountAtomElec(self):
m = Chem.MolFromSmiles("c1n(C)ccc1")
self.failUnlessEqual(Chem.CountAtomElec(m.GetAtomWithIdx(0)),1)
self.failUnlessEqual(Chem.CountAtomElec(m.GetAtomWithIdx(1)),2)
def testAtomHasConjugatedBond(self):
m = Chem.MolFromSmiles("c1n(C)ccc1")
self.failUnless(Chem.AtomHasConjugatedBond(m.GetAtomWithIdx(1)))
self.failIf(Chem.AtomHasConjugatedBond(m.GetAtomWithIdx(2)))
if __name__ == '__main__':
if "RDTESTCASE" in os.environ: