/*===========================================================================*\ * * * OpenFlipper * * Copyright (c) 2001-2015, RWTH-Aachen University * * Department of Computer Graphics and Multimedia * * All rights reserved. * * www.openflipper.org * * * *---------------------------------------------------------------------------* * This file is part of OpenFlipper. * *---------------------------------------------------------------------------* * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * * * 1. Redistributions of source code must retain the above copyright notice, * * this list of conditions and the following disclaimer. * * * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * * * 3. Neither the name of the copyright holder nor the names of its * * contributors may be used to endorse or promote products derived from * * this software without specific prior written permission. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * \*===========================================================================*/ #include #include #include "PyLogHook.h" #include "PythonInterpreter.hh" #include #include namespace py = pybind11; static Core* core_; static pybind11::module mainModule_; static PythonInterpreter* interpreter_ = nullptr; /** \brief Stores a clean dictionary for interpreter reset * */ static PyObject* global_dict_clean_ = nullptr; void setCorePointer( Core* _core ) { core_ = _core; } PythonInterpreter* PythonInterpreter::getInstance() { if (interpreter_ == nullptr) { interpreter_ = new PythonInterpreter(); } return interpreter_; } PythonInterpreter::PythonInterpreter() { } PythonInterpreter::~PythonInterpreter() { } bool PythonInterpreter::modulesInitialized() { ///@TODO: Why does this work? return static_cast(mainModule_); } void PythonInterpreter::initPython() { if (Py_IsInitialized() ) return; std::cerr << "A" << std::endl; py::initialize_interpreter(); std::cerr << "B" << std::endl; PyEval_InitThreads(); std::cerr << "C" << std::endl; if (!modulesInitialized()) { std::cerr << "D" << std::endl; //dlopen("libpython3.5m.so.1.0", RTLD_LAZY | RTLD_GLOBAL); py::module main{ py::module::import("__main__") }; // redirect python output tyti::pylog::redirect_stderr([this](const char*w) {this->pyError(w); }); tyti::pylog::redirect_stdout([this](const char* w) {this->pyOutput(w); }); std::cerr << "E" << std::endl; // add openflipper module py::object main_namespace = main.attr("__dict__"); std::cerr << "F" << std::endl; py::module of_module(py::module::import("openflipper")); main_namespace["openflipper"] = of_module; std::cerr << "G" << std::endl; global_dict_clean_ = PyDict_Copy(PyModule_GetDict(main.ptr())); std::cerr << "H" << std::endl; // set the main module member to a validate state, shows, that all modules are successfully initialized mainModule_ = std::move(main); std::cerr << "I" << std::endl; // Do not release the GIL until all modules are initalzed PyEval_SaveThread(); std::cerr << "J" << std::endl; } } void PythonInterpreter::resetInterpreter() { if (!Py_IsInitialized() || !modulesInitialized()) return; PyGILState_STATE state = PyGILState_Ensure(); PyObject* dict = PyModule_GetDict(mainModule_.ptr()); PyDict_Clear(dict); PyDict_Update(dict, global_dict_clean_); PyGILState_Release(state); } bool PythonInterpreter::runScript(QString _script) { std::cerr << "runScript" << std::endl; // init try { std::cerr << "Run Init Python" << std::endl; initPython(); std::cerr << ".. Done" << std::endl; } catch (py::error_already_set &e) { pyError(e.what()); return false; } PyGILState_STATE state = PyGILState_Ensure(); PyThreadState* tstate = PyGILState_GetThisThreadState(); auto locals = mainModule_.attr("__dict__"); bool result = true; try { std::cerr << "Now executing script:" << std::endl; std::cerr << _script.toStdString() << std::endl; py::exec((const char*)_script.toLatin1(), py::globals(), locals); std::cerr << "Finished successfully" << std::endl; } catch (py::error_already_set &e) { pyError(e.what()); e.restore(); result = false; } catch (const std::runtime_error &e) { pyError(e.what()); pyOutput("Restarting Interpreter."); resetInterpreter(); result = false; state = PyGILState_Ensure(); } PyGILState_Release(state); return result; } // Python callback functions void PythonInterpreter::pyOutput(const char* w) { std::cerr << "Python output:\n " << w << std::endl; Q_EMIT log(LOGOUT, QString(w)); } void PythonInterpreter::pyError(const char* w) { std::cerr << "Python error:\n " << w << std::endl; Q_EMIT log(LOGERR, QString(w)); } //import openflipper // //a = openflipper.core() // //a.updateView() //print("AAAAAAAAAAAA") //a = openflipper.core() // //print("BBBBBBBBBB") //a.updateView() //print("CCCCCCCCCc") namespace pybind11 { namespace detail { template <> struct type_caster { public: /** * This macro establishes the name 'str' in * function signatures and declares a local variable * 'value' of type QVariant */ PYBIND11_TYPE_CASTER(QString, _("str")); /** * Conversion part 1 (Python->C++): convert a PyObject into a inty * instance or return false upon failure. The second argument * indicates whether implicit conversions should be applied. */ bool load(handle src, bool ) { /* Extract PyObject from handle */ PyObject *source = src.ptr(); if (!PyUnicode_Check(source)) return false; long int size; char *ptr = PyUnicode_AsUTF8AndSize(source, &size); if (!ptr) { return NULL; } /* Now try to convert into a C++ int */ value = QString::fromUtf8(ptr, size); /* Ensure return code was OK (to avoid out-of-range errors etc) */ return ( !PyErr_Occurred() ); } /** * Conversion part 2 (C++ -> Python): convert an QVariant instance into * a Python object. The second and third arguments are used to * indicate the return value policy and parent object (for * ``return_value_policy::reference_internal``) and are generally * ignored by implicit casters. */ static handle cast(QString src, return_value_policy /* policy */, handle /* parent */) { return (PyUnicode_FromString( src.toUtf8().data()) ); } }; }} // namespace pybind11::detail PYBIND11_EMBEDDED_MODULE(openflipper, m) { // Export our core. Make sure that the c++ worlds core objet is not deleted if // the python side gets deleted!! py::class_> core(m, "core"); // On the c++ side we will just return the existing core instance // and prevent the system to recreate a new core as we need // to work on the existing one. core.def(py::init([]() { return core_; })); core.def("updateView", &Core::updateView); core.def("clearAll", &Core::clearAll); core.def("writeVersionNumbers", &Core::writeVersionNumbers); std::cerr << "CorePointer : " << core_ << std::endl;; }