From 5258e90bae113d18bef7d88db90a7442d7190c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Monta=C3=B1ana=20G=C3=B3mez?= Date: Mon, 30 Oct 2023 11:31:11 +0100 Subject: [PATCH] Turn Wrapper to singleton --- src/CMakeLists.txt | 2 +- src/PyClassifier.cc | 21 +++++ src/PyClassifier.h | 19 ++++ src/PyWrap.cc | 219 +++++++++++++++++++++++++++----------------- src/PyWrap.h | 18 +++- src/STree.cc | 10 ++ src/STree.h | 16 ++++ src/SVC.cc | 10 ++ src/SVC.h | 16 ++++ src/main.cc | 10 +- 10 files changed, 249 insertions(+), 92 deletions(-) create mode 100644 src/PyClassifier.cc create mode 100644 src/PyClassifier.h create mode 100644 src/STree.cc create mode 100644 src/STree.h create mode 100644 src/SVC.cc create mode 100644 src/SVC.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 44420fe..33ace1e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ include_directories(${Python3_INCLUDE_DIRS}) -add_executable(main main.cc PyWrap.cc) +add_executable(main main.cc STree.cc SVC.cc PyClassifier.cc PyWrap.cc) target_link_libraries(main ${Python3_LIBRARIES}) diff --git a/src/PyClassifier.cc b/src/PyClassifier.cc new file mode 100644 index 0000000..b72f19b --- /dev/null +++ b/src/PyClassifier.cc @@ -0,0 +1,21 @@ +#include "PyClassifier.h" + +namespace pywrap { + + PyClassifier::PyClassifier(const std::string& module, const std::string& className) : module(module), className(className) + { + pyWrap = PyWrap::GetInstance(); + pyWrap->importClass(module, className); + } + + PyClassifier::~PyClassifier() + { + pyWrap->clean(module, className); + } + + void PyClassifier::callMethod(const std::string& method) + { + pyWrap->callMethod(module, className, method); + } + +} /* namespace PyWrap */ \ No newline at end of file diff --git a/src/PyClassifier.h b/src/PyClassifier.h new file mode 100644 index 0000000..3610033 --- /dev/null +++ b/src/PyClassifier.h @@ -0,0 +1,19 @@ +#ifndef PYCLASSIFER_H +#define PYCLASSIFER_H +#include +#include "PyWrap.h" + +namespace pywrap { + class PyClassifier { + public: + PyClassifier(const std::string& module, const std::string& className); + virtual ~PyClassifier(); + void callMethod(const std::string& method); + private: + PyWrap* pyWrap; + std::string module; + std::string className; + }; + +} /* namespace pywrap */ +#endif /* PYCLASSIFER_H */ \ No newline at end of file diff --git a/src/PyWrap.cc b/src/PyWrap.cc index 5783fb9..c1dd263 100644 --- a/src/PyWrap.cc +++ b/src/PyWrap.cc @@ -5,14 +5,36 @@ #include #include -using namespace std; namespace pywrap { - PyWrap::PyWrap(const std::string& moduleName, const std::string& className) + PyWrap* PyWrap::wrapper = nullptr; + + PyWrap* PyWrap::GetInstance() + { + if (wrapper == nullptr) { + std::cout << "Creando instancia" << std::endl; + wrapper = new PyWrap(); + std::cout << "Instancia creada" << std::endl; + } + return wrapper; + } + + PyWrap::PyWrap() { PyStatus status = initPython(); if (PyStatus_Exception(status)) { throw std::runtime_error("Error initializing Python"); } + + } + + void PyWrap::importClass(const std::string& moduleName, const std::string& className) + { + std::cout << "Importando clase" << std::endl; + auto result = moduleClassMap.find({ moduleName, className }); + if (result != moduleClassMap.end()) { + return; + } + std::cout << "No estaba en el mapa" << std::endl; module = PyImport_ImportModule(moduleName.c_str()); if (PyErr_Occurred()) { errorAbort("Could't import module " + moduleName); @@ -25,105 +47,132 @@ namespace pywrap { if (PyErr_Occurred()) { errorAbort("Couldn't create instance of class " + className); } + moduleClassMap[{moduleName, className}] = { module, classObject, instance }; + std::cout << "Clase importada" << std::endl; } + + void PyWrap::clean(const std::string& moduleName, const std::string& className) + { + std::cout << "Limpiando" << std::endl; + auto result = moduleClassMap.find({ moduleName, className }); + if (result == moduleClassMap.end()) { + return; + } + std::cout << "--> Limpiando" << std::endl; + Py_DECREF(std::get<0>(result->second)); + Py_DECREF(std::get<1>(result->second)); + Py_DECREF(std::get<2>(result->second)); + moduleClassMap.erase(result); + std::cout << "Limpieza terminada" << std::endl; + } + PyWrap::~PyWrap() { - Py_DECREF(instance); - Py_DECREF(classObject); - Py_DECREF(module); + for (const auto& item : moduleClassMap) { + Py_DECREF(std::get<0>(item.second)); + Py_DECREF(std::get<1>(item.second)); + Py_DECREF(std::get<2>(item.second)); + } Py_Finalize(); } - void PyWrap::errorAbort(const string& message) + void PyWrap::errorAbort(const std::string& message) { - cerr << message << endl; + std::cerr << message << std::endl; PyErr_Print(); exit(1); } - void PyWrap::callMethod(const string& method) + void PyWrap::callMethod(const std::string& moduleName, const std::string& className, const std::string& method) { + std::cout << "Llamando método" << std::endl; + auto item = moduleClassMap.find({ moduleName, className }); + if (item == moduleClassMap.end()) { + errorAbort("Module " + moduleName + " and class " + className + " not found"); + } + std::cout << "Clase encontrada" << std::endl; + instance = std::get<2>(item->second); PyObject* result; if (!(result = PyObject_CallMethod(instance, method.c_str(), NULL))) errorAbort("Couldn't call method " + method); - cout << "Result: " << PyUnicode_AsUTF8(result) << endl; + std::cout << "Result: " << PyUnicode_AsUTF8(result) << std::endl; Py_DECREF(result); } - void PyWrap::doCommand2() - { - PyObject* list = Py_BuildValue("[s]", "Stree"); - // PyObject* module = PyImport_ImportModuleEx("stree", NULL, NULL, list); - PyObject* module = PyImport_ImportModule("stree"); - if (PyErr_Occurred()) { - PyErr_Print(); - cout << "Fails to obtain the module.\n"; - return; - } - cout << "Antes de empezar" << endl; - if (module != nullptr) { - cout << "Lo consiguió!!!" << endl; - // dict is a borrowed reference. - auto pdict = PyModule_GetDict(module); - if (pdict == nullptr) { - cout << "Fails to get the dictionary.\n"; - return; - } - Py_DECREF(module); - PyObject* pKeys = PyDict_Keys(pdict); - PyObject* pValues = PyDict_Values(pdict); - map my_map; - cout << "size: " << PyDict_Size(pdict) << endl; - char* cstr_key = new char[100]; - char* cstr_value = new char[500]; - for (Py_ssize_t i = 0; i < PyDict_Size(pdict); ++i) { - PyArg_Parse(PyList_GetItem(pKeys, i), "s", &cstr_key); - PyArg_Parse(PyList_GetItem(pValues, i), "s", &cstr_value); - //cout << cstr<< " "<< cstr2 < my_map; + // cout << "size: " << PyDict_Size(pdict) << endl; + // char* cstr_key = new char[100]; + // char* cstr_value = new char[500]; + // for (Py_ssize_t i = 0; i < PyDict_Size(pdict); ++i) { + // PyArg_Parse(PyList_GetItem(pKeys, i), "s", &cstr_key); + // PyArg_Parse(PyList_GetItem(pValues, i), "s", &cstr_value); + // //cout << cstr<< " "<< cstr2 < #include +#include +#include namespace pywrap { + /* + Singleton class to handle Python interpreter. + */ class PyWrap { public: - PyWrap(const std::string& moduleName, const std::string& className); + PyWrap(PyWrap& other) = delete; + static PyWrap* GetInstance(); + void operator=(const PyWrap&) = delete; ~PyWrap(); - void callMethod(const std::string& method); - void doCommand2(); + void callMethod(const std::string& moduleName, const std::string& className, const std::string& method); + void importClass(const std::string& moduleName, const std::string& className); + void clean(const std::string& moduleName, const std::string& className); + // void doCommand2(); private: + PyWrap(); void errorAbort(const std::string& message); PyStatus initPython(); + static PyWrap* wrapper; + std::map, std::tuple> moduleClassMap; PyObject* module; PyObject* classObject; PyObject* instance; diff --git a/src/STree.cc b/src/STree.cc new file mode 100644 index 0000000..3db97a7 --- /dev/null +++ b/src/STree.cc @@ -0,0 +1,10 @@ +#include "STree.h" + +namespace pywrap { + + void STree::version() + { + callMethod("version"); + } + +} /* namespace pywrap */ \ No newline at end of file diff --git a/src/STree.h b/src/STree.h new file mode 100644 index 0000000..3484555 --- /dev/null +++ b/src/STree.h @@ -0,0 +1,16 @@ +#ifndef STREE_H +#define STREE_H +#include "PyClassifier.h" + +namespace pywrap { + class STree : public PyClassifier { + public: + STree() : PyClassifier("stree", "Stree") {}; + ~STree() = default; + void version(); + private: + + }; + +} /* namespace pywrap */ +#endif /* STREE_H */ \ No newline at end of file diff --git a/src/SVC.cc b/src/SVC.cc new file mode 100644 index 0000000..2d9dcb9 --- /dev/null +++ b/src/SVC.cc @@ -0,0 +1,10 @@ +#include "SVC.h" + +namespace pywrap { + + void SVC::version() + { + callMethod("_repr_html_"); + } + +} /* namespace pywrap */ \ No newline at end of file diff --git a/src/SVC.h b/src/SVC.h new file mode 100644 index 0000000..e58d615 --- /dev/null +++ b/src/SVC.h @@ -0,0 +1,16 @@ +#ifndef SVC_H +#define SVC_H +#include "PyClassifier.h" + +namespace pywrap { + class SVC : public PyClassifier { + public: + SVC() : PyClassifier("sklearn.svm", "SVC") {}; + ~SVC() = default; + void version(); + private: + + }; + +} /* namespace pywrap */ +#endif /* STREE_H */ \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index 49ff087..37e33a1 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,10 +1,14 @@ -#include "PyWrap.h" +#include "STree.h" +#include "SVC.h" int main(int argc, char* argv[]) { // auto wrap = pywrap::PyWrap("stree", "Stree"); // wrap.callMethod("version"); - auto wrap2 = pywrap::PyWrap("sklearn.svm", "SVC"); - wrap2.callMethod("_repr_html_"); + auto stree = pywrap::STree(); + stree.version(); + auto svc = pywrap::SVC(); + svc.version(); + stree.version(); return 0; } \ No newline at end of file