Beispiel #1
0
    def presentContent(self, **kwargs: object) -> XMLContent:
        proc = cast(ProductDetails_GET.Processor, kwargs['proc'])
        productDefId = proc.args.id
        producers = proc.producers
        consumers = proc.consumers

        numProducers = len(producers)
        numConsumers = len(consumers)
        deleteProduct = ( 'Delete this product: '
            'not possible, because it is currently being used by ',
            str(numProducers), ' ', pluralize('producer', numProducers),
            ' and ',
            str(numConsumers), ' ', pluralize('consumer', numConsumers), '.'
            ) if producers or consumers else pageLink(
                'ProductDelete', DeleteArgs(id = productDefId)
                )[ 'Delete this Product' ]

        yield xhtml.h3[ 'Details of product ', xhtml.b[ productDefId ], ':' ]
        yield xhtml.div(class_='hgroup wrap')[
            DetailsTable.instance,
            GraphPanel.instance
            ].present(graph=proc.graph, **kwargs)
        yield xhtml.p[
            pageLink('ProductEdit', proc.args)[ 'Edit this product' ],
            xhtml.br,
            deleteProduct
            ]
Beispiel #2
0
 def presentContent(self, **kwargs: object) -> XMLContent:
     proc = cast(FastExecute_GET.Processor, kwargs['proc'])
     configs = proc.configs
     tagged = proc.args.configId is None
     if configs:
         numJobs = sum(len(config.targets) or 1 for config in configs)
         yield xhtml.p['Create ', xhtml.b[str(numJobs), ' ',
                                          pluralize('job', numJobs)],
                       ' from the ',
                       pluralize('configuration', len(configs)),
                       ' listed below?']
         yield makeForm(args=PostArgs(
             # Args used by 'cancel':
             RefererArgs.subset(proc.args),
             # Args used by 'execute':
             confirmedId=(config.getId() for config in configs
                          )))[xhtml.p[actionButtons(Actions)]].present(
                              **kwargs)
         yield FastConfigTable.instance.present(**kwargs)
     elif tagged:
         yield (xhtml.p['No configuration matches'
                        ' tag key ', xhtml.b[proc.args.tagkey],
                        ' and value ', xhtml.b[proc.args.tagvalue],
                        '.'], self.backToReferer(proc.args))
     else:
         yield (xhtml.p['No configuration named ',
                        xhtml.b[proc.args.configId],
                        ' exists.'], self.backToReferer(proc.args))
Beispiel #3
0
 def iterLinks(self, proc: Processor) -> Iterable[XMLContent]:
     yield pageLink('FastExecute', proc.args)[
         'Execute this configuration'
         ], ' (confirmation only)'
     configId = proc.args.configId
     yield pageLink('Execute', config=configId)[
         'Load this configuration'
         ], ' (provide inputs and parameters)'
     yield pageLink('ReportIndex', desc=configId)[
         'Show history of this configuration'
         ]
     yield pageLink('Execute', config=configId, step='edit')[
         'Edit this configuration'
         ]
     if proc.scheduleIds:
         numSchedules = len(proc.scheduleIds)
         yield (
             'Delete this configuration: not possible, because it is'
             ' currently being used by ', str(numSchedules), ' ',
             pluralize('schedule', numSchedules), '.'
             )
     else:
         yield pageLink('DelJobConfig', DeleteArgs(id=configId))[
             'Delete this configuration'
             ]
Beispiel #4
0
def fetchRecordForDeletion(proc: RecordDeleteProcessor[DeleteArgsT, DBRecord],
                           recordId: str) -> DBRecord:
    """Tries to fetch the record with the given ID.
    Raises PresentableError if the record does not exist or can currently
    not be deleted.
    """

    try:
        record = proc.db[recordId]
    except KeyError:
        raise PresentableError(
            xhtml.p['Cannot delete ', proc.recordName, ' ', xhtml.b[recordId],
                    ' because it does not exist (anymore).'])

    try:
        proc.checkState(record)
    except RecordInUseError as ex:
        raise PresentableError(
            xhtml.p['Cannot delete ', proc.recordName, ' ', xhtml.b[recordId],
                    ' because it is used in the following ',
                    pluralize(ex.refererName, ex.referers), ':'] +
            unorderedList[(ex.presenter(referer)
                           for referer in sorted(ex.referers))].present())

    return record
Beispiel #5
0
    def presentTaskFilter(self, args: ReportTaskArgs) -> XMLContent:
        yield 'Showing data from ',

        execState = args.execState
        if execState is not ExecutionState.ALL:
            yield xhtml.b[execState.name.lower()], ' '

        taskNames = args.task
        yield xhtml[', '].join(xhtml.b[name] for name in sorted(taskNames))
        yield ' tasks'

        owners = args.owner
        if owners:
            yield ' owned by '
            yield xhtml[', '].join(xhtml.b[name] for name in sorted(owners))

        targets = args.target
        if targets:
            yield ' for ', pluralize('target', len(targets)), ' '
            yield xhtml[', '].join(xhtml.b[name] for name in sorted(targets))

        ctabove = args.ctabove
        ctbelow = args.ctbelow
        if ctabove and ctbelow:
            yield (' created between ', xhtml.b[formatTime(ctabove)], ' and ',
                   xhtml.b[formatTime(ctbelow)])
        elif ctabove:
            yield ' created after ', xhtml.b[formatTime(ctabove)]
        elif ctbelow:
            yield ' created before ', xhtml.b[formatTime(ctbelow)]

        yield '.'
Beispiel #6
0
 def presentContent(self, **kwargs: object) -> XMLContent:
     proc = cast(ShowJobs_GET.Processor, kwargs['proc'])
     if len(proc.jobs) != 0:
         if proc.req.refererPage in ('BatchExecute', 'Execute',
                                     'FastExecute'):
             yield xhtml.p['Created the following ',
                           pluralize('job', len(proc.jobs)), ':']
         yield ShowJobsTable.instance.present(**kwargs)
     if len(proc.invalidJobIds) != 0:
         yield (xhtml.p['The following jobs ', xhtml.b['do not exist'],
                        ': '], unorderedList[proc.invalidJobIds])
     if len(proc.jobs) == 0 and len(proc.invalidJobIds) == 0:
         yield xhtml.p['No job IDs specified.']
Beispiel #7
0
    def presentContent(self, **kwargs: object) -> XMLContent:
        proc = cast(TaskDetails_GET.Processor, kwargs['proc'])
        taskDefId = proc.args.id
        configs = proc.configs

        yield xhtml.h3['Details of task definition ', xhtml.b[taskDefId], ':']
        yield DetailsTable.instance.present(**kwargs)
        yield xhtml.p[createTaskHistoryLink(taskDefId)]
        numConfigs = len(configs)
        yield xhtml.p[
            pageLink('TaskEdit', proc.args)['Edit this task definition'],
            xhtml.br,
            ('Delete this task definition: not possible, because it is '
             'currently being used by ', str(numConfigs), ' ',
             pluralize('configuration', numConfigs), '.'
             ) if configs else pageLink('TaskDelete', DeleteArgs(
                 id=taskDefId))['Delete this task definition']]
    def presentContent(self, **kwargs: object) -> XMLContent:
        proc = cast(FrameworkDetails_GET.Processor, kwargs['proc'])
        frameworkId = proc.args.id
        children = proc.children
        numChildren = len(children)
        deleteFramework = (
            'Delete this framework: not possible, '
            'because it is currently being used by ', str(numChildren), ' ',
            pluralize('task definition', numChildren), '.'
            ) if children else pageLink(
                'FrameworkDelete', DeleteArgs(id = frameworkId)
                )[ 'Delete this framework' ]

        yield xhtml.h3[ 'Details of framework ', xhtml.b[ frameworkId ], ':' ]
        yield xhtml.div(class_='hgroup wrap')[
            DetailsTable.instance,
            GraphPanel.instance
            ].present(graph=proc.graph, **kwargs)
        yield xhtml.p[
            pageLink('FrameworkEdit', proc.args)[ 'Edit this framework' ],
            xhtml.br,
            deleteFramework
            ]
Beispiel #9
0
    def __init__(self, table: 'DataTable[Record]', proc: PageProcessor):
        super().__init__()

        columns = tuple(table.iterColumns(proc=proc, data=None))

        dbName = table.dbName
        db: Optional[Database[Any]] = \
                None if dbName is None else getattr(proc, dbName)
        records = table.getRecordsToQuery(proc)
        if isinstance(records, SizedABC):
            unfilteredNrRecords: Optional[int] = len(records)
        elif db is not None:
            unfilteredNrRecords = len(db)
        else:
            # We could store all records in a list or wrap a counting iterator
            # around it, but so far that has not been necessary.
            unfilteredNrRecords = None

        sortField = table.sortField
        if sortField is None:
            # We don't know if getRecordsToQuery() has filtered or not.
            filtered = None
            if isinstance(records, list):
                records = cast(List[Record], records)
            else:
                records = list(records)
        else:
            sortOrder = cast(Sequence[str], getattr(proc.args, sortField))
            cleanSortOrder = self.__cleanSortOrder(columns, sortOrder)
            if sortOrder != cleanSortOrder:
                if proc.args.isArgument(sortField):
                    raise ArgsCorrected(
                        proc.args.override(**{sortField: cleanSortOrder}))
                else:
                    setattr(proc.args, sortField, cleanSortOrder)
            query: List[RecordProcessor] = list(table.iterFilters(proc))
            filtered = bool(query)
            keyMap = _buildKeyMap(columns, proc)
            sortKeys = (keyMap.get(key, key) for key in cleanSortOrder)
            # TODO: Maybe we should have a class (RecordCollection?) for
            #       records that are not DBRecords or to keep track of
            #       a subset of a full DB. Then 'uniqueKeys' could be moved
            #       from DataTable to RecordCollection.
            getRetriever: Callable[[str], Retriever[Record, Comparable]]
            if db is None:
                getRetriever = itemgetter
                uniqueKeys = table.uniqueKeys or ()
            else:
                getRetriever = db.retrieverFor
                assert table.uniqueKeys is None, "table's uniqueKeys is ignored"
                uniqueKeys = db.uniqueKeys
            retrievers: List[Retriever[Record, Comparable]] = []
            for key in sortKeys:
                if callable(key):
                    retrievers.append(substMissingForNone(key))
                else:
                    retrievers.append(substMissingForNone(getRetriever(key)))
                    if key in uniqueKeys:
                        break
            else:
                retrievers.append(
                    cast(Callable[[Record], Comparable],
                         lambda record: record))
            query.append(KeySorter(retrievers))
            records = runQuery(query, records)

        totalNrRecords = len(records)
        tabOffsetField = table.tabOffsetField
        if tabOffsetField is not None:
            tabOffset: int = getattr(proc.args, tabOffsetField)
            recordsPerPage = table.recordsPerPage
            if tabOffset < 0:
                # User tried to be funny and entered negative offset in URL.
                # Clip to first tab.
                newOffset = 0
            elif tabOffset >= totalNrRecords:
                # URL could be manipulated or were are looking at a database
                # from which records were recently deleted.
                # Clip to last tab.
                newOffset = (totalNrRecords // recordsPerPage) * recordsPerPage
            else:
                # Make sure the first record on a tab matches the tab label.
                # Round down to current tab label.
                newOffset = (tabOffset // recordsPerPage) * recordsPerPage
            if newOffset != tabOffset:
                raise ArgsCorrected(
                    proc.args.override(**{tabOffsetField: newOffset}))
            records = records[tabOffset:tabOffset + table.recordsPerPage]

        objectName = table.objectName
        if objectName is None:
            assert db is not None
            objectName = pluralize(db.description, 42)
        self.objectName = objectName

        self.columns = columns
        self.records = records
        self.unfilteredNrRecords = unfilteredNrRecords
        self.totalNrRecords = totalNrRecords
        self.filtered = filtered
Beispiel #10
0
    def __setState(self,
                   result: Optional[ResultCode],
                   newState: str,
                   summary: Optional[str],
                   outputs: Optional[Mapping[str, str]] = None
                   ) -> None:
        products = self.getProduced()

        # Check if non-existing output.PRODUCT.locators are set.
        if outputs:
            filteredOutputs = dict(outputs)
            unknownProducts = [
                outputName
                for outputName in outputs.keys()
                if all(outputName != product.getName() for product in products)
                ]
            if unknownProducts:
                # Remove locators for non-existing products.
                for productName in unknownProducts:
                    del filteredOutputs[productName]
                # Overrule result and summary.
                result = ResultCode.WARNING
                summary = \
                    'Wrapper sets output locator for non-existing %s: %s' % (
                        pluralize('product', unknownProducts),
                        ', '.join(sorted(unknownProducts))
                        )
        else:
            filteredOutputs = {}

        if result is not None:
            self._properties['result'] = result
        if summary is not None:
            self._properties['summary'] = summary
        self._properties['state'] = newState
        self._properties['stoptime'] = getTime()
        if 'abort' in self._properties:
            del self._properties['abort']
        if 'alert' in self._properties:
            del self._properties['alert']

        # Update state of outputs.
        for product in products:
            # Store locator.
            locator = filteredOutputs.get(product.getName())
            if locator is not None:
                product.storeLocator(locator, self.getName())
            # Is the product done now?
            # pylint: disable=protected-access
            if product.isCombined():
                if self.getJob()._isProductFixed(product):
                    product.done()
            else:
                # Locator availability determines whether product is available
                # or not. This new behaviour was introduced in SoftFab 2.10.0,
                # along with local products.
                if locator is None:
                    if self.getJob()._isProductFixed(product):
                        self.getJob()._blockProduct(product)
                else:
                    product.done()

        # Trigger property cache for task objects in joblib.
        if self.hasResult():
            self.getTask().initCached(resultOnly = False)