class Task(object): def __init__(self, request): self._request = request self._cond = QWaitCondition() def getRequest(self): return self._request def waitForResponse(self): self._cond.wait(QMutex()) x = self._response del self._response return x def addResponse(self, response): # Don't allow two responses to the same # request. Could possibly happen # if someone clicks accept/reject and simultaneously # closes the window, somehow, triggering # the closeEvent if self._cond: self._response = response self._cond.wakeAll() self._cond = None def setType(self, dialogType): """ Set what type of task this is. The dialogtype is the construtor for the Dialog that is to be invoked, when onSystrayActivated is invoked later on""" self.dialogType = dialogType def getType(self): return self.dialogType
class VcsStatusMonitorThread(QThread): """ Class implementing the VCS status monitor thread base class. @signal vcsStatusMonitorData(QStringList) emitted to update the VCS status @signal vcsStatusMonitorStatus(QString, QString) emitted to signal the status of the monitoring thread (ok, nok, op) and a status message """ def __init__(self, interval, projectDir, vcs, parent = None): """ Constructor @param interval new interval in seconds (integer) @param projectDir project directory to monitor (string or QString) @param vcs reference to the version control object @param parent reference to the parent object (QObject) """ QThread.__init__(self, parent) self.setObjectName("VcsStatusMonitorThread") self.setTerminationEnabled(True) self.projectDir = QString(projectDir) self.vcs = vcs self.interval = interval self.autoUpdate = False self.statusList = QStringList() self.reportedStates = {} self.shouldUpdate = False self.monitorMutex = QMutex() self.monitorCondition = QWaitCondition() self.__stopIt = False def run(self): """ Protected method implementing the tasks action. """ while not self.__stopIt: # perform the checking task self.statusList.clear() self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), QString("wait"), self.trUtf8("Waiting for lock")) try: locked = self.vcs.vcsExecutionMutex.tryLock(5000) except TypeError: locked = self.vcs.vcsExecutionMutex.tryLock() if locked: try: self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), QString("op"), self.trUtf8("Checking repository status")) res, statusMsg = self._performMonitor() finally: self.vcs.vcsExecutionMutex.unlock() if res: status = QString("ok") else: status = QString("nok") self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), QString("send"), self.trUtf8("Sending data")) self.emit(SIGNAL("vcsStatusMonitorData(QStringList)"), QStringList(self.statusList)) self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), status, statusMsg) else: self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), QString("timeout"), self.trUtf8("Timed out waiting for lock")) if self.autoUpdate and self.shouldUpdate: try: self.vcs.vcsUpdate(self.projectDir, True) continue # check again except TypeError: pass # compatibility for older VCS plugins self.shouldUpdate = False # wait until interval has expired checking for a stop condition self.monitorMutex.lock() if not self.__stopIt: self.monitorCondition.wait(self.monitorMutex, self.interval * 1000) self.monitorMutex.unlock() self.exit() def setInterval(self, interval): """ Public method to change the monitor interval. @param interval new interval in seconds (integer) """ locked = self.monitorMutex.tryLock() self.interval = interval self.monitorCondition.wakeAll() if locked: self.monitorMutex.unlock() def getInterval(self): """ Public method to get the monitor interval. @return interval in seconds (integer) """ return self.interval def setAutoUpdate(self, auto): """ Public method to enable the auto update function. @param auto status of the auto update function (boolean) """ self.autoUpdate = auto def getAutoUpdate(self): """ Public method to retrieve the status of the auto update function. @return status of the auto update function (boolean) """ return self.autoUpdate def checkStatus(self): """ Public method to wake up the status monitor thread. """ locked = self.monitorMutex.tryLock() self.monitorCondition.wakeAll() if locked: self.monitorMutex.unlock() def stop(self): """ Public method to stop the monitor thread. """ locked = self.monitorMutex.tryLock() self.__stopIt = True self.monitorCondition.wakeAll() if locked: self.monitorMutex.unlock() def clearCachedState(self, name): """ Public method to clear the cached VCS state of a file/directory. @param name name of the entry to be cleared (QString or string) """ project = e4App().getObject("Project") key = project.getRelativePath(unicode(name)) try: del self.reportedStates[key] except KeyError: pass def _performMonitor(self): """ Protected method implementing the real monitoring action. This method must be overridden and populate the statusList member variable with a list of strings giving the status in the first column and the path relative to the project directory starting with the third column. The allowed status flags are: <ul> <li>"A" path was added but not yet comitted</li> <li>"M" path has local changes</li> <li>"O" path was removed</li> <li>"R" path was deleted and then re-added</li> <li>"U" path needs an update</li> <li>"Z" path contains a conflict</li> <li>" " path is back at normal</li> </ul> @return tuple of flag indicating successful operation (boolean) and a status message in case of non successful operation (QString) """ raise RuntimeError('Not implemented')
class _FTSearchThread(QThread): '''This thread performs full text search in the background''' searchFinished = pyqtSignal() searchError = pyqtSignal() def __init__(self, searcher, parent): QThread.__init__(self, parent) self._searcher = searcher self._quit = False self._mutex = QMutex() self._pending = QWaitCondition() self._collector = None self._query = None self._result = None def run(self): while not self._quit: self._mutex.lock() if not self._query: self._pending.wait(self._mutex) query = self._query self._query = None self._mutex.unlock() # search if query: (query_str1, query_str2, itemtypes, limit, highlight, merge) = query self._mutex.lock() collector = self._searcher.make_collector(limit) self._collector = collector self._mutex.unlock() try: result = self._searcher.search(collector, query_str1, query_str2, itemtypes, highlight) except: self._mutex.lock() self._result = None self._mutex.unlock() self.searchError.emit() else: if collector.aborted: pass else: self._mutex.lock() self._result = (merge, result) self._mutex.unlock() self.searchFinished.emit() self._mutex.lock() self._collector = None self._mutex.unlock() def cancel(self): self._mutex.lock() self._query = None if self._collector: self._collector.abort() self._mutex.unlock() def quit(self): self._mutex.lock() if self._collector: self._collector.abort() self._query = None self._quit = True self._mutex.unlock() self._pending.wakeAll() def update_query(self, query_str1=None, query_str2=None, itemtypes=(), limit=1000, highlight=False, merge=False): self._mutex.lock() if self._collector: self._collector.abort() self._query = (query_str1, query_str2, itemtypes, limit, highlight, merge) self._mutex.unlock() self._pending.wakeAll() def take_result(self): self._mutex.lock() r = self._result self._result = None self._mutex.unlock() return r
class TestThread(QThread): def __init__(self, suite, items, stopOnError, stopOnFail, xmlRPCUrl): QThread.__init__(self) self.suite = suite self.items = items executionDelay = self.suite.sliderSpeed.value() / 1000 # convert to seconds self.sync = QMutex() self.pauseCond = QWaitCondition() self.executionPaused = False self.autoPlayer = AutoPlayer(executionDelay, self.sync, self.pauseCond, xmlRPCUrl) self.executionStopped = False self.stopOnError = stopOnError self.stopOnFail = stopOnFail self._connectSignals() def _connectSignals(self): self.connect(self.suite,SIGNAL("pauseExecution"), self.pauseExecution) self.connect(self.suite,SIGNAL("unpauseExecution"), self.unpauseExecution) self.connect(self.suite,SIGNAL("executionStopped"), self.stopExecution) self.connect(self.autoPlayer,SIGNAL("logMessage"), self.suite.logMessage) self.connect(self.suite.sliderSpeed, SIGNAL('valueChanged(int)'), self.updateExecutionSpeed) def checkForPause(self): """ Check if the pause flag has been set""" self.sync.lock() if(self.executionPaused): self.pauseCond.wait(self.sync) self.sync.unlock() def run(self): self.emit(SIGNAL('updateExecutionButtons'), False) # set default icon for all items for item in self.items: self.emit(SIGNAL('updateItemStatus'), item, TestCaseStatus.UNTESTED, False) # parse and execute test caeses handNumber = 1 failedTc = 0 successfulTc = 0 errorTc = 0 for item in self.items: try: self.checkForPause() if self.executionStopped: return self.emit(SIGNAL('logMessage'), " => Test case : " + item.text(),LogStyle.TITLE) self.emit(SIGNAL('updateItemStatus'), item, TestCaseStatus.UNTESTED, True) tc = item.data(Qt.UserRole) # get file name #parse test case tcp = TestCaseParser(tc.file) tcp.parse() #start test successful = self.autoPlayer.startTest(tcp, handNumber) self.checkForPause() if self.executionStopped: return if successful: self.emit(SIGNAL('updateItemStatus'), item, TestCaseStatus.SUCCESS, True) successfulTc += 1 else: self.emit(SIGNAL('updateItemStatus'), item, TestCaseStatus.FAILED, True) failedTc += 1 if(self.stopOnFail): break handNumber += 1 except ParserException as e: self.emit(SIGNAL('updateItemStatus'), item, TestCaseStatus.ERROR, True) self.emit(SIGNAL('logMessage'),"Parsing error: " + str(e),LogStyle.WARNING) errorTc += 1 if(self.stopOnError): break except socket.error: self.emit(SIGNAL('logMessage'),"Can't connect to player",LogStyle.ERROR) self.stopExecution() self.emit(SIGNAL('updateExecutionButtons'), True) return except Exception as e: self.emit(SIGNAL('logMessage'),"Unknown error: " + str(e),LogStyle.ERROR) raise self.emit(SIGNAL('logMessage'), " => Execution finished",LogStyle.TITLE) if(len(self.items) > 1): self.emit(SIGNAL('logMessage'), "Result => Total: {0}, Successful: {1}, Failed: {2}, Error: {3}" .format(len(self.items),successfulTc,failedTc,errorTc),LogStyle.TITLE) self.emit(SIGNAL('updateExecutionButtons'), True) def pauseExecution(self): """ Pause test case execution """ self.sync.lock() self.executionPaused = True self.autoPlayer.pause() self.sync.unlock() def unpauseExecution(self): """ Unpause test case execution """ self.sync.lock() self.executionPaused = False self.autoPlayer.unpause() self.pauseCond.wakeAll() self.sync.unlock() def stopExecution(self): """ Stop test case execution """ if(self.executionPaused): self.unpauseExecution() self.executionStopped = True self.autoPlayer.stop() def updateExecutionSpeed(self, value): executionDelay = value / 1000 # convert to seconds self.autoPlayer.executionDelay = executionDelay
class RenderThread(QThread): """ Thread object that takes control over an actual object exposing thoses methods with immediate return with delayed responses. """ def __init__(self, parent): QThread.__init__(self, parent) self.classObjectLock = QMutex(QMutex.Recursive) self.classParamDict = {} self.classInstanceDict = {} self.queueLock = QMutex(QMutex.Recursive) self.queueHasJobsLock = QMutex() # lock lighter than queueLock # while waiting for this lock no # lock on the latter can be hold self.queueHasJobsCondition = QWaitCondition() self.renderQueue = [] # contains all render requests self.newestId = 0 # newest job Id self.renderingLock = QMutex(QMutex.Recursive) self.renderingFinishedLock = QMutex() # lock lighter than renderingLock # while waiting for this lock no # lock on the latter can be hold self.renderingFinishedCondition = QWaitCondition() self.currentlyRenderingJob = None def quit(self): self.dequeueAll() while self.classInstanceDict: classObject = self.classInstanceDict.keys()[0] self.removeObject(classObject) # enqueue meta command self.enqueue(None, 'quit') self.wait() def setObject(self, classObject, *args, **param): """Add or reset a class handled by this render thread.""" if not self.isRunning(): raise Exception( "Thread needs to be running before objects can be created.") self.classObjectLock.lock() if classObject in self.classParamDict: # TODO remove, or change reloadObject() #if self.classParamDict[classObject] == (args, param): #self.classObjectLock.unlock() ## no changes done #return self.removeObject(classObject) self.classParamDict[classObject] = (args, param) self.classInstanceDict[classObject] = None self.enqueueWait(classObject, '__init__', *args, **param) #self.enqueue(classObject, '__init__', *args, **param) ## return only once object is created #self.renderingFinishedLock.lock() #while not self.classInstanceDict[classObject]: #self.renderingFinishedCondition.wait(self.renderingFinishedLock) #self.renderingFinishedLock.unlock() #self.classObjectLock.unlock() def reloadObject(self, classObject): """Reloads a class object.""" self.classObjectLock.lock() if classObject not in self.classParamDict: self.classObjectLock.unlock() raise Exception("Object not set") args, param = self.classParamDict[classObject] self.setObject(classObject, *args, **param) self.classObjectLock.unlock() def hasObject(self, classObject): """returns the object's instance created by the thread.""" QMutexLocker(self.classObjectLock) return classObject in self.classInstanceDict def getObjectInstance(self, classObject): """returns the object's instance created by the thread.""" QMutexLocker(self.classObjectLock) return self.classInstanceDict[classObject] def removeObject(self, classObject): """ Removes the given object's instance from the render thread, removing all affiliated jobs from the queue and canceling an eventually current rendered method. """ self.classObjectLock.lock() self.queueHasJobsLock.lock() self.queueLock.lock() # clear all not yet rendered content from the queue newQueue = [] for entry in self.renderQueue: jobId, entryClassObject, _, _, _ = entry if classObject != entryClassObject: newQueue.append(entry) else: self.emit(SIGNAL("jobDequeued"), jobId) self.renderQueue = newQueue # interrupt currently rendering self.renderingLock.lock() if self.currentlyRenderingJob: _, entryClassObject, _, _, _ = self.currentlyRenderingJob if classObject == entryClassObject: self.cancelCurrentJob() self.renderingLock.unlock() del self.classParamDict[classObject] del self.classInstanceDict[classObject] self.queueHasJobsLock.unlock() self.queueLock.unlock() self.classObjectLock.unlock() def enqueue(self, classObject, method, *args, **param): self.classObjectLock.lock() if classObject and classObject not in self.classParamDict: self.classObjectLock.unlock() raise Exception("Object not set") self.queueHasJobsLock.lock() self.queueLock.lock() self.newestId = (self.newestId + 1) % sys.maxint jobId = self.newestId self.renderQueue.append((jobId, classObject, method, args, param)) self.queueLock.unlock() self.queueHasJobsCondition.wakeAll() self.queueHasJobsLock.unlock() self.classObjectLock.unlock() if classObject: self.emit(SIGNAL("jobEnqueued"), jobId) return jobId def enqueueWait(self, classObject, method, *args, **param): """Enqueues a job and waits until it finishes.""" def inQueue(jobId): QMutexLocker(self.queueLock) for qjobId, _, _, _, _ in self.renderQueue: if jobId == qjobId: return True QMutexLocker(self.renderingLock) if self.currentlyRenderingJob: qjobId, _, _, _, _ = self.currentlyRenderingJob if jobId == qjobId: return True return False jobId = self.enqueue(classObject, method, *args, **param) if jobId == None: return # return only once method has finished self.renderingFinishedLock.lock() while inQueue(jobId): self.renderingFinishedCondition.wait(self.renderingFinishedLock) self.renderingFinishedLock.unlock() return jobId def getJobEntry(self, jobId): self.queueLock.lock() for idx, entry in enumerate(self.renderQueue): entryJobId, _, _, _, _ = entry if entryJobId == jobId: break else: entryJobId = None self.queueLock.unlock() return entryJobId def dequeue(self, jobId): QMutexLocker(self.queueHasJobsLock) QMutexLocker(self.queueLock) # search for entry jobEntry = self.getJobEntry(jobId) if jobEntry: idx = self.renderQueue.index(jobEntry) del self.renderQueue[idx] self.emit(SIGNAL("jobDequeued"), jobId) return True else: # interrupt currently rendering QMutexLocker(self.renderingLock) if self.currentlyRenderingJob: entryJobId, _, _, _, _ = self.currentlyRenderingJob if entryJobId == jobId: self.cancelCurrentJob() return True return False def dequeueMethod(self, classObject, method): self.queueHasJobsLock.lock() self.queueLock.lock() # clear all not yet rendered content from the queue newQueue = [] for entry in self.renderQueue: jobId, entryClassObject, entryMethod, _, _ = entry if classObject != entryClassObject or method != entryMethod: newQueue.append(entry) else: self.emit(SIGNAL("jobDequeued"), jobId) self.renderQueue = newQueue # interrupt currently rendering self.renderingLock.lock() if self.currentlyRenderingJob: _, entryClassObject, entryMethod, _, _ = self.currentlyRenderingJob if classObject == entryClassObject and method == entryMethod: self.cancelCurrentJob() self.renderingLock.unlock() self.queueLock.unlock() self.queueHasJobsLock.unlock() def dequeueAll(self): self.queueHasJobsLock.lock() self.queueLock.lock() # signal all for jobId, _, _, _, _ in self.renderQueue: self.emit(SIGNAL("jobDequeued"), jobId) self.renderQueue = [] # interrupt currently rendering self.renderingLock.lock() if self.currentlyRenderingJob: self.cancelCurrentJob() self.renderingLock.unlock() self.queueLock.unlock() self.queueHasJobsLock.unlock() def isRendering(self): self.queueLock.lock() self.renderingLock.lock() rendering = len(self.renderQueue) > 0 \ or self.currentlyRenderingJob != None self.renderingLock.unlock() self.queueLock.unlock() return rendering def cancelCurrentJob(self): """ This method is called when the currently rendered job should be canceled. The default implementation doesn't handle any object specific cancel operations and by default returns False. An actual implementation should call the current object's cancel routine and then call clearCurrentJob() to clear the current job and finally return True. """ return False def clearCurrentJob(self): """ This method needs to be called before the current job is canceled. """ self.renderingLock.lock() self.currentlyRenderingJob = None self.renderingLock.unlock() def run(self): while True: self.queueHasJobsLock.lock() hasJobWaiting = len(self.renderQueue) > 0 while not hasJobWaiting: self.emit(SIGNAL("queueEmpty")) self.queueHasJobsCondition.wait(self.queueHasJobsLock) hasJobWaiting = len(self.renderQueue) > 0 self.queueLock.lock() self.renderingLock.lock() self.currentlyRenderingJob = self.renderQueue.pop(0) jobId, entryClassObject, method, args, param \ = self.currentlyRenderingJob self.renderingLock.unlock() self.queueLock.unlock() self.queueHasJobsLock.unlock() if entryClassObject != None: if method == '__init__': classInstance = entryClassObject(*args, **param) self.classInstanceDict[entryClassObject] = classInstance self.emit(SIGNAL("objectCreated"), jobId, entryClassObject) else: classInstance = self.classInstanceDict[entryClassObject] try: content = getattr(classInstance, method)(*args, **param) self.finishJob(jobId, entryClassObject, method, args, param, content) except BaseException, e: if self.currentlyRenderingJob: stacktrace = traceback.format_exc() self.emit(SIGNAL("jobErrorneous"), jobId, entryClassObject, method, args, param, e, stacktrace) else: # job got canceled self.emit(SIGNAL("jobCanceled"), jobId, entryClassObject, method, args, param) self.renderingFinishedLock.lock() self.clearCurrentJob() self.renderingFinishedCondition.wakeAll() self.renderingFinishedLock.unlock() if entryClassObject == None and method == 'quit': return
class _FTSearchThread(QThread): '''This thread performs full text search in the background''' searchFinished = pyqtSignal() searchError = pyqtSignal() def __init__(self, searcher, parent): QThread.__init__(self, parent) self._searcher = searcher self._quit = False self._mutex = QMutex() self._pending = QWaitCondition() self._collector = None self._query = None self._result = None def run(self): while not self._quit: self._mutex.lock() if not self._query: self._pending.wait(self._mutex) query = self._query self._query = None self._mutex.unlock() # search if query: (query_str1, query_str2, itemtypes, limit, highlight, merge) = query self._mutex.lock() collector = self._searcher.make_collector(limit) self._collector = collector self._mutex.unlock() try: result = self._searcher.search( collector, query_str1, query_str2, itemtypes, highlight) except: self._mutex.lock() self._result = None self._mutex.unlock() self.searchError.emit() else: if collector.aborted: pass else: self._mutex.lock() self._result = (merge, result) self._mutex.unlock() self.searchFinished.emit() self._mutex.lock() self._collector = None self._mutex.unlock() def cancel(self): self._mutex.lock() self._query = None if self._collector: self._collector.abort() self._mutex.unlock() def quit(self): self._mutex.lock() if self._collector: self._collector.abort() self._query = None self._quit = True self._mutex.unlock() self._pending.wakeAll() def update_query(self, query_str1=None, query_str2=None, itemtypes=(), limit=1000, highlight=False, merge=False): self._mutex.lock() if self._collector: self._collector.abort() self._query = (query_str1, query_str2, itemtypes, limit, highlight, merge) self._mutex.unlock() self._pending.wakeAll() def take_result(self): self._mutex.lock() r = self._result self._result = None self._mutex.unlock() return r