13 #include <pybind11/embed.h>
15 #include <QApplication>
16 #include <QCoreApplication>
18 #include <QListWidgetItem>
19 #include <QMessageBox>
40 globals[
"__name__"] =
"__main__";
42 globals[
"__builtins__"] = PyEval_GetBuiltins();
63 const auto movePolicy = py::return_value_policy::move;
69 globals[
"__file__"] = filepath;
70 py::eval_file(filepath, globals);
72 catch (
const std::exception &e)
82 template <pybind11::eval_mode mode>
83 void PythonInterpreter::executeCodeString(
const std::string &code,
94 const QColor
orange(255, 100, 0);
98 if (output !=
nullptr)
100 const auto movePolicy = py::return_value_policy::move;
104 py::eval<mode>(code, state.globals, state.locals);
109 py::eval<mode>(code, state.globals, state.locals);
112 catch (
const std::exception &e)
116 auto message =
new QListWidgetItem(e.what());
117 message->setForeground(
Qt::red);
118 output->addItem(message);
126 m_isExecuting =
false;
134 executeCodeString<py::eval_mode::eval_statements>(code, output, state);
141 executeCodeString<py::eval_mode::eval_single_statement>(code, output, state);
157 m_isExecuting =
true;
161 py::gil_scoped_acquire scopedGil;
165 catch (
const std::exception &e)
167 CVLog::Error(
"Failed to start Python actions: %s", e.what());
169 m_isExecuting =
false;
184 const auto displaydlopenError = []()
186 char *
error = dlerror();
193 QDir appDir = QCoreApplication::applicationDirPath();
194 QString libDirPath = QString(
"%1/lib").arg(appDir.absolutePath());
195 QDir libDir(libDirPath);
203 libDir.setNameFilters(filters);
204 QStringList fileList = libDir.entryList(QDir::Files);
205 if (!fileList.isEmpty())
207 QString soFilePath = QString(
"%1/%2").arg(libDirPath, fileList.first());
212 if (!m_libPythonHandle)
214 displaydlopenError();
217 "libpython%d.%dm.so*",
222 libDir.setNameFilters(filters);
223 fileList = libDir.entryList(QDir::Files);
224 if (!fileList.isEmpty())
226 QString soFilePath = QString(
"%1/%2").arg(libDirPath, fileList.first());
231 if (!m_libPythonHandle)
233 displaydlopenError();
248 m_config =
config.pythonCompatiblePaths();
252 PyConfig_InitPythonConfig(&pyConfig);
253 pyConfig.isolated = 1;
255 status = PyConfig_SetString(&pyConfig, &pyConfig.home, m_config.
pythonHome());
256 if (PyStatus_Exception(status))
258 PyConfig_Clear(&pyConfig);
259 throw std::runtime_error(status.err_msg);
262 status = PyConfig_SetString(&pyConfig, &pyConfig.pythonpath_env, m_config.
pythonPath());
263 if (PyStatus_Exception(status))
265 PyConfig_Clear(&pyConfig);
266 throw std::runtime_error(status.err_msg);
269 status = PyConfig_Read(&pyConfig);
270 if (PyStatus_Exception(status))
272 PyConfig_Clear(&pyConfig);
273 throw std::runtime_error(status.err_msg);
276 status = Py_InitializeFromConfig(&pyConfig);
277 if (PyStatus_Exception(status))
279 PyConfig_Clear(&pyConfig);
280 throw std::runtime_error(status.err_msg);
290 py::module::import(
"ccinternals");
295 return Py_IsInitialized();
300 if (Py_IsInitialized())
302 py::finalize_interpreter();
304 if (m_libPythonHandle)
306 dlclose(m_libPythonHandle);
307 m_libPythonHandle =
nullptr;
317 return m_isExecuting;
constexpr Version PythonVersion(PY_MAJOR_VERSION, PY_MINOR_VERSION, PY_MICRO_VERSION)
Python Version the plugin was compiled against.
static py::dict CreateGlobals()
PluginLogger< CVLog::LOG_WARNING > plgWarning
PluginLogger< CVLog::LOG_STANDARD > plgPrint
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
const wchar_t * pythonPath() const
Returns the pythonPath.
const wchar_t * pythonHome() const
Returns the pythonHome.
void executeCode(const std::string &code, QListWidget *output)
void executeFunction(const pybind11::object &function)
void executeCodeWithState(const std::string &code, QListWidget *output, PythonInterpreter::State &state)
const PythonConfigPaths & config() const
PythonInterpreter(QObject *parent=nullptr)
static bool IsInitialized()
bool executeFile(const std::string &filePath)
Execution functions (and slots)
void executeStatementWithState(const std::string &code, QListWidget *output, PythonInterpreter::State &state)
void initialize(const PythonConfig &config)
Redirects messages to ACloudViewer's console output.
static void error(char *msg)
constexpr Rgb red(MAX, 0, 0)
constexpr Rgb orange(MAX, MAX/2, 0)