import shutil import uuid from contextlib import closing from pathlib import Path from flask import abort from flask import make_response from flask import request from flask.views import View from pycs import db from pycs import settings from pycs.database.LabelProvider import LabelProvider from pycs.database.Model import Model from pycs.database.Project import Project from pycs.frontend.endpoints.projects.ExecuteExternalStorage import ExecuteExternalStorage from pycs.frontend.endpoints.projects.ExecuteLabelProvider import ExecuteLabelProvider from pycs.frontend.notifications.NotificationManager import NotificationManager from pycs.jobs.JobRunner import JobRunner from pycs.util.PipelineUtil import load_from_root_folder as load_pipeline class CreateProject(View): """ create a project, insert data into database and create directories """ # 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): # extract request data data = request.get_json(force=True) name = data.get('name') description = data.get('description') if name is None: abort(400, "name argument is missing!") if description is None: abort(400, "description argument is missing!") model_id = int(data['model']) model = Model.get_or_404(model_id) label_provider_id = data.get('label') label_provider = None if label_provider_id is not None: label_provider = LabelProvider.get_or_404(label_provider_id) # create project folder project_folder = Path(settings.projects_folder, str(uuid.uuid1())) project_folder.mkdir(parents=True) temp_folder = project_folder / 'temp' temp_folder.mkdir() # check project data directory if data['external'] is None: external_data = False data_folder = project_folder / 'data' data_folder.mkdir() else: external_data = True data_folder = Path(data['external']) # check if exists if not data_folder.exists(): return abort(400, f"External folder does not exist: {data_folder}") # copy model to project folder model_folder = project_folder / 'model' shutil.copytree(model.root_folder, str(model_folder)) with db.session.begin_nested(): model, is_new = model.copy_to( name=f'{model.name} ({name})', root_folder=str(model_folder), commit=False) model.flush() if not is_new: # pragma: no cover abort(400, f"Could not copy model! Model in \"{model_folder}\" already exists!") project = Project.new(name=name, description=description, model_id=model.id, label_provider_id=label_provider_id, root_folder=str(project_folder), external_data=external_data, data_folder=str(data_folder)) # execute label provider and add labels to project if label_provider is not None: ExecuteLabelProvider.execute_label_provider(self.nm, self.jobs, project, label_provider) # load model and add collections to the project def load_model_and_get_collections(): with closing(load_pipeline(model.root_folder)) as pipeline: return pipeline.collections() def add_collections_to_project(provided_collections): with db.session.begin_nested(): for position, collection in enumerate(provided_collections, 1): project.create_collection(commit=False, position=position, **collection) self.jobs.run(project, 'Media Collections', f'{project.name}', f'{project.id}/media-collections', executable=load_model_and_get_collections, result=add_collections_to_project) # find media files if external_data: ExecuteExternalStorage.find_media_files(self.nm, self.jobs, project) # fire event self.nm.create_model(model) self.nm.create_project(project) # return success response return make_response()