From dd66faff459f74f9bbe74b322d544cb611de8c70 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby <pierre-antoine.rouby@inrae.fr> Date: Mon, 19 Jun 2023 16:48:38 +0200 Subject: [PATCH] SolverLog: Working solver start. --- src/Solver/ASolver.py | 85 +++++++++++++++++++++++++++++++++--- src/Solver/Mage.py | 2 + src/View/RunSolver/Window.py | 30 ++++++++++--- 3 files changed, 104 insertions(+), 13 deletions(-) diff --git a/src/Solver/ASolver.py b/src/Solver/ASolver.py index ba1e511e..78eb87d5 100644 --- a/src/Solver/ASolver.py +++ b/src/Solver/ASolver.py @@ -1,23 +1,28 @@ # -*- coding: utf-8 -*- import os -import subprocess + +from signal import SIGTERM, SIGSTOP, SIGCONT +from subprocess import Popen, PIPE, STDOUT, TimeoutExpired from enum import Enum from Model.Except import NotImplementedMethodeError class STATUS(Enum): + NOT_LAUNCHED = -1 STOPED = 0 RUNNING = 1 FAILED = 2 CONF_ERROR = 3 + KILLED = 4 + PAUSED = 5 class AbstractSolver(object): def __init__(self, name): super(AbstractSolver, self).__init__() self._current_process = None - self._status = STATUS.STOPED + self._status = STATUS.NOT_LAUNCHED # Informations self._type = "" @@ -32,6 +37,9 @@ class AbstractSolver(object): self._cmd_solver = "" self._cmd_output = "" + self._process = None + self._output = None + def __str__(self): return f"{self._name} : {self._type} : {self._description}" @@ -117,16 +125,79 @@ class AbstractSolver(object): if self._cmd_solver == "": return True - return False + cmd = self._cmd_solver + cmd = cmd.replace("@path", self._path_solver).split() + + exe = cmd[0] + args = cmd[1:] + + self._process.start( + exe, args, + ) + self._process.readyRead.connect(self._data_ready) - def run_output_data_fomater(self, ): + return True + + def run_output_data_fomater(self): if self._cmd_output == "": return True return False + def _data_ready(self): + s = self._process.readAll().data().decode() + if self._output is not None: + self._output.put(s) + + def run(self, process, output_queue): + self._process = process + self._output = output_queue + + if self.run_input_data_fomater(): + if self.run_solver(): + return self.run_output_data_fomater() + def kill(self): - return False + if self._process is None: + return True - def readline(self): - return "" + self._process.kill() + self._status = STATUS.KILLED + return True + + def start(self): + if self._process is None: + return False + + if self._status == STATUS.PAUSED: + os.kill(self._process.pid(), SIGCONT) + self._status = STATUS.RUNNING + else: + self.run_solver() + + return True + + def pause(self): + if self._process is None: + return False + + os.kill(self._process.pid(), SIGSTOP) + self._status = STATUS.PAUSED + return True + + def stop(self): + if self._process is None: + return False + + self._process.terminate() + self._status = STATUS.STOPED + return True + + + def wait(self): + if self._process is None: + return False + + self._process.wait() + self._status = STATUS.STOPED + return True diff --git a/src/Solver/Mage.py b/src/Solver/Mage.py index e038495f..57e32d61 100644 --- a/src/Solver/Mage.py +++ b/src/Solver/Mage.py @@ -12,6 +12,7 @@ class Mage(AbstractSolver): self._cmd_solver = "@path @input -o @output" self._cmd_output = "" + @classmethod def default_parameters(cls): lst = super(Mage, cls).default_parameters() @@ -44,6 +45,7 @@ class Mage(AbstractSolver): return lst + class Mage7(Mage): def __init__(self, name): super(Mage7, self).__init__(name) diff --git a/src/View/RunSolver/Window.py b/src/View/RunSolver/Window.py index 5c5c23c3..42d7e464 100644 --- a/src/View/RunSolver/Window.py +++ b/src/View/RunSolver/Window.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from queue import Queue from tools import trace, timer from View.ASubWindow import ASubWindow, ASubMainWindow @@ -12,7 +13,7 @@ from PyQt5.QtGui import ( from PyQt5.QtCore import ( Qt, QVariant, QAbstractTableModel, QCoreApplication, QModelIndex, pyqtSlot, - QRect, QTimer, + QRect, QTimer, QProcess, ) from PyQt5.QtWidgets import ( @@ -20,6 +21,7 @@ from PyQt5.QtWidgets import ( QFileDialog, QTableView, QAbstractItemView, QUndoStack, QShortcut, QAction, QItemDelegate, QComboBox, QVBoxLayout, QHeaderView, QTabWidget, + QTextEdit, ) _translate = QCoreApplication.translate @@ -51,7 +53,6 @@ class SelectSolverWindow(ASubWindow, ListedSubWindow): def setup_connections(self): self.find(QPushButton, "pushButton_run").clicked.connect(self.accept) self.find(QPushButton, "pushButton_cancel").clicked.connect(self.reject) - @property def solver(self): return self._solver @@ -77,6 +78,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow): self._study = study self._config = config self._solver = solver + self._process = QProcess(parent) super(SolverLogWindow, self).__init__( name=self._title, ui="SolverLog", parent=parent @@ -88,6 +90,10 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow): self.setup_connections() self._alarm.start(500) + self._output = Queue() + + self._log(f" *** Run solver {self._solver.name}") + self._solver.run(self._process, self._output) def setup_action(self): self.find(QAction, "action_start").setEnabled(False) @@ -104,26 +110,38 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow): self._alarm.timeout.connect(self.update) + def _log(self, msg): + msg = msg.rsplit('\n')[0] + self.find(QTextEdit, "textEdit").append(msg) def update(self): - print("update") + while self._output.qsize() != 0: + s = self._output.get() + print(s) + self._log(s) def start(self): - print("start") + self._log(" *** Start") + + self._solver.start() self.find(QAction, "action_start").setEnabled(False) self.find(QAction, "action_pause").setEnabled(True) self.find(QAction, "action_stop").setEnabled(True) def pause(self): - print("pause") + self._log(" *** Pause") + + self._solver.pause() self.find(QAction, "action_start").setEnabled(True) self.find(QAction, "action_pause").setEnabled(False) self.find(QAction, "action_stop").setEnabled(True) def stop(self): - print("stop") + self._log(" *** Stop") + + self._solver.kill() self.find(QAction, "action_start").setEnabled(True) self.find(QAction, "action_pause").setEnabled(False) -- GitLab