Short of spawning a subprocess and using IPC, you don't have many, if any, options. The Qt gui loop and the sd functions need the main thread, if one takes a long running task, that's that.
One way to accomplish the IPC, is to use the QLocalServer and QLocalSocket that come with QtCore. The following was scratched out here and by no means will work out of the box, but it might get you started
# your sd plugin
import subprocess
from PySide2 import QtCore, QtWidgets
class MyServer(QtCore.QObject):
connected = QtCore.Signal()
def __init__(self):
self._sockets = []
self.wants_to_quit = False
self._server = QtCore.QLocalServer(QtWidgets.QApplication.instance())
self._server.listen("my-pipe") # Named pipe to communicate, might need to make unique if multiple servers
self._server.newConnection.connect(self._new_connection)
def _new_connection(self, socket):
self._sockets.append(socket)
socket.readyRead.connect(self._read_from_socket)
self.connected.emit()
def _read_from_socket(self, socket):
message = socket.readAll().decode('utf-8')
if message = 'CANCEL':
self.wants_to_quit = True
def write_to_sockets(self, message):
for s in self._sockets:
s.write(message)
s.flush()
SOCKET_SERVER = MyServer()
# -- In the plugin, for some long running task
def long_running_task(self):
# Use an event loop to wait while the process starts before running the task
timer = QtCore.QTimer()
timer.setInterval(3000) # 3 second timeout
loop = QtCore.QEventLoop()
SOCKET_SERVER.connected.connect(loop.quit)
timer.timeout.connect(loop.quit)
loop.quit.connect(timer.stop)
# Finally, start the rocess
subprocess.Popen(["python", "/path/to/progress/script.py", "my-pipe"])
loop.exec_() # Run the event loop until connected
# -- start work, periodically send a message of progress
SOCKET_SERVER.write_to_sockets("progress:10")
if SOCKET_SERVER.wants_to_quit:
SOCKET_SERVER.deleteLater() # Deleting the qobject should clean up connections and sockets
return
Then, in the client, you open a socket connection to that main process
# /path/to/progress/script.py
import sys
from PySide import QtCore, QtWidgets
app = QtWidgets.QApplication(sys.argv)
PIPE_NAME = sys.argv[-1]
class MyProgress(QtWidgets.QDialog):
# ... Layout
def process_message(self, message):
message = message.decode('utf-8') # Comes in as bytes
if 'progress' in message:
self._progress = int(message.replace('progress:', '')
def on_cancel_clicked(self):
self.socket.write("CANCEL") # Send back to the server that we want to cancel
self.socket.flush()
self.reject() # Clean up this dialog, let the process die and clean up the environment
my_progress = MyProgress()
socket = QtCore.QLocalSocket(app)
my_progress.socket = socket
socket.connectToServer(PIPE_NAME)
if (socket.waitForConnected(1000)):
# We're connected, we can receive information from the server now
socket.readyRead.connect(my_process.process_message)
my_process.exec_() # Show out dialog