Exemple #1
0
async def update_model(
        model_id: UUID,
        model_patch: ScientificModelPatch,
        token: HTTPAuthorizationCredentials = Depends(auth),
):
    # if payload contains a project_id, check permissions for that id
    if model_patch.project_id and not (await is_collab_member(
            model_patch.project_id, token.credentials)
                                       or await is_admin(token.credentials)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=
            f"This account is not a member of Collab #{model_patch.project_id}",
        )
    # retrieve stored model
    model_project = ModelProject.from_uuid(str(model_id),
                                           kg_client,
                                           api="nexus")
    stored_model = ScientificModel.from_kg_object(model_project, kg_client)
    # if retrieved project_id is different to payload id, check permissions for that id
    if stored_model.project_id != model_patch.project_id and not (
            await is_collab_member(stored_model.project_id, token.credentials)
            or await is_admin(token.credentials)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=
            f"Access to this model is restricted to members of Collab #{stored_model.project_id}",
        )
    # if alias changed, check uniqueness of new alias
    if (model_patch.alias and model_patch.alias != stored_model.alias
            and model_alias_exists(model_patch.alias, kg_client)):
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=
            f"Another model with alias '{model_patch.alias}' already exists.",
        )
    # todo: if model id provided in payload, check it matches the model_id parameter
    # todo: if model uri provided in payload, check it matches the id

    # here we are updating the pydantic model `stored_model`, then recreating the kg objects
    # from this. It might be more efficient to directly update `model_project`.
    # todo: profile both possible implementations
    update_data = model_patch.dict(exclude_unset=True)
    for field, value in update_data.items():
        if field in ("author", "owner"):
            update_data[field] = [Person(**p) for p in update_data[field]]
    updated_model = stored_model.copy(update=update_data)
    kg_objects = updated_model.to_kg_objects()
    for obj in kg_objects:
        obj.save(kg_client)
    model_project = kg_objects[-1]
    assert isinstance(model_project, ModelProject)
    return ScientificModel.from_kg_object(model_project, kg_client)
async def _get_model_by_id_or_alias(model_id, token):
    try:
        model_id = UUID(model_id)
        model_project = ModelProject.from_uuid(str(model_id), kg_client, api="nexus")
    except ValueError:
        model_alias = str(model_id)
        model_project = ModelProject.from_alias(model_alias, kg_client, api="nexus")
    if not model_project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Model with ID or alias '{model_id}' not found.",
        )
    # todo: fairgraph should accept UUID object as well as str
    await _check_model_access(model_project, token)
    return model_project
def _are_model_instance_version_unique_kg(instance_json, kg_client):
    """
    Check if versions of model instance are unique
    :param instance_json: datas of instance
    :type instance_json: dict
    :returns: response
    :rtype: boolean
    """
    new_version_name = instance_json['version']
    model_project = ModelProject.from_uuid(instance_json['model_id'], kg_client)
    if model_project.instances:
        all_instances_versions_name = [inst.resolve(kg_client).version for inst in as_list(model_project.instances)]
        if new_version_name in all_instances_versions_name:
            return False
    return True
Exemple #4
0
async def delete_model_instance(
    model_id: UUID,
    model_instance_id: UUID,
    token: HTTPAuthorizationCredentials = Depends(auth)):
    # todo: handle non-existent UUID
    model_project = ModelProject.from_uuid(str(model_id),
                                           kg_client,
                                           api="nexus")
    if not (await is_collab_member(model_project.collab_id, token.credentials)
            or await is_admin(token.credentials)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=
            f"Access to this model is restricted to members of Collab #{model_project.collab_id}",
        )
    await _delete_model_instance(model_instance_id, model_project)
Exemple #5
0
async def delete_model(model_id: UUID,
                       token: HTTPAuthorizationCredentials = Depends(auth)):
    # todo: handle non-existent UUID
    model_project = ModelProject.from_uuid(str(model_id),
                                           kg_client,
                                           api="nexus")
    if not (await is_collab_member(model_project.collab_id, token.credentials)
            or await is_admin(token.credentials)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=
            f"Access to this model is restricted to members of Collab #{model_project.collab_id}",
        )
    model_project.delete(kg_client)
    for model_instance in as_list(model_project.instances):
        # todo: we should possibly also delete emodels, modelscripts, morphologies,
        # but need to check they're not shared with other instances
        model_instance.delete(kg_client)
    def save(self):
        # todo: Create/update EModel, MEModel and Morphology where model_scope is "single cell"
        if self.obj is None:  # create
            model_project = ModelProject.from_uuid(self.data["model_id"],
                                                   self.client,
                                                   api="nexus")
            script = ModelScript(name="ModelScript for {} @ {}".format(
                model_project.name, self.data["version"]),
                                 code_format=self.data.get("code_format"),
                                 code_location=self.data["source"],
                                 license=self.data.get("license"))
            script.save(self.client)

            if model_project.model_of and model_project.model_of.label == "single cell" and "morphology" in self.data:
                e_model = EModel(name="EModel for {} @ {}".format(
                    model_project.name, self.data["version"]),
                                 brain_region=model_project.brain_region,
                                 species=model_project.species,
                                 model_of=None,
                                 main_script=None,
                                 release=None)
                e_model.save(self.client)
                morph = Morphology(name="Morphology for {} @ {}".format(
                    model_project.name, self.data["version"]),
                                   cell_type=model_project.celltype,
                                   morphology_file=self.data["morphology"])
                morph.save(self.client)
                minst = MEModel(name="ModelInstance for {} @ {}".format(
                    model_project.name, self.data["version"]),
                                description=self.data.get("description", ""),
                                brain_region=model_project.brain_region,
                                species=model_project.species,
                                model_of=None,
                                main_script=script,
                                e_model=e_model,
                                morphology=morph,
                                version=self.data["version"],
                                parameters=self.data.get("parameters"),
                                timestamp=datetime.now(),
                                release=None)
            else:
                minst = ModelInstance(name="ModelInstance for {} @ {}".format(
                    model_project.name, self.data["version"]),
                                      description=self.data.get(
                                          "description", ""),
                                      brain_region=model_project.brain_region,
                                      species=model_project.species,
                                      model_of=None,
                                      main_script=script,
                                      version=self.data["version"],
                                      parameters=self.data.get("parameters"),
                                      timestamp=datetime.now(),
                                      release=None)
            minst.save(self.client)
            self.obj = minst

            if model_project.instances:
                if not isinstance(model_project.instances, list):
                    model_project.instances = [model_project.instances]
                model_project.instances.append(minst)
            else:
                model_project.instances = [minst]
            model_project.save(self.client)

        else:  # update
            instance_changed = False
            script_changed = False
            morphology_changed = False

            def resolve_obj(obj):
                if isinstance(obj, KGProxy):
                    return obj.resolve(self.client, api="nexus")
                else:
                    return obj

            if "name" in self.data:
                self.obj.name = self.data["name"]
                # todo: also update e_model and morphology
                instance_changed = True
            if "description" in self.data:
                self.obj.description = self.data.get("description", "")
                instance_changed = True
            if "version" in self.data:
                self.obj.version = self.data["version"]
                instance_changed = True
            if "parameters" in self.data:
                self.obj.parameters = self.data.get("parameters")
                instance_changed = True
            if "code_format" in self.data:
                self.obj.main_script = resolve_obj(self.obj.main_script)
                self.obj.main_script.code_format = self.data.get("code_format")
                script_changed = True
            if "source" in self.data:
                self.obj.main_script = resolve_obj(self.obj.main_script)
                self.obj.main_script.code_location = self.data["source"]
                script_changed = True
            if "license" in self.data:
                self.obj.main_script = resolve_obj(self.obj.main_script)
                self.obj.main_script.license = self.data.get("license")
                script_changed = True
            if "morphology" in self.data and self.data[
                    "morphology"] is not None:
                self.obj.morphology = resolve_obj(self.obj.morphology)
                self.obj.morphology.morphology_file = self.data["morphology"]
                morphology_changed = True
            logger.debug("Morphology changed: {}".format(morphology_changed))
            logger.debug("Script changed: {}".format(script_changed))
            logger.debug("Instance changed: {}".format(instance_changed))
            if morphology_changed:
                self.obj.morphology.save(self.client)
            if script_changed:
                self.obj.main_script.save(self.client)
            if instance_changed:
                self.obj.save(self.client)

        return self.obj