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 (
5055)
5156from mavedb .models .contributor import Contributor
5257from mavedb .models .enums .processing_state import ProcessingState
58+ from mavedb .models .enums .user_role import UserRole
5359from mavedb .models .experiment import Experiment
5460from mavedb .models .license import License
5561from mavedb .models .mapped_variant import MappedVariant
5864from mavedb .models .target_gene import TargetGene
5965from mavedb .models .target_sequence import TargetSequence
6066from mavedb .models .variant import Variant
61- from mavedb .view_models import mapped_variant , score_set
67+ from mavedb .view_models import mapped_variant , score_set , calibration
6268from mavedb .view_models .search import ScoreSetsSearch
6369
6470logger = logging .getLogger (__name__ )
@@ -185,6 +191,7 @@ def get_score_set_scores_csv(
185191 urn : str ,
186192 start : int = Query (default = None , description = "Start index for pagination" ),
187193 limit : int = Query (default = None , description = "Number of variants to return" ),
194+ drop_na_columns : Optional [bool ] = None ,
188195 db : Session = Depends (deps .get_db ),
189196 user_data : Optional [UserData ] = Depends (get_current_user ),
190197) -> Any :
@@ -219,7 +226,7 @@ def get_score_set_scores_csv(
219226
220227 assert_permission (user_data , score_set , Action .READ )
221228
222- csv_str = get_score_set_scores_as_csv (db , score_set , start , limit )
229+ csv_str = get_score_set_scores_as_csv (db , score_set , start , limit , drop_na_columns )
223230 return StreamingResponse (iter ([csv_str ]), media_type = "text/csv" )
224231
225232
@@ -239,6 +246,7 @@ async def get_score_set_counts_csv(
239246 urn : str ,
240247 start : int = Query (default = None , description = "Start index for pagination" ),
241248 limit : int = Query (default = None , description = "Number of variants to return" ),
249+ drop_na_columns : Optional [bool ] = None ,
242250 db : Session = Depends (deps .get_db ),
243251 user_data : Optional [UserData ] = Depends (get_current_user ),
244252) -> Any :
@@ -273,7 +281,7 @@ async def get_score_set_counts_csv(
273281
274282 assert_permission (user_data , score_set , Action .READ )
275283
276- csv_str = get_score_set_counts_as_csv (db , score_set , start , limit )
284+ csv_str = get_score_set_counts_as_csv (db , score_set , start , limit , drop_na_columns )
277285 return StreamingResponse (iter ([csv_str ]), media_type = "text/csv" )
278286
279287
@@ -347,8 +355,10 @@ async def create_score_set(
347355 raise HTTPException (status_code = status .HTTP_400_BAD_REQUEST , detail = "Unknown experiment" )
348356 # Not allow add score set in meta-analysis experiments.
349357 if any (s .meta_analyzes_score_sets for s in experiment .score_sets ):
350- raise HTTPException (status_code = status .HTTP_403_FORBIDDEN ,
351- detail = "Score sets may not be added to a meta-analysis experiment." )
358+ raise HTTPException (
359+ status_code = status .HTTP_403_FORBIDDEN ,
360+ detail = "Score sets may not be added to a meta-analysis experiment." ,
361+ )
352362
353363 save_to_logging_context ({"experiment" : experiment .urn })
354364 assert_permission (user_data , experiment , Action .ADD_SCORE_SET )
@@ -668,6 +678,43 @@ async def upload_score_set_variant_data(
668678 return item
669679
670680
681+ @router .post (
682+ "/score-sets/{urn}/calibration/data" ,
683+ response_model = score_set .ScoreSet ,
684+ responses = {422 : {}},
685+ response_model_exclude_none = True ,
686+ )
687+ async def update_score_set_calibration_data (
688+ * ,
689+ urn : str ,
690+ calibration_update : dict [str , calibration .Calibration ],
691+ db : Session = Depends (deps .get_db ),
692+ user_data : UserData = Depends (RoleRequirer ([UserRole .admin ])),
693+ ):
694+ """
695+ Update thresholds / score calibrations for a score set.
696+ """
697+ save_to_logging_context ({"requested_resource" : urn , "resource_property" : "score_thresholds" })
698+
699+ try :
700+ item = db .scalars (select (ScoreSet ).where (ScoreSet .urn == urn )).one ()
701+ except NoResultFound :
702+ logger .info (
703+ msg = "Failed to add score thresholds; The requested score set does not exist." , extra = logging_context ()
704+ )
705+ raise HTTPException (status_code = 404 , detail = f"score set with URN '{ urn } ' not found" )
706+
707+ assert_permission (user_data , item , Action .UPDATE )
708+
709+ item .score_calibrations = {k : v .dict () for k , v in calibration_update .items ()}
710+ db .add (item )
711+ db .commit ()
712+ db .refresh (item )
713+
714+ save_to_logging_context ({"updated_resource" : item .urn })
715+ return item
716+
717+
671718@router .put (
672719 "/score-sets/{urn}" , response_model = score_set .ScoreSet , responses = {422 : {}}, response_model_exclude_none = True
673720)
0 commit comments