99from fastapi .encoders import jsonable_encoder
1010from fastapi .exceptions import HTTPException
1111from fastapi .responses import StreamingResponse
12- from sqlalchemy import or_
13- from sqlalchemy .exc import MultipleResultsFound
12+ from sqlalchemy import or_ , select
13+ from sqlalchemy .exc import MultipleResultsFound , NoResultFound
1414from sqlalchemy .orm import Session
1515
1616from mavedb import deps
1717from mavedb .lib .authentication import UserData
18- from mavedb .lib .authorization import get_current_user , require_current_user , require_current_user_with_email
18+ from mavedb .lib .authorization import (
19+ get_current_user ,
20+ require_current_user ,
21+ require_current_user_with_email ,
22+ RoleRequirer ,
23+ )
1924from mavedb .lib .contributors import find_or_create_contributor
2025from mavedb .lib .exceptions import MixedTargetError , NonexistentOrcidUserError , ValidationError
2126from mavedb .lib .identifiers import (
4954)
5055from mavedb .models .contributor import Contributor
5156from mavedb .models .enums .processing_state import ProcessingState
57+ from mavedb .models .enums .user_role import UserRole
5258from mavedb .models .experiment import Experiment
5359from mavedb .models .license import License
5460from mavedb .models .mapped_variant import MappedVariant
5763from mavedb .models .target_gene import TargetGene
5864from mavedb .models .target_sequence import TargetSequence
5965from mavedb .models .variant import Variant
60- from mavedb .view_models import mapped_variant , score_set
66+ from mavedb .view_models import mapped_variant , score_set , calibration
6167from mavedb .view_models .search import ScoreSetsSearch
6268
6369logger = logging .getLogger (__name__ )
@@ -174,6 +180,7 @@ def get_score_set_scores_csv(
174180 urn : str ,
175181 start : int = Query (default = None , description = "Start index for pagination" ),
176182 limit : int = Query (default = None , description = "Number of variants to return" ),
183+ drop_na_columns : Optional [bool ] = None ,
177184 db : Session = Depends (deps .get_db ),
178185 user_data : Optional [UserData ] = Depends (get_current_user ),
179186) -> Any :
@@ -208,7 +215,7 @@ def get_score_set_scores_csv(
208215
209216 assert_permission (user_data , score_set , Action .READ )
210217
211- csv_str = get_score_set_scores_as_csv (db , score_set , start , limit )
218+ csv_str = get_score_set_scores_as_csv (db , score_set , start , limit , drop_na_columns )
212219 return StreamingResponse (iter ([csv_str ]), media_type = "text/csv" )
213220
214221
@@ -228,6 +235,7 @@ async def get_score_set_counts_csv(
228235 urn : str ,
229236 start : int = Query (default = None , description = "Start index for pagination" ),
230237 limit : int = Query (default = None , description = "Number of variants to return" ),
238+ drop_na_columns : Optional [bool ] = None ,
231239 db : Session = Depends (deps .get_db ),
232240 user_data : Optional [UserData ] = Depends (get_current_user ),
233241) -> Any :
@@ -262,7 +270,7 @@ async def get_score_set_counts_csv(
262270
263271 assert_permission (user_data , score_set , Action .READ )
264272
265- csv_str = get_score_set_counts_as_csv (db , score_set , start , limit )
273+ csv_str = get_score_set_counts_as_csv (db , score_set , start , limit , drop_na_columns )
266274 return StreamingResponse (iter ([csv_str ]), media_type = "text/csv" )
267275
268276
@@ -336,8 +344,10 @@ async def create_score_set(
336344 raise HTTPException (status_code = status .HTTP_400_BAD_REQUEST , detail = "Unknown experiment" )
337345 # Not allow add score set in meta-analysis experiments.
338346 if any (s .meta_analyzes_score_sets for s in experiment .score_sets ):
339- raise HTTPException (status_code = status .HTTP_403_FORBIDDEN ,
340- detail = "Score sets may not be added to a meta-analysis experiment." )
347+ raise HTTPException (
348+ status_code = status .HTTP_403_FORBIDDEN ,
349+ detail = "Score sets may not be added to a meta-analysis experiment." ,
350+ )
341351
342352 save_to_logging_context ({"experiment" : experiment .urn })
343353 assert_permission (user_data , experiment , Action .ADD_SCORE_SET )
@@ -656,6 +666,43 @@ async def upload_score_set_variant_data(
656666 return item
657667
658668
669+ @router .post (
670+ "/score-sets/{urn}/calibration/data" ,
671+ response_model = score_set .ScoreSet ,
672+ responses = {422 : {}},
673+ response_model_exclude_none = True ,
674+ )
675+ async def update_score_set_calibration_data (
676+ * ,
677+ urn : str ,
678+ calibration_update : dict [str , calibration .Calibration ],
679+ db : Session = Depends (deps .get_db ),
680+ user_data : UserData = Depends (RoleRequirer ([UserRole .admin ])),
681+ ):
682+ """
683+ Update thresholds / score calibrations for a score set.
684+ """
685+ save_to_logging_context ({"requested_resource" : urn , "resource_property" : "score_thresholds" })
686+
687+ try :
688+ item = db .scalars (select (ScoreSet ).where (ScoreSet .urn == urn )).one ()
689+ except NoResultFound :
690+ logger .info (
691+ msg = "Failed to add score thresholds; The requested score set does not exist." , extra = logging_context ()
692+ )
693+ raise HTTPException (status_code = 404 , detail = f"score set with URN '{ urn } ' not found" )
694+
695+ assert_permission (user_data , item , Action .UPDATE )
696+
697+ item .score_calibrations = {k : v .dict () for k , v in calibration_update .items ()}
698+ db .add (item )
699+ db .commit ()
700+ db .refresh (item )
701+
702+ save_to_logging_context ({"updated_resource" : item .urn })
703+ return item
704+
705+
659706@router .put (
660707 "/score-sets/{urn}" , response_model = score_set .ScoreSet , responses = {422 : {}}, response_model_exclude_none = True
661708)
0 commit comments