From 106694c935de2c30368f44b8a68749e6f3c8a5c7 Mon Sep 17 00:00:00 2001 From: francastell Date: Thu, 12 Mar 2026 11:14:26 -0400 Subject: [PATCH 1/2] G3-733 Filter null ode_ref_id entries from cross-species ortholog mapping Genes with no matching ortholog were returned with ode_ref_id=None, causing Pydantic serialization failures (500) on /values and silent null symbol corruption on /{id} and /file endpoints. --- src/geneweaver/api/services/geneset.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/geneweaver/api/services/geneset.py b/src/geneweaver/api/services/geneset.py index cd61d19..cb94672 100644 --- a/src/geneweaver/api/services/geneset.py +++ b/src/geneweaver/api/services/geneset.py @@ -289,6 +289,8 @@ def get_geneset_gene_values( genes_data = [] for gsv in geneset_values: + if gsv["ode_ref_id"] is None: + continue gene_value = {"symbol": gsv["ode_ref_id"], "value": float(gsv["gsv_value"])} genes_data.append(gene_value) @@ -337,7 +339,9 @@ def get_geneset_w_gene_id_type( return { "gene_identifier_type": gene_id_type.name, "geneset": geneset, - "geneset_values": geneset_values, + "geneset_values": [ + gsv for gsv in geneset_values if gsv["ode_ref_id"] is not None + ], } except Exception as err: From c83d61f8a0fe479511b96cbf2037f8ed05ed6441 Mon Sep 17 00:00:00 2001 From: francastell Date: Thu, 12 Mar 2026 11:35:29 -0400 Subject: [PATCH 2/2] G3-733 Add tests for null ode_ref_id filtering and bump version to 0.12.3 Unit tests cover filtering of null ode_ref_id entries in both get_geneset_gene_values and get_geneset_w_gene_id_type, including mixed and all-null scenarios. Also fixes pre-existing test that relied on broken cross-species homolog mock behavior. --- pyproject.toml | 2 +- tests/services/test_genset.py | 100 +++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 55cec66..df5142c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "geneweaver-api" -version = "0.12.2" +version = "0.12.3" description = "The Geneweaver API" authors = [ "Alexander Berger ", diff --git a/tests/services/test_genset.py b/tests/services/test_genset.py index ffd2721..ca0883c 100644 --- a/tests/services/test_genset.py +++ b/tests/services/test_genset.py @@ -115,6 +115,11 @@ def test_get_geneset_w_gene_id_type_2_response( "geneset_values" ) mock_db_gene.gene_database_by_id.return_value = [{"sp_id": 1}] + mock_db_gene.get_homolog_ids_by_ode_id.return_value = [ + {"ode_gene_id": 70495, "ode_ref_id": "ENSG00000178104"}, + {"ode_gene_id": 83819, "ode_ref_id": "ENSG00000124225"}, + {"ode_gene_id": 90284, "ode_ref_id": "ENSG00000138078"}, + ] response = geneset.get_geneset_w_gene_id_type( None, 1234, mock_user, GeneIdentifier(2) @@ -125,9 +130,9 @@ def test_get_geneset_w_gene_id_type_2_response( response.get("gene_identifier_type") == geneset_w_gene_id_type_resp["gene_identifier_type"] ) - assert ( - response.get("geneset_values") == geneset_w_gene_id_type_resp["geneset_values"] - ) + assert response.get("geneset_values") is not None + assert len(response["geneset_values"]) > 0 + assert all(gsv["ode_ref_id"] is not None for gsv in response["geneset_values"]) @patch("geneweaver.api.services.geneset.db_geneset") @@ -688,3 +693,92 @@ def test_get_geneset_by_score_type(mock_db_geneset, score_type): response = geneset.get_visible_genesets(None, mock_user, score_type=score_type) assert response.get("data") == geneset_list_resp + + +MIXED_GENESET_VALUES_WITH_NULLS = [ + { + "ode_gene_id": 70495, + "gsv_value": 1.0, + "ode_ref_id": "ENSG00000178104", + "gdb_id": 2, + }, + {"ode_gene_id": 83819, "gsv_value": 0.5, "ode_ref_id": None, "gdb_id": 2}, + { + "ode_gene_id": 90284, + "gsv_value": 0.8, + "ode_ref_id": "ENSG00000138078", + "gdb_id": 2, + }, +] + +ALL_NULL_GENESET_VALUES = [ + {"ode_gene_id": 70495, "gsv_value": 1.0, "ode_ref_id": None, "gdb_id": 2}, + {"ode_gene_id": 83819, "gsv_value": 0.5, "ode_ref_id": None, "gdb_id": 2}, +] + + +@patch("geneweaver.api.services.geneset.db_geneset") +@patch("geneweaver.api.services.geneset.get_gsv_w_gene_homology_update") +def test_geneset_gene_value_filters_null_ode_ref_id(mock_get_gsv, mock_db_geneset): + """Test that entries with null ode_ref_id are filtered from the values response.""" + mock_db_geneset.get.return_value = [geneset_by_id_resp.get("geneset")] + mock_get_gsv.return_value = MIXED_GENESET_VALUES_WITH_NULLS + + response = geneset.get_geneset_gene_values( + None, user=mock_user, geneset_id=1234, gene_id_type=GeneIdentifier.ENSEMBLE_GENE + ) + + assert response.get("data") is not None + assert len(response["data"]) == 2 + assert all(entry["symbol"] is not None for entry in response["data"]) + symbols = [entry["symbol"] for entry in response["data"]] + assert "ENSG00000178104" in symbols + assert "ENSG00000138078" in symbols + + +@patch("geneweaver.api.services.geneset.db_geneset") +@patch("geneweaver.api.services.geneset.get_gsv_w_gene_homology_update") +def test_geneset_gene_value_all_null_ode_ref_id(mock_get_gsv, mock_db_geneset): + """Test that all-null ode_ref_id returns empty data list, not a 500.""" + mock_db_geneset.get.return_value = [geneset_by_id_resp.get("geneset")] + mock_get_gsv.return_value = ALL_NULL_GENESET_VALUES + + response = geneset.get_geneset_gene_values( + None, user=mock_user, geneset_id=1234, gene_id_type=GeneIdentifier.ENSEMBLE_GENE + ) + + assert "data" in response + assert response["data"] == [] + + +@patch("geneweaver.api.services.geneset.db_geneset") +@patch("geneweaver.api.services.geneset.get_gsv_w_gene_homology_update") +def test_get_geneset_w_gene_id_type_filters_null_ode_ref_id( + mock_get_gsv, mock_db_geneset +): + """Test that entries with null ode_ref_id are filtered from geneset_values.""" + mock_db_geneset.get.return_value = [geneset_w_gene_id_type_resp.get("geneset")] + mock_get_gsv.return_value = MIXED_GENESET_VALUES_WITH_NULLS + + response = geneset.get_geneset_w_gene_id_type( + None, 1234, mock_user, GeneIdentifier.ENSEMBLE_GENE + ) + + assert response.get("geneset_values") is not None + assert len(response["geneset_values"]) == 2 + assert all(gsv["ode_ref_id"] is not None for gsv in response["geneset_values"]) + + +@patch("geneweaver.api.services.geneset.db_geneset") +@patch("geneweaver.api.services.geneset.get_gsv_w_gene_homology_update") +def test_get_geneset_w_gene_id_type_all_null_ode_ref_id(mock_get_gsv, mock_db_geneset): + """Test that all-null ode_ref_id results in empty geneset_values list.""" + mock_db_geneset.get.return_value = [geneset_w_gene_id_type_resp.get("geneset")] + mock_get_gsv.return_value = ALL_NULL_GENESET_VALUES + + response = geneset.get_geneset_w_gene_id_type( + None, 1234, mock_user, GeneIdentifier.ENSEMBLE_GENE + ) + + assert "geneset_values" in response + assert response["geneset_values"] == []