Skip to content

Commit a59011f

Browse files
committed
Expand Editable Metadata for Score Sets
1 parent 1d65c1d commit a59011f

File tree

5 files changed

+467
-185
lines changed

5 files changed

+467
-185
lines changed

src/mavedb/routers/score_sets.py

Lines changed: 56 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,9 @@ async def upload_score_set_variant_data(
646646
return item
647647

648648

649-
@router.put("/score-sets/{urn}", response_model=score_set.ScoreSet, responses={422: {}})
649+
@router.put(
650+
"/score-sets/{urn}", response_model=score_set.ScoreSet, responses={422: {}}, response_model_exclude_none=True
651+
)
650652
async def update_score_set(
651653
*,
652654
urn: str,
@@ -668,68 +670,65 @@ async def update_score_set(
668670

669671
assert_permission(user_data, item, Action.UPDATE)
670672

671-
# Editing unpublished score set
672-
if item.private is True:
673-
license_ = None
673+
for var, value in vars(item_update).items():
674+
if var not in [
675+
"contributors",
676+
"score_ranges",
677+
"doi_identifiers",
678+
"experiment_urn",
679+
"license_id",
680+
"secondary_publication_identifiers",
681+
"primary_publication_identifiers",
682+
"target_genes",
683+
]:
684+
setattr(item, var, value) if value else None
685+
686+
if item_update.license_id is not None:
687+
save_to_logging_context({"license": item_update.license_id})
688+
license_ = db.query(License).filter(License.id == item_update.license_id).one_or_none()
689+
690+
if not license_:
691+
logger.info(
692+
msg="Failed to update score set; The requested license does not exist.", extra=logging_context()
693+
)
694+
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Unknown license")
674695

675-
if item_update.license_id is not None:
676-
save_to_logging_context({"license": item_update.license_id})
677-
license_ = db.query(License).filter(License.id == item_update.license_id).one_or_none()
696+
item.license = license_
678697

679-
if not license_:
680-
logger.info(
681-
msg="Failed to update score set; The requested license does not exist.", extra=logging_context()
682-
)
683-
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Unknown license")
698+
item.doi_identifiers = [
699+
await find_or_create_doi_identifier(db, identifier.identifier)
700+
for identifier in item_update.doi_identifiers or []
701+
]
702+
primary_publication_identifiers = [
703+
await find_or_create_publication_identifier(db, identifier.identifier, identifier.db_name)
704+
for identifier in item_update.primary_publication_identifiers or []
705+
]
706+
publication_identifiers = [
707+
await find_or_create_publication_identifier(db, identifier.identifier, identifier.db_name)
708+
for identifier in item_update.secondary_publication_identifiers or []
709+
] + primary_publication_identifiers
684710

685-
item.license = license_
711+
# create a temporary `primary` attribute on each of our publications that indicates
712+
# to our association proxy whether it is a primary publication or not
713+
primary_identifiers = [p.identifier for p in primary_publication_identifiers]
714+
for publication in publication_identifiers:
715+
setattr(publication, "primary", publication.identifier in primary_identifiers)
686716

687-
for var, value in vars(item_update).items():
688-
if var not in [
689-
"contributors",
690-
"score_ranges",
691-
"doi_identifiers",
692-
"experiment_urn",
693-
"license_id",
694-
"secondary_publication_identifiers",
695-
"primary_publication_identifiers",
696-
"target_genes",
697-
]:
698-
setattr(item, var, value) if value else None
699-
700-
try:
701-
item.contributors = [
702-
await find_or_create_contributor(db, contributor.orcid_id)
703-
for contributor in item_update.contributors or []
704-
]
705-
except NonexistentOrcidUserError as e:
706-
logger.error(msg="Could not find ORCID user with the provided user ID.", extra=logging_context())
707-
raise pydantic.ValidationError(
708-
[pydantic.error_wrappers.ErrorWrapper(ValidationError(str(e)), loc="contributors")],
709-
model=score_set.ScoreSetUpdate,
710-
)
717+
item.publication_identifiers = publication_identifiers
711718

712-
item.doi_identifiers = [
713-
await find_or_create_doi_identifier(db, identifier.identifier)
714-
for identifier in item_update.doi_identifiers or []
715-
]
716-
primary_publication_identifiers = [
717-
await find_or_create_publication_identifier(db, identifier.identifier, identifier.db_name)
718-
for identifier in item_update.primary_publication_identifiers or []
719+
try:
720+
item.contributors = [
721+
await find_or_create_contributor(db, contributor.orcid_id) for contributor in item_update.contributors or []
719722
]
720-
publication_identifiers = [
721-
await find_or_create_publication_identifier(db, identifier.identifier, identifier.db_name)
722-
for identifier in item_update.secondary_publication_identifiers or []
723-
] + primary_publication_identifiers
724-
725-
# create a temporary `primary` attribute on each of our publications that indicates
726-
# to our association proxy whether it is a primary publication or not
727-
primary_identifiers = [pub.identifier for pub in primary_publication_identifiers]
728-
for publication in publication_identifiers:
729-
setattr(publication, "primary", publication.identifier in primary_identifiers)
730-
731-
item.publication_identifiers = publication_identifiers
723+
except NonexistentOrcidUserError as e:
724+
logger.error(msg="Could not find ORCID user with the provided user ID.", extra=logging_context())
725+
raise pydantic.ValidationError(
726+
[pydantic.error_wrappers.ErrorWrapper(ValidationError(str(e)), loc="contributors")],
727+
model=score_set.ScoreSetUpdate,
728+
)
732729

730+
# Score set has not been published and attributes affecting scores may still be edited.
731+
if item.private:
733732
if item_update.score_ranges:
734733
item.score_ranges = item_update.score_ranges.dict()
735734
else:
@@ -884,35 +883,8 @@ async def update_score_set(
884883
if job is not None:
885884
save_to_logging_context({"worker_job_id": job.job_id})
886885
logger.info(msg="Enqueud variant creation job.", extra=logging_context())
887-
888-
for var, value in vars(item_update).items():
889-
if var not in [
890-
"score_ranges",
891-
"contributors",
892-
"doi_identifiers",
893-
"experiment_urn",
894-
"primary_publication_identifiers",
895-
"secondary_publication_identifiers",
896-
"target_genes",
897-
]:
898-
setattr(item, var, value) if value else None
899-
900-
# Editing published score set
901886
else:
902-
for var, value in vars(item_update).items():
903-
if var in ["title", "method_text", "abstract_text", "short_description"]:
904-
setattr(item, var, value) if value else None
905-
try:
906-
item.contributors = [
907-
await find_or_create_contributor(db, contributor.orcid_id)
908-
for contributor in item_update.contributors or []
909-
]
910-
except NonexistentOrcidUserError as e:
911-
logger.error(msg="Could not find ORCID user with the provided user ID.", extra=logging_context())
912-
raise pydantic.ValidationError(
913-
[pydantic.error_wrappers.ErrorWrapper(ValidationError(str(e)), loc="contributors")],
914-
model=score_set.ScoreSetUpdate,
915-
)
887+
logger.debug(msg="Skipped score range and target gene update. Score set is published.", extra=logging_context())
916888

917889
db.add(item)
918890
db.commit()

tests/helpers/constants.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@
1313
VALID_ACCESSION = "NM_001637.3"
1414
VALID_GENE = "BRCA1"
1515

16+
SAVED_PUBMED_PUBLICATION = {
17+
"identifier": "20711194",
18+
"dbName": "PubMed",
19+
"title": "None",
20+
"authors": [],
21+
"abstract": "test",
22+
"doi": "test",
23+
"publicationYear": 1999,
24+
"publicationJournal": "test",
25+
"url": "http://www.ncbi.nlm.nih.gov/pubmed/20711194",
26+
"referenceHtml": ". None. test. 1999; (Unknown volume):(Unknown pages). test",
27+
"id": 1,
28+
}
29+
30+
SAVED_DOI_IDENTIFIER = {
31+
"identifier": TEST_CROSSREF_IDENTIFIER,
32+
"url": f"https://doi.org/{TEST_CROSSREF_IDENTIFIER}",
33+
"id": 1,
34+
}
35+
1636
TEST_USER = {
1737
"username": "0000-1111-2222-3333",
1838
"first_name": "First",
@@ -24,6 +44,18 @@
2444
"is_first_login": True,
2545
}
2646

47+
CONTRIBUTOR = {
48+
"orcid_id": TEST_USER["username"],
49+
"given_name": TEST_USER["first_name"],
50+
"family_name": TEST_USER["last_name"],
51+
}
52+
53+
SAVED_CONTRIBUTOR = {
54+
"orcidId": TEST_USER["username"],
55+
"givenName": TEST_USER["first_name"],
56+
"familyName": TEST_USER["last_name"],
57+
}
58+
2759
TEST_USER_DECODED_JWT = {
2860
"sub": TEST_USER["username"],
2961
"given_name": TEST_USER["first_name"],
@@ -41,6 +73,18 @@
4173
"is_first_login": True,
4274
}
4375

76+
EXTRA_CONTRIBUTOR = {
77+
"orcid_id": EXTRA_USER["username"],
78+
"given_name": EXTRA_USER["first_name"],
79+
"family_name": EXTRA_USER["last_name"],
80+
}
81+
82+
SAVED_EXTRA_CONTRIBUTOR = {
83+
"orcidId": EXTRA_USER["username"],
84+
"givenName": EXTRA_USER["first_name"],
85+
"familyName": EXTRA_USER["last_name"],
86+
}
87+
4488
EXTRA_USER_DECODED_JWT = {
4589
"sub": EXTRA_USER["username"],
4690
"given_name": EXTRA_USER["first_name"],
@@ -293,6 +337,31 @@
293337
"version": "1.0",
294338
}
295339

340+
SAVED_SHORT_TEST_LICENSE = {
341+
"id": TEST_LICENSE["id"],
342+
"shortName": TEST_LICENSE["short_name"],
343+
"longName": TEST_LICENSE["long_name"],
344+
"link": TEST_LICENSE["link"],
345+
"version": TEST_LICENSE["version"],
346+
}
347+
348+
EXTRA_LICENSE = {
349+
"id": 2,
350+
"short_name": "Extra",
351+
"long_name": "License",
352+
"text": "Don't be tooooo evil.",
353+
"link": "localhost",
354+
"version": "1.0",
355+
}
356+
357+
SAVED_SHORT_EXTRA_LICENSE = {
358+
"id": EXTRA_LICENSE["id"],
359+
"shortName": EXTRA_LICENSE["short_name"],
360+
"longName": EXTRA_LICENSE["long_name"],
361+
"link": EXTRA_LICENSE["link"],
362+
"version": EXTRA_LICENSE["version"],
363+
}
364+
296365
TEST_SEQ_SCORESET = {
297366
"title": "Test Score Set Title",
298367
"short_description": "Test score set",
@@ -457,6 +526,7 @@
457526
"targetGenes": [
458527
{
459528
"name": "TEST2",
529+
"id": 2,
460530
"category": "protein_coding",
461531
"externalIdentifiers": [],
462532
"targetAccession": {"accession": VALID_ACCESSION, "assembly": "GRCh37", "gene": VALID_GENE},
@@ -515,3 +585,20 @@
515585
"dcd_mapping_version": "pytest.0.0",
516586
"mapped_date_utc": datetime.isoformat(datetime.now()),
517587
}
588+
589+
590+
TEST_SCORESET_RANGE = {
591+
"wt_score": 1.0,
592+
"ranges": [
593+
{"label": "test1", "classification": "normal", "range": (0, 2.0)},
594+
{"label": "test2", "classification": "abnormal", "range": (-2.0, 0)},
595+
],
596+
}
597+
598+
TEST_SAVED_SCORESET_RANGE = {
599+
"wtScore": 1.0,
600+
"ranges": [
601+
{"label": "test1", "classification": "normal", "range": [0.0, 2.0]},
602+
{"label": "test2", "classification": "abnormal", "range": [-2.0, 0.0]},
603+
],
604+
}

tests/helpers/util.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jsonschema
66
from arq import ArqRedis
77
from sqlalchemy import select
8+
from sqlalchemy.exc import NoResultFound
89

910
from mavedb.lib.score_sets import columns_for_dataset, create_variants, create_variants_data, csv_data_to_df
1011
from mavedb.lib.validation.dataframe import validate_and_standardize_dataframe_pair
@@ -27,8 +28,13 @@ def add_contributor(db, urn, model, orcid_id: str, given_name: str, family_name:
2728
"""Without making an API call, add a new contributor to the record (experiment or score set) with given urn and model."""
2829
item = db.query(model).filter(model.urn == urn).one_or_none()
2930
assert item is not None
30-
contributor = Contributor(orcid_id=orcid_id, given_name=given_name, family_name=family_name)
31-
db.add(contributor)
31+
32+
try:
33+
contributor = db.execute(select(Contributor).where(Contributor.orcid_id == orcid_id)).one()
34+
except NoResultFound:
35+
contributor = Contributor(orcid_id=orcid_id, given_name=given_name, family_name=family_name)
36+
db.add(contributor)
37+
3238
item.contributors = [contributor]
3339
db.add(item)
3440
db.commit()
@@ -214,3 +220,16 @@ def mark_user_inactive(session, username):
214220

215221
async def awaitable_exception():
216222
return Exception()
223+
224+
225+
def update_expected_response_for_created_resources(expected_response, created_experiment, created_score_set):
226+
expected_response.update({"urn": created_score_set["urn"]})
227+
expected_response["experiment"].update(
228+
{
229+
"urn": created_experiment["urn"],
230+
"experimentSetUrn": created_experiment["experimentSetUrn"],
231+
"scoreSetUrns": [created_score_set["urn"]],
232+
}
233+
)
234+
235+
return expected_response

tests/routers/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pytest
77

88
from mavedb.models.controlled_keyword import ControlledKeyword
9+
from mavedb.models.contributor import Contributor
910
from mavedb.models.enums.user_role import UserRole
1011
from mavedb.models.license import License
1112
from mavedb.models.role import Role
@@ -14,9 +15,11 @@
1415
from tests.helpers.constants import (
1516
ADMIN_USER,
1617
EXTRA_USER,
18+
EXTRA_CONTRIBUTOR,
1719
TEST_CDOT_TRANSCRIPT,
1820
TEST_DB_KEYWORDS,
1921
TEST_LICENSE,
22+
EXTRA_LICENSE,
2023
TEST_TAXONOMY,
2124
TEST_USER,
2225
)
@@ -41,6 +44,8 @@ def setup_router_db(session):
4144
db.add(User(**ADMIN_USER, role_objs=[Role(name=UserRole.admin)]))
4245
db.add(Taxonomy(**TEST_TAXONOMY))
4346
db.add(License(**TEST_LICENSE))
47+
db.add(License(**EXTRA_LICENSE))
48+
db.add(Contributor(**EXTRA_CONTRIBUTOR))
4449
db.bulk_save_objects([ControlledKeyword(**keyword_obj) for keyword_obj in TEST_DB_KEYWORDS])
4550
db.commit()
4651

0 commit comments

Comments
 (0)