#include "pythonrunner.h" #include #include #include #include PythonRunner::PythonRunner(QTextEdit* outputWidget, QObject* parent) : QObject(parent), m_outputWidget(outputWidget), m_process(nullptr), m_venvProcess(nullptr), venvReady(false) { m_process = new QProcess(this); connect(m_process, &QProcess::readyReadStandardOutput, this, &PythonRunner::onOutputAvailable); connect(m_process, &QProcess::readyReadStandardError, this, &PythonRunner::onErrorAvailable); connect(m_process, QOverload::of(&QProcess::finished), this, &PythonRunner::onProcessFinished); // Start venv setup in background QThread::create([this]() { setupVenv(); }); } PythonRunner::~PythonRunner() { if (m_process) { m_process->terminate(); m_process->waitForFinished(1000); } if (m_venvProcess) { m_venvProcess->terminate(); m_venvProcess->waitForFinished(1000); } } QString PythonRunner::venvPath() { return dir.path() + QDir::separator() + "venv"; } QString PythonRunner::pythonExePath() { QString venv = venvPath(); #ifdef Q_OS_WIN return venv + "\\Scripts\\python.exe"; #else return venv + "/bin/python"; #endif } void PythonRunner::ensureVenvReady() { QMutexLocker locker(&venvMutex); if (!venvReady) { venvCondition.wait(&venvMutex); } } void PythonRunner::setupVenv() { QString venv = venvPath(); QString pythonCmd = "python3"; #ifdef Q_OS_WIN pythonCmd = "python"; #endif // Check if venv already exists QDir venvDir(venv); if (venvDir.exists()) { venvReady = true; emit venvSetupProgress("Virtual environment already exists"); return; } // Create virtual environment emit venvSetupProgress("Creating virtual environment..."); m_venvProcess = new QProcess(); connect(m_venvProcess, QOverload::of(&QProcess::finished), this, &PythonRunner::onVenvProcessFinished); QStringList args; #ifdef Q_OS_WIN args << "-m" << "venv" << "venv"; #else args << "-m" << "venv" << venv; #endif m_venvProcess->setWorkingDirectory(dir.path()); m_venvProcess->start(pythonCmd, args); if (!m_venvProcess->waitForStarted()) { emit venvSetupProgress("Failed to start venv creation process"); venvReady = false; m_venvProcess->deleteLater(); m_venvProcess = nullptr; } } void PythonRunner::onVenvProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitStatus == QProcess::NormalExit && exitCode == 0) { // Install eismultiplexer package emit venvSetupProgress("Installing eismultiplexer package..."); QProcess installProcess; installProcess.setWorkingDirectory(dir.path()); QStringList installArgs; installArgs << "-m" << "pip" << "install" << "eismultiplexer"; installProcess.start(pythonExePath(), installArgs); if (!installProcess.waitForFinished(30000)) { // 30 second timeout emit venvSetupProgress("Package installation timed out"); venvReady = false; } else { QByteArray output = installProcess.readAllStandardOutput(); QByteArray error = installProcess.readAllStandardError(); if (!error.isEmpty()) { emit venvSetupProgress("Installation error: " + QString::fromLocal8Bit(error)); venvReady = false; } else { emit venvSetupProgress("Package installed successfully"); venvReady = true; } } } else { emit venvSetupProgress(QString("Virtual environment creation failed with code %1").arg(exitCode)); venvReady = false; } // Clean up m_venvProcess->deleteLater(); m_venvProcess = nullptr; } bool PythonRunner::runScript(const QString& scriptContent) { if (m_process->state() == QProcess::Running) { m_process->terminate(); m_process->waitForFinished(1000); } m_outputWidget->clear(); // Check if venv is ready if (!venvReady) { m_outputWidget->append("Error: Virtual environment not ready. Please wait for the setup to complete.\n"); emit scriptFinished(-1); return false; } m_outputWidget->append("Running script in virtual environment...\n"); QString pythonPath = pythonExePath(); m_process->start(pythonPath, QStringList() << "-u" << "-c" << scriptContent); return true; } void PythonRunner::stopScript() { if (m_process && m_process->state() == QProcess::Running) { m_process->terminate(); } } void PythonRunner::onOutputAvailable() { QByteArray output = m_process->readAllStandardOutput(); m_outputWidget->append(output); m_outputWidget->moveCursor(QTextCursor::End); } void PythonRunner::onErrorAvailable() { QByteArray error = m_process->readAllStandardError(); m_outputWidget->append(error); m_outputWidget->moveCursor(QTextCursor::End); } void PythonRunner::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 was stopped\n"); } emit scriptFinished(exitCode); } void PythonRunner::onVenvSetupFinished() { // This slot can be used to handle venv setup completion if needed }