from contextlib import closing from flask import abort from flask import make_response from flask import request from flask.views import View from pycs import db from pycs.database.LabelProvider import LabelProvider from pycs.database.Project import Project from pycs.frontend.notifications.NotificationManager import NotificationManager from pycs.jobs.JobGroupBusyException import JobGroupBusyException from pycs.jobs.JobRunner import JobRunner class ExecuteLabelProvider(View): """ execute the label provider associated with a passed project identifier """ # pylint: disable=arguments-differ methods = ['POST'] def __init__(self, nm: NotificationManager, jobs: JobRunner): # pylint: disable=invalid-name self.nm = nm self.jobs = jobs def dispatch_request(self, project_id: int): project = Project.get_or_404(project_id) # extract request data data = request.get_json(force=True) if not data.get('execute', False): abort(400, "execute flag is missing") # get label provider label_provider = project.label_provider if label_provider is None: abort(400, "This project does not have a label provider.") # execute label provider and add labels to project try: self.execute_label_provider(self.nm, self.jobs, project, label_provider) except JobGroupBusyException: abort(400, "Label provider already running.") return make_response() @staticmethod def execute_label_provider(nm: NotificationManager, jobs: JobRunner, project: Project, label_provider: LabelProvider): """ start a job that loads and executes a label provider and saves its results to the database afterwards :param nm: notification manager object :param jobs: job runner object :param project: project :param label_provider: label provider :return: """ # pylint: disable=invalid-name # receive loads and executes the given label provider def receive(): with closing(label_provider.load()) as label_provider_impl: return label_provider_impl.get_labels() project_id = project.id # result adds the received labels to the database and fires events def result(provided_labels): nonlocal project_id def _inner(labels, project_id): project = Project.query.get(project_id) labels = project.bulk_create_labels(labels) for label in labels: nm.create_label(label) if db.session().in_transaction(): _inner(provided_labels, project_id) else: with db.session.begin(): _inner(provided_labels, project_id) # run job with given functions jobs.run(project, 'Label Provider', f'{project.name} ({label_provider.name})', f'{project.id}/label-provider', receive, result=result)