Skip to content

Commit 0a0ebaa

Browse files
authored
Merge pull request #447 from VariantEffect/bugfix/estelle/61/numScoreSetsAndExperiments
Bugfix/estelle/61/num score sets and experiments
2 parents 13157ea + 2a22cd2 commit 0a0ebaa

File tree

14 files changed

+443
-32
lines changed

14 files changed

+443
-32
lines changed

docker-compose-dev.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ services:
2323
- "8002:8000"
2424
volumes:
2525
- .:/code
26-
- mavedb-seqrepo-dev:/usr/local/share/seqrepo
2726

2827
worker:
2928
image: mavedb-api/mavedb-worker:dev
@@ -42,7 +41,6 @@ services:
4241
LOG_CONFIG: dev
4342
volumes:
4443
- .:/code
45-
- mavedb-seqrepo-dev:/usr/local/share/seqrepo
4644
depends_on:
4745
- db
4846
- redis

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "mavedb"
7-
version = "2025.1.1"
7+
version = "2025.1.2"
88
description = "API for MaveDB, the database of Multiplexed Assays of Variant Effect."
99
license = "AGPL-3.0-only"
1010
readme = "README.md"

src/mavedb/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
logger = module_logging.getLogger(__name__)
77

88
__project__ = "mavedb-api"
9-
__version__ = "2025.1.1"
9+
__version__ = "2025.1.2"
1010

1111
logger.info(f"MaveDB {__version__}")

src/mavedb/lib/experiments.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
from sqlalchemy import func, or_, not_
55
from sqlalchemy.orm import Session
66

7+
from mavedb.lib.authentication import UserData
78
from mavedb.lib.logging.context import logging_context, save_to_logging_context
9+
from mavedb.lib.permissions import Action
10+
from mavedb.lib.score_sets import find_superseded_score_set_tail
811
from mavedb.models.contributor import Contributor
912
from mavedb.models.controlled_keyword import ControlledKeyword
1013
from mavedb.models.experiment import Experiment
@@ -14,6 +17,7 @@
1417
from mavedb.models.publication_identifier import PublicationIdentifier
1518
from mavedb.models.score_set import ScoreSet
1619
from mavedb.models.user import User
20+
from mavedb.view_models import experiment
1721
from mavedb.view_models.search import ExperimentsSearch
1822

1923
logger = logging.getLogger(__name__)
@@ -108,7 +112,7 @@ def search_experiments(
108112
# Keep experiments without any score sets
109113
not_(Experiment.score_sets.any()),
110114
# Keep experiments where score sets exist but have no meta_analyzes_score_sets
111-
Experiment.score_sets.any(not_(ScoreSet.meta_analyzes_score_sets.any()))
115+
Experiment.score_sets.any(not_(ScoreSet.meta_analyzes_score_sets.any())),
112116
)
113117
)
114118
else:
@@ -125,3 +129,30 @@ def search_experiments(
125129
)
126130

127131
return items
132+
133+
134+
def enrich_experiment_with_num_score_sets(
135+
item_update: Experiment, user_data: Optional[UserData]
136+
) -> experiment.Experiment:
137+
"""
138+
Validate and update the number of score set in experiment. The superseded score set is excluded.
139+
Data structure: experiment{score_set_urns, num_score_sets}
140+
"""
141+
filter_superseded_score_set_tails = [
142+
find_superseded_score_set_tail(score_set, Action.READ, user_data) for score_set in item_update.score_sets
143+
]
144+
filtered_score_set_urns = sorted(
145+
{
146+
score_set.urn
147+
for score_set in filter_superseded_score_set_tails
148+
if score_set is not None and score_set.urn is not None
149+
}
150+
)
151+
152+
updated_experiment = experiment.Experiment.from_orm(item_update).copy(
153+
update={
154+
"num_score_sets": len(filtered_score_set_urns),
155+
"score_set_urns": filtered_score_set_urns,
156+
}
157+
)
158+
return updated_experiment

src/mavedb/routers/experiment_sets.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from mavedb import deps
99
from mavedb.lib.authentication import UserData, get_current_user
10+
from mavedb.lib.experiments import enrich_experiment_with_num_score_sets
1011
from mavedb.lib.logging import LoggedRoute
1112
from mavedb.lib.logging.context import logging_context, save_to_logging_context
1213
from mavedb.lib.permissions import Action, has_permission
@@ -51,5 +52,13 @@ def fetch_experiment_set(
5152

5253
# Filter experiment sub-resources to only those experiments readable by the requesting user.
5354
item.experiments[:] = [exp for exp in item.experiments if has_permission(user_data, exp, Action.READ).permitted]
55+
enriched_experiments = [
56+
enrich_experiment_with_num_score_sets(exp, user_data)
57+
for exp in item.experiments
58+
]
59+
enriched_item = experiment_set.ExperimentSet.from_orm(item).copy(update={
60+
"experiments": enriched_experiments,
61+
"numExperiments": len(enriched_experiments)
62+
})
5463

55-
return item
64+
return enriched_item

src/mavedb/routers/experiments.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from mavedb.lib.authorization import require_current_user, require_current_user_with_email
1515
from mavedb.lib.contributors import find_or_create_contributor
1616
from mavedb.lib.exceptions import NonexistentOrcidUserError
17-
from mavedb.lib.experiments import search_experiments as _search_experiments
17+
from mavedb.lib.experiments import search_experiments as _search_experiments, enrich_experiment_with_num_score_sets
1818
from mavedb.lib.identifiers import (
1919
find_or_create_doi_identifier,
2020
find_or_create_publication_identifier,
@@ -89,7 +89,11 @@ def search_experiments(search: ExperimentsSearch, db: Session = Depends(deps.get
8989
"""
9090
Search experiments.
9191
"""
92-
return _search_experiments(db, None, search)
92+
items = _search_experiments(db, None, search)
93+
return [
94+
enrich_experiment_with_num_score_sets(exp, None)
95+
for exp in items
96+
]
9397

9498

9599
@router.post(
@@ -105,7 +109,11 @@ def search_my_experiments(
105109
"""
106110
Search experiments created by the current user..
107111
"""
108-
return _search_experiments(db, user_data.user, search)
112+
items = _search_experiments(db, user_data.user, search)
113+
return [
114+
enrich_experiment_with_num_score_sets(exp, user_data)
115+
for exp in items
116+
]
109117

110118

111119
@router.get(
@@ -120,7 +128,7 @@ def fetch_experiment(
120128
urn: str,
121129
db: Session = Depends(deps.get_db),
122130
user_data: Optional[UserData] = Depends(get_current_user),
123-
) -> Experiment:
131+
) -> experiment.Experiment:
124132
"""
125133
Fetch a single experiment by URN.
126134
"""
@@ -133,7 +141,7 @@ def fetch_experiment(
133141
raise HTTPException(status_code=404, detail=f"Experiment with URN {urn} not found")
134142

135143
assert_permission(user_data, item, Action.READ)
136-
return item
144+
return enrich_experiment_with_num_score_sets(item, user_data)
137145

138146

139147
@router.get(
@@ -184,6 +192,13 @@ def get_experiment_score_sets(
184192
else:
185193
filtered_score_sets.sort(key=attrgetter("urn"))
186194
save_to_logging_context({"associated_resources": [item.urn for item in score_set_result]})
195+
enriched_score_sets = []
196+
for fs in filtered_score_sets:
197+
enriched_experiment = enrich_experiment_with_num_score_sets(fs.experiment, user_data)
198+
response_item = score_set.ScoreSet.from_orm(fs).copy(update={"experiment": enriched_experiment})
199+
enriched_score_sets.append(response_item)
200+
201+
return enriched_score_sets
187202

188203
return filtered_score_sets
189204

@@ -429,7 +444,7 @@ async def update_experiment(
429444
db.refresh(item)
430445

431446
save_to_logging_context({"updated_resource": item.urn})
432-
return item
447+
return enrich_experiment_with_num_score_sets(item, user_data)
433448

434449

435450
@router.delete("/experiments/{urn}", response_model=None, responses={422: {}})

src/mavedb/routers/mapped_variant.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ async def fetch_mapped_variant_by_variant_urn(db, urn: str) -> Optional[MappedVa
2626
db.query(MappedVariant)
2727
.filter(Variant.urn == urn)
2828
.filter(MappedVariant.variant_id == Variant.id)
29-
.filter(MappedVariant.current is True)
29+
.filter(MappedVariant.current) # filter current is true
3030
.one_or_none()
3131
)
3232
except MultipleResultsFound:

src/mavedb/routers/score_sets.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
)
2424
from mavedb.lib.contributors import find_or_create_contributor
2525
from mavedb.lib.exceptions import MixedTargetError, NonexistentOrcidUserError, ValidationError
26+
from mavedb.lib.experiments import enrich_experiment_with_num_score_sets
2627
from mavedb.lib.identifiers import (
2728
create_external_gene_identifier_offset,
2829
find_or_create_doi_identifier,
@@ -72,7 +73,7 @@
7273

7374
async def fetch_score_set_by_urn(
7475
db, urn: str, user: Optional[UserData], owner_or_contributor: Optional[UserData], only_published: bool
75-
) -> Optional[ScoreSet]:
76+
) -> ScoreSet:
7677
"""
7778
Fetch one score set by URN, ensuring that the user has read permission.
7879
@@ -135,7 +136,15 @@ def search_score_sets(
135136
Search score sets.
136137
"""
137138
score_sets = _search_score_sets(db, None, search)
138-
return fetch_superseding_score_set_in_search_result(score_sets, user_data, search)
139+
updated_score_sets = fetch_superseding_score_set_in_search_result(score_sets, user_data, search)
140+
enriched_score_sets = []
141+
if updated_score_sets:
142+
for u in updated_score_sets:
143+
enriched_experiment = enrich_experiment_with_num_score_sets(u.experiment, user_data)
144+
response_item = score_set.ScoreSet.from_orm(u).copy(update={"experiment": enriched_experiment})
145+
enriched_score_sets.append(response_item)
146+
147+
return enriched_score_sets
139148

140149

141150
@router.get("/score-sets/mapped-genes", status_code=200, response_model=dict[str, list[str]])
@@ -183,7 +192,15 @@ def search_my_score_sets(
183192
Search score sets created by the current user..
184193
"""
185194
score_sets = _search_score_sets(db, user_data.user, search)
186-
return fetch_superseding_score_set_in_search_result(score_sets, user_data, search)
195+
updated_score_sets = fetch_superseding_score_set_in_search_result(score_sets, user_data, search)
196+
enriched_score_sets = []
197+
if updated_score_sets:
198+
for u in updated_score_sets:
199+
enriched_experiment = enrich_experiment_with_num_score_sets(u.experiment, user_data)
200+
response_item = score_set.ScoreSet.from_orm(u).copy(update={"experiment": enriched_experiment})
201+
enriched_score_sets.append(response_item)
202+
203+
return enriched_score_sets
187204

188205

189206
@router.get(
@@ -203,7 +220,9 @@ async def show_score_set(
203220
Fetch a single score set by URN.
204221
"""
205222
save_to_logging_context({"requested_resource": urn})
206-
return await fetch_score_set_by_urn(db, urn, user_data, None, False)
223+
item = await fetch_score_set_by_urn(db, urn, user_data, None, False)
224+
enriched_experiment = enrich_experiment_with_num_score_sets(item.experiment, user_data)
225+
return score_set.ScoreSet.from_orm(item).copy(update={"experiment": enriched_experiment})
207226

208227

209228
@router.get(
@@ -647,7 +666,9 @@ async def create_score_set(
647666
db.refresh(item)
648667

649668
save_to_logging_context({"created_resource": item.urn})
650-
return item
669+
670+
enriched_experiment = enrich_experiment_with_num_score_sets(item.experiment, user_data)
671+
return score_set.ScoreSet.from_orm(item).copy(update={"experiment": enriched_experiment})
651672

652673

653674
@router.post(
@@ -711,7 +732,8 @@ async def upload_score_set_variant_data(
711732
db.add(item)
712733
db.commit()
713734
db.refresh(item)
714-
return item
735+
enriched_experiment = enrich_experiment_with_num_score_sets(item.experiment, user_data)
736+
return score_set.ScoreSet.from_orm(item).copy(update={"experiment": enriched_experiment})
715737

716738

717739
@router.post(
@@ -748,7 +770,8 @@ async def update_score_set_calibration_data(
748770
db.refresh(item)
749771

750772
save_to_logging_context({"updated_resource": item.urn})
751-
return item
773+
enriched_experiment = enrich_experiment_with_num_score_sets(item.experiment, user_data)
774+
return score_set.ScoreSet.from_orm(item).copy(update={"experiment": enriched_experiment})
752775

753776

754777
@router.put(
@@ -1004,7 +1027,9 @@ async def update_score_set(
10041027
db.refresh(item)
10051028

10061029
save_to_logging_context({"updated_resource": item.urn})
1007-
return item
1030+
1031+
enriched_experiment = enrich_experiment_with_num_score_sets(item.experiment, user_data)
1032+
return score_set.ScoreSet.from_orm(item).copy(update={"experiment": enriched_experiment})
10081033

10091034

10101035
@router.delete("/score-sets/{urn}", responses={422: {}})
@@ -1142,7 +1167,8 @@ async def publish_score_set(
11421167
msg="Failed to enqueue published variant materialized view refresh job.", extra=logging_context()
11431168
)
11441169

1145-
return item
1170+
enriched_experiment = enrich_experiment_with_num_score_sets(item.experiment, user_data)
1171+
return score_set.ScoreSet.from_orm(item).copy(update={"experiment": enriched_experiment})
11461172

11471173

11481174
@router.get(
@@ -1276,3 +1302,4 @@ async def get_clinical_controls_options_for_score_set(
12761302
dict(zip(("db_name", "available_versions"), (db_name, db_versions)))
12771303
for db_name, db_versions in clinical_control_options.items()
12781304
]
1305+

src/mavedb/view_models/experiment.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ def publication_identifiers_validator(cls, value, values, field) -> list[Publica
132132

133133
# Properties to return to non-admin clients
134134
class Experiment(SavedExperiment):
135+
num_score_sets: Optional[int] = None
135136
score_set_urns: list[str]
136137
processing_state: Optional[str]
137138
doi_identifiers: Sequence[DoiIdentifier]

src/mavedb/view_models/experiment_set.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class ExperimentSet(SavedExperimentSet):
4545
created_by: Optional[User]
4646
modified_by: Optional[User]
4747
experiments: Sequence[Experiment]
48+
num_experiments: Optional[int] = None
4849

4950

5051
# Properties to return to admin clients

0 commit comments

Comments
 (0)