mirror of
https://git.salome-platform.org/gitpub/modules/geom.git
synced 2024-12-26 17:30:35 +05:00
[bos #38044][EDF] (2023-T3) Support for automatic reparation. Initial commit for the process implementation.
This commit is contained in:
parent
4e90f531cf
commit
0c71d36f22
@ -35,6 +35,7 @@ IF(SALOME_BUILD_GUI)
|
|||||||
geomrepairadv_logger.py
|
geomrepairadv_logger.py
|
||||||
geomrepairadv_progress.py
|
geomrepairadv_progress.py
|
||||||
geomrepairadv_worker.py
|
geomrepairadv_worker.py
|
||||||
|
geomrepairadv_worker_messages.py
|
||||||
locate_subshapes.py
|
locate_subshapes.py
|
||||||
locate_subshapes_algo.py
|
locate_subshapes_algo.py
|
||||||
locate_subshapes_limits.py
|
locate_subshapes_limits.py
|
||||||
|
@ -22,30 +22,39 @@
|
|||||||
import inspect
|
import inspect
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
|
|
||||||
from qtsalome import QApplication, pyqtSignal, QThread, Qt, QTimer
|
from qtsalome import QApplication, Qt, QTimer
|
||||||
from .geomrepairadv_logger import logger
|
from .geomrepairadv_logger import logger
|
||||||
|
from .geomrepairadv_worker_messages import MessageHandlerFactory
|
||||||
|
from multiprocessing import Process, Pipe
|
||||||
|
|
||||||
|
import CORBA
|
||||||
|
|
||||||
|
|
||||||
class Worker(QThread):
|
class Worker(Process):
|
||||||
"""
|
"""
|
||||||
Creates a tread to run a given target function with a progress dialog as a parent.
|
Creates a process to run a given target function with a progress dialog as a parent.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
progress_update = pyqtSignal(int)
|
|
||||||
thread_failed = pyqtSignal()
|
|
||||||
work_completed = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, parent=None, target=None, args=None):
|
def __init__(self, parent=None, target=None, args=None):
|
||||||
super().__init__(parent)
|
super().__init__()
|
||||||
|
|
||||||
# Set target function and it's arguments
|
# Set target function and its arguments
|
||||||
self.target = target
|
self.target = target
|
||||||
self.args = args
|
self.args = args
|
||||||
|
|
||||||
# Update a progress bar each time we receive an update signal
|
# Create a pipe for communication
|
||||||
self.progress_update.connect(parent.setValue)
|
self.parent_conn, self.child_conn = Pipe()
|
||||||
self.thread_failed.connect(parent.on_failed)
|
|
||||||
self.work_completed.connect(parent.on_completed)
|
# Set a timer to handle signals non-blocking way
|
||||||
|
self.signals_timer = QTimer()
|
||||||
|
self.signals_timer.timeout.connect(self.handle_signals)
|
||||||
|
self.signals_timer.start(1000)
|
||||||
|
|
||||||
|
# Create a message handler factory
|
||||||
|
self.message_handler_factory = MessageHandlerFactory()
|
||||||
|
|
||||||
|
# Store parent for signal handling
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
# Calculate total amount of lines in executed function
|
# Calculate total amount of lines in executed function
|
||||||
source_lines = inspect.getsourcelines(target)
|
source_lines = inspect.getsourcelines(target)
|
||||||
@ -53,7 +62,7 @@ class Worker(QThread):
|
|||||||
first_line = source_lines[1]
|
first_line = source_lines[1]
|
||||||
|
|
||||||
# Set a progress emitter to update the progress from the target
|
# Set a progress emitter to update the progress from the target
|
||||||
self.progress_emitter = ProgressEmitter(self.progress_update, total_lines, first_line)
|
self.progress_emitter = ProgressEmitter(self.child_conn, total_lines, first_line)
|
||||||
|
|
||||||
# Set a variable for result
|
# Set a variable for result
|
||||||
self.result = None
|
self.result = None
|
||||||
@ -70,23 +79,17 @@ class Worker(QThread):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Wait mode cursor
|
|
||||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
|
||||||
|
|
||||||
self.result = self.target(self.args, self.progress_emitter)
|
self.result = self.target(self.args, self.progress_emitter)
|
||||||
|
|
||||||
# Reset the progress when finished
|
# Reset the progress when finished
|
||||||
self.progress_update.emit(100)
|
self.child_conn.send(('progress', 100))
|
||||||
|
|
||||||
if not self.is_canceled():
|
if not self.is_canceled():
|
||||||
self.work_completed.emit()
|
self.child_conn.send(('completed', self.result))
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(format_exc())
|
logger.error(format_exc())
|
||||||
self.thread_failed.emit()
|
self.child_conn.send(('failed',))
|
||||||
|
|
||||||
finally:
|
|
||||||
QApplication.restoreOverrideCursor()
|
|
||||||
|
|
||||||
|
|
||||||
def is_canceled(self):
|
def is_canceled(self):
|
||||||
@ -106,9 +109,6 @@ class Worker(QThread):
|
|||||||
# can return from the running function gracefully.
|
# can return from the running function gracefully.
|
||||||
self.progress_emitter.stop()
|
self.progress_emitter.stop()
|
||||||
|
|
||||||
# Termination doesn't call a final block inside run()
|
|
||||||
QApplication.restoreOverrideCursor()
|
|
||||||
|
|
||||||
# Set a timer for a case when the running function
|
# Set a timer for a case when the running function
|
||||||
# doesn't use emitter or does so heavy job that it would take
|
# doesn't use emitter or does so heavy job that it would take
|
||||||
# a lot of time for waiting and we need to terminate it.
|
# a lot of time for waiting and we need to terminate it.
|
||||||
@ -121,10 +121,26 @@ class Worker(QThread):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Check if the job is still running and need to be terminated
|
# Check if the job is still running and need to be terminated
|
||||||
if self.isRunning():
|
if self.is_alive():
|
||||||
logger.warning('Thread will be terminated!')
|
logger.warning('Process will be terminated!')
|
||||||
|
|
||||||
super().terminate()
|
super().terminate()
|
||||||
|
|
||||||
|
self.on_finished()
|
||||||
|
|
||||||
|
|
||||||
|
def on_finished(self):
|
||||||
|
"""
|
||||||
|
Called when the execution is finished.
|
||||||
|
"""
|
||||||
|
|
||||||
|
logger.debug('on_finished called')
|
||||||
|
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
self.signals_timer.stop()
|
||||||
|
|
||||||
|
self.join()
|
||||||
|
|
||||||
|
|
||||||
def get_result(self):
|
def get_result(self):
|
||||||
"""
|
"""
|
||||||
@ -134,6 +150,37 @@ class Worker(QThread):
|
|||||||
return self.result
|
return self.result
|
||||||
|
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""
|
||||||
|
Starts the process and sets up the communication with the parent.
|
||||||
|
"""
|
||||||
|
super().start()
|
||||||
|
self.handle_signals()
|
||||||
|
|
||||||
|
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_signals(self):
|
||||||
|
"""
|
||||||
|
Handles signals from the child process.
|
||||||
|
"""
|
||||||
|
|
||||||
|
logger.debug('handle_signals called')
|
||||||
|
|
||||||
|
if not self.parent_conn.poll():
|
||||||
|
return
|
||||||
|
|
||||||
|
msg = self.parent_conn.recv()
|
||||||
|
logger.debug('msg: %s', msg)
|
||||||
|
|
||||||
|
# Get a handler for the message type
|
||||||
|
handler = self.message_handler_factory.get_handler(msg[0])
|
||||||
|
if handler:
|
||||||
|
handler.handle(msg, self)
|
||||||
|
else:
|
||||||
|
logger.error('No handler for message type: %s', msg[0])
|
||||||
|
|
||||||
|
|
||||||
class ProgressEmitter():
|
class ProgressEmitter():
|
||||||
"""
|
"""
|
||||||
Helper class to reduce code repetition while update progress
|
Helper class to reduce code repetition while update progress
|
||||||
@ -173,6 +220,6 @@ class ProgressEmitter():
|
|||||||
progress_value = (line - self.first_line) / self.progress_percent
|
progress_value = (line - self.first_line) / self.progress_percent
|
||||||
logger.debug('progress_value: %d', progress_value)
|
logger.debug('progress_value: %d', progress_value)
|
||||||
|
|
||||||
self.progress_update.emit(int(progress_value))
|
self.progress_update.send(['progress', int(progress_value)])
|
||||||
|
|
||||||
return self.is_running
|
return self.is_running
|
||||||
|
119
src/RepairGUIAdv/geomrepairadv_worker_messages.py
Normal file
119
src/RepairGUIAdv/geomrepairadv_worker_messages.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2014-2024 EDF
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# See https://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
|
||||||
|
#
|
||||||
|
# Author : Konstantin Leontev (OpenCascade S.A.S)
|
||||||
|
|
||||||
|
class MessageHandler:
|
||||||
|
"""
|
||||||
|
MessageHandler is a base class for handling messages
|
||||||
|
between child and worker processes in the progress bar Worker class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def handle(self, msg, worker):
|
||||||
|
"""
|
||||||
|
Handle the given message.
|
||||||
|
|
||||||
|
This method should be implemented by subclasses to define how to process
|
||||||
|
the given message.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg: The message to be handled.
|
||||||
|
worker: The worker context or object related to the message.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: If the method is not implemented by a subclass.
|
||||||
|
"""
|
||||||
|
|
||||||
|
raise NotImplementedError("Subclasses should implement this method")
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressHandler(MessageHandler):
|
||||||
|
"""
|
||||||
|
ProgressHandler updates progress bar with a value from a message.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def handle(self, msg, worker):
|
||||||
|
"""
|
||||||
|
Sets a new value for a worker progress bar.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg (tuple): A tuple where the second element is the value to be set.
|
||||||
|
worker (object): The worker object that has a setValue method.
|
||||||
|
"""
|
||||||
|
|
||||||
|
worker.parent.setValue(msg[1])
|
||||||
|
|
||||||
|
|
||||||
|
class CompletedHandler(MessageHandler):
|
||||||
|
"""
|
||||||
|
CompletedHandler handles the completion of the worker process.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def handle(self, msg, worker):
|
||||||
|
"""
|
||||||
|
Handles the given message by performing actions on the worker object.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg: The message to handle.
|
||||||
|
worker: The worker object that contains the methods to be called.
|
||||||
|
"""
|
||||||
|
|
||||||
|
worker.result = msg[1]
|
||||||
|
|
||||||
|
worker.parent.on_completed()
|
||||||
|
worker.on_finished()
|
||||||
|
|
||||||
|
|
||||||
|
class FailedHandler(MessageHandler):
|
||||||
|
"""
|
||||||
|
FailedHandler handles the failure of the worker process.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def handle(self, msg, worker):
|
||||||
|
"""
|
||||||
|
Handles the given message by invoking the worker's failure handler,
|
||||||
|
stopping the timer, and joining the worker thread.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg: The message to handle.
|
||||||
|
worker: The worker object that contains the failure handler, timer, and worker thread.
|
||||||
|
"""
|
||||||
|
|
||||||
|
worker.parent.on_failed()
|
||||||
|
worker.on_finished()
|
||||||
|
|
||||||
|
|
||||||
|
class MessageHandlerFactory:
|
||||||
|
"""
|
||||||
|
MessageHandlerFactory creates a handler for a given message type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.handlers = {
|
||||||
|
'progress': ProgressHandler(),
|
||||||
|
'completed': CompletedHandler(),
|
||||||
|
'failed': FailedHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_handler(self, msg_type):
|
||||||
|
"""
|
||||||
|
Returns a handler for the given message type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.handlers.get(msg_type, None)
|
Loading…
Reference in New Issue
Block a user