Skip to content

Commit e4ec609

Browse files
authored
Merge pull request #355 from VariantEffect/bugfix/bencap/329/editable-dataset-metadata
Expand Editable Score Set Metadata
2 parents 6074a38 + 9dae7ac commit e4ec609

File tree

7 files changed

+468
-186
lines changed

7 files changed

+468
-186
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ mypy_path = "mypy_stubs"
9999
addopts = "-v -rP --import-mode=importlib --disable-socket --allow-hosts localhost,::1,127.0.0.1"
100100
asyncio_mode = 'strict'
101101
testpaths = "tests/"
102+
pythonpath = "."
102103
norecursedirs = "tests/helpers/"
103104
# Uncomment the following lines to include application log output in Pytest logs.
104105
# log_cli = true

src/mavedb/routers/score_sets.py

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

653653

654-
@router.put("/score-sets/{urn}", response_model=score_set.ScoreSet, responses={422: {}})
654+
@router.put(
655+
"/score-sets/{urn}", response_model=score_set.ScoreSet, responses={422: {}}, response_model_exclude_none=True
656+
)
655657
async def update_score_set(
656658
*,
657659
urn: str,
@@ -673,68 +675,65 @@ async def update_score_set(
673675

674676
assert_permission(user_data, item, Action.UPDATE)
675677

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

680-
if item_update.license_id is not None:
681-
save_to_logging_context({"license": item_update.license_id})
682-
license_ = db.query(License).filter(License.id == item_update.license_id).one_or_none()
701+
item.license = license_
683702

684-
if not license_:
685-
logger.info(
686-
msg="Failed to update score set; The requested license does not exist.", extra=logging_context()
687-
)
688-
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Unknown license")
703+
item.doi_identifiers = [
704+
await find_or_create_doi_identifier(db, identifier.identifier)
705+
for identifier in item_update.doi_identifiers or []
706+
]
707+
primary_publication_identifiers = [
708+
await find_or_create_publication_identifier(db, identifier.identifier, identifier.db_name)
709+
for identifier in item_update.primary_publication_identifiers or []
710+
]
711+
publication_identifiers = [
712+
await find_or_create_publication_identifier(db, identifier.identifier, identifier.db_name)
713+
for identifier in item_update.secondary_publication_identifiers or []
714+
] + primary_publication_identifiers
689715

690-
item.license = license_
716+
# create a temporary `primary` attribute on each of our publications that indicates
717+
# to our association proxy whether it is a primary publication or not
718+
primary_identifiers = [p.identifier for p in primary_publication_identifiers]
719+
for publication in publication_identifiers:
720+
setattr(publication, "primary", publication.identifier in primary_identifiers)
691721

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

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

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

922894
db.add(item)
923895
db.commit()

src/mavedb/view_models/score_set.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ def wild_type_score_in_normal_range(cls, field_value: Optional[ScoreRanges]):
254254
range_model.range for range_model in field_value.ranges if range_model.classification == "normal"
255255
]
256256
for range in normal_ranges:
257-
print(range)
258257
if field_value.wt_score >= inf_or_float(range[0], lower=True) and field_value.wt_score < inf_or_float(
259258
range[1], lower=False
260259
):

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"],
@@ -305,6 +349,31 @@
305349
"version": "1.0",
306350
}
307351

352+
SAVED_SHORT_TEST_LICENSE = {
353+
"id": TEST_LICENSE["id"],
354+
"shortName": TEST_LICENSE["short_name"],
355+
"longName": TEST_LICENSE["long_name"],
356+
"link": TEST_LICENSE["link"],
357+
"version": TEST_LICENSE["version"],
358+
}
359+
360+
EXTRA_LICENSE = {
361+
"id": 2,
362+
"short_name": "Extra",
363+
"long_name": "License",
364+
"text": "Don't be tooooo evil.",
365+
"link": "localhost",
366+
"version": "1.0",
367+
}
368+
369+
SAVED_SHORT_EXTRA_LICENSE = {
370+
"id": EXTRA_LICENSE["id"],
371+
"shortName": EXTRA_LICENSE["short_name"],
372+
"longName": EXTRA_LICENSE["long_name"],
373+
"link": EXTRA_LICENSE["link"],
374+
"version": EXTRA_LICENSE["version"],
375+
}
376+
308377
TEST_SEQ_SCORESET = {
309378
"title": "Test Score Set Title",
310379
"short_description": "Test score set",
@@ -485,6 +554,7 @@
485554
{
486555
"recordType": "TargetGene",
487556
"name": "TEST2",
557+
"id": 2,
488558
"category": "protein_coding",
489559
"externalIdentifiers": [],
490560
"targetAccession": {
@@ -548,3 +618,20 @@
548618
"dcd_mapping_version": "pytest.0.0",
549619
"mapped_date_utc": datetime.isoformat(datetime.now()),
550620
}
621+
622+
623+
TEST_SCORESET_RANGE = {
624+
"wt_score": 1.0,
625+
"ranges": [
626+
{"label": "test1", "classification": "normal", "range": (0, 2.0)},
627+
{"label": "test2", "classification": "abnormal", "range": (-2.0, 0)},
628+
],
629+
}
630+
631+
TEST_SAVED_SCORESET_RANGE = {
632+
"wtScore": 1.0,
633+
"ranges": [
634+
{"label": "test1", "classification": "normal", "range": [0.0, 2.0]},
635+
{"label": "test2", "classification": "abnormal", "range": [-2.0, 0.0]},
636+
],
637+
}

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)