Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose replaceAtomWithQueryAtom to Python #7380

Merged
merged 4 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion Code/GraphMol/QueryOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,8 @@ RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeMHAtomQuery();
// CXSMILES
const std::vector<std::string> complexQueries = {"A", "AH", "Q", "QH",
"X", "XH", "M", "MH"};
RDKIT_GRAPHMOL_EXPORT void convertComplexNameToQuery(Atom *query, std::string_view symb);
RDKIT_GRAPHMOL_EXPORT void convertComplexNameToQuery(Atom *query,
std::string_view symb);

//! returns a Query for matching atoms that have ring bonds
template <class T>
Expand Down Expand Up @@ -1099,6 +1100,9 @@ inline bool isAtomDummy(const Atom *a) {
namespace QueryOps {
RDKIT_GRAPHMOL_EXPORT void completeMolQueries(
RWMol *mol, unsigned int magicVal = 0xDEADBEEF);
// Replaces the given atom in the molecule with a QueryAtom that is otherwise
// a copy of the given atom. Returns a pointer to that atom.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// a copy of the given atom. Returns a pointer to that atom.
// a copy of the given atom. Returns a pointer to that atom.
// if the atom already has a query, nothing will be changed

// if the atom already has a query, nothing will be changed
RDKIT_GRAPHMOL_EXPORT Atom *replaceAtomWithQueryAtom(RWMol *mol, Atom *atom);

RDKIT_GRAPHMOL_EXPORT void finalizeQueryFromDescription(
Expand Down
42 changes: 29 additions & 13 deletions Code/GraphMol/Wrap/Queries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ Ret *PropQueryWithTol(const std::string &propname, const ExplicitBitVect &v,
return res;
}

namespace {
Atom *replaceAtomWithQueryAtomHelper(ROMol &mol, Atom &atom) {
return QueryOps::replaceAtomWithQueryAtom(static_cast<RWMol *>(&mol), &atom);
}
} // namespace

struct queries_wrapper {
static void wrap() {
#define QADEF1(_funcname_) \
Expand Down Expand Up @@ -210,29 +216,29 @@ struct queries_wrapper {

python::def("HasPropQueryAtom", HasPropQueryAtom,
(python::arg("propname"), python::arg("negate") = false),
"Returns a QueryAtom that matches when the propery 'propname' "
"Returns a QueryAtom that matches when the property 'propname' "
"exists in the atom.",
python::return_value_policy<python::manage_new_object>());

python::def("HasPropQueryBond", HasPropQueryBond,
(python::arg("propname"), python::arg("negate") = false),
"Returns a QueryBond that matches when the propery 'propname' "
"Returns a QueryBond that matches when the property 'propname' "
"exists in the bond.",
python::return_value_policy<python::manage_new_object>());

python::def("HasIntPropWithValueQueryAtom",
PropQueryWithTol<Atom, QueryAtom, int>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false, python::arg("tolerance") = 0),
"Returns a QueryAtom that matches when the propery 'propname' "
"Returns a QueryAtom that matches when the property 'propname' "
"has the specified int value.",
python::return_value_policy<python::manage_new_object>());

python::def("HasBoolPropWithValueQueryAtom",
PropQuery<Atom, QueryAtom, bool>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false),
"Returns a QueryAtom that matches when the propery 'propname' "
"Returns a QueryAtom that matches when the property 'propname' "
"has the specified boolean"
" value.",
python::return_value_policy<python::manage_new_object>());
Expand All @@ -241,7 +247,7 @@ struct queries_wrapper {
PropQuery<Atom, QueryAtom, std::string>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false),
"Returns a QueryAtom that matches when the propery 'propname' "
"Returns a QueryAtom that matches when the property 'propname' "
"has the specified string "
"value.",
python::return_value_policy<python::manage_new_object>());
Expand All @@ -250,7 +256,7 @@ struct queries_wrapper {
PropQueryWithTol<Atom, QueryAtom, double>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false, python::arg("tolerance") = 0.0),
"Returns a QueryAtom that matches when the propery 'propname' "
"Returns a QueryAtom that matches when the property 'propname' "
"has the specified "
"value +- tolerance",
python::return_value_policy<python::manage_new_object>());
Expand All @@ -259,7 +265,7 @@ struct queries_wrapper {
PropQueryWithTol<Atom, QueryAtom>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false, python::arg("tolerance") = 0),
"Returns a QueryAtom that matches when the propery 'propname' "
"Returns a QueryAtom that matches when the property 'propname' "
"has the specified explicit bit vector"
" value. The Tolerance is the allowed Tanimoto difference",
python::return_value_policy<python::manage_new_object>());
Expand All @@ -268,29 +274,29 @@ struct queries_wrapper {
// Bond Queries
python::def("HasPropQueryBond", HasPropQueryBond,
(python::arg("propname"), python::arg("negate") = false),
"Returns a QueryBond that matches when the propery 'propname' "
"Returns a QueryBond that matches when the property 'propname' "
"exists in the bond.",
python::return_value_policy<python::manage_new_object>());

python::def("HasPropQueryBond", HasPropQueryBond,
(python::arg("propname"), python::arg("negate") = false),
"Returns a QueryBond that matches when the propery 'propname' "
"Returns a QueryBond that matches when the property 'propname' "
"exists in the bond.",
python::return_value_policy<python::manage_new_object>());

python::def("HasIntPropWithValueQueryBond",
PropQueryWithTol<Bond, QueryBond, int>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false, python::arg("tolerance") = 0),
"Returns a QueryBond that matches when the propery 'propname' "
"Returns a QueryBond that matches when the property 'propname' "
"has the specified int value.",
python::return_value_policy<python::manage_new_object>());

python::def("HasBoolPropWithValueQueryBond",
PropQuery<Bond, QueryBond, bool>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false),
"Returns a QueryBond that matches when the propery 'propname' "
"Returns a QueryBond that matches when the property 'propname' "
"has the specified boolean"
" value.",
python::return_value_policy<python::manage_new_object>());
Expand All @@ -299,7 +305,7 @@ struct queries_wrapper {
PropQuery<Bond, QueryBond, std::string>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false),
"Returns a QueryBond that matches when the propery 'propname' "
"Returns a QueryBond that matches when the property 'propname' "
"has the specified string "
"value.",
python::return_value_policy<python::manage_new_object>());
Expand All @@ -308,10 +314,20 @@ struct queries_wrapper {
PropQueryWithTol<Bond, QueryBond, double>,
(python::arg("propname"), python::arg("val"),
python::arg("negate") = false, python::arg("tolerance") = 0.0),
"Returns a QueryBond that matches when the propery 'propname' "
"Returns a QueryBond that matches when the property 'propname' "
"has the specified "
"value +- tolerance",
python::return_value_policy<python::manage_new_object>());

std::string docString = R"DOC(Changes the given atom in the molecule to
a query atom and returns the atom which can then be modified, for example
with additional query constraints added. The new atom is otherwise a copy
of the old.
If the atom already has a query, nothing will be changed.)DOC";
python::def(
"ReplaceAtomWithQueryAtom", replaceAtomWithQueryAtomHelper,
(python::arg("mol"), python::arg("atom")), docString.c_str(),
python::return_value_policy<python::reference_existing_object>());
};
};
} // namespace RDKit
Expand Down
13 changes: 13 additions & 0 deletions Code/GraphMol/Wrap/rough_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3920,6 +3920,19 @@ def testAdjustQueryPropertiesgithubIssue1474(self):
self.assertEqual(ap.GetAtomWithIdx(0).GetPropsAsDict()["foo"], "bar")
self.assertEqual(ap.GetAtomWithIdx(1).GetPropsAsDict()["foo"], "bar")

def testReplaceAtomWithQueryAtom(self):
mol = Chem.MolFromSmiles("CC(C)C")
qmol = Chem.MolFromSmiles("C")
matches = mol.GetSubstructMatches(qmol)
self.assertEqual(((0,), (1,), (2,), (3,)), matches)

atom = qmol.GetAtomWithIdx(0)
natom = rdqueries.ReplaceAtomWithQueryAtom(qmol, atom)
qa = rdqueries.ExplicitDegreeEqualsQueryAtom(3)
natom.ExpandQuery(qa, Chem.CompositeQueryType.COMPOSITE_AND)
matches = mol.GetSubstructMatches(qmol)
self.assertEqual(((1,),), matches)

def testGithubIssue579(self):
fileN = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol', 'FileParsers', 'test_data',
'NCI_aids_few.sdf.gz')
Expand Down