// $Id$ // // Copyright (C) 2003-2006 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 PY_ARRAY_UNIQUE_SYMBOL rdchem_array_API #include #include "rdchem.h" #include #include #include #include #ifdef RDK_THREADSAFE_SSS // Thread local storage for output buffer for RDKit Logging #include #endif #include #include #include "seqs.hpp" namespace python = boost::python; using namespace RDKit; namespace RDKit { void tossit() { throw IndexErrorException(1); } } void rdExceptionTranslator(RDKit::ConformerException const &x) { RDUNUSED_PARAM(x); PyErr_SetString(PyExc_ValueError, "Bad Conformer Id"); } void rdSanitExceptionTranslator(RDKit::MolSanitizeException const &x) { std::ostringstream ss; ss << "Sanitization error: " << x.message(); PyErr_SetString(PyExc_ValueError, ss.str().c_str()); } void wrap_table(); void wrap_atom(); void wrap_conformer(); void wrap_bond(); void wrap_mol(); void wrap_ringinfo(); void wrap_EditableMol(); void wrap_monomerinfo(); void wrap_resmolsupplier(); void wrap_molbundle(); struct PySysErrWrite : std::ostream, std::streambuf { std::string prefix; PySysErrWrite(std::string prefix) : std::ostream(this), prefix(std::move(prefix)) {} int overflow(int c) override { write(c); return 0; } #ifdef RDK_THREADSAFE_SSS void write(char c) { // enable thread safe logging static thread_local std::string buffer = ""; buffer += c; if (c == '\n') { // Python IO is not thread safe, so grab the GIL PyGILState_STATE gstate; gstate = PyGILState_Ensure(); PySys_WriteStderr("%s", (prefix + buffer).c_str()); PyGILState_Release(gstate); buffer.clear(); } } #else std::string buffer; // unlimited! flushes in endl void write(char c) { buffer += c; if (c == '\n') { PySys_WriteStderr("%s", (prefix + buffer).c_str()); buffer.clear(); } } #endif }; void RDLogError(const std::string &msg) { NOGIL gil; BOOST_LOG(rdErrorLog) << msg.c_str() << std::endl; } void RDLogWarning(const std::string &msg) { NOGIL gil; BOOST_LOG(rdWarningLog) << msg.c_str() << std::endl; } void WrapLogs() { static PySysErrWrite debug("RDKit DEBUG: "); static PySysErrWrite error("RDKit ERROR: "); static PySysErrWrite info("RDKit INFO: "); static PySysErrWrite warning("RDKit WARNING: "); if (rdDebugLog == nullptr || rdInfoLog == nullptr || rdErrorLog == nullptr || rdWarningLog == nullptr) { RDLog::InitLogs(); } if (rdDebugLog != nullptr) rdDebugLog->SetTee(debug); if (rdInfoLog != nullptr) rdInfoLog->SetTee(info); if (rdErrorLog != nullptr) rdErrorLog->SetTee(error); if (rdWarningLog != nullptr) rdWarningLog->SetTee(warning); } BOOST_PYTHON_MODULE(rdchem) { python::scope().attr("__doc__") = "Module containing the core chemistry functionality of the RDKit"; RegisterListConverter(); RegisterListConverter(); rdkit_import_array(); python::register_exception_translator( &rdSanitExceptionTranslator); python::def("WrapLogs", WrapLogs, "Wrap the internal RDKit streams so they go to python's " "SysStdErr"); python::def("LogWarningMsg", RDLogWarning, "Log a warning message to the RDKit warning logs"); python::def("LogErrorMsg", RDLogError, "Log a warning message to the RDKit error logs"); //********************************************* // // Utility Classes // //********************************************* python::class_( "_ROAtomSeq", "Read-only sequence of atoms, not constructable from Python.", python::no_init) .def("__iter__", &AtomIterSeq::__iter__, python::return_internal_reference< 1, python::with_custodian_and_ward_postcall<0, 1>>()) .def(NEXT_METHOD, &AtomIterSeq::next, python::return_value_policy()) .def("__len__", &AtomIterSeq::len) .def("__getitem__", &AtomIterSeq::get_item, python::return_value_policy()); python::class_("_ROQAtomSeq", "Read-only sequence of atoms matching a " "query, not constructable from Python.", python::no_init) .def("__iter__", &QueryAtomIterSeq::__iter__, python::return_internal_reference< 1, python::with_custodian_and_ward_postcall<0, 1>>()) .def(NEXT_METHOD, &QueryAtomIterSeq::next, python::return_value_policy()) .def("__len__", &QueryAtomIterSeq::len) .def("__getitem__", &QueryAtomIterSeq::get_item, python::return_value_policy()); python::class_( "_ROBondSeq", "Read-only sequence of bonds, not constructable from Python.", python::no_init) // FIX: we ought to be able to expose an iteration interface .def("__len__", &BondIterSeq::len) .def("__getitem__", &BondIterSeq::get_item, python::return_value_policy()); //********************************************* // // Classes // //********************************************* wrap_table(); wrap_atom(); wrap_conformer(); wrap_bond(); wrap_mol(); wrap_EditableMol(); wrap_ringinfo(); wrap_monomerinfo(); wrap_resmolsupplier(); wrap_molbundle(); //********************************************* // // Functions // //********************************************* std::string docString; python::def("tossit", tossit); }