class RemoteExecutionThread(QtCore.QThread): """ Threaded external processor execution""" #=================================================================================================== # C L A S S _ACTIVE_THREAD_STORAGE = [] #___________________________________________________________________________________________________ __init__ def __init__(self, parent, **kwargs): QtCore.QThread.__init__(self, parent) self._events = dict() self._log = Logger(self) self._log.trace = True self._log.addPrintCallback(self._handleLogWritten) self._response = None self._output = None self._error = None self._explicitComplete = ArgsUtils.get('explicitComplete', False, kwargs) class RETCompleteSignal(QtCore.QObject): signal = QtCore.Signal(dict) self._completeSignal = RETCompleteSignal() class RETLogSignal(QtCore.QObject): signal = QtCore.Signal(str) self._logSignal = RETLogSignal() class RETProgressSignal(QtCore.QObject): signal = QtCore.Signal(dict) self._progressSignal = RETProgressSignal() class RETEventSignal(QtCore.QObject): signal = QtCore.Signal(dict) self._eventSignal = RETEventSignal() # Add the thread to the static active thread storage so that it won't be garbage collected # until the thread completes. self.__class__._ACTIVE_THREAD_STORAGE.append(self) self._connectSignals(**kwargs) #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: log @property def log(self): return self._log #___________________________________________________________________________________________________ GS: logSignal @property def logSignal(self): return self._logSignal #___________________________________________________________________________________________________ GS: completeSignal @property def completeSignal(self): return self._completeSignal #___________________________________________________________________________________________________ GS: progressSignal @property def progressSignal(self): return self._progressSignal #___________________________________________________________________________________________________ GS: response @property def response(self): return self._response #___________________________________________________________________________________________________ GS: output @property def output(self): return self._output #___________________________________________________________________________________________________ GS: error @property def error(self): return self._error #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ dispatchEvent def dispatchEvent(self, identifier, target =None, data =None): self._eventSignal.signal.emit({ 'id':identifier, 'source':self, 'target':target if target else self, 'data':data }) #___________________________________________________________________________________________________ execute def execute( self, callback =None, logCallback =None, progressCallback =None, eventCallback =None, **kwargs ): self._connectSignals( callback=callback, logCallback=logCallback, progressCallback=progressCallback, eventCallback=eventCallback, **kwargs) self.start() #___________________________________________________________________________________________________ run def run(self): """ Thread run method.""" response = self._runImpl() if self._explicitComplete: return self._runComplete(response) #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _connectSignals def _connectSignals(self, **kwargs): logCallback = ArgsUtils.get('logCallback', None, kwargs) if logCallback: self._logSignal.signal.connect(logCallback) completeCallback = ArgsUtils.get('callback', None, kwargs) if completeCallback: self._completeSignal.signal.connect(completeCallback) progressCallback = ArgsUtils.get('progressCallback', None, kwargs) if progressCallback: self._progressSignal.signal.connect(progressCallback) eventCallback = ArgsUtils.get('eventCallback', None, kwargs) if eventCallback: self._eventSignal.signal.connect(eventCallback) #___________________________________________________________________________________________________ _runComplete def _runComplete(self, response): self._response = response if self._response is None: self._response = 0 self._completeSignal.signal.emit({ 'response':self._response, 'error':self._error, 'output':self._output, 'thread':self }) # Remove the thread from the active thread storage so that it can be garbage collected. self.__class__._ACTIVE_THREAD_STORAGE.remove(self) #___________________________________________________________________________________________________ _runImpl def _runImpl(self): return 0 #=================================================================================================== # H A N D L E R S #___________________________________________________________________________________________________ _handleLogWritten def _handleLogWritten(self, logger, value): self._logSignal.signal.emit(value)
class RemoteExecutionThread(QtCore.QThread): """ Threaded external processor execution""" #=================================================================================================== # C L A S S _ACTIVE_THREAD_STORAGE = [] completeSignal = QtCore.Signal(object) eventSignal = QtCore.Signal(object) logSignal = QtCore.Signal(object) progressSignal = QtCore.Signal(object) #___________________________________________________________________________________________________ __init__ def __init__(self, parent, **kwargs): QtCore.QThread.__init__(self, parent) self.userData = ArgsUtils.get('userData', None, kwargs) self._events = dict() self._log = Logger(self) self._log.trace = True self._log.addPrintCallback(self._handleLogWritten) self._logger = self._log self._maxLogBufferSize = 0 self._logBuffer = [] self._returnCode = None self._output = None self._error = None self._explicitComplete = ArgsUtils.get('explicitComplete', False, kwargs) # Add the thread to the static active thread storage so that it won't be garbage collected # until the thread completes. self.__class__._ACTIVE_THREAD_STORAGE.append(self) self._connectSignals(**kwargs) #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: success @property def success(self): return self.returnCode == 0 #___________________________________________________________________________________________________ GS: log @property def log(self): return self._log #___________________________________________________________________________________________________ GS: logger @property def logger(self): return self._log #___________________________________________________________________________________________________ GS: response @property def response(self): warnings.warn( 'RemoteExceutionThread.response is deprecated in favor of .returnCode', DeprecationWarning) self._log.write('[DEPRECATION WARNING]: Use returnCode instead of response', traceStack=True) return self._returnCode #___________________________________________________________________________________________________ GS: returnCode @property def returnCode(self): return self._returnCode #___________________________________________________________________________________________________ GS: output @property def output(self): return self._output #___________________________________________________________________________________________________ GS: error @property def error(self): return self._error #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ dispatchEvent def dispatchEvent(self, signal, identifier =None, data =None): signal.emit(RemoteThreadEvent( identifier=identifier, target=self, data=data)) #___________________________________________________________________________________________________ execute def execute( self, callback =None, logCallback =None, progressCallback =None, eventCallback =None, **kwargs ): self._connectSignals( callback=callback, logCallback=logCallback, progressCallback=progressCallback, eventCallback=eventCallback, **kwargs) self.start() #___________________________________________________________________________________________________ run def run(self): """ Thread run method.""" response = self._runImpl() if self._explicitComplete: return self._runComplete(response) #___________________________________________________________________________________________________ connectSignals def connectSignals(self, onComplete =None, onLog =None, onProgress =None, onEvent =None): """ Quick access method to connect callbacks to the various remote thread signals. """ return self._connectSignals( callback=onComplete, logCallback=onLog, progressCallback=onProgress, eventCallback=onEvent) #___________________________________________________________________________________________________ enableLogBuffer def enableLogBuffer(self, maxLength = 0): self._maxLogBufferSize = maxLength #___________________________________________________________________________________________________ disableLogBuffer def disableLogBuffer(self): self.flushLogBuffer(disable=True) #___________________________________________________________________________________________________ flushLogBuffer def flushLogBuffer(self, disable =False): if disable: self._maxLogBufferSize = 0 if self._logBuffer: b = self._logBuffer self._logBuffer = [] self.dispatchEvent(self.logSignal, 'log', {'message':'\n'.join(b)}) #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _connectSignals def _connectSignals(self, **kwargs): logCallback = ArgsUtils.get('logCallback', None, kwargs) if logCallback: self.logSignal.connect(logCallback) completeCallback = ArgsUtils.get('callback', None, kwargs) if completeCallback: self.completeSignal.connect(completeCallback) progressCallback = ArgsUtils.get('progressCallback', None, kwargs) if progressCallback: self.progressSignal.connect(progressCallback) eventCallback = ArgsUtils.get('eventCallback', None, kwargs) if eventCallback: self.eventSignal.connect(eventCallback) #___________________________________________________________________________________________________ _runComplete def _runComplete(self, response): self._returnCode = response if self._returnCode is None: self._returnCode = 0 self.dispatchEvent(self.completeSignal, 'complete', { 'response':self._returnCode, 'error':self._error, 'output':self._output, 'thread':self, 'userData':self.userData }) # Remove the thread from the active thread storage so that it can be garbage collected. self.__class__._ACTIVE_THREAD_STORAGE.remove(self) #___________________________________________________________________________________________________ _runImpl def _runImpl(self): return 0 #=================================================================================================== # H A N D L E R S #___________________________________________________________________________________________________ _handleLogWritten def _handleLogWritten(self, logger, value): if self._maxLogBufferSize > 0: self._logBuffer.append(value) if len(self._logBuffer) > self._maxLogBufferSize: self.flushLogBuffer() else: self.dispatchEvent(self.logSignal, 'log', {'message':value})