Skip to content

Commit

Permalink
fix(plate upload) (#137) (patch)
Browse files Browse the repository at this point in the history
Fix plate upload bug
  • Loading branch information
ChrOertlin authored Apr 12, 2024
1 parent 7077b18 commit ef3db16
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 37 deletions.
13 changes: 9 additions & 4 deletions genotype_api/api/endpoints/plates.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from genotype_api.database.store import Store, get_store
from genotype_api.dto.plate import PlateResponse
from genotype_api.dto.user import CurrentUser
from genotype_api.exceptions import PlateNotFoundError
from genotype_api.exceptions import PlateNotFoundError, PlateExistsError
from genotype_api.security import get_active_user
from genotype_api.services.endpoint_services.plate_service import PlateService

Expand All @@ -24,15 +24,20 @@ def get_plate_service(store: Store = Depends(get_store)) -> PlateService:

@router.post(
"/plate",
response_model=PlateResponse,
response_model_exclude={"plate_status_counts"},
)
def upload_plate(
file: UploadFile = File(...),
plate_service: PlateService = Depends(get_plate_service),
current_user: CurrentUser = Depends(get_active_user),
):
return plate_service.upload_plate(file)

try:
plate_service.upload_plate(file)
except PlateExistsError:
raise HTTPException(
detail="Plate already exists in the database.", status_code=HTTPStatus.BAD_REQUEST
)
return JSONResponse("Plate uploaded successfully", status_code=status.HTTP_201_CREATED)


@router.patch(
Expand Down
2 changes: 1 addition & 1 deletion genotype_api/database/crud/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def get_analysis_by_type_and_sample_id(self, analysis_type: str, sample_id: str)
return (
self.session.query(Analysis)
.filter(Analysis.sample_id == sample_id, Analysis.type == analysis_type)
.one()
.first()
)

def get_plate_by_id(self, plate_id: int) -> Plate:
Expand Down
4 changes: 4 additions & 0 deletions genotype_api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,7 @@ class SampleExistsError(Exception):

class SNPExistsError(Exception):
pass


class PlateExistsError(Exception):
pass
20 changes: 4 additions & 16 deletions genotype_api/file_parsing/excel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Code to work with excel files"""

import logging
from datetime import datetime
from pathlib import Path
from typing import ByteString, Iterable

Expand Down Expand Up @@ -70,7 +71,7 @@ def parse_sample_id(sample_id: str, include_key: str = None) -> str | None:
LOG.info("Use sample id %s", sample_id)
return sample_id

def generate_analyses(self) -> Iterable[Analysis]:
def generate_analyses(self, plate_id: int) -> Iterable[Analysis]:
"""Loop over the rows and create one analysis for each individual"""
nr_row: int
row: list[str]
Expand All @@ -95,6 +96,8 @@ def generate_analyses(self) -> Iterable[Analysis]:
sample_id=sample_id,
sex=sex,
genotypes=genotypes,
plate_id=plate_id,
created_at=datetime.now(),
)

@staticmethod
Expand Down Expand Up @@ -134,18 +137,3 @@ def parse_sex(sex_cells: list[str]) -> str:
# assays returned conflicting results
message = "conflicting sex predictions: {}".format(sex_cells)
raise SexConflictError(message)


if __name__ == "__main__":
import sys

import coloredlogs

coloredlogs.install()

in_file = Path(sys.argv[1])
# include_key = "ID-CG-"
include_key = "-CG-"
genotype_analysis = GenotypeAnalysis(in_file, include_key)
for analysis in genotype_analysis.generate_analyses():
print(analysis)
33 changes: 17 additions & 16 deletions genotype_api/services/endpoint_services/plate_service.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
"""Module to holds the plate service."""

import logging
from datetime import datetime
from http.client import HTTPException

from io import BytesIO
from pathlib import Path


from fastapi import UploadFile
from pydantic import EmailStr
from starlette import status

from genotype_api.constants import Types
from genotype_api.database.filter_models.plate_models import PlateSignOff, PlateOrderParams
from genotype_api.database.models import Plate, Analysis, User
from genotype_api.database.models import Plate, Analysis, User, Sample
from genotype_api.dto.plate import PlateResponse, UserOnPlate, AnalysisOnPlate, SampleStatus
from genotype_api.exceptions import PlateNotFoundError, UserNotFoundError
from genotype_api.exceptions import PlateNotFoundError, UserNotFoundError, PlateExistsError
from genotype_api.file_parsing.excel import GenotypeAnalysis
from genotype_api.file_parsing.files import check_file
from genotype_api.services.endpoint_services.base_service import BaseService
Expand Down Expand Up @@ -68,33 +69,33 @@ def _get_plate_id_from_file(file_name: Path) -> str:
# Get the plate id from the standardized name of the plate
return file_name.name.split("_", 1)[0]

def upload_plate(self, file: UploadFile) -> PlateResponse:
def upload_plate(self, file: UploadFile) -> None:
file_name: Path = check_file(file_path=file.filename, extension=".xlsx")
plate_id: str = self._get_plate_id_from_file(file_name)
db_plate = self.store.get_plate_by_plate_id(plate_id)
if db_plate:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"Plate with id {db_plate.id} already exists",
)
raise PlateExistsError

excel_parser = GenotypeAnalysis(
excel_file=BytesIO(file.file.read()),
file_name=str(file_name),
include_key="-CG-",
)
analyses: list[Analysis] = list(excel_parser.generate_analyses())

plate_obj = Plate(plate_id=plate_id)
plate: Plate = self.store.create_plate(plate=plate_obj)
new_plate: Plate = self.store.get_plate_by_plate_id(plate_id=plate_id)
analyses: list[Analysis] = list(excel_parser.generate_analyses(plate_id=new_plate.id))
self.store.check_analyses_objects(analyses=analyses, analysis_type=Types.GENOTYPE)
self.store.create_analyses_samples(analyses=analyses)
plate_obj = Plate(plate_id=plate_id)
for analysis in analyses:
self.store.create_analysis(analysis=analysis)
plate_obj.analyses = analyses
plate: Plate = self.store.create_plate(plate=plate_obj)
for analysis in plate.analyses:
self.store.refresh_sample_status(sample=analysis.sample)
for analysis in analyses:
sample: Sample = self.store.get_sample_by_id(sample_id=analysis.sample_id)
self.store.refresh_sample_status(sample=sample)
self.store.refresh_plate(plate=plate)

return self._create_plate_response(plate)

def update_plate_sign_off(
self, plate_id: int, user_email: EmailStr, method_document: str, method_version: str
) -> PlateResponse:
Expand Down

0 comments on commit ef3db16

Please sign in to comment.