mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
441 lines
17 KiB
C++
441 lines
17 KiB
C++
// $Id$
|
|
//
|
|
// Copyright (C) 2003-2009 Greg Landrum and Rational Discovery LLC
|
|
//
|
|
// @@ All Rights Reserved @@
|
|
// This file is part of the RDKit.
|
|
// The contents are covered by the terms of the BSD license
|
|
// which is included in the file license.txt, found at the root
|
|
// of the RDKit source tree.
|
|
//
|
|
#define NO_IMPORT_ARRAY
|
|
#include <boost/python.hpp>
|
|
#include <string>
|
|
|
|
#include "rdchem.h"
|
|
#include "seqs.hpp"
|
|
// ours
|
|
#include <RDBoost/pyint_api.h>
|
|
#include <GraphMol/RDKitBase.h>
|
|
#include <GraphMol/QueryOps.h>
|
|
#include <GraphMol/MolPickler.h>
|
|
#include <GraphMol/Substruct/SubstructMatch.h>
|
|
#include <boost/python/iterator.hpp>
|
|
#include <boost/python/copy_non_const_reference.hpp>
|
|
|
|
namespace python = boost::python;
|
|
|
|
|
|
namespace RDKit {
|
|
|
|
std::string MolToBinary(const ROMol &self){
|
|
std::string res;
|
|
MolPickler::pickleMol(self,res);
|
|
return res;
|
|
}
|
|
//
|
|
// allows molecules to be pickled.
|
|
// since molecules have a constructor that takes a binary string
|
|
// we only need to provide getinitargs()
|
|
//
|
|
struct mol_pickle_suite : python::pickle_suite
|
|
{
|
|
static python::tuple
|
|
getinitargs(const ROMol& self)
|
|
{
|
|
return python::make_tuple(MolToBinary(self));
|
|
};
|
|
};
|
|
|
|
bool HasSubstructMatchStr(std::string pkl, const ROMol &query,
|
|
bool recursionPossible=true,bool useChirality=false,
|
|
bool useQueryQueryMatches=false){
|
|
ROMol *mol;
|
|
try {
|
|
mol = new ROMol(pkl);
|
|
} catch (...) {
|
|
mol = NULL;
|
|
}
|
|
if(!mol){
|
|
throw ValueErrorException("Null Molecule");
|
|
}
|
|
MatchVectType res;
|
|
bool hasM=SubstructMatch(*mol,query,res,recursionPossible,useChirality,useQueryQueryMatches);
|
|
delete mol;
|
|
return hasM;
|
|
}
|
|
|
|
bool HasSubstructMatch(const ROMol &mol, const ROMol &query,
|
|
bool recursionPossible=true,bool useChirality=false,
|
|
bool useQueryQueryMatches=false){
|
|
MatchVectType res;
|
|
return SubstructMatch(mol,query,res,recursionPossible,useChirality,useQueryQueryMatches);
|
|
}
|
|
|
|
PyObject *convertMatches(MatchVectType &matches){
|
|
PyObject *res = PyTuple_New(matches.size());
|
|
MatchVectType::const_iterator i;
|
|
for(i=matches.begin();i!=matches.end();i++){
|
|
PyTuple_SetItem(res,i->first,PyInt_FromLong(i->second));
|
|
}
|
|
return res;
|
|
}
|
|
PyObject *GetSubstructMatch(const ROMol &mol, const ROMol &query,bool useChirality=false,
|
|
bool useQueryQueryMatches=false){
|
|
MatchVectType matches;
|
|
SubstructMatch(mol,query,matches,true,useChirality,useQueryQueryMatches);
|
|
return convertMatches(matches);
|
|
}
|
|
|
|
PyObject *GetSubstructMatches(const ROMol &mol, const ROMol &query,bool uniquify=true,
|
|
bool useChirality=false,
|
|
bool useQueryQueryMatches=false){
|
|
std::vector< MatchVectType > matches;
|
|
int matched = SubstructMatch(mol,query,matches,uniquify,true,useChirality,useQueryQueryMatches);
|
|
PyObject *res = PyTuple_New(matched);
|
|
for(int idx=0;idx<matched;idx++){
|
|
PyTuple_SetItem(res,idx,convertMatches(matches[idx]));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
unsigned int AddMolConformer(ROMol &mol, Conformer *conf, bool assignId=false) {
|
|
Conformer *nconf = new Conformer(*conf);
|
|
return mol.addConformer(nconf, assignId);
|
|
}
|
|
|
|
Conformer *GetMolConformer(ROMol &mol, int id=-1) {
|
|
return &(mol.getConformer(id));
|
|
}
|
|
|
|
PyObject* GetMolConformers(ROMol &mol) {
|
|
PyObject *res = PyTuple_New(mol.getNumConformers());
|
|
ROMol::ConformerIterator ci;
|
|
unsigned int i = 0;
|
|
for (ci = mol.beginConformers(); ci != mol.endConformers(); ci++) {
|
|
PyTuple_SetItem(res, i, python::converter::shared_ptr_to_python(*ci));
|
|
i++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
std::string MolGetProp(const ROMol &mol,const char *key){
|
|
if(!mol.hasProp(key)){
|
|
PyErr_SetString(PyExc_KeyError,key);
|
|
throw python::error_already_set();
|
|
}
|
|
std::string res;
|
|
mol.getProp(key,res);
|
|
return res;
|
|
}
|
|
|
|
int MolHasProp(const ROMol &mol,const char *key){
|
|
int res = mol.hasProp(key);
|
|
//std::cout << "key: " << key << ": " << res << std::endl;
|
|
return res;
|
|
}
|
|
void MolSetProp(const ROMol &mol,const char *key,std::string val,
|
|
bool computed=false){
|
|
mol.setProp(key, val, computed);
|
|
}
|
|
|
|
void MolClearProp(const ROMol &mol,const char *key) {
|
|
if(!mol.hasProp(key)){
|
|
return;
|
|
}
|
|
mol.clearProp(key);
|
|
}
|
|
|
|
void MolClearComputedProps(const ROMol &mol) {
|
|
mol.clearComputedProps();
|
|
}
|
|
|
|
void MolDebug(const ROMol &mol){
|
|
mol.debugMol(std::cout);
|
|
}
|
|
|
|
// FIX: we should eventually figure out how to do iterators properly
|
|
AtomIterSeq *MolGetAtoms(ROMol *mol){
|
|
AtomIterSeq *res = new AtomIterSeq(mol->beginAtoms(),mol->endAtoms());
|
|
return res;
|
|
}
|
|
QueryAtomIterSeq *MolGetAromaticAtoms(ROMol *mol){
|
|
QueryAtom *qa=new QueryAtom();
|
|
qa->setQuery(makeAtomAromaticQuery());
|
|
QueryAtomIterSeq *res = new QueryAtomIterSeq(mol->beginQueryAtoms(qa),
|
|
mol->endQueryAtoms());
|
|
return res;
|
|
}
|
|
QueryAtomIterSeq *MolGetQueryAtoms(ROMol *mol,QueryAtom *qa){
|
|
QueryAtomIterSeq *res = new QueryAtomIterSeq(mol->beginQueryAtoms(qa),
|
|
mol->endQueryAtoms());
|
|
return res;
|
|
}
|
|
|
|
//AtomIterSeq *MolGetHeteros(ROMol *mol){
|
|
// AtomIterSeq *res = new AtomIterSeq(mol->beginHeteros(),
|
|
// mol->endHeteros());
|
|
// return res;
|
|
//}
|
|
BondIterSeq *MolGetBonds(ROMol *mol){
|
|
BondIterSeq *res = new BondIterSeq(mol->beginBonds(),mol->endBonds());
|
|
return res;
|
|
}
|
|
|
|
int getMolNumAtoms(const ROMol &mol, int onlyHeavy, bool onlyExplicit){
|
|
if(onlyHeavy>-1){
|
|
BOOST_LOG(rdWarningLog)<<"WARNING: the onlyHeavy argument to mol.GetNumAtoms() has been deprecated. Please use the onlyExplicit argument instead or mol.GetNumHeavyAtoms() if you want the heavy atom count."<<std::endl;
|
|
return mol.getNumAtoms(onlyHeavy);
|
|
}
|
|
return mol.getNumAtoms(onlyExplicit);
|
|
}
|
|
|
|
|
|
|
|
std::string molClassDoc = "The Molecule class.\n\n\
|
|
In addition to the expected Atoms and Bonds, molecules contain:\n\
|
|
- a collection of Atom and Bond bookmarks indexed with integers\n\
|
|
that can be used to flag and retrieve particular Atoms or Bonds\n\
|
|
using the {get|set}{Atom|Bond}Bookmark() methods.\n\n\
|
|
- a set of string-valued properties. These can have arbitrary string\n\
|
|
labels and can be set and retrieved using the {set|get}Prop() methods\n\
|
|
Molecular properties can be tagged as being *computed*, in which case\n\
|
|
they will be automatically cleared under certain circumstances (when the\n\
|
|
molecule itself is modified, for example).\n\
|
|
Molecules also have the concept of *private* properties, which are tagged\n\
|
|
by beginning the property name with an underscore (_).\n";
|
|
struct mol_wrapper {
|
|
static void wrap(){
|
|
python::register_exception_translator<ConformerException>(&rdExceptionTranslator);
|
|
|
|
python::class_<ROMol,ROMOL_SPTR,boost::noncopyable>("Mol",
|
|
molClassDoc.c_str(),
|
|
python::init<>("Constructor, takes no arguments"))
|
|
.def(python::init<const std::string &>())
|
|
.def(python::init<const ROMol &>())
|
|
.def("GetNumAtoms",getMolNumAtoms,
|
|
(python::arg("onlyHeavy")=-1,
|
|
python::arg("onlyExplicit")=true),
|
|
"Returns the number of atoms in the molecule.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - onlyExplicit: (optional) include only explicit atoms (atoms in the molecular graph)\n"
|
|
" defaults to 1.\n"
|
|
" NOTE: the onlyHeavy argument is deprecated\n"
|
|
|
|
)
|
|
.def("GetNumHeavyAtoms",&ROMol::getNumHeavyAtoms,
|
|
"Returns the number of heavy atoms (atomic number >1) in the molecule.\n\n"
|
|
)
|
|
.def("GetAtomWithIdx",(Atom * (ROMol::*)(unsigned int))&ROMol::getAtomWithIdx,
|
|
python::return_internal_reference<1,
|
|
python::with_custodian_and_ward_postcall<0,1> >(),
|
|
"Returns a particular Atom.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - idx: which Atom to return\n\n"
|
|
" NOTE: atom indices start at 0\n")
|
|
|
|
.def("GetNumBonds",&ROMol::getNumBonds,
|
|
(python::arg("onlyHeavy")=true),
|
|
"Returns the number of Bonds in the molecule.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - onlyHeavy: (optional) include only bonds to heavy atoms (not Hs)\n"
|
|
" defaults to 1.\n")
|
|
|
|
.def("GetBondWithIdx",(Bond * (ROMol::*)(unsigned int))&ROMol::getBondWithIdx,
|
|
python::return_internal_reference<1,
|
|
python::with_custodian_and_ward_postcall<0,1> >(),
|
|
"Returns a particular Bond.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - idx: which Bond to return\n\n"
|
|
" NOTE: bond indices start at 0\n")
|
|
|
|
.def("GetNumConformers", &ROMol::getNumConformers,
|
|
"Return the number of conformations on the molecule")
|
|
|
|
.def("AddConformer", AddMolConformer,
|
|
(python::arg("self"),python::arg("conf"),
|
|
python::arg("assignId")=false),
|
|
"Add a conformer to the molecule and return the conformer ID")
|
|
|
|
.def("GetConformer", GetMolConformer,
|
|
(python::arg("self"),python::arg("id")=-1),
|
|
"Get the conformer with a specified ID",
|
|
python::return_internal_reference<1,
|
|
python::with_custodian_and_ward_postcall<0,1> >())
|
|
|
|
.def("GetConformers", GetMolConformers,
|
|
"Get all the conformers as a tuple")
|
|
|
|
.def("RemoveAllConformers", &ROMol::clearConformers,
|
|
"Remove all the conformations on the molecule")
|
|
|
|
.def("RemoveConformer", &ROMol::removeConformer,
|
|
"Remove the conformer with the specified ID")
|
|
.def("GetBondBetweenAtoms",
|
|
(Bond *(ROMol::*)(unsigned int,unsigned int))&ROMol::getBondBetweenAtoms,
|
|
python::return_internal_reference<1,
|
|
python::with_custodian_and_ward_postcall<0,1> >(),
|
|
"Returns the bond between two atoms, if there is one.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - idx1,idx2: the Atom indices\n\n"
|
|
" Returns:\n"
|
|
" The Bond between the two atoms, if such a bond exists.\n"
|
|
" If there is no Bond between the atoms, None is returned instead.\n\n"
|
|
" NOTE: bond indices start at 0\n"
|
|
)
|
|
|
|
// substructures
|
|
.def("HasSubstructMatch",HasSubstructMatch,
|
|
(python::arg("self"),python::arg("query"),
|
|
python::arg("recursionPossible")=true,
|
|
python::arg("useChirality")=false,
|
|
python::arg("useQueryQueryMatches")=false),
|
|
"Queries whether or not the molecule contains a particular substructure.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - query: a Molecule\n\n"
|
|
" - recursionPossible: (optional)\n\n"
|
|
" - useChirality: enables the use of stereochemistry in the matching\n\n"
|
|
" - useQueryQueryMatches: use query-query matching logic\n\n"
|
|
" RETURNS: True or False\n")
|
|
.def("GetSubstructMatch",GetSubstructMatch,
|
|
(python::arg("self"),python::arg("query"),
|
|
python::arg("useChirality")=false,
|
|
python::arg("useQueryQueryMatches")=false),
|
|
"Returns the indices of the molecule's atoms that match a substructure query.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - query: a Molecule\n\n"
|
|
" - useChirality: enables the use of stereochemistry in the matching\n\n"
|
|
" - useQueryQueryMatches: use query-query matching logic\n\n"
|
|
" RETURNS: a tuple of integers\n\n"
|
|
" NOTES:\n"
|
|
" - only a single match is returned\n"
|
|
" - the ordering of the indices corresponds to the atom ordering\n"
|
|
" in the query. For example, the first index is for the atom in\n"
|
|
" this molecule that matches the first atom in the query.\n"
|
|
)
|
|
|
|
.def("GetSubstructMatches",
|
|
GetSubstructMatches,
|
|
(python::arg("self"),python::arg("query"),
|
|
python::arg("uniquify")=true,
|
|
python::arg("useChirality")=false,
|
|
python::arg("useQueryQueryMatches")=false),
|
|
"Returns tuples of the indices of the molecule's atoms that match a substructure query.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - query: a Molecule.\n"
|
|
" - uniquify: (optional) determines whether or not the matches are uniquified.\n"
|
|
" Defaults to 1.\n\n"
|
|
" - useChirality: enables the use of stereochemistry in the matching\n\n"
|
|
" - useQueryQueryMatches: use query-query matching logic\n\n"
|
|
" RETURNS: a tuple of tuples of integers\n\n"
|
|
" NOTE:\n"
|
|
" - the ordering of the indices corresponds to the atom ordering\n"
|
|
" in the query. For example, the first index is for the atom in\n"
|
|
" this molecule that matches the first atom in the query.\n")
|
|
|
|
// properties
|
|
.def("SetProp",MolSetProp,
|
|
(python::arg("self"), python::arg("key"),
|
|
python::arg("val"), python::arg("computed")=false),
|
|
"Sets a molecular property\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - key: the name of the property to be set (a string).\n"
|
|
" - value: the property value (a string).\n"
|
|
" - computed: (optional) marks the property as being computed.\n"
|
|
" Defaults to 0.\n\n")
|
|
.def("HasProp",MolHasProp,
|
|
"Queries a molecule to see if a particular property has been assigned.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - key: the name of the property to check for (a string).\n")
|
|
|
|
.def("GetProp",MolGetProp,
|
|
"Returns the value of the property.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - key: the name of the property to return (a string).\n\n"
|
|
" RETURNS: a string\n\n"
|
|
" NOTE:\n"
|
|
" - If the property has not been set, a KeyError exception will be raised.\n")
|
|
|
|
.def("ClearProp", MolClearProp,
|
|
"Removes a property from the molecule.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - key: the name of the property to clear (a string).\n")
|
|
|
|
.def("ClearComputedProps", MolClearComputedProps,
|
|
"Removes all computed properties from the molecule.\n\n")
|
|
|
|
.def("UpdatePropertyCache", &ROMol::updatePropertyCache,
|
|
(python::arg("self"),python::arg("strict")=true),
|
|
"Regenerates computed properties like implicit valence and ring information.\n\n")
|
|
|
|
|
|
.def("GetPropNames",&ROMol::getPropList,
|
|
(python::arg("self"),python::arg("includePrivate")=false,
|
|
python::arg("includeComputed")=false),
|
|
"Returns a tuple with all property names for this molecule.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - includePrivate: (optional) toggles inclusion of private properties in the result set.\n"
|
|
" Defaults to 0.\n"
|
|
" - includeComputed: (optional) toggles inclusion of computed properties in the result set.\n"
|
|
" Defaults to 0.\n\n"
|
|
" RETURNS: a tuple of strings\n")
|
|
|
|
.def("GetAtoms",MolGetAtoms,
|
|
python::return_value_policy<python::manage_new_object,
|
|
python::with_custodian_and_ward_postcall<0,1> >(),
|
|
"Returns a read-only sequence containing all of the molecule's Atoms.\n")
|
|
.def("GetAromaticAtoms",MolGetAromaticAtoms,
|
|
python::return_value_policy<python::manage_new_object,
|
|
python::with_custodian_and_ward_postcall<0,1> >(),
|
|
"Returns a read-only sequence containing all of the molecule's aromatic Atoms.\n")
|
|
.def("GetAtomsMatchingQuery",MolGetQueryAtoms,
|
|
python::return_value_policy<python::manage_new_object,
|
|
python::with_custodian_and_ward_postcall<0,1> >(),
|
|
"Returns a read-only sequence containing all of the atoms in a molecule that match the query atom.\n")
|
|
|
|
.def("GetBonds",MolGetBonds,
|
|
python::return_value_policy<python::manage_new_object,
|
|
python::with_custodian_and_ward_postcall<0,1> >(),
|
|
"Returns a read-only sequence containing all of the molecule's Bonds.\n")
|
|
|
|
// enable pickle support
|
|
.def_pickle(mol_pickle_suite())
|
|
|
|
.def("Debug",MolDebug,
|
|
"Prints debugging information about the molecule.\n")
|
|
|
|
.def("ToBinary",MolToBinary,
|
|
"Returns a binary string representation of the molecule.\n")
|
|
|
|
.def("GetRingInfo",&ROMol::getRingInfo,
|
|
python::return_value_policy<python::reference_existing_object>(),
|
|
"Returns the number of molecule's RingInfo object.\n\n")
|
|
;
|
|
|
|
// ---------------------------------------------------------------------------------------------
|
|
python::def("_HasSubstructMatchStr",
|
|
HasSubstructMatchStr,
|
|
(python::arg("pkl"),python::arg("query"),
|
|
python::arg("recursionPossible")=true,
|
|
python::arg("useChirality")=false,
|
|
python::arg("useQueryQueryMatches")=false
|
|
),
|
|
"This function is included to speed substructure queries from databases, \n"
|
|
"it's probably not of\n"
|
|
"general interest.\n\n"
|
|
" ARGUMENTS:\n"
|
|
" - pkl: a Molecule pickle\n\n"
|
|
" - query: a Molecule\n\n"
|
|
" - recursionPossible: (optional)\n\n"
|
|
" - useChirality: (optional)\n\n"
|
|
" - useQueryQueryMatches: use query-query matching logic\n\n"
|
|
" RETURNS: True or False\n");
|
|
|
|
|
|
};
|
|
};
|
|
}// end of namespace
|
|
void wrap_mol() {
|
|
RDKit::mol_wrapper::wrap();
|
|
}
|