From a3fbd2877b2174fff2094151d0eca038f99e3a0c Mon Sep 17 00:00:00 2001 From: Carl Philipp Klemm Date: Mon, 13 Oct 2025 16:45:50 +0200 Subject: [PATCH] cpython attempt --- CMakeLists.txt | 20 ++++++++++--- pythonembed.cpp | 80 +++++++++++++++++++++++++++++-------------------- pythonembed.h | 10 ++----- 3 files changed, 66 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32b9cc7..9914ced 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,20 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(EISMULIPLEXER REQUIRED eismuliplexer) find_package(Qt6 REQUIRED COMPONENTS Widgets) find_package(Qt6 REQUIRED COMPONENTS Core) -# find_package(Python3 REQUIRED) - Removed since we're using QProcess instead of embedding Python +find_package(Python3 REQUIRED) + +# Manually set Python include directory if not found +if(NOT Python3_INCLUDE_DIRS) + execute_process(COMMAND python3 -c "import sysconfig; print(sysconfig.get_paths()['include'])" + OUTPUT_VARIABLE PYTHON_INCLUDE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(Python3_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") +endif() + +# Manually set Python libraries if not found +if(NOT Python3_LIBRARIES) + set(Python3_LIBRARIES python3.12) +endif() set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) @@ -53,9 +66,8 @@ add_executable(${PROJECT_NAME} set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE ON) target_compile_options(${PROJECT_NAME} PUBLIC "-Wall") target_include_directories(${PROJECT_NAME} PUBLIC QCodeEditor) -# target_include_directories(${PROJECT_NAME} PRIVATE ${Python3_INCLUDE_DIRS}) - Removed since we're using QProcess instead of embedding Python -target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Core ${EISMULIPLEXER_LIBRARIES} QCodeEditor) -# ${Python3_LIBRARIES} - Removed since we're using QProcess instead of embedding Python +target_include_directories(${PROJECT_NAME} PRIVATE ${Python3_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Core ${EISMULIPLEXER_LIBRARIES} QCodeEditor ${Python3_LIBRARIES}) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/resources/eismultiplexerqt.png PROPERTIES QT_RESOURCE_ALIAS eismultiplexerqt.png) qt_add_resources(${PROJECT_NAME} "resources" PREFIX "/" FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/eismultiplexerqt.png ) install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/pythonembed.cpp b/pythonembed.cpp index f6df212..fa2c0c1 100644 --- a/pythonembed.cpp +++ b/pythonembed.cpp @@ -1,59 +1,73 @@ #include "pythonembed.h" +#include #include PythonEmbed::PythonEmbed(QTextEdit* outputWidget, QObject* parent) - : QObject(parent), m_outputWidget(outputWidget), m_process(nullptr) { - m_process = new QProcess(this); - connect(m_process, &QProcess::readyReadStandardOutput, this, &PythonEmbed::onOutputAvailable); - connect(m_process, &QProcess::readyReadStandardError, this, &PythonEmbed::onErrorAvailable); - connect(m_process, QOverload::of(&QProcess::finished), this, &PythonEmbed::onProcessFinished); + : QObject(parent), m_outputWidget(outputWidget) { + // Initialize Python + Py_Initialize(); + + m_initialized = true; + + // Initialize the output widget with Python prompt + m_outputWidget->clear(); + m_outputWidget->append("Python 3.11.2 (main, Oct 5 2023, 17:20:59) [GCC 11.4.0] on linux\n"); + m_outputWidget->append("Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\n"); + m_outputWidget->append(">>> "); } PythonEmbed::~PythonEmbed() { - if (m_process) { - m_process->terminate(); - m_process->waitForFinished(1000); + if (m_initialized) { + Py_Finalize(); } } void PythonEmbed::runScript(const QString& scriptContent) { - if (m_process->state() == QProcess::Running) { - m_process->terminate(); - m_process->waitForFinished(1000); + if (!m_initialized) { + m_outputWidget->append("Python not initialized\n"); + return; } - m_outputWidget->clear(); - m_outputWidget->append("Python 3.11.2 (main, Oct 5 2023, 17:20:59) [GCC 11.4.0] on linux\n"); - m_outputWidget->append("Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\n"); + // Convert QString to const char* + QByteArray scriptBytes = scriptContent.toUtf8(); + const char* script = scriptBytes.constData(); - m_process->start("python3", QStringList() << "-c" << scriptContent); + // Run the script + PyRun_SimpleString(script); + + // Check for any errors + if (PyErr_Occurred()) { + handlePythonError("Script execution error"); + } else { + m_outputWidget->append("\n>>> "); + } } void PythonEmbed::stopScript() { - if (m_process && m_process->state() == QProcess::Running) { - m_process->terminate(); - } + // In this simple implementation, we don't have a running Python thread + // to stop, but we could add that functionality later } -void PythonEmbed::onOutputAvailable() { - QByteArray output = m_process->readAllStandardOutput(); - m_outputWidget->append(output); - m_outputWidget->moveCursor(QTextCursor::End); -} +void PythonEmbed::handlePythonError(const char* context) { + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + if (type) { + PyObject *str = PyObject_Str(value); + PyObject *bytes = PyUnicode_AsEncodedString(str, "utf-8", "strict"); + const char *error_msg = PyBytes_AS_STRING(bytes); -void PythonEmbed::onErrorAvailable() { - QByteArray error = m_process->readAllStandardError(); - m_outputWidget->append(error); - m_outputWidget->moveCursor(QTextCursor::End); -} + QString errorString = QString::fromUtf8(context) + ": " + QString::fromUtf8(error_msg); + m_outputWidget->append(errorString); -void PythonEmbed::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { - if (exitStatus == QProcess::NormalExit && exitCode != 0) { - m_outputWidget->append(QString("Process exited with code %1\n").arg(exitCode)); - } else if (exitStatus == QProcess::CrashExit) { - m_outputWidget->append("Python process crashed\n"); + Py_DecRef(str); + Py_DecRef(bytes); + Py_DecRef(type); + Py_DecRef(value); + Py_DecRef(traceback); + } else { + m_outputWidget->append(QString::fromUtf8(context) + ": No error information available"); } } diff --git a/pythonembed.h b/pythonembed.h index b48bded..ef272bb 100644 --- a/pythonembed.h +++ b/pythonembed.h @@ -4,7 +4,6 @@ #define PYTHONEMBED_H #include -#include #include class PythonEmbed : public QObject { @@ -17,14 +16,11 @@ public: void runScript(const QString& scriptContent); void stopScript(); -private slots: - void onOutputAvailable(); - void onErrorAvailable(); - void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); - private: + void handlePythonError(const char* context); + QTextEdit* m_outputWidget; - QProcess* m_process; + bool m_initialized = false; }; #endif // PYTHONEMBED_H