From 329d91d1203e6876bf54424fc612939527517213 Mon Sep 17 00:00:00 2001 From: EstelleDa Date: Mon, 22 Dec 2025 16:59:05 +1100 Subject: [PATCH 1/3] Modify the Gene Ontology related validators and tests. --- .../lib/validation/constants/general.py | 1 + src/mavedb/lib/validation/keywords.py | 12 ++-- tests/helpers/constants.py | 13 ++++- tests/routers/test_experiments.py | 57 ++++++++++++++++--- 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/mavedb/lib/validation/constants/general.py b/src/mavedb/lib/validation/constants/general.py index 92b4fd5bb..d994dfcc0 100644 --- a/src/mavedb/lib/validation/constants/general.py +++ b/src/mavedb/lib/validation/constants/general.py @@ -44,6 +44,7 @@ variant_count_data = "count_data" required_score_column = "score" +multi_value_keys = ["molecular mechanism assessed"] valid_dataset_columns = [score_columns, count_columns] valid_variant_columns = [variant_score_data, variant_count_data] diff --git a/src/mavedb/lib/validation/keywords.py b/src/mavedb/lib/validation/keywords.py index 305a7c5aa..7d90ac047 100644 --- a/src/mavedb/lib/validation/keywords.py +++ b/src/mavedb/lib/validation/keywords.py @@ -1,5 +1,6 @@ from typing import Optional +from mavedb.lib.validation.constants.general import multi_value_keys from mavedb.lib.validation.exceptions import ValidationError from mavedb.lib.validation.utilities import is_null @@ -7,7 +8,7 @@ def validate_code(key: str, label: str, code: Optional[str]): # TODO(#511) Re-enable the Gene Ontology code requirement. pass - # if key.lower() == "phenotypic assay mechanism" and label.lower() != "other": + # if key.lower() == "molecular mechanism assessed" and label.lower() != "other": # # The Gene Ontology accession is a unique seven digit identifier prefixed by GO:. # # e.g. GO:0005739, GO:1904659, or GO:0016597. # if code is None or not re.match(r"^GO:\d{7}$", code): @@ -26,9 +27,12 @@ def validate_duplicates(keywords: list): keys = [] labels = [] for k in keywords: - keys.append(k.keyword.key.lower()) # k: ExperimentControlledKeywordCreate object - if k.keyword.label.lower() != "other": - labels.append(k.keyword.label.lower()) + key = k.keyword.key.lower() + label = k.keyword.label.lower() + if key not in multi_value_keys: + keys.append(key) + if label != "other": + labels.append(label) keys_set = set(keys) labels_set = set(labels) diff --git a/tests/helpers/constants.py b/tests/helpers/constants.py index 481b5703f..02a013e82 100644 --- a/tests/helpers/constants.py +++ b/tests/helpers/constants.py @@ -429,19 +429,26 @@ }, {"key": "Delivery Method", "label": "Other", "special": False, "description": "Description"}, { - "key": "Phenotypic Assay Mechanism", + "key": "Molecular Mechanism Assessed", "label": "Other", "code": None, "special": False, "description": "Description", }, { - "key": "Phenotypic Assay Mechanism", - "label": "Label", + "key": "Molecular Mechanism Assessed", + "label": "Sodium channel activity", "code": "GO:1234567", "special": False, "description": "Description", }, + { + "key": "Molecular Mechanism Assessed", + "label": "Calcium-mediated signaling", + "code": "GO:1134567", + "special": False, + "description": "Description", + }, { "key": "Phenotypic Assay Profiling Strategy", "label": "Shotgun sequencing", diff --git a/tests/routers/test_experiments.py b/tests/routers/test_experiments.py index 1a04ed6a2..d2bddc586 100644 --- a/tests/routers/test_experiments.py +++ b/tests/routers/test_experiments.py @@ -528,8 +528,8 @@ def test_create_experiment_that_keyword_gene_ontology_has_valid_code(client, set "keywords": [ { "keyword": { - "key": "Phenotypic Assay Mechanism", - "label": "Label", + "key": "Molecular Mechanism Assessed", + "label": "Sodium channel activity", "code": "GO:1234567", "special": False, "description": "Description", @@ -541,8 +541,8 @@ def test_create_experiment_that_keyword_gene_ontology_has_valid_code(client, set response = client.post("/api/v1/experiments/", json=experiment) assert response.status_code == 200 response_data = response.json() - assert response_data["keywords"][0]["keyword"]["key"] == "Phenotypic Assay Mechanism" - assert response_data["keywords"][0]["keyword"]["label"] == "Label" + assert response_data["keywords"][0]["keyword"]["key"] == "Molecular Mechanism Assessed" + assert response_data["keywords"][0]["keyword"]["label"] == "Sodium channel activity" assert response_data["keywords"][0]["keyword"]["code"] == "GO:1234567" @@ -551,7 +551,7 @@ def test_create_experiment_that_keyword_gene_ontology_is_other_without_code(clie "keywords": [ { "keyword": { - "key": "Phenotypic Assay Mechanism", + "key": "Molecular Mechanism Assessed", "label": "Other", "code": None, "description": "Description", @@ -564,17 +564,60 @@ def test_create_experiment_that_keyword_gene_ontology_is_other_without_code(clie response = client.post("/api/v1/experiments/", json=experiment) assert response.status_code == 200 response_data = response.json() - assert response_data["keywords"][0]["keyword"]["key"] == "Phenotypic Assay Mechanism" + assert response_data["keywords"][0]["keyword"]["key"] == "Molecular Mechanism Assessed" assert response_data["keywords"][0]["keyword"]["label"] == "Other" +def test_create_experiment_that_keywords_has_multiple_molecular_mechanism_assessed_labels(client, setup_router_db): + valid_keywords = { + "keywords": [ + { + "keyword": { + "key": "Molecular Mechanism Assessed", + "label": "Sodium channel activity", + "code": "GO:1234567", + "special": False, + "description": "Description", + }, + }, + { + "keyword": { + "key": "Molecular Mechanism Assessed", + "label": "Calcium-mediated signaling", + "code": "GO:1134567", + "special": False, + "description": "Description", + }, + } + ], + } + experiment = {**TEST_MINIMAL_EXPERIMENT, **valid_keywords} + response = client.post("/api/v1/experiments/", json=experiment) + assert response.status_code == 200 + response_data = response.json() + assert len(response_data["keywords"]) == 2 + labels = {kw["keyword"]["label"] for kw in response_data["keywords"]} + codes = {kw["keyword"]["code"] for kw in response_data["keywords"]} + keys = {kw["keyword"]["key"] for kw in response_data["keywords"]} + + assert keys == {"Molecular Mechanism Assessed"} + assert labels == { + "Sodium channel activity", + "Calcium-mediated signaling", + } + assert codes == { + "GO:1234567", + "GO:1134567", + } + + # TODO(#511) Re-enable the Gene Ontology code requirement. # def test_cannot_create_experiment_that_keyword_has_an_invalid_code(client, setup_router_db): # invalid_keyword = { # "keywords": [ # { # "keyword": { -# "key": "Phenotypic Assay Mechanism", +# "key": "Molecular Mechanism Assessed", # "label": "Label", # "code": "invalid", # "description": "Description", From 45bced4fdf9cb21f4d74b22ca1e80fe5367d0de8 Mon Sep 17 00:00:00 2001 From: Estelle Da Date: Mon, 30 Mar 2026 15:26:37 +1100 Subject: [PATCH 2/3] Doesn't allow multiple keys for molecular mechanism assessed yet. And comment the related test. --- src/mavedb/lib/validation/keywords.py | 17 ++++-- tests/routers/test_experiments.py | 84 +++++++++++++-------------- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/src/mavedb/lib/validation/keywords.py b/src/mavedb/lib/validation/keywords.py index 7d90ac047..915f4c16e 100644 --- a/src/mavedb/lib/validation/keywords.py +++ b/src/mavedb/lib/validation/keywords.py @@ -27,12 +27,17 @@ def validate_duplicates(keywords: list): keys = [] labels = [] for k in keywords: - key = k.keyword.key.lower() - label = k.keyword.label.lower() - if key not in multi_value_keys: - keys.append(key) - if label != "other": - labels.append(label) + keys.append(k.keyword.key.lower()) # k: ExperimentControlledKeywordCreate object + if k.keyword.label.lower() != "other": + labels.append(k.keyword.label.lower()) + # TODO: When molecular mechanism assessed has one GO with one key, we'll available this validator. + # Currently molecular mechanism assessed has combined GO terms in value. + # key = k.keyword.key.lower() + # label = k.keyword.label.lower() + # if key not in multi_value_keys: + # keys.append(key) + # if label != "other": + # labels.append(label) keys_set = set(keys) labels_set = set(labels) diff --git a/tests/routers/test_experiments.py b/tests/routers/test_experiments.py index 61a266737..08b42298f 100644 --- a/tests/routers/test_experiments.py +++ b/tests/routers/test_experiments.py @@ -564,50 +564,50 @@ def test_create_experiment_that_keyword_gene_ontology_is_other_without_code(clie assert response_data["keywords"][0]["keyword"]["label"] == "Other" -def test_create_experiment_that_keywords_has_multiple_molecular_mechanism_assessed_labels(client, setup_router_db): - valid_keywords = { - "keywords": [ - { - "keyword": { - "key": "Molecular Mechanism Assessed", - "label": "Sodium channel activity", - "code": "GO:1234567", - "special": False, - "description": "Description", - }, - }, - { - "keyword": { - "key": "Molecular Mechanism Assessed", - "label": "Calcium-mediated signaling", - "code": "GO:1134567", - "special": False, - "description": "Description", - }, - } - ], - } - experiment = {**TEST_MINIMAL_EXPERIMENT, **valid_keywords} - response = client.post("/api/v1/experiments/", json=experiment) - assert response.status_code == 200 - response_data = response.json() - assert len(response_data["keywords"]) == 2 - labels = {kw["keyword"]["label"] for kw in response_data["keywords"]} - codes = {kw["keyword"]["code"] for kw in response_data["keywords"]} - keys = {kw["keyword"]["key"] for kw in response_data["keywords"]} - - assert keys == {"Molecular Mechanism Assessed"} - assert labels == { - "Sodium channel activity", - "Calcium-mediated signaling", - } - assert codes == { - "GO:1234567", - "GO:1134567", - } +# TODO(#511) Re-enable the Gene Ontology code requirement. +# def test_create_experiment_that_keywords_has_multiple_molecular_mechanism_assessed_labels(client, setup_router_db): +# valid_keywords = { +# "keywords": [ +# { +# "keyword": { +# "key": "Molecular Mechanism Assessed", +# "label": "Sodium channel activity", +# "code": "GO:1234567", +# "special": False, +# "description": "Description", +# }, +# }, +# { +# "keyword": { +# "key": "Molecular Mechanism Assessed", +# "label": "Calcium-mediated signaling", +# "code": "GO:1134567", +# "special": False, +# "description": "Description", +# }, +# } +# ], +# } +# experiment = {**TEST_MINIMAL_EXPERIMENT, **valid_keywords} +# response = client.post("/api/v1/experiments/", json=experiment) +# assert response.status_code == 200 +# response_data = response.json() +# assert len(response_data["keywords"]) == 2 +# labels = {kw["keyword"]["label"] for kw in response_data["keywords"]} +# codes = {kw["keyword"]["code"] for kw in response_data["keywords"]} +# keys = {kw["keyword"]["key"] for kw in response_data["keywords"]} +# +# assert keys == {"Molecular Mechanism Assessed"} +# assert labels == { +# "Sodium channel activity", +# "Calcium-mediated signaling", +# } +# assert codes == { +# "GO:1234567", +# "GO:1134567", +# } -# TODO(#511) Re-enable the Gene Ontology code requirement. # def test_cannot_create_experiment_that_keyword_has_an_invalid_code(client, setup_router_db): # invalid_keyword = { # "keywords": [ From 55b885a46703df7b20a164aacc8ba60d1fcf487e Mon Sep 17 00:00:00 2001 From: Estelle Da Date: Mon, 30 Mar 2026 15:30:23 +1100 Subject: [PATCH 3/3] Comment unnecessary import. --- src/mavedb/lib/validation/keywords.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mavedb/lib/validation/keywords.py b/src/mavedb/lib/validation/keywords.py index 915f4c16e..237804f1c 100644 --- a/src/mavedb/lib/validation/keywords.py +++ b/src/mavedb/lib/validation/keywords.py @@ -1,6 +1,6 @@ from typing import Optional -from mavedb.lib.validation.constants.general import multi_value_keys +#from mavedb.lib.validation.constants.general import multi_value_keys from mavedb.lib.validation.exceptions import ValidationError from mavedb.lib.validation.utilities import is_null