Skip to content

Commit 66ff1d9

Browse files
committed
Merge branch 'release-2024.4.2' into estelle/excludeMetaAnalysisExperiment
2 parents d464740 + 97deb21 commit 66ff1d9

File tree

12 files changed

+146
-65
lines changed

12 files changed

+146
-65
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import sqlalchemy as sa
2+
from sqlalchemy.orm import Session, configure_mappers
3+
4+
from mavedb.models import *
5+
from mavedb.models.enums.target_category import TargetCategory
6+
from mavedb.models.target_gene import TargetGene
7+
8+
from mavedb.db.session import SessionLocal
9+
10+
configure_mappers()
11+
12+
def api_like_target_gene_category(category: str):
13+
if category == "Protein coding":
14+
return TargetCategory.protein_coding
15+
elif category == "Other noncoding":
16+
return TargetCategory.other_noncoding
17+
elif category == "Regulatory":
18+
return TargetCategory.regulatory
19+
else:
20+
raise ValueError()
21+
22+
23+
def do_migration(db: Session):
24+
target_genes = db.scalars(sa.select(TargetGene)).all()
25+
26+
for target in target_genes:
27+
target.category = api_like_target_gene_category(target.category)
28+
db.add(target)
29+
30+
db.commit()
31+
32+
33+
if __name__ == "__main__":
34+
db = SessionLocal()
35+
db.current_user = None # type: ignore
36+
37+
do_migration(db)
38+
39+
db.commit()
40+
db.close()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""Target category enum
2+
3+
Revision ID: 03c7124c33e1
4+
Revises: 2b6f40ea2fb6
5+
Create Date: 2024-11-01 11:27:03.609116
6+
7+
"""
8+
9+
from alembic import op
10+
import sqlalchemy as sa
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = "03c7124c33e1"
15+
down_revision = "2b6f40ea2fb6"
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.alter_column(
23+
"target_genes",
24+
"category",
25+
type_=sa.Enum(
26+
"protein_coding",
27+
"other_noncoding",
28+
"regulatory",
29+
name="targetcategory",
30+
native_enum=False,
31+
create_constraint=True,
32+
length=32,
33+
),
34+
)
35+
# ### end Alembic commands ###
36+
37+
38+
def downgrade():
39+
# ### commands auto generated by Alembic - please adjust! ###
40+
op.alter_column(
41+
"target_genes",
42+
"category",
43+
type_=sa.String(),
44+
existing_type=sa.Enum(
45+
"protein_coding",
46+
"other_noncoding",
47+
"regulatory",
48+
name="targetcategory",
49+
native_enum=False,
50+
create_constraint=True,
51+
length=32,
52+
),
53+
)
54+
# ### end Alembic commands ###
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
valid_categories = ["Protein coding", "Regulatory", "Other noncoding"]
21
valid_sequence_types = ["infer", "dna", "protein"]

src/mavedb/lib/validation/target.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,10 @@
11
from fqfa import infer_sequence_type
22
from fqfa.validator import amino_acids_validator, dna_bases_validator
33

4-
from mavedb.lib.validation.constants.target import valid_categories, valid_sequence_types
4+
from mavedb.lib.validation.constants.target import valid_sequence_types
55
from mavedb.lib.validation.exceptions import ValidationError
66

77

8-
def validate_target_category(category: str):
9-
"""
10-
If the target category provided does not fall within a pre-defined list of valid categories.
11-
12-
Parameters
13-
__________
14-
category: str
15-
The target category to be validated.
16-
17-
Raises
18-
______
19-
ValidationError
20-
If the target category provided is not valid.
21-
"""
22-
if category not in valid_categories:
23-
raise ValidationError(
24-
"{} is not a valid target category. Valid categories are "
25-
"Protein coding, Regulatory, and Other noncoding".format(category)
26-
)
27-
28-
298
def validate_sequence_category(sequence_type: str):
309
"""
3110
If the sequence type provided does not fall within a pre-defined list of valid sequence types.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from enum import Enum
2+
3+
4+
class TargetCategory(str, Enum):
5+
protein_coding = "protein_coding"
6+
regulatory = "regulatory"
7+
other_noncoding = "other_noncoding"

src/mavedb/models/target_gene.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from datetime import date
22
from typing import TYPE_CHECKING
33

4-
from sqlalchemy import Column, Date, ForeignKey, Integer, String
4+
from sqlalchemy import Column, Date, Enum, ForeignKey, Integer, String
55
from sqlalchemy.dialects.postgresql import JSONB
66
from sqlalchemy.orm import Mapped, backref, relationship
77

88
from mavedb.db.base import Base
9+
from mavedb.models.enums.target_category import TargetCategory
910
from mavedb.models.score_set import ScoreSet
1011
from mavedb.models.target_accession import TargetAccession
1112
from mavedb.models.target_sequence import TargetSequence
@@ -24,7 +25,10 @@ class TargetGene(Base):
2425
id = Column(Integer, primary_key=True)
2526

2627
name = Column(String, nullable=False)
27-
category = Column(String, nullable=False)
28+
category = Column(
29+
Enum(TargetCategory, create_constraint=True, length=32, native_enum=False, validate_strings=True),
30+
nullable=False,
31+
)
2832

2933
score_set_id = Column("scoreset_id", Integer, ForeignKey("scoresets.id"), index=True, nullable=False)
3034
score_set: Mapped[ScoreSet] = relationship(back_populates="target_genes", single_parent=True, uselist=True)

src/mavedb/routers/score_sets.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ async def create_score_set(
334334
msg="Failed to create score set; The requested experiment does not exist.", extra=logging_context()
335335
)
336336
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Unknown experiment")
337+
# Not allow add score set in meta-analysis experiments.
338+
if any(s.meta_analyzes_score_sets for s in experiment.score_sets):
339+
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
340+
detail="Score sets may not be added to a meta-analysis experiment.")
337341

338342
save_to_logging_context({"experiment": experiment.urn})
339343
assert_permission(user_data, experiment, Action.ADD_SCORE_SET)
@@ -386,7 +390,7 @@ async def create_score_set(
386390
)
387391

388392
if len(meta_analyzes_score_sets) > 0:
389-
# If any existing score set is a meta-analysis for score sets in the same collection of exepriment sets, use its
393+
# If any existing score set is a meta-analysis for score sets in the same collection of experiment sets, use its
390394
# experiment as the parent of our new meta-analysis. Otherwise, create a new experiment.
391395
meta_analyzes_experiment_sets = list(
392396
set(

src/mavedb/view_models/target_gene.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pydantic import root_validator
55
from pydantic.utils import GetterDict
66

7-
from mavedb.lib.validation import target
7+
from mavedb.models.enums.target_category import TargetCategory
88
from mavedb.view_models import external_gene_identifier_offset
99
from mavedb.view_models.base.base import BaseModel, validator
1010
from mavedb.view_models.target_accession import SavedTargetAccession, TargetAccession, TargetAccessionCreate
@@ -40,18 +40,15 @@ class TargetGeneBase(BaseModel):
4040
"""Base class for target gene view models."""
4141

4242
name: str
43-
category: str
43+
category: TargetCategory
4444
external_identifiers: Sequence[external_gene_identifier_offset.ExternalGeneIdentifierOffsetBase]
4545

4646
class Config:
4747
getter_dict: ExternalIdentifiersGetter
4848

4949

5050
class TargetGeneModify(TargetGeneBase):
51-
@validator("category")
52-
def validate_category(cls, v):
53-
target.validate_target_category(v)
54-
return v
51+
pass
5552

5653

5754
class TargetGeneCreate(TargetGeneModify):

tests/helpers/constants.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@
301301
"target_genes": [
302302
{
303303
"name": "TEST1",
304-
"category": "Protein coding",
304+
"category": "protein_coding",
305305
"external_identifiers": [],
306306
"target_sequence": {
307307
"sequence_type": "dna",
@@ -327,7 +327,7 @@
327327
"targetGenes": [
328328
{
329329
"name": "TEST1",
330-
"category": "Protein coding",
330+
"category": "protein_coding",
331331
"externalIdentifiers": [],
332332
"targetSequence": {
333333
"sequenceType": "dna",
@@ -369,7 +369,7 @@
369369
"targetGenes": [
370370
{
371371
"name": "TEST1",
372-
"category": "Protein coding",
372+
"category": "protein_coding",
373373
"externalIdentifiers": [],
374374
"id": 1,
375375
"targetSequence": {
@@ -413,7 +413,7 @@
413413
"targetGenes": [
414414
{
415415
"name": "TEST2",
416-
"category": "Protein coding",
416+
"category": "protein_coding",
417417
"externalIdentifiers": [],
418418
"targetAccession": {"accession": VALID_ACCESSION, "assembly": "GRCh37", "gene": VALID_GENE},
419419
}
@@ -428,7 +428,7 @@
428428
"target_genes": [
429429
{
430430
"name": "TEST2",
431-
"category": "Protein coding",
431+
"category": "protein_coding",
432432
"external_identifiers": [],
433433
"target_accession": {"accession": VALID_ACCESSION, "assembly": "GRCh37", "gene": VALID_GENE},
434434
}
@@ -457,7 +457,7 @@
457457
"targetGenes": [
458458
{
459459
"name": "TEST2",
460-
"category": "Protein coding",
460+
"category": "protein_coding",
461461
"externalIdentifiers": [],
462462
"targetAccession": {"accession": VALID_ACCESSION, "assembly": "GRCh37", "gene": VALID_GENE},
463463
}

tests/routers/test_score_set.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,17 @@ def test_cannot_create_score_set_without_email(client, setup_router_db):
174174
assert response_data["detail"] in "There must be an email address associated with your account to use this feature."
175175

176176

177+
def test_cannot_create_score_set_with_invalid_target_gene_category(client, setup_router_db):
178+
experiment = create_experiment(client)
179+
score_set_post_payload = deepcopy(TEST_MINIMAL_SEQ_SCORESET)
180+
score_set_post_payload["experimentUrn"] = experiment["urn"]
181+
score_set_post_payload["targetGenes"][0]["category"] = "some_invalid_target_category"
182+
response = client.post("/api/v1/score-sets/", json=score_set_post_payload)
183+
assert response.status_code == 422
184+
response_data = response.json()
185+
assert "value is not a valid enumeration member;" in response_data["detail"][0]["msg"]
186+
187+
177188
def test_get_own_private_score_set(client, setup_router_db):
178189
experiment = create_experiment(client)
179190
score_set = create_seq_score_set(client, experiment["urn"])

0 commit comments

Comments
 (0)