Skip to content

Commit 5361fd7

Browse files
committed
Find a potential bug from the failed tests. Haven't add related new tests yet.
1 parent bec2b5c commit 5361fd7

File tree

3 files changed

+100
-50
lines changed

3 files changed

+100
-50
lines changed

src/mavedb/lib/score_sets.py

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import io
33
import logging
44
import re
5-
from typing import Any, BinaryIO, Iterable, Optional, Sequence
5+
from operator import attrgetter
6+
from typing import Any, BinaryIO, Iterable, Optional, TYPE_CHECKING, Sequence
67

78
import numpy as np
89
import pandas as pd
@@ -43,10 +44,13 @@
4344
from mavedb.models.taxonomy import Taxonomy
4445
from mavedb.models.uniprot_identifier import UniprotIdentifier
4546
from mavedb.models.uniprot_offset import UniprotOffset
46-
from mavedb.models.user import User
4747
from mavedb.models.variant import Variant
4848
from mavedb.view_models.search import ScoreSetsSearch
4949

50+
if TYPE_CHECKING:
51+
from mavedb.lib.authentication import UserData
52+
from mavedb.lib.permissions import Action
53+
5054
VariantData = dict[str, Optional[dict[str, dict]]]
5155

5256
logger = logging.getLogger(__name__)
@@ -62,20 +66,19 @@ def options(cls) -> list[str]:
6266
return [cls.NUCLEOTIDE, cls.TRANSCRIPT, cls.PROTEIN]
6367

6468

65-
def search_score_sets(db: Session, owner_or_contributor: Optional[User], search: ScoreSetsSearch) -> list[ScoreSet]:
69+
def search_score_sets(db: Session, owner_or_contributor: Optional["UserData"], search: ScoreSetsSearch) -> list[ScoreSet]:
70+
# Prevent circular import
71+
from mavedb.lib.permissions import Action
6672
save_to_logging_context({"score_set_search_criteria": search.dict()})
6773

6874
query = db.query(ScoreSet) # \
6975
# .filter(ScoreSet.private.is_(False))
7076

71-
# filter out the score sets that are replaced by other score sets
72-
query = query.filter(~ScoreSet.superseding_score_set.has())
73-
7477
if owner_or_contributor is not None:
7578
query = query.filter(
7679
or_(
77-
ScoreSet.created_by_id == owner_or_contributor.id,
78-
ScoreSet.contributors.any(Contributor.orcid_id == owner_or_contributor.username),
80+
ScoreSet.created_by_id == owner_or_contributor.user.id,
81+
ScoreSet.contributors.any(Contributor.orcid_id == owner_or_contributor.user.username),
7982
)
8083
)
8184

@@ -253,13 +256,36 @@ def search_score_sets(db: Session, owner_or_contributor: Optional[User], search:
253256
.order_by(Experiment.title)
254257
.all()
255258
)
259+
# Remove superseded score set
256260
if not score_sets:
257-
score_sets = []
258-
259-
save_to_logging_context({"matching_resources": len(score_sets)})
260-
logger.debug(msg=f"Score set search yielded {len(score_sets)} matching resources.", extra=logging_context())
261+
final_score_sets: list[ScoreSet] = []
262+
else:
263+
published_filter = search.published if search.published is not None else None
264+
print(len(score_sets))
265+
filtered_score_sets = [
266+
find_superseded_score_set_tail(
267+
score_set,
268+
Action.READ,
269+
owner_or_contributor,
270+
published_filter
271+
) for score_set in score_sets
272+
]
273+
print(len(filtered_score_sets))
274+
# Remove None item.
275+
filtered_score_sets = [score_set for score_set in filtered_score_sets if score_set is not None]
276+
print(len(filtered_score_sets))
277+
if filtered_score_sets:
278+
# final_score_sets = sorted(set(filtered_score_sets), key=attrgetter("urn"))
279+
final_score_sets = filtered_score_sets.sort(key=attrgetter("urn"))
280+
for f in filtered_score_sets:
281+
print(f.urn)
282+
else:
283+
final_score_sets = []
261284

262-
return score_sets # filter_visible_score_sets(score_sets)
285+
save_to_logging_context({"matching_resources": len(final_score_sets)})
286+
logger.debug(msg=f"Score set search yielded {len(final_score_sets)} matching resources.", extra=logging_context())
287+
print(len(final_score_sets))
288+
return final_score_sets # filter_visible_score_sets(score_sets)
263289

264290

265291
def find_meta_analyses_for_experiment_sets(db: Session, urns: list[str]) -> list[ScoreSet]:
@@ -306,6 +332,54 @@ def find_meta_analyses_for_experiment_sets(db: Session, urns: list[str]) -> list
306332
)
307333

308334

335+
def find_superseded_score_set_tail(
336+
score_set: ScoreSet,
337+
action: Optional["Action"] = None,
338+
user_data: Optional["UserData"] = None,
339+
publish: Optional[bool] = None) -> Optional[ScoreSet]:
340+
from mavedb.lib.permissions import has_permission
341+
if publish is not None:
342+
if publish is True:
343+
while score_set.superseding_score_set is not None:
344+
next_score_set_in_chain = score_set.superseding_score_set
345+
# Find the final published one.
346+
if action is not None and has_permission(user_data, score_set, action).permitted \
347+
and next_score_set_in_chain.published_date is None:
348+
return score_set
349+
score_set = next_score_set_in_chain
350+
else:
351+
# Unpublished score set should not be superseded.
352+
# It should not have superseding score set, but possible have superseded score set.
353+
if action is not None and score_set.published_date is None \
354+
and has_permission(user_data, score_set, action).permitted:
355+
return score_set
356+
else:
357+
return None
358+
else:
359+
while score_set.superseding_score_set is not None:
360+
next_score_set_in_chain = score_set.superseding_score_set
361+
362+
# If we were given a permission to check and the next score set in the chain does not have that permission,
363+
# pretend like we have reached the end of the chain. Otherwise, continue to the next score set.
364+
if action is not None and not has_permission(user_data, next_score_set_in_chain, action).permitted:
365+
return score_set
366+
367+
score_set = next_score_set_in_chain
368+
369+
# Handle unpublished superseding score set case.
370+
# The score set has superseded score set but has not superseding score set.
371+
if action is not None and not has_permission(user_data, score_set, action).permitted:
372+
while score_set.superseded_score_set is not None:
373+
next_score_set_in_chain = score_set.superseded_score_set
374+
if has_permission(user_data, next_score_set_in_chain, action).permitted:
375+
return next_score_set_in_chain
376+
else:
377+
score_set = next_score_set_in_chain
378+
return None
379+
380+
return score_set
381+
382+
309383
def get_score_set_counts_as_csv(
310384
db: Session,
311385
score_set: ScoreSet,

src/mavedb/routers/experiments.py

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
from mavedb.lib.keywords import search_keyword
2323
from mavedb.lib.logging import LoggedRoute
2424
from mavedb.lib.logging.context import logging_context, save_to_logging_context
25-
from mavedb.lib.permissions import Action, assert_permission, has_permission
25+
from mavedb.lib.permissions import Action, assert_permission
26+
from mavedb.lib.score_sets import find_superseded_score_set_tail
2627
from mavedb.lib.validation.exceptions import ValidationError
2728
from mavedb.lib.validation.keywords import validate_keyword_list
2829
from mavedb.models.contributor import Contributor
@@ -169,51 +170,26 @@ def get_experiment_score_sets(
169170
.filter(~ScoreSet.superseding_score_set.has())
170171
.all()
171172
)
172-
superseding_score_sets = (
173-
db.query(ScoreSet)
174-
.filter(ScoreSet.experiment_id == experiment.id)
175-
.filter(ScoreSet.superseding_score_set.has())
176-
.all()
177-
)
178173

179-
updated_score_set_result = []
180-
for s in score_set_result:
181-
current_version = s
182-
while current_version:
183-
if current_version.superseded_score_set:
184-
if not has_permission(user_data, current_version, Action.READ).permitted:
185-
next_version: Optional[ScoreSet] = next(
186-
(sup for sup in superseding_score_sets if sup.urn == current_version.superseded_score_set.urn),
187-
None
188-
)
189-
# handle poetry run mypy src/ error so that add next_version
190-
if next_version:
191-
current_version = next_version
192-
else:
193-
break
194-
else:
195-
break
196-
else:
197-
break
198-
if current_version:
199-
updated_score_set_result.append(current_version)
200-
else:
201-
updated_score_set_result.append(s)
202-
203-
score_set_result[:] = [
204-
score_set for score_set in updated_score_set_result if has_permission(user_data, score_set, Action.READ).permitted
174+
superseded_score_set_tails = [
175+
find_superseded_score_set_tail(
176+
score_set,
177+
Action.READ,
178+
user_data,
179+
None
180+
) for score_set in score_set_result
205181
]
206182

207-
if not score_set_result:
183+
if not superseded_score_set_tails:
208184
save_to_logging_context({"associated_resources": []})
209185
logger.info(msg="No score sets are associated with the requested experiment.", extra=logging_context())
210186

211187
raise HTTPException(status_code=404, detail="no associated score sets")
212188
else:
213-
score_set_result.sort(key=attrgetter("urn"))
189+
superseded_score_set_tails.sort(key=attrgetter("urn"))
214190
save_to_logging_context({"associated_resources": [item.urn for item in score_set_result]})
215191

216-
return score_set_result
192+
return superseded_score_set_tails
217193

218194

219195
@router.post(

src/mavedb/routers/score_sets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def search_my_score_sets(
139139
"""
140140
Search score sets created by the current user..
141141
"""
142-
return _search_score_sets(db, user_data.user, search)
142+
return _search_score_sets(db, user_data, search)
143143

144144

145145
@router.get(

0 commit comments

Comments
 (0)