Skip to content

Commit 844addc

Browse files
committed
fix: résolution de l'erreur invokeMethod via QTimer.singleShot et correction définitive du threading QProcess
1 parent f24d5ab commit 844addc

2 files changed

Lines changed: 22 additions & 10 deletions

File tree

pycompiler_ark/Core/SysDependencyManager.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class SysDependencyManager:
3636
"""
3737

3838
def __init__(self, parent_widget: Optional[QObject] = None):
39-
# parent_widget is used as the parent for QProcess
39+
# parent_widget is used for UI callbacks and global task registration
4040
self.parent_widget = parent_widget
4141
self._ui_callbacks: dict = {}
4242

@@ -77,9 +77,10 @@ def shell_run(
7777
) -> Optional[QProcess]:
7878
"""Runs a command without elevation."""
7979
try:
80-
# IMPORTANT: QProcess must be created on the GUI thread if parent is a widget.
81-
# However, if parent_widget is a QObject on the correct thread, it's fine.
82-
proc = QProcess(self.parent_widget)
80+
# IMPORTANT: We create QProcess WITHOUT a parent here.
81+
# This allows it to be created and waited for (waitForFinished)
82+
# in the background thread without violating Qt thread ownership rules.
83+
proc = QProcess()
8384
if cwd:
8485
proc.setWorkingDirectory(cwd)
8586

@@ -101,6 +102,7 @@ def _finished_wrapper(ec, es):
101102

102103
proc.finished.connect(_finished_wrapper)
103104

105+
# Note: The process is registered for global cleanup tracking
104106
self._register_task(proc, None, "commande système", "system command")
105107
proc.start()
106108
return proc

pycompiler_ark/Ui/Gui/Dialogs/SysDependencyUI.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import shutil
2323
from typing import Any, Optional
2424

25-
from PySide6.QtCore import QProcess, QObject, Signal, Slot, QMetaObject, Qt
25+
from PySide6.QtCore import QProcess, QObject, QTimer, Qt
2626
from PySide6.QtWidgets import QMessageBox
2727

2828
from pycompiler_ark.Core.SysDependencyManager import SysDependencyManager
@@ -32,7 +32,7 @@
3232
class SysDependencyUI(SysDependencyManager):
3333
"""
3434
GUI extension of SysDependencyManager.
35-
Proxies GUI calls to the main thread to avoid segfaults.
35+
Proxies GUI calls to the main thread to avoid segfaults and PySide6 signature errors.
3636
"""
3737

3838
def __init__(self, parent_widget=None):
@@ -54,7 +54,7 @@ def _ui_tr(self, fr: str, en: str) -> str:
5454

5555
def _ui_register_task(self, proc: QProcess, dlg: Optional[Any], label_fr: str, label_en: str) -> None:
5656
if self.parent_widget is None: return
57-
# Simple task registration is generally thread-safe if it's just a list
57+
# Task registration is generally thread-safe for list operations
5858
try:
5959
tasks = getattr(self.parent_widget, "_sysdep_tasks", [])
6060
tasks.append({"process": proc, "dialog": dlg, "label_fr": label_fr, "label_en": label_en})
@@ -71,9 +71,13 @@ def _ui_unregister_task(self, proc: QProcess) -> None:
7171
pass
7272

7373
def _invoke_gui(self, method: callable, *args):
74-
"""Invoke a method on the GUI thread."""
74+
"""
75+
Invoke a method on the GUI thread using QTimer.singleShot.
76+
This is the most compatible way to pass a lambda/callable across threads in PySide6.
77+
"""
7578
if self.parent_widget:
76-
QMetaObject.invokeMethod(self.parent_widget, lambda: method(*args), Qt.QueuedConnection)
79+
# QTimer.singleShot(0, context, callable) ensures execution in context's thread
80+
QTimer.singleShot(0, self.parent_widget, lambda: method(*args))
7781
else:
7882
method(*args)
7983

@@ -84,14 +88,20 @@ def _show():
8488

8589
def _show_progress(self, title_fr: str, title_en: str, msg_fr: str, msg_en: str):
8690
def _create():
91+
# Close existing one if any
92+
if self._progress_dlg:
93+
try: self._progress_dlg.close()
94+
except Exception: pass
95+
8796
self._progress_dlg = ProgressDialog(self.tr(title_fr, title_en), self.parent_widget)
8897
self._progress_dlg.set_message(self.tr(msg_fr, msg_en))
8998
self._progress_dlg.show()
9099
self._invoke_gui(_create)
91100

92101
def _update_progress(self, msg: str):
93102
def _upd():
94-
if self._progress_dlg: self._progress_dlg.set_message(msg)
103+
if self._progress_dlg:
104+
self._progress_dlg.set_message(msg)
95105
self._invoke_gui(_upd)
96106

97107
def _close_progress(self):

0 commit comments

Comments
 (0)