def iterRows(self, proc: Processor) -> Iterator[Sequence[str]]: tasks = proc.tasks taskRunDB = proc.taskRunDB # Determine all keys that exist for the given task names. keys = sorted(union( taskRunDB.getKeys(taskName) for taskName in proc.args.task )) yield [ 'create date', 'create time', 'result' ] + keys for task in tasks: taskName = task.getName() taskKeys = taskRunDB.getKeys(taskName) # TODO: Which properties are useful to export? timestamp = formatTime(task.getJob().getCreateTime()) # Assuming format "2008-09-16 15:21" results = [timestamp[:10], timestamp[-5:], getTaskStatus(task)] for key in keys: if key in taskKeys: # TODO: Querying one run at a time is not really efficient. data = list(taskRunDB.getData( taskName, [ task.getLatestRun().getId() ], key )) if len(data) == 0: results.append('') else: assert len(data) == 1 value = data[0][1] results.append(str(value)) else: results.append('') yield results
def createStatusBar(tasks: Sequence[Task], length: int = 10) -> XMLContent: if len(tasks) == 0: return None elif len(tasks) <= length: return xhtml.table(class_='statusfew')[xhtml.tbody[xhtml.tr[(xhtml.td( class_=getTaskStatus(task)) for task in tasks)]]] else: statusFreq = dict.fromkeys(statusList, 0) for task in tasks: statusFreq[getTaskStatus(task)] += 1 def iterBars() -> Iterator[XMLContent]: for status in statusList: freq = statusFreq[status] if freq != 0: yield xhtml.td( style=f'width:{100 * freq // len(tasks):d}%', class_=status)[str(freq)] return xhtml.table( class_='statusmany')[xhtml.tbody[xhtml.tr[iterBars()]]]
def getJobStatus(job: Job) -> str: '''Summarizes the current status of the given job by combining the task statuses into a single value. ''' # Return cached status, if available. jobId = job.getId() status = _finalJobStatus.get(jobId) if status is None: status = combinedStatus( getTaskStatus(task) for task in job.iterTasks()) assert status is not None if job.hasFinalResult(): # Status will never change again, so store it. _finalJobStatus[jobId] = status return status
def getProductStatus(job: Job, name: str) -> Optional[str]: '''Returns the status of the product with the given name. Raises KeyError if there is no product with the given name in the given job. ''' product = job.getProduct(name) if not product.isCombined(): if product.isBlocked(): return 'cancelled' elif product.isAvailable(): # In the case of multiple producers, we don't know which # producer created the default locator, so there is no # obviously right choice for the status. # So we choose something simple instead. return 'ok' # Not blocked and not available, so must be idle or busy. # The generic case can handle that just fine. return combinedStatus( getTaskStatus(task) for task in job.getProducers(name))
def iterRows(self, **kwargs: object) -> Iterator[XMLContent]: proc = cast(ProcT, kwargs['proc']) job = cast(JobProcessorMixin, proc).job jobId = job.getId() products = self.getProducts(proc) hasLocal = any(prod.isLocal() for prod in products) for product in products: productName = product.getName() potentialProducers = { task.getName() for task in job.getProducers(productName) } actualProducers = { taskName for taskName, locator_ in product.getProducers() } # For user inputs, actualProducers includes tasks that are not # in potentialProducers. producers = sorted( self.filterProducers(proc, potentialProducers | actualProducers)) rowStyle = getProductStatus(job, productName) if self.showColors \ else None consumers = sorted(job.getConsumers(productName)) first = True for taskName in producers: task = job.getTask(taskName) if task is None: # No actual producer; this must be an input product. producerStatus = 'ok' finishedTask = True else: producerStatus = getTaskStatus(task) finishedTask = task.isExecutionFinished() cells = [] if first: cells.append(cell(rowspan=len(producers))[productName]) if first and hasLocal: cells.append( cell(rowspan=len(producers)) [createTaskRunnerDetailsLink(( product.getLocalAt() or '?') if product.isLocal( ) and not product.isBlocked() else None)]) if self.showProducers: cells.append( cell( class_=producerStatus if self.showColors else None) ['(job input)' if task is None else createTaskInfoLink( jobId, taskName)]) if first and self.showConsumers: cells.append( cell(rowspan=len(producers))[xhtml.br.join( createTaskInfoLink(jobId, consumer.getName()) for consumer in consumers)]) locator = product.getLocator(taskName) if locator is None and not actualProducers: # For old jobs, only one locator per product was stored. locator = product.getLocator() if not self.showColors: locatorStyle = None elif locator is None: assert task is not None, \ f'input without locator: {taskName}' if finishedTask: locatorStyle = 'cancelled' else: locatorStyle = getTaskStatus(task) else: locatorStyle = producerStatus cells.append( cell(class_=locatorStyle)[formatLocator( product, locator, finishedTask)]) yield row(class_=rowStyle)[cells] first = False
def iterRowStyles( # pylint: disable=unused-argument self, rowNr: int, record: Task, **kwargs: object) -> Iterator[str]: yield getTaskStatus(record)