From 433f674f0e1d24da7d36ba44f4e929a04c27c1ee Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Thu, 6 Aug 2026 10:54:13 -0400 Subject: [PATCH 01/20] add datasetTypes to ui for family delete --- .../DataManagement/components/TriggerSearchDataUpdatePages.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx b/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx index c127b52f66..4c44c33ea4 100644 --- a/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx +++ b/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx @@ -43,6 +43,7 @@ const FAMILY_FIELDS = [ placeholder: 'Search for a family', validate: validators.required, }, + { ...DATASET_TYPE_FIELD, name: 'datasetTypes', multiple: true }, ] const TriggerSearchDataUpdateForm = ({ entity, fields }) => ( From 838fdea74588d97dbeeb8b715b81aa257534d1a0 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Thu, 6 Aug 2026 11:01:37 -0400 Subject: [PATCH 02/20] explicitly set dataset types to disable for delete family ui --- seqr/utils/add_data_utils.py | 4 +++- seqr/views/apis/data_manager_api.py | 5 ++++- seqr/views/apis/data_manager_api_tests.py | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/seqr/utils/add_data_utils.py b/seqr/utils/add_data_utils.py index 81dc2e50a7..978610b7df 100644 --- a/seqr/utils/add_data_utils.py +++ b/seqr/utils/add_data_utils.py @@ -63,7 +63,7 @@ def update_airtable_loading_tracking_status(project, status, additional_update=N update={'Status': status, **(additional_update or {})}, ) -def trigger_delete_families_search(project, family_guids, user=None): +def trigger_delete_families_search(project, family_guids, user=None, dataset_types=None): num_updated = 0 updated_families = set() for dataset in Dataset.objects.filter(active_individuals__family__guid__in=family_guids).distinct(): @@ -80,6 +80,8 @@ def trigger_delete_families_search(project, family_guids, user=None): logger.info(message, user) variables = {'project_guid': project.guid, 'family_guids': family_guids} + if dataset_types: + variables['dataset_types'] = dataset_types _enqueue_pipeline_request('delete_families', variables, user) info.append('Triggered delete family data') return info diff --git a/seqr/views/apis/data_manager_api.py b/seqr/views/apis/data_manager_api.py index caf655deca..aad43189fa 100644 --- a/seqr/views/apis/data_manager_api.py +++ b/seqr/views/apis/data_manager_api.py @@ -424,8 +424,11 @@ def trigger_delete_project(request): def trigger_delete_family(request): request_json = json.loads(request.body) family_guid = request_json.pop('family') + dataset_types = request_json.get('datasetTypes') or [] + if Dataset.DATASET_TYPE_SV_CALLS in dataset_types: + dataset_types.append('GCNV') project = Project.objects.get(family__guid=family_guid) - info = trigger_delete_families_search(project, [family_guid], request.user) + info = trigger_delete_families_search(project, [family_guid], request.user, dataset_types) return create_json_response({'info': info}) diff --git a/seqr/views/apis/data_manager_api_tests.py b/seqr/views/apis/data_manager_api_tests.py index 04eabf3a23..1cf8bc4b98 100644 --- a/seqr/views/apis/data_manager_api_tests.py +++ b/seqr/views/apis/data_manager_api_tests.py @@ -1325,7 +1325,7 @@ def test_trigger_delete_family(self): self.check_data_manager_login(url) Project.objects.filter(guid=PROJECT_GUID).update(genome_version='38') - response = self.client.post(url, content_type='application/json', data=json.dumps({'family': 'F000002_2'})) + response = self.client.post(url, content_type='application/json', data=json.dumps({'family': 'F000002_2', 'datasetTypes': ['SNV_INDEL', 'SV']})) self.assertEqual(response.status_code, 200) self.assertDictEqual(response.json(), { 'info': [ @@ -1340,6 +1340,7 @@ def test_trigger_delete_family(self): self.assertDictEqual(json.loads(responses.calls[-1].request.body), { 'project_guid': 'R0001_1kg', 'family_guids': ['F000002_2'], + 'dataset_types': ['SNV_INDEL', 'SV', 'GCNV'], }) From b10848547aefae08758e06fe70e20c065481f0da Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Thu, 6 Aug 2026 11:12:23 -0400 Subject: [PATCH 03/20] remove required validation in ui --- .../DataManagement/components/TriggerSearchDataUpdatePages.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx b/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx index 4c44c33ea4..1ebb6c62f0 100644 --- a/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx +++ b/ui/pages/DataManagement/components/TriggerSearchDataUpdatePages.jsx @@ -43,7 +43,7 @@ const FAMILY_FIELDS = [ placeholder: 'Search for a family', validate: validators.required, }, - { ...DATASET_TYPE_FIELD, name: 'datasetTypes', multiple: true }, + { ...DATASET_TYPE_FIELD, name: 'datasetTypes', multiple: true, validate: null }, ] const TriggerSearchDataUpdateForm = ({ entity, fields }) => ( From cdc536a249b571b08a61505a093cfc1ed8efe125 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 13:24:28 -0400 Subject: [PATCH 04/20] better mocking for loading temp file --- seqr/views/apis/anvil_workspace_api_tests.py | 44 ++++++++++---------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/seqr/views/apis/anvil_workspace_api_tests.py b/seqr/views/apis/anvil_workspace_api_tests.py index cb95ae16c1..8a5a2511ec 100644 --- a/seqr/views/apis/anvil_workspace_api_tests.py +++ b/seqr/views/apis/anvil_workspace_api_tests.py @@ -565,13 +565,10 @@ def setUp(self): patcher = mock.patch('seqr.utils.add_data_utils.logger') self.mock_add_data_utils_logger = patcher.start() self.addCleanup(patcher.stop) - patcher = mock.patch('seqr.views.apis.anvil_workspace_api.load_uploaded_file') - self.mock_load_file = patcher.start() - self.mock_load_file.return_value = LOAD_SAMPLE_DATA - self.addCleanup(patcher.stop) patcher = mock.patch('seqr.utils.file_utils.subprocess.Popen') self.mock_subprocess = patcher.start() self.mock_subprocess.return_value.wait.return_value = 0 + self.mock_subprocess.return_value.stdout = [json.dumps(LOAD_SAMPLE_DATA).encode('utf-8')] self.addCleanup(patcher.stop) patcher = mock.patch('seqr.views.utils.export_utils.TemporaryDirectory') mock_tempdir = patcher.start() @@ -596,6 +593,9 @@ def setUp(self): super().setUp() + def _set_load_file_iter(self, data): + self.mock_subprocess.return_value.stdout = [json.dumps(data).encode('utf-8')] + @mock.patch('seqr.models.Family._compute_guid', lambda family: f'F_{family.family_id}_{family.project.workspace_name[17:]}') @mock.patch('seqr.models.Project._compute_guid', lambda project: f'P_{project.name}') @responses.activate @@ -612,8 +612,8 @@ def test_create_project_from_workspace(self): # Test valid operation responses.calls.reset() - self.mock_load_file.return_value = LOAD_SAMPLE_DATA - self.mock_subprocess.return_value.wait.side_effect = [0, 1, 0] + self._set_load_file_iter(LOAD_SAMPLE_DATA) + self.mock_subprocess.return_value.wait.side_effect = [0, 0, 1, 0] response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY)) self.assertEqual(response.status_code, 200) project = Project.objects.get(workspace_namespace=TEST_WORKSPACE_NAMESPACE, workspace_name=TEST_NO_PROJECT_WORKSPACE_NAME) @@ -685,14 +685,14 @@ def test_add_workspace_data(self, mock_compute_indiv_guid): self._test_errors(url, ['uploadedFileId', 'fullDataPath', 'vcfSamples'], TEST_WORKSPACE_NAME, has_existing_data=True) # Test loading data from empty ped file - self.mock_load_file.return_value = LOAD_SAMPLE_DATA[:1] + self._set_load_file_iter(LOAD_SAMPLE_DATA[:1]) response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY)) self.assertEqual(response.status_code, 400) response_json = response.json() self.assertListEqual(response_json['errors'], ['No samples found in the pedigree file']) # Test Individual ID exists in an omitted family and missing loaded samples - self.mock_load_file.return_value = LOAD_SAMPLE_DATA + INVALID_ADDED_SAMPLE_DATA + self._set_load_file_iter(LOAD_SAMPLE_DATA + INVALID_ADDED_SAMPLE_DATA) response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY)) self.assertEqual(response.status_code, 400) response_json = response.json() @@ -705,7 +705,7 @@ def test_add_workspace_data(self, mock_compute_indiv_guid): ]) # Test project still has pending loading - self.mock_load_file.return_value = LOAD_SAMPLE_DATA + self._set_load_file_iter(LOAD_SAMPLE_DATA) response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY_ADD_DATA)) self.assertEqual(response.status_code, 400) self.assertListEqual(response.json()['errors'], [ @@ -714,8 +714,8 @@ def test_add_workspace_data(self, mock_compute_indiv_guid): ]) # Test a valid operation - self.mock_subprocess.return_value.wait.side_effect = [0, 1, 0] - self.mock_load_file.return_value = LOAD_SAMPLE_DATA_ALL_PENDING + self.mock_subprocess.return_value.wait.side_effect = [0, 0, 1, 0] + self._set_load_file_iter(LOAD_SAMPLE_DATA_ALL_PENDING) mock_compute_indiv_guid.side_effect = ['I0000020_hg00735', 'I0000021_hg00736'] response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY_ADD_DATA)) self.assertEqual(response.status_code, 200) @@ -734,7 +734,7 @@ def test_add_workspace_data(self, mock_compute_indiv_guid): self._assert_valid_operation(Project.objects.get(guid=PROJECT1_GUID)) - self.mock_load_file.return_value = LOAD_SAMPLE_DATA_ALL_PENDING_PROJECT_2 + self._set_load_file_iter(LOAD_SAMPLE_DATA_ALL_PENDING_PROJECT_2) mock_compute_indiv_guid.side_effect = ['I0000021_na19675_1', 'I0000022_na19678', 'I0000023_hg00735'] url = reverse(add_workspace_data, args=[PROJECT2_GUID]) self._test_mv_file_and_triggering_loading_exception( @@ -749,20 +749,20 @@ def _test_errors(self, url, fields, workspace_name, has_existing_data=False): self.mock_get_ws_access_level.assert_called_with(self.manager_user, TEST_WORKSPACE_NAMESPACE, workspace_name) # test missing columns - self.mock_load_file.return_value = [['family', 'individual'], ['1', '2']] + self._set_load_file_iter([['family', 'individual'], ['1', '2']]) response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY)) self.assertEqual(response.status_code, 400) response_json = response.json() self.assertListEqual(response_json['errors'], ['Missing required columns: Affected, HPO Terms, Sex']) - self.mock_load_file.return_value = LOAD_SAMPLE_DATA + MISSING_REQUIRED_SAMPLE_DATA + self._set_load_file_iter(LOAD_SAMPLE_DATA + MISSING_REQUIRED_SAMPLE_DATA) response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY)) self.assertEqual(response.status_code, 400) response_json = response.json() self.assertListEqual(response_json['errors'], ['Missing Sex in row #4', 'Missing Affected in row #4']) # test sample data error and missing samples - self.mock_load_file.return_value = LOAD_SAMPLE_DATA + BAD_SAMPLE_DATA + self._set_load_file_iter(LOAD_SAMPLE_DATA + BAD_SAMPLE_DATA) response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY)) self.assertEqual(response.status_code, 400) response_json = response.json() @@ -780,7 +780,7 @@ def _test_errors(self, url, fields, workspace_name, has_existing_data=False): 'NA19681 has invalid HPO terms: HP:0100258', ]) - self.mock_load_file.return_value = LOAD_SAMPLE_DATA_NO_AFFECTED + self._set_load_file_iter(LOAD_SAMPLE_DATA_NO_AFFECTED) response = self.client.post(url, content_type='application/json', data=json.dumps(REQUEST_BODY)) self.assertEqual(response.status_code, 400) response_json = response.json() @@ -834,11 +834,13 @@ def _assert_valid_operation(self, project, test_add_data=True): gs_path = f'gs://seqr-loading-temp/v3.1/{genome_version}/SNV_INDEL/pedigrees/WES/' self.mock_subprocess.assert_has_calls([ + mock.call(f'gsutil ls gs://seqr-scratch-temp/temp_upload_test_temp_file_id.json.gz', stdout=-1, stderr=-2, shell=True), # nosec + mock.call().wait(), + mock.call(f'gsutil cat gs://seqr-scratch-temp/temp_upload_test_temp_file_id.json.gz | gunzip -c -q - ', stdout=-1, stderr=-2, shell=True), # nosec mock.call(f'gsutil mv {TEMP_PATH}/* {gs_path}', stdout=-1, stderr=-2, shell=True), # nosec mock.call().wait(), mock.call('gsutil ls gs://seqr-loading-temp/v3.1/db_id_to_gene_id.csv.gz', stdout=-1, stderr=-2, shell=True), # nosec mock.call().wait(), - mock.call().stdout.__iter__(), mock.call(f'gsutil mv {TEMP_PATH}/* gs://seqr-loading-temp/v3.1/', stdout=-1, stderr=-2, shell=True), # nosec mock.call().wait(), ]) @@ -913,11 +915,11 @@ def _success_slack_message(self, project, sample_summary, genome_version, variab Loading pipeline is triggered with: ```{json.dumps(variables, indent=4)}```""" - @staticmethod - def _raise_move_file_error(command, *args, **kwargs): + def _raise_move_file_error(self, command, *args, **kwargs): mock_subprocess = mock.MagicMock() - mock_subprocess.wait.return_value = 1 if 'pedigrees' in command else 0 - mock_subprocess.stdout = [b'Something wrong while moving the file.'] + is_mv_pedigree_command = 'pedigrees' in command + mock_subprocess.wait.return_value = 1 if is_mv_pedigree_command else 0 + mock_subprocess.stdout = [b'Something wrong while moving the file.'] if is_mv_pedigree_command else self.mock_subprocess.return_value.stdout return mock_subprocess def _test_mv_file_and_triggering_loading_exception(self, url, workspace, sample_data, genome_version, request_body, num_samples=None, sample_type='WES'): From de53ef826d63c02dda7f6607f8f711eb70ed8bff Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 13:47:59 -0400 Subject: [PATCH 05/20] include unchanged individuals in anvil loading --- seqr/views/apis/anvil_workspace_api.py | 2 +- seqr/views/utils/individual_utils.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/seqr/views/apis/anvil_workspace_api.py b/seqr/views/apis/anvil_workspace_api.py index 01bf0f1be2..825db188a4 100644 --- a/seqr/views/apis/anvil_workspace_api.py +++ b/seqr/views/apis/anvil_workspace_api.py @@ -253,7 +253,7 @@ def _validate_expected_samples(vcf_samples, loaded_sample_types, loaded_individu def _trigger_add_workspace_data(project, pedigree_records, user, data_path, sample_type, previous_loaded_ids=None, get_pedigree_json=False): # add families and individuals according to the uploaded individual records pedigree_json, individual_ids = add_or_update_individuals_and_families( - project, individual_records=pedigree_records, user=user, get_update_json=get_pedigree_json, get_updated_individual_db_ids=True, + project, individual_records=pedigree_records, user=user, get_update_json=get_pedigree_json, get_individual_db_ids=True, allow_features_update=True, skip_gt_stats_rebuild=True, ) num_updated_individuals = len(individual_ids) diff --git a/seqr/views/utils/individual_utils.py b/seqr/views/utils/individual_utils.py index e396c365e9..39d9fd952c 100644 --- a/seqr/views/utils/individual_utils.py +++ b/seqr/views/utils/individual_utils.py @@ -20,7 +20,7 @@ def _get_record_individual_id(record): return record.get(JsonConstants.PREVIOUS_INDIVIDUAL_ID_COLUMN) or record[JsonConstants.INDIVIDUAL_ID_COLUMN] -def add_or_update_individuals_and_families(project, individual_records, user, get_update_json=True, get_updated_individual_db_ids=False, get_created_counts=False, allow_features_update=False, skip_gt_stats_rebuild=False): +def add_or_update_individuals_and_families(project, individual_records, user, get_update_json=True, get_individual_db_ids=False, get_created_counts=False, allow_features_update=False, skip_gt_stats_rebuild=False): updated_family_ids = set() updated_individuals = set() updated_affected = set() @@ -55,11 +55,14 @@ def add_or_update_individuals_and_families(project, individual_records, user, ge individual_id__in=[_get_record_individual_id(record) for record in individual_records]): individual_lookup[i.individual_id][i.family] = i + all_individuals = set() for record in individual_records: - created_individual = _update_from_record( + created_individual, individual_db_id = _update_from_record( record, user, families_by_id, individual_lookup, updated_family_ids, updated_individuals, updated_affected, updated_sex, updated_metadata, parent_updates, updated_note_ids, allow_features_update) if created_individual: num_created_individuals += 1 + if get_individual_db_ids: + all_individuals.add(individual_db_id) for update in parent_updates: individual = update.pop('individual') @@ -84,8 +87,8 @@ def add_or_update_individuals_and_families(project, individual_records, user, ge if get_update_json: pedigree_json = _get_updated_pedigree_json(updated_individuals, updated_family_models, updated_note_ids, user) - if get_updated_individual_db_ids: - return pedigree_json, {i.id for i in updated_individuals} + if get_individual_db_ids: + return pedigree_json, all_individuals if get_created_counts: return pedigree_json, num_created_families, num_created_individuals @@ -161,7 +164,7 @@ def _update_from_record(record, user, families_by_id, individual_lookup, updated if family.pedigree_image: updated_family_ids.add(family.id) - return created_individual + return created_individual, individual.id def delete_individuals(project, individual_guids, user): From 4f2d2af5a56c7aaafa8583272e182e9d9eec6d32 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 14:05:34 -0400 Subject: [PATCH 06/20] test loading for unchanged individuals --- seqr/fixtures/1kg_project.json | 4 ++-- seqr/views/apis/anvil_workspace_api_tests.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/seqr/fixtures/1kg_project.json b/seqr/fixtures/1kg_project.json index 4b2f54e9c1..ddf811bc12 100644 --- a/seqr/fixtures/1kg_project.json +++ b/seqr/fixtures/1kg_project.json @@ -801,10 +801,10 @@ "sex": "M", "affected": "A", "display_name": "", - "notes": "", + "notes": "some noted data", "population": "ASJ", "consanguinity": false, - "features": [{"id": "HP:0011675"}, {"id": "HP:0001509"}], + "features": [{"id": "HP:0001508"}, {"id": "HP:0011675"}], "case_review_status": "E", "case_review_status_last_modified_date": "2017-03-12T22:34:52.302Z", "case_review_status_last_modified_by": null, diff --git a/seqr/views/apis/anvil_workspace_api_tests.py b/seqr/views/apis/anvil_workspace_api_tests.py index 8a5a2511ec..88c898a5aa 100644 --- a/seqr/views/apis/anvil_workspace_api_tests.py +++ b/seqr/views/apis/anvil_workspace_api_tests.py @@ -42,7 +42,7 @@ ] LOAD_SAMPLE_DATA_ALL_PENDING_PROJECT_2 = LOAD_SAMPLE_DATA + [ - ["11", "NA20885", "", "", "", "Male", "Affected", "HP:0001508", "", ""], + ["11", "NA20885", "", "", "", "Male", "Affected", "HP:0011675;HP:0001508", "some noted data", ""], ["12", "NA20888", "", "", "", "Male", "Affected", "HP:0001508", "", ""], ] From 965db3b6c7201e755b6bda810cd32e7b94c7d935 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 14:25:54 -0400 Subject: [PATCH 07/20] codacy --- seqr/views/apis/anvil_workspace_api_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seqr/views/apis/anvil_workspace_api_tests.py b/seqr/views/apis/anvil_workspace_api_tests.py index 88c898a5aa..5e3a42be7e 100644 --- a/seqr/views/apis/anvil_workspace_api_tests.py +++ b/seqr/views/apis/anvil_workspace_api_tests.py @@ -834,9 +834,9 @@ def _assert_valid_operation(self, project, test_add_data=True): gs_path = f'gs://seqr-loading-temp/v3.1/{genome_version}/SNV_INDEL/pedigrees/WES/' self.mock_subprocess.assert_has_calls([ - mock.call(f'gsutil ls gs://seqr-scratch-temp/temp_upload_test_temp_file_id.json.gz', stdout=-1, stderr=-2, shell=True), # nosec + mock.call('gsutil ls gs://seqr-scratch-temp/temp_upload_test_temp_file_id.json.gz', stdout=-1, stderr=-2, shell=True), # nosec mock.call().wait(), - mock.call(f'gsutil cat gs://seqr-scratch-temp/temp_upload_test_temp_file_id.json.gz | gunzip -c -q - ', stdout=-1, stderr=-2, shell=True), # nosec + mock.call('gsutil cat gs://seqr-scratch-temp/temp_upload_test_temp_file_id.json.gz | gunzip -c -q - ', stdout=-1, stderr=-2, shell=True), # nosec mock.call(f'gsutil mv {TEMP_PATH}/* {gs_path}', stdout=-1, stderr=-2, shell=True), # nosec mock.call().wait(), mock.call('gsutil ls gs://seqr-loading-temp/v3.1/db_id_to_gene_id.csv.gz', stdout=-1, stderr=-2, shell=True), # nosec From f35776ab21eac8a551b120be0023c199448229e1 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 14:38:30 -0400 Subject: [PATCH 08/20] Revert "test loading for unchanged individuals" This reverts commit 4f2d2af5a56c7aaafa8583272e182e9d9eec6d32. --- seqr/fixtures/1kg_project.json | 4 ++-- seqr/views/apis/anvil_workspace_api_tests.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/seqr/fixtures/1kg_project.json b/seqr/fixtures/1kg_project.json index ddf811bc12..4b2f54e9c1 100644 --- a/seqr/fixtures/1kg_project.json +++ b/seqr/fixtures/1kg_project.json @@ -801,10 +801,10 @@ "sex": "M", "affected": "A", "display_name": "", - "notes": "some noted data", + "notes": "", "population": "ASJ", "consanguinity": false, - "features": [{"id": "HP:0001508"}, {"id": "HP:0011675"}], + "features": [{"id": "HP:0011675"}, {"id": "HP:0001509"}], "case_review_status": "E", "case_review_status_last_modified_date": "2017-03-12T22:34:52.302Z", "case_review_status_last_modified_by": null, diff --git a/seqr/views/apis/anvil_workspace_api_tests.py b/seqr/views/apis/anvil_workspace_api_tests.py index 5e3a42be7e..a494c48048 100644 --- a/seqr/views/apis/anvil_workspace_api_tests.py +++ b/seqr/views/apis/anvil_workspace_api_tests.py @@ -42,7 +42,7 @@ ] LOAD_SAMPLE_DATA_ALL_PENDING_PROJECT_2 = LOAD_SAMPLE_DATA + [ - ["11", "NA20885", "", "", "", "Male", "Affected", "HP:0011675;HP:0001508", "some noted data", ""], + ["11", "NA20885", "", "", "", "Male", "Affected", "HP:0001508", "", ""], ["12", "NA20888", "", "", "", "Male", "Affected", "HP:0001508", "", ""], ] From 2e806f99e1257cd3378db646a3fced8caa8a31dc Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 14:45:31 -0400 Subject: [PATCH 09/20] better test fixture for unchanged --- seqr/fixtures/1kg_project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seqr/fixtures/1kg_project.json b/seqr/fixtures/1kg_project.json index 4b2f54e9c1..dec04bf2d2 100644 --- a/seqr/fixtures/1kg_project.json +++ b/seqr/fixtures/1kg_project.json @@ -757,7 +757,7 @@ "sex": "M", "affected": "A", "display_name": "", - "notes": "", + "features": [{"id": "HP:0001508"}], "case_review_status": "", "case_review_status_last_modified_date": null, "case_review_status_last_modified_by": null, From 0b1b3803d4c6111cb0096b514e9bc6ce83c808fa Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 14:49:21 -0400 Subject: [PATCH 10/20] fix test --- seqr/views/apis/anvil_workspace_api_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seqr/views/apis/anvil_workspace_api_tests.py b/seqr/views/apis/anvil_workspace_api_tests.py index a494c48048..0851d96b9b 100644 --- a/seqr/views/apis/anvil_workspace_api_tests.py +++ b/seqr/views/apis/anvil_workspace_api_tests.py @@ -724,10 +724,10 @@ def test_add_workspace_data(self, mock_compute_indiv_guid): self.assertSetEqual(set(response_json['individualsByGuid'].keys()), { 'I0000020_hg00735', 'I000001_na19675', 'I000003_na19679', 'I0000021_hg00736', 'I000007_na20870', 'I000009_na20874', 'I000004_hg00731', 'I000010_na20875', 'I000008_na20872', 'I000005_hg00732', - 'I000006_hg00733', 'I000013_na20878', 'I000012_na20877', + 'I000006_hg00733', 'I000012_na20877', }) self.assertSetEqual(set(response_json['familiesByGuid'].keys()), { - 'F000001_1', 'F000015_21', 'F000006_6', 'F000013_13', 'F000005_5', 'F000009_9', 'F000008_8', 'F000004_4', + 'F000001_1', 'F000015_21', 'F000006_6', 'F000013_13', 'F000005_5', 'F000008_8', 'F000004_4', 'F000002_2', 'F000003_3', }) self.assertEqual(list(response_json['familyNotesByGuid'].keys()), ['FAN000005_21_c_a_new_family']) From 139b37b8af7584df14fac3389abe8da984be332c Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 15:32:38 -0400 Subject: [PATCH 11/20] update detail schema one result per sample --- vlm/match.py | 24 ++-- vlm/test_vlm.py | 370 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 283 insertions(+), 111 deletions(-) diff --git a/vlm/match.py b/vlm/match.py index 5d52533c81..e885cb278f 100644 --- a/vlm/match.py +++ b/vlm/match.py @@ -170,9 +170,8 @@ async def _get_match_detail_results(match: list[tuple], lift_match: Optional[lis async with ClientSession(ONTOLOGY_API_URL) as session: for f_i, (samples, has_discovery, has_excluded) in enumerate(match + (lift_match or [])): family_id = f'F_{f_i}' - proband = None - relatives = [] pedigree = [] + phenopackets = [] for s_i, (affected, sex, *sample) in enumerate(samples): individual_id = f'I_{f_i}_{s_i}' sex = SEX_LOOKUP.get(sex, 'OTHER_SEX') @@ -188,22 +187,15 @@ async def _get_match_detail_results(match: list[tuple], lift_match: Optional[lis phenopacket = await _format_phenopacket( hpo_label_map, mondo_label_map, session, individual_id, has_discovery, has_excluded, sex, *sample, ) - if affected == 'A' and proband is None: - proband = phenopacket - else: - relatives.append(phenopacket) - - if not proband: - proband = relatives[0] - relatives = relatives[1:] - - results.append({ - 'id': family_id, - 'proband': proband, - 'relatives': relatives, + phenopackets.append(phenopacket) + + results += [{ + 'id': phenopacket['id'], + 'proband': phenopacket, + 'relatives': [p for p in phenopackets if p != phenopacket], 'pedigree': {'persons': pedigree}, 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, - }) + } for phenopacket in phenopackets] result_sets = [ (None, len(results), results), diff --git a/vlm/test_vlm.py b/vlm/test_vlm.py index fcbf1b82b7..cd91da3395 100644 --- a/vlm/test_vlm.py +++ b/vlm/test_vlm.py @@ -32,16 +32,6 @@ def inject_fixtures(self, caplog): @aioresponses(passthrough=['http://127.0.0.1']) async def test_match(self, mocked_responses): response = { - 'beaconHandovers': [ - { - 'handoverType': { - 'id': 'TestVLM', - 'label': 'TestVLM browser', - }, - 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=38&variantId=1-38724419-T-G', - 'email': None, - } - ], 'meta': { 'apiVersion': 'v1.0', 'beaconId': 'com.gnx.beacon.v2', @@ -52,10 +42,6 @@ async def test_match(self, mocked_responses): } ] }, - 'responseSummary': { - 'exists': True, - 'total': 7, - }, 'response': { 'resultSets': [ { @@ -90,16 +76,6 @@ async def test_match(self, mocked_responses): } } only_37_response = { - 'beaconHandovers': [ - { - 'handoverType': { - 'id': 'TestVLM', - 'label': 'TestVLM browser', - }, - 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=37&variantId=7-143270172-A-G', - 'email': None, - } - ], 'meta': { 'apiVersion': 'v1.0', 'beaconId': 'com.gnx.beacon.v2', @@ -110,10 +86,6 @@ async def test_match(self, mocked_responses): } ] }, - 'responseSummary': { - 'exists': True, - 'total': 1, - }, 'response': { 'resultSets': [ { @@ -148,16 +120,6 @@ async def test_match(self, mocked_responses): } } empty_response = { - 'beaconHandovers': [ - { - 'handoverType': { - 'id': 'TestVLM', - 'label': 'TestVLM browser', - }, - 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=38&variantId=7-143270172-A-G', - 'email': None, - } - ], 'meta': { 'apiVersion': 'v1.0', 'beaconId': 'com.gnx.beacon.v2', @@ -168,10 +130,6 @@ async def test_match(self, mocked_responses): } ] }, - 'responseSummary': { - 'exists': False, - 'total': 0, - }, 'response': { 'resultSets': [ { @@ -226,16 +184,6 @@ async def test_match_details(self, mocked_responses): }) response = { - 'beaconHandovers': [ - { - 'handoverType': { - 'id': 'TestVLM', - 'label': 'TestVLM browser', - }, - 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=38&variantId=1-38724419-T-G', - 'email': None, - } - ], 'meta': { 'apiVersion': 'v1.0', 'beaconId': 'com.gnx.beacon.v2', @@ -246,10 +194,6 @@ async def test_match_details(self, mocked_responses): } ] }, - 'responseSummary': { - 'exists': True, - 'total': 5, - }, 'response': { 'resultSets': [ { @@ -258,7 +202,7 @@ async def test_match_details(self, mocked_responses): 'setType': 'Family', 'resultsCount': 5, 'results': [{ - 'id': 'F_0', + 'id': 'I_0_1', 'pedigree': { 'persons': [{ 'affected_status': 'UNAFFECTED', @@ -374,7 +318,123 @@ async def test_match_details(self, mocked_responses): }], 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, }, { - 'id': 'F_1', + 'id': 'I_0_0', + 'pedigree': { + 'persons': [{ + 'affected_status': 'UNAFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'MALE', + }, { + 'affected_status': 'AFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'OTHER_SEX', + }], + }, + 'proband': { + 'id': 'I_0_0', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, + }, + 'interpretation_status': 'REJECTED', + 'subject_or_biosample_id': 'I_0_0', + }], + }, + 'id': 'I_0_0', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_0_0', + 'sex': 'MALE', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), + }], + }, + }, + 'relatives': [{ + 'id': 'I_0_1', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, + }, + 'interpretation_status': 'REJECTED', + 'subject_or_biosample_id': 'I_0_1', + }], + }, + 'id': 'I_0_1', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [ + {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, + {'id': 'HP:0011675', 'label': 'Arrhythmia'}, + ], + 'subject': { + 'id': 'I_0_1', + 'sex': 'OTHER_SEX', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'hp', + 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', + 'name': 'Human Phenotype Ontology', + 'namespacePrefix': 'HP', + 'url': 'http://purl.obolibrary.org/obo/hp.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), + }], + }, + }], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_1_0', 'pedigree': { 'persons': [{ 'affected_status': 'AFFECTED', @@ -441,7 +501,7 @@ async def test_match_details(self, mocked_responses): 'relatives': [], 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, }, { - 'id': 'F_2', + 'id': 'I_2_0', 'pedigree': { 'persons': [{ 'affected_status': 'MISSING', @@ -539,7 +599,105 @@ async def test_match_details(self, mocked_responses): }], 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, }, { - 'id': 'F_3', + 'id': 'I_2_1', + 'pedigree': { + 'persons': [{ + 'affected_status': 'MISSING', + 'family_id': 'F_2', + 'individual_id': 'I_2_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'UNKNOWN_SEX', + }, { + 'affected_status': 'MISSING', + 'family_id': 'F_2', + 'individual_id': 'I_2_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'FEMALE', + }], + }, + 'proband': { + 'id': 'I_2_1', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'MONDO:0044970', 'label': 'mitochondrial disease'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, + }, + 'interpretation_status': 'CANDIDATE', + 'subject_or_biosample_id': 'I_2_1', + }], + }, + 'id': 'I_2_1', + 'progress_status': 'SOLVED', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_2_1', + 'sex': 'FEMALE', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'mondo', + 'iriPrefix': 'http://purl.obolibrary.org/obo/MONDO_', + 'name': 'Mondo Disease Ontology', + 'namespacePrefix': 'MONDO', + 'url': 'http://purl.obolibrary.org/obo/mondo.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), + }], + }, + }, + 'relatives': [{ + 'id': 'I_2_0', + 'interpretations': [{ + 'diagnosis': { + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, + }, + 'interpretation_status': 'CANDIDATE', + 'subject_or_biosample_id': 'I_2_0', + }], + }, + 'id': 'I_2_0', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_2_0', + 'sex': 'UNKNOWN_SEX', + }, + 'meta_data': { + 'submitted_by': '', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }], + }, + }], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_3_0', 'pedigree': { 'persons': [{ 'affected_status': 'AFFECTED', @@ -589,7 +747,7 @@ async def test_match_details(self, mocked_responses): 'relatives': [], 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, }, { - 'id': 'F_4', + 'id': 'I_4_0', 'pedigree': { 'persons': [{ 'affected_status': 'AFFECTED', @@ -643,16 +801,6 @@ async def test_match_details(self, mocked_responses): } } only_37_response = { - 'beaconHandovers': [ - { - 'handoverType': { - 'id': 'TestVLM', - 'label': 'TestVLM browser', - }, - 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=37&variantId=7-143270172-A-G', - 'email': None, - } - ], 'meta': { 'apiVersion': 'v1.0', 'beaconId': 'com.gnx.beacon.v2', @@ -663,10 +811,6 @@ async def test_match_details(self, mocked_responses): } ] }, - 'responseSummary': { - 'exists': True, - 'total': 1, - }, 'response': { 'resultSets': [ { @@ -675,7 +819,7 @@ async def test_match_details(self, mocked_responses): 'setType': 'Family', 'resultsCount': 1, 'results': [{ - 'id': 'F_0', + 'id': 'I_0_0', 'pedigree': { 'persons': [{ 'affected_status': 'AFFECTED', @@ -747,16 +891,6 @@ async def test_match_details(self, mocked_responses): } } empty_response = { - 'beaconHandovers': [ - { - 'handoverType': { - 'id': 'TestVLM', - 'label': 'TestVLM browser', - }, - 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=38&variantId=7-143270172-A-G', - 'email': None, - } - ], 'meta': { 'apiVersion': 'v1.0', 'beaconId': 'com.gnx.beacon.v2', @@ -767,10 +901,6 @@ async def test_match_details(self, mocked_responses): } ] }, - 'responseSummary': { - 'exists': False, - 'total': 0, - }, 'response': { 'resultSets': [ { @@ -801,7 +931,24 @@ async def _test_match_endpoint(self, path, mocked_responses, response, only_37_r async with self.client.request('GET', f'/vlm/{path}?assemblyId=GRCh38&referenceName=1&start=38724419&referenceBases=T&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, response) + full_response = { + 'beaconHandovers': [ + { + 'handoverType': { + 'id': 'TestVLM', + 'label': 'TestVLM browser', + }, + 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=38&variantId=1-38724419-T-G', + 'email': None, + } + ], + 'responseSummary': { + 'exists': True, + 'total': 7, + }, + **response, + } + self.assertDictEqual(resp_json, full_response) mocked_responses.assert_called_with( 'https://vlm-auth.us.auth0.com/oauth/token', method='POST', @@ -819,22 +966,55 @@ async def _test_match_endpoint(self, path, mocked_responses, response, only_37_r async with self.client.request('GET', f'/vlm/{path}?assemblyId=GRCh37&referenceName=1&start=39190091&referenceBases=T&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, response) + self.assertDictEqual(resp_json, full_response) + full_only_37_response = { + 'beaconHandovers': [ + { + 'handoverType': { + 'id': 'TestVLM', + 'label': 'TestVLM browser', + }, + 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=37&variantId=7-143270172-A-G', + 'email': None, + } + ], + 'responseSummary': { + 'exists': True, + 'total': 1, + }, + **only_37_response, + } async with self.client.request('GET', f'/vlm/{path}?assemblyId=hg19&referenceName=chr7&start=143270172&referenceBases=A&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, only_37_response) + self.assertDictEqual(resp_json, full_only_37_response) async with self.client.request('GET', f'/vlm/{path}?assemblyId=GRCh38&referenceName=chr7&start=143573079&referenceBases=A&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, only_37_response) + self.assertDictEqual(resp_json, full_only_37_response) async with self.client.request('GET', f'/vlm/{path}?assemblyId=hg38&referenceName=chr7&start=143270172&referenceBases=A&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, empty_response) + self.assertDictEqual(resp_json, { + 'beaconHandovers': [ + { + 'handoverType': { + 'id': 'TestVLM', + 'label': 'TestVLM browser', + }, + 'url': 'https://test-seqr.org/variant_lookup?genomeVersion=38&variantId=7-143270172-A-G', + 'email': None, + } + ], + 'responseSummary': { + 'exists': False, + 'total': 0, + }, + **empty_response, + }) @aioresponses(passthrough=['http://127.0.0.1']) async def test_match_error(self, mocked_responses): From 134dff259e85d400917ce60381526e090c72abb2 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 15:39:32 -0400 Subject: [PATCH 12/20] reduce test copy paste --- vlm/test_vlm.py | 1595 +++++++++++++++++++++++------------------------ 1 file changed, 770 insertions(+), 825 deletions(-) diff --git a/vlm/test_vlm.py b/vlm/test_vlm.py index cd91da3395..5de2400d4a 100644 --- a/vlm/test_vlm.py +++ b/vlm/test_vlm.py @@ -31,139 +31,107 @@ def inject_fixtures(self, caplog): @aioresponses(passthrough=['http://127.0.0.1']) async def test_match(self, mocked_responses): - response = { - 'meta': { - 'apiVersion': 'v1.0', - 'beaconId': 'com.gnx.beacon.v2', - 'returnedSchemas': [ - { - 'entityType': 'genomicVariant', - 'schema': 'ga4gh-beacon-variant-v2.0.0', - } - ] - }, - 'response': { - 'resultSets': [ - { - 'exists': True, - 'id': 'TestVLM Homozygous', - 'results': [], - 'resultsCount': 3, - 'setType': 'genomicVariant' - }, - { - 'exists': True, - 'id': 'TestVLM Heterozygous', - 'results': [], - 'resultsCount': 4, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Hemizygous', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Unknown', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - ], - } + meta = { + 'apiVersion': 'v1.0', + 'beaconId': 'com.gnx.beacon.v2', + 'returnedSchemas': [ + { + 'entityType': 'genomicVariant', + 'schema': 'ga4gh-beacon-variant-v2.0.0', + } + ] } - only_37_response = { - 'meta': { - 'apiVersion': 'v1.0', - 'beaconId': 'com.gnx.beacon.v2', - 'returnedSchemas': [ - { - 'entityType': 'genomicVariant', - 'schema': 'ga4gh-beacon-variant-v2.0.0', - } - ] + results = [ + { + 'exists': True, + 'id': 'TestVLM Homozygous', + 'results': [], + 'resultsCount': 3, + 'setType': 'genomicVariant' }, - 'response': { - 'resultSets': [ - { - 'exists': True, - 'id': 'TestVLM Homozygous', - 'results': [], - 'resultsCount': 1, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Heterozygous', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Hemizygous', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Unknown', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - ], - } - } - empty_response = { - 'meta': { - 'apiVersion': 'v1.0', - 'beaconId': 'com.gnx.beacon.v2', - 'returnedSchemas': [ - { - 'entityType': 'genomicVariant', - 'schema': 'ga4gh-beacon-variant-v2.0.0', - } - ] + { + 'exists': True, + 'id': 'TestVLM Heterozygous', + 'results': [], + 'resultsCount': 4, + 'setType': 'genomicVariant' }, - 'response': { - 'resultSets': [ - { - 'exists': False, - 'id': 'TestVLM Homozygous', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Heterozygous', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Hemizygous', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - { - 'exists': False, - 'id': 'TestVLM Unknown', - 'results': [], - 'resultsCount': 0, - 'setType': 'genomicVariant' - }, - ], - } - } - await self._test_match_endpoint('match', mocked_responses, response, only_37_response, empty_response) + { + 'exists': False, + 'id': 'TestVLM Hemizygous', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + { + 'exists': False, + 'id': 'TestVLM Unknown', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + ] + only_37_results = [ + { + 'exists': True, + 'id': 'TestVLM Homozygous', + 'results': [], + 'resultsCount': 1, + 'setType': 'genomicVariant' + }, + { + 'exists': False, + 'id': 'TestVLM Heterozygous', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + { + 'exists': False, + 'id': 'TestVLM Hemizygous', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + { + 'exists': False, + 'id': 'TestVLM Unknown', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + ] + empty_results = [ + { + 'exists': False, + 'id': 'TestVLM Homozygous', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + { + 'exists': False, + 'id': 'TestVLM Heterozygous', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + { + 'exists': False, + 'id': 'TestVLM Hemizygous', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + { + 'exists': False, + 'id': 'TestVLM Unknown', + 'results': [], + 'resultsCount': 0, + 'setType': 'genomicVariant' + }, + ] + await self._test_match_endpoint('match', mocked_responses, meta, results, only_37_results, empty_results) @aioresponses(passthrough=['http://127.0.0.1']) async def test_match_details(self, mocked_responses): @@ -183,739 +151,707 @@ async def test_match_details(self, mocked_responses): 'definition': '', }) - response = { - 'meta': { - 'apiVersion': 'v1.0', - 'beaconId': 'com.gnx.beacon.v2', - 'returnedSchemas': [ - { - 'entityType': 'Family', - 'schema': 'phenopacket-2.0', - } - ] - }, - 'response': { - 'resultSets': [ - { - 'exists': True, - 'id': 'TestVLM', - 'setType': 'Family', - 'resultsCount': 5, - 'results': [{ - 'id': 'I_0_1', - 'pedigree': { - 'persons': [{ - 'affected_status': 'UNAFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'MALE', - }, { - 'affected_status': 'AFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_1', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'OTHER_SEX', - }], - }, - 'proband': { - 'id': 'I_0_1', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, - }, - }, - 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_1', - }], + meta = { + 'apiVersion': 'v1.0', + 'beaconId': 'com.gnx.beacon.v2', + 'returnedSchemas': [ + { + 'entityType': 'Family', + 'schema': 'phenopacket-2.0', + } + ] + } + results = [ + { + 'exists': True, + 'id': 'TestVLM', + 'setType': 'Family', + 'resultsCount': 5, + 'results': [{ + 'id': 'I_0_1', + 'pedigree': { + 'persons': [{ + 'affected_status': 'UNAFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'MALE', + }, { + 'affected_status': 'AFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'OTHER_SEX', + }], + }, + 'proband': { + 'id': 'I_0_1', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, }, - 'id': 'I_0_1', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'REJECTED', + 'subject_or_biosample_id': 'I_0_1', }], - 'phenotypic_features': [ - {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, - {'id': 'HP:0011675', 'label': 'Arrhythmia'}, - ], - 'subject': { - 'id': 'I_0_1', - 'sex': 'OTHER_SEX', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'hp', - 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', - 'name': 'Human Phenotype Ontology', - 'namespacePrefix': 'HP', - 'url': 'http://purl.obolibrary.org/obo/hp.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), - }, { - 'id': 'omim', - 'iriPrefix': 'https://www.omim.org/entry/', - 'name': 'Online Mendelian Inheritance in Man', - 'namespacePrefix': 'OMIM', - 'url': 'https://www.omim.org', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, }, - 'relatives': [{ - 'id': 'I_0_0', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, - }, - }, - 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_0', - }], + 'id': 'I_0_1', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [ + {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, + {'id': 'HP:0011675', 'label': 'Arrhythmia'}, + ], + 'subject': { + 'id': 'I_0_1', + 'sex': 'OTHER_SEX', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'hp', + 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', + 'name': 'Human Phenotype Ontology', + 'namespacePrefix': 'HP', + 'url': 'http://purl.obolibrary.org/obo/hp.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), + }], + }, + }, + 'relatives': [{ + 'id': 'I_0_0', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, }, - 'id': 'I_0_0', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'REJECTED', + 'subject_or_biosample_id': 'I_0_0', }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_0_0', - 'sex': 'MALE', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'omim', - 'iriPrefix': 'https://www.omim.org/entry/', - 'name': 'Online Mendelian Inheritance in Man', - 'namespacePrefix': 'OMIM', - 'url': 'https://www.omim.org', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, + }, + 'id': 'I_0_0', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_0_0', + 'sex': 'MALE', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), }], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, + }], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_0_0', + 'pedigree': { + 'persons': [{ + 'affected_status': 'UNAFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'MALE', }, { - 'id': 'I_0_0', - 'pedigree': { - 'persons': [{ - 'affected_status': 'UNAFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'MALE', - }, { - 'affected_status': 'AFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_1', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'OTHER_SEX', + 'affected_status': 'AFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'OTHER_SEX', + }], + }, + 'proband': { + 'id': 'I_0_0', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, + }, + 'interpretation_status': 'REJECTED', + 'subject_or_biosample_id': 'I_0_0', }], }, - 'proband': { - 'id': 'I_0_0', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, - }, - }, - 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_0', - }], + 'id': 'I_0_0', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_0_0', + 'sex': 'MALE', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), + }], + }, + }, + 'relatives': [{ + 'id': 'I_0_1', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, }, - 'id': 'I_0_0', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'REJECTED', + 'subject_or_biosample_id': 'I_0_1', }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_0_0', - 'sex': 'MALE', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'omim', - 'iriPrefix': 'https://www.omim.org/entry/', - 'name': 'Online Mendelian Inheritance in Man', - 'namespacePrefix': 'OMIM', - 'url': 'https://www.omim.org', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, }, - 'relatives': [{ - 'id': 'I_0_1', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, - }, - }, - 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_1', - }], + 'id': 'I_0_1', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [ + {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, + {'id': 'HP:0011675', 'label': 'Arrhythmia'}, + ], + 'subject': { + 'id': 'I_0_1', + 'sex': 'OTHER_SEX', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'hp', + 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', + 'name': 'Human Phenotype Ontology', + 'namespacePrefix': 'HP', + 'url': 'http://purl.obolibrary.org/obo/hp.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), + }], + }, + }], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_1_0', + 'pedigree': { + 'persons': [{ + 'affected_status': 'AFFECTED', + 'family_id': 'F_1', + 'individual_id': 'I_1_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'OTHER_SEX', + }], + }, + 'proband': { + 'id': 'I_1_0', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, }, - 'id': 'I_0_1', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'REJECTED', + 'subject_or_biosample_id': 'I_1_0', }], - 'phenotypic_features': [ - {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, - {'id': 'HP:0011675', 'label': 'Arrhythmia'}, - ], - 'subject': { - 'id': 'I_0_1', - 'sex': 'OTHER_SEX', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'hp', - 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', - 'name': 'Human Phenotype Ontology', - 'namespacePrefix': 'HP', - 'url': 'http://purl.obolibrary.org/obo/hp.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), - }, { - 'id': 'omim', - 'iriPrefix': 'https://www.omim.org/entry/', - 'name': 'Online Mendelian Inheritance in Man', - 'namespacePrefix': 'OMIM', - 'url': 'https://www.omim.org', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, + }, + 'id': 'I_1_0', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [ + {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, + {'id': 'HP:0011675', 'label': 'Arrhythmia'}, + ], + 'subject': { + 'id': 'I_1_0', + 'sex': 'OTHER_SEX', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'hp', + 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', + 'name': 'Human Phenotype Ontology', + 'namespacePrefix': 'HP', + 'url': 'http://purl.obolibrary.org/obo/hp.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), }], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, + }, + 'relatives': [], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_2_0', + 'pedigree': { + 'persons': [{ + 'affected_status': 'MISSING', + 'family_id': 'F_2', + 'individual_id': 'I_2_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'UNKNOWN_SEX', }, { - 'id': 'I_1_0', - 'pedigree': { - 'persons': [{ - 'affected_status': 'AFFECTED', - 'family_id': 'F_1', - 'individual_id': 'I_1_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'OTHER_SEX', - }], - }, - 'proband': { - 'id': 'I_1_0', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, - }, - }, - 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_1_0', - }], + 'affected_status': 'MISSING', + 'family_id': 'F_2', + 'individual_id': 'I_2_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'FEMALE', + }], + }, + 'proband': { + 'id': 'I_2_0', + 'interpretations': [{ + 'diagnosis': { + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, }, - 'id': 'I_1_0', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'CANDIDATE', + 'subject_or_biosample_id': 'I_2_0', }], - 'phenotypic_features': [ - {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, - {'id': 'HP:0011675', 'label': 'Arrhythmia'}, - ], - 'subject': { - 'id': 'I_1_0', - 'sex': 'OTHER_SEX', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'hp', - 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', - 'name': 'Human Phenotype Ontology', - 'namespacePrefix': 'HP', - 'url': 'http://purl.obolibrary.org/obo/hp.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), - }, { - 'id': 'omim', - 'iriPrefix': 'https://www.omim.org/entry/', - 'name': 'Online Mendelian Inheritance in Man', - 'namespacePrefix': 'OMIM', - 'url': 'https://www.omim.org', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, }, - 'relatives': [], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, - }, { 'id': 'I_2_0', - 'pedigree': { - 'persons': [{ - 'affected_status': 'MISSING', - 'family_id': 'F_2', - 'individual_id': 'I_2_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'UNKNOWN_SEX', - }, { - 'affected_status': 'MISSING', - 'family_id': 'F_2', - 'individual_id': 'I_2_1', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'FEMALE', - }], - }, - 'proband': { - 'id': 'I_2_0', - 'interpretations': [{ - 'diagnosis': { - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, - }, - }, - 'interpretation_status': 'CANDIDATE', - 'subject_or_biosample_id': 'I_2_0', - }], + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_2_0', + 'sex': 'UNKNOWN_SEX', + }, + 'meta_data': { + 'submitted_by': '', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }], + }, + }, + 'relatives': [{ + 'id': 'I_2_1', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'MONDO:0044970', 'label': 'mitochondrial disease'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, }, - 'id': 'I_2_0', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'CANDIDATE', + 'subject_or_biosample_id': 'I_2_1', }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_2_0', - 'sex': 'UNKNOWN_SEX', - }, - 'meta_data': { - 'submitted_by': '', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }], - }, }, - 'relatives': [{ - 'id': 'I_2_1', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'MONDO:0044970', 'label': 'mitochondrial disease'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, - }, - }, - 'interpretation_status': 'CANDIDATE', - 'subject_or_biosample_id': 'I_2_1', - }], - }, - 'id': 'I_2_1', - 'progress_status': 'SOLVED', - }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_2_1', - 'sex': 'FEMALE', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'mondo', - 'iriPrefix': 'http://purl.obolibrary.org/obo/MONDO_', - 'name': 'Mondo Disease Ontology', - 'namespacePrefix': 'MONDO', - 'url': 'http://purl.obolibrary.org/obo/mondo.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, + 'id': 'I_2_1', + 'progress_status': 'SOLVED', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_2_1', + 'sex': 'FEMALE', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'mondo', + 'iriPrefix': 'http://purl.obolibrary.org/obo/MONDO_', + 'name': 'Mondo Disease Ontology', + 'namespacePrefix': 'MONDO', + 'url': 'http://purl.obolibrary.org/obo/mondo.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), }], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, + }], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_2_1', + 'pedigree': { + 'persons': [{ + 'affected_status': 'MISSING', + 'family_id': 'F_2', + 'individual_id': 'I_2_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'UNKNOWN_SEX', }, { - 'id': 'I_2_1', - 'pedigree': { - 'persons': [{ - 'affected_status': 'MISSING', - 'family_id': 'F_2', - 'individual_id': 'I_2_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'UNKNOWN_SEX', - }, { - 'affected_status': 'MISSING', - 'family_id': 'F_2', - 'individual_id': 'I_2_1', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'FEMALE', - }], - }, - 'proband': { - 'id': 'I_2_1', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'MONDO:0044970', 'label': 'mitochondrial disease'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, - }, - }, - 'interpretation_status': 'CANDIDATE', - 'subject_or_biosample_id': 'I_2_1', - }], + 'affected_status': 'MISSING', + 'family_id': 'F_2', + 'individual_id': 'I_2_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'FEMALE', + }], + }, + 'proband': { + 'id': 'I_2_1', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'MONDO:0044970', 'label': 'mitochondrial disease'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, }, - 'id': 'I_2_1', - 'progress_status': 'SOLVED', + 'interpretation_status': 'CANDIDATE', + 'subject_or_biosample_id': 'I_2_1', }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_2_1', - 'sex': 'FEMALE', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'mondo', - 'iriPrefix': 'http://purl.obolibrary.org/obo/MONDO_', - 'name': 'Mondo Disease Ontology', - 'namespacePrefix': 'MONDO', - 'url': 'http://purl.obolibrary.org/obo/mondo.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, }, - 'relatives': [{ - 'id': 'I_2_0', - 'interpretations': [{ - 'diagnosis': { - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, - }, - }, - 'interpretation_status': 'CANDIDATE', - 'subject_or_biosample_id': 'I_2_0', - }], - }, - 'id': 'I_2_0', - 'progress_status': 'UNKNOWN_PROGRESS', - }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_2_0', - 'sex': 'UNKNOWN_SEX', - }, - 'meta_data': { - 'submitted_by': '', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }], - }, + 'id': 'I_2_1', + 'progress_status': 'SOLVED', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_2_1', + 'sex': 'FEMALE', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'mondo', + 'iriPrefix': 'http://purl.obolibrary.org/obo/MONDO_', + 'name': 'Mondo Disease Ontology', + 'namespacePrefix': 'MONDO', + 'url': 'http://purl.obolibrary.org/obo/mondo.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), }], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, - }, { - 'id': 'I_3_0', - 'pedigree': { - 'persons': [{ - 'affected_status': 'AFFECTED', - 'family_id': 'F_3', - 'individual_id': 'I_3_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'MALE', - }], - }, - 'proband': { - 'id': 'I_3_0', - 'interpretations': [{ - 'diagnosis': { - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': { - 'id': 'GENO:0000135', 'label': 'heterozygous'}, - }, - }, - 'interpretation_status': 'UNKNOWN_STATUS', - 'subject_or_biosample_id': 'I_3_0', - }], + }, + }, + 'relatives': [{ + 'id': 'I_2_0', + 'interpretations': [{ + 'diagnosis': { + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, }, - 'id': 'I_3_0', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'CANDIDATE', + 'subject_or_biosample_id': 'I_2_0', }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_3_0', - 'sex': 'MALE', - }, - 'meta_data': { - 'submitted_by': 'seqr-test@gmail.com,test@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }], - }, }, - 'relatives': [], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, - }, { - 'id': 'I_4_0', - 'pedigree': { - 'persons': [{ - 'affected_status': 'AFFECTED', - 'family_id': 'F_4', - 'individual_id': 'I_4_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'MALE', + 'id': 'I_2_0', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_2_0', + 'sex': 'UNKNOWN_SEX', + }, + 'meta_data': { + 'submitted_by': '', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }], + }, + }], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_3_0', + 'pedigree': { + 'persons': [{ + 'affected_status': 'AFFECTED', + 'family_id': 'F_3', + 'individual_id': 'I_3_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'MALE', + }], + }, + 'proband': { + 'id': 'I_3_0', + 'interpretations': [{ + 'diagnosis': { + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': { + 'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, + }, + 'interpretation_status': 'UNKNOWN_STATUS', + 'subject_or_biosample_id': 'I_3_0', }], }, - 'proband': { - 'id': 'I_4_0', - 'interpretations': [{ - 'diagnosis': { - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, - }, - }, - 'interpretation_status': 'UNKNOWN_STATUS', - 'subject_or_biosample_id': 'I_4_0', - }], + 'id': 'I_3_0', + 'progress_status': 'UNKNOWN_PROGRESS', + }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_3_0', + 'sex': 'MALE', + }, + 'meta_data': { + 'submitted_by': 'seqr-test@gmail.com,test@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }], + }, + }, + 'relatives': [], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }, { + 'id': 'I_4_0', + 'pedigree': { + 'persons': [{ + 'affected_status': 'AFFECTED', + 'family_id': 'F_4', + 'individual_id': 'I_4_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'MALE', + }], + }, + 'proband': { + 'id': 'I_4_0', + 'interpretations': [{ + 'diagnosis': { + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + }, }, - 'id': 'I_4_0', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'UNKNOWN_STATUS', + 'subject_or_biosample_id': 'I_4_0', }], - 'phenotypic_features': [], - 'subject': { - 'id': 'I_4_0', - 'sex': 'MALE', - }, - 'meta_data': { - 'submitted_by': 'seqr-test@gmail.com,test@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }], - }, }, - 'relatives': [], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + 'id': 'I_4_0', + 'progress_status': 'UNKNOWN_PROGRESS', }], + 'phenotypic_features': [], + 'subject': { + 'id': 'I_4_0', + 'sex': 'MALE', + }, + 'meta_data': { + 'submitted_by': 'seqr-test@gmail.com,test@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }], + }, }, - ], - } - } - only_37_response = { - 'meta': { - 'apiVersion': 'v1.0', - 'beaconId': 'com.gnx.beacon.v2', - 'returnedSchemas': [ - { - 'entityType': 'Family', - 'schema': 'phenopacket-2.0', - } - ] + 'relatives': [], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }], }, - 'response': { - 'resultSets': [ - { - 'exists': True, - 'id': 'TestVLM', - 'setType': 'Family', - 'resultsCount': 1, - 'results': [{ - 'id': 'I_0_0', - 'pedigree': { - 'persons': [{ - 'affected_status': 'AFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'OTHER_SEX', - }], - }, - 'proband': { - 'id': 'I_0_0', - 'interpretations': [{ - 'diagnosis': { - 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, - 'genomic_interpretations': [{ - 'call': { - 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, - }, - }, - 'interpretation_status': 'UNKNOWN_STATUS', - 'subject_or_biosample_id': 'I_0_0', - }], + ] + only_37_results = [ + { + 'exists': True, + 'id': 'TestVLM', + 'setType': 'Family', + 'resultsCount': 1, + 'results': [{ + 'id': 'I_0_0', + 'pedigree': { + 'persons': [{ + 'affected_status': 'AFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'OTHER_SEX', + }], + }, + 'proband': { + 'id': 'I_0_0', + 'interpretations': [{ + 'diagnosis': { + 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, + 'genomic_interpretations': [{ + 'call': { + 'variation_descriptor': { + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + }, }, - 'id': 'I_0_0', - 'progress_status': 'UNKNOWN_PROGRESS', + 'interpretation_status': 'UNKNOWN_STATUS', + 'subject_or_biosample_id': 'I_0_0', }], - 'phenotypic_features': [ - {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, - {'id': 'HP:0011675', 'label': 'Arrhythmia'}, - ], - 'subject': { - 'id': 'I_0_0', - 'sex': 'OTHER_SEX', - }, - 'meta_data': { - 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', - 'phenopacket_schema_version': '2.0', - 'resources': [{ - 'id': 'geno', - 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', - 'name': 'GENO ontology', - 'namespacePrefix': 'GENO', - 'url': 'http://purl.obolibrary.org/obo/geno.owl', - 'version': '2026-02-02', - }, { - 'id': 'hp', - 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', - 'name': 'Human Phenotype Ontology', - 'namespacePrefix': 'HP', - 'url': 'http://purl.obolibrary.org/obo/hp.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), - }, { - 'id': 'omim', - 'iriPrefix': 'https://www.omim.org/entry/', - 'name': 'Online Mendelian Inheritance in Man', - 'namespacePrefix': 'OMIM', - 'url': 'https://www.omim.org', - 'version': datetime.now().strftime('%Y-%m-%d'), - }], - }, }, - 'relatives': [], - 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + 'id': 'I_0_0', + 'progress_status': 'UNKNOWN_PROGRESS', }], + 'phenotypic_features': [ + {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, + {'id': 'HP:0011675', 'label': 'Arrhythmia'}, + ], + 'subject': { + 'id': 'I_0_0', + 'sex': 'OTHER_SEX', + }, + 'meta_data': { + 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', + 'phenopacket_schema_version': '2.0', + 'resources': [{ + 'id': 'geno', + 'iriPrefix': 'http://purl.obolibrary.org/obo/GENO_', + 'name': 'GENO ontology', + 'namespacePrefix': 'GENO', + 'url': 'http://purl.obolibrary.org/obo/geno.owl', + 'version': '2026-02-02', + }, { + 'id': 'hp', + 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', + 'name': 'Human Phenotype Ontology', + 'namespacePrefix': 'HP', + 'url': 'http://purl.obolibrary.org/obo/hp.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), + }, { + 'id': 'omim', + 'iriPrefix': 'https://www.omim.org/entry/', + 'name': 'Online Mendelian Inheritance in Man', + 'namespacePrefix': 'OMIM', + 'url': 'https://www.omim.org', + 'version': datetime.now().strftime('%Y-%m-%d'), + }], + }, }, - ], - } - } - empty_response = { - 'meta': { - 'apiVersion': 'v1.0', - 'beaconId': 'com.gnx.beacon.v2', - 'returnedSchemas': [ - { - 'entityType': 'Family', - 'schema': 'phenopacket-2.0', - } - ] + 'relatives': [], + 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, + }], }, - 'response': { - 'resultSets': [ - { - 'exists': False, - 'id': 'TestVLM', - 'results': [], - 'resultsCount': 0, - 'setType': 'Family' - }, - ], - } - } - await self._test_match_endpoint('match_details', mocked_responses, response, only_37_response, empty_response) + ] + empty_results = [ + { + 'exists': False, + 'id': 'TestVLM', + 'results': [], + 'resultsCount': 0, + 'setType': 'Family' + }, + ] + await self._test_match_endpoint('match_details', mocked_responses, meta, results, only_37_results, empty_results) - async def _test_match_endpoint(self, path, mocked_responses, response, only_37_response, empty_response): + async def _test_match_endpoint(self, path, mocked_responses, meta, results, only_37_results, empty_results): mocked_responses.post( 'https://vlm-auth.us.auth0.com/oauth/token', payload={'access_token': 'test_token'}, repeat=True, # nosec @@ -931,7 +867,7 @@ async def _test_match_endpoint(self, path, mocked_responses, response, only_37_r async with self.client.request('GET', f'/vlm/{path}?assemblyId=GRCh38&referenceName=1&start=38724419&referenceBases=T&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - full_response = { + response = { 'beaconHandovers': [ { 'handoverType': { @@ -942,13 +878,16 @@ async def _test_match_endpoint(self, path, mocked_responses, response, only_37_r 'email': None, } ], + 'meta': meta, 'responseSummary': { 'exists': True, 'total': 7, }, - **response, + 'response': { + 'resultSets': results, + }, } - self.assertDictEqual(resp_json, full_response) + self.assertDictEqual(resp_json, response) mocked_responses.assert_called_with( 'https://vlm-auth.us.auth0.com/oauth/token', method='POST', @@ -966,9 +905,9 @@ async def _test_match_endpoint(self, path, mocked_responses, response, only_37_r async with self.client.request('GET', f'/vlm/{path}?assemblyId=GRCh37&referenceName=1&start=39190091&referenceBases=T&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, full_response) + self.assertDictEqual(resp_json, response) - full_only_37_response = { + only_37_response = { 'beaconHandovers': [ { 'handoverType': { @@ -979,21 +918,24 @@ async def _test_match_endpoint(self, path, mocked_responses, response, only_37_r 'email': None, } ], + 'meta': meta, 'responseSummary': { 'exists': True, 'total': 1, }, - **only_37_response, + 'response': { + 'resultSets': only_37_results, + }, } async with self.client.request('GET', f'/vlm/{path}?assemblyId=hg19&referenceName=chr7&start=143270172&referenceBases=A&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, full_only_37_response) + self.assertDictEqual(resp_json, only_37_response) async with self.client.request('GET', f'/vlm/{path}?assemblyId=GRCh38&referenceName=chr7&start=143573079&referenceBases=A&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) resp_json = await resp.json() - self.assertDictEqual(resp_json, full_only_37_response) + self.assertDictEqual(resp_json, only_37_response) async with self.client.request('GET', f'/vlm/{path}?assemblyId=hg38&referenceName=chr7&start=143270172&referenceBases=A&alternateBases=G', headers=headers) as resp: self.assertEqual(resp.status, 200) @@ -1009,11 +951,14 @@ async def _test_match_endpoint(self, path, mocked_responses, response, only_37_r 'email': None, } ], + 'meta': meta, 'responseSummary': { 'exists': False, 'total': 0, }, - **empty_response, + 'response': { + 'resultSets': empty_results, + }, }) @aioresponses(passthrough=['http://127.0.0.1']) From c4eb38190e3d2b6f7658f2fa7d6a7800b6c8af77 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 17:01:00 -0400 Subject: [PATCH 13/20] debug --- vlm/test_vlm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vlm/test_vlm.py b/vlm/test_vlm.py index 5de2400d4a..248f6a4a35 100644 --- a/vlm/test_vlm.py +++ b/vlm/test_vlm.py @@ -849,6 +849,7 @@ async def test_match_details(self, mocked_responses): 'setType': 'Family' }, ] + self.maxDiff = None await self._test_match_endpoint('match_details', mocked_responses, meta, results, only_37_results, empty_results) async def _test_match_endpoint(self, path, mocked_responses, meta, results, only_37_results, empty_results): From 495a5fb192e15ab821127d52465ec43a943fc00d Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 17:08:19 -0400 Subject: [PATCH 14/20] fix test fiture order --- vlm/test_vlm.py | 160 ++++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/vlm/test_vlm.py b/vlm/test_vlm.py index 248f6a4a35..d39e606074 100644 --- a/vlm/test_vlm.py +++ b/vlm/test_vlm.py @@ -168,49 +168,46 @@ async def test_match_details(self, mocked_responses): 'setType': 'Family', 'resultsCount': 5, 'results': [{ - 'id': 'I_0_1', + 'id': 'I_0_0', 'pedigree': { - 'persons': [{ - 'affected_status': 'UNAFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'MALE', - }, { - 'affected_status': 'AFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_1', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'OTHER_SEX', - }], + 'persons': [{ + 'affected_status': 'UNAFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'MALE', + }, { + 'affected_status': 'AFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'OTHER_SEX', + }], }, 'proband': { - 'id': 'I_0_1', + 'id': 'I_0_0', 'interpretations': [{ 'diagnosis': { 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, 'genomic_interpretations': [{ 'call': { 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, }, }, 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_1', + 'subject_or_biosample_id': 'I_0_0', }], }, - 'id': 'I_0_1', + 'id': 'I_0_0', 'progress_status': 'UNKNOWN_PROGRESS', }], - 'phenotypic_features': [ - {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, - {'id': 'HP:0011675', 'label': 'Arrhythmia'}, - ], + 'phenotypic_features': [], 'subject': { - 'id': 'I_0_1', - 'sex': 'OTHER_SEX', + 'id': 'I_0_0', + 'sex': 'MALE', }, 'meta_data': { 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', @@ -222,13 +219,6 @@ async def test_match_details(self, mocked_responses): 'namespacePrefix': 'GENO', 'url': 'http://purl.obolibrary.org/obo/geno.owl', 'version': '2026-02-02', - }, { - 'id': 'hp', - 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', - 'name': 'Human Phenotype Ontology', - 'namespacePrefix': 'HP', - 'url': 'http://purl.obolibrary.org/obo/hp.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), }, { 'id': 'omim', 'iriPrefix': 'https://www.omim.org/entry/', @@ -240,27 +230,30 @@ async def test_match_details(self, mocked_responses): }, }, 'relatives': [{ - 'id': 'I_0_0', + 'id': 'I_0_1', 'interpretations': [{ 'diagnosis': { 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, 'genomic_interpretations': [{ 'call': { 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, }, }, 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_0', + 'subject_or_biosample_id': 'I_0_1', }], }, - 'id': 'I_0_0', + 'id': 'I_0_1', 'progress_status': 'UNKNOWN_PROGRESS', }], - 'phenotypic_features': [], + 'phenotypic_features': [ + {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, + {'id': 'HP:0011675', 'label': 'Arrhythmia'}, + ], 'subject': { - 'id': 'I_0_0', - 'sex': 'MALE', + 'id': 'I_0_1', + 'sex': 'OTHER_SEX', }, 'meta_data': { 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', @@ -272,6 +265,13 @@ async def test_match_details(self, mocked_responses): 'namespacePrefix': 'GENO', 'url': 'http://purl.obolibrary.org/obo/geno.owl', 'version': '2026-02-02', + }, { + 'id': 'hp', + 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', + 'name': 'Human Phenotype Ontology', + 'namespacePrefix': 'HP', + 'url': 'http://purl.obolibrary.org/obo/hp.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), }, { 'id': 'omim', 'iriPrefix': 'https://www.omim.org/entry/', @@ -284,46 +284,49 @@ async def test_match_details(self, mocked_responses): }], 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, }, { - 'id': 'I_0_0', + 'id': 'I_0_1', 'pedigree': { - 'persons': [{ - 'affected_status': 'UNAFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_0', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'MALE', - }, { - 'affected_status': 'AFFECTED', - 'family_id': 'F_0', - 'individual_id': 'I_0_1', - 'maternal_id': '0', - 'paternal_id': '0', - 'sex': 'OTHER_SEX', - }], + 'persons': [{ + 'affected_status': 'UNAFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_0', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'MALE', + }, { + 'affected_status': 'AFFECTED', + 'family_id': 'F_0', + 'individual_id': 'I_0_1', + 'maternal_id': '0', + 'paternal_id': '0', + 'sex': 'OTHER_SEX', + }], }, 'proband': { - 'id': 'I_0_0', + 'id': 'I_0_1', 'interpretations': [{ 'diagnosis': { 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, 'genomic_interpretations': [{ 'call': { 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, + 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, }, }, 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_0', + 'subject_or_biosample_id': 'I_0_1', }], }, - 'id': 'I_0_0', + 'id': 'I_0_1', 'progress_status': 'UNKNOWN_PROGRESS', }], - 'phenotypic_features': [], + 'phenotypic_features': [ + {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, + {'id': 'HP:0011675', 'label': 'Arrhythmia'}, + ], 'subject': { - 'id': 'I_0_0', - 'sex': 'MALE', + 'id': 'I_0_1', + 'sex': 'OTHER_SEX', }, 'meta_data': { 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', @@ -335,6 +338,13 @@ async def test_match_details(self, mocked_responses): 'namespacePrefix': 'GENO', 'url': 'http://purl.obolibrary.org/obo/geno.owl', 'version': '2026-02-02', + }, { + 'id': 'hp', + 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', + 'name': 'Human Phenotype Ontology', + 'namespacePrefix': 'HP', + 'url': 'http://purl.obolibrary.org/obo/hp.owl', + 'version': datetime.now().strftime('%Y-%m-%d'), }, { 'id': 'omim', 'iriPrefix': 'https://www.omim.org/entry/', @@ -346,30 +356,27 @@ async def test_match_details(self, mocked_responses): }, }, 'relatives': [{ - 'id': 'I_0_1', + 'id': 'I_0_0', 'interpretations': [{ 'diagnosis': { 'disease': {'id': 'OMIM:615123', 'label': 'Immunodeficiency 38'}, 'genomic_interpretations': [{ 'call': { 'variation_descriptor': { - 'allelic_state': {'id': 'GENO:0000136', 'label': 'homozygous'}, + 'allelic_state': {'id': 'GENO:0000135', 'label': 'heterozygous'}, }, }, 'interpretation_status': 'REJECTED', - 'subject_or_biosample_id': 'I_0_1', + 'subject_or_biosample_id': 'I_0_0', }], }, - 'id': 'I_0_1', + 'id': 'I_0_0', 'progress_status': 'UNKNOWN_PROGRESS', }], - 'phenotypic_features': [ - {'id': 'HP:0002011', 'label': 'Morphological central nervous system abnormality'}, - {'id': 'HP:0011675', 'label': 'Arrhythmia'}, - ], + 'phenotypic_features': [], 'subject': { - 'id': 'I_0_1', - 'sex': 'OTHER_SEX', + 'id': 'I_0_0', + 'sex': 'MALE', }, 'meta_data': { 'submitted_by': 'test@broadinstitute.org,vlm@broadinstitute.org', @@ -381,13 +388,6 @@ async def test_match_details(self, mocked_responses): 'namespacePrefix': 'GENO', 'url': 'http://purl.obolibrary.org/obo/geno.owl', 'version': '2026-02-02', - }, { - 'id': 'hp', - 'iriPrefix': 'http://purl.obolibrary.org/obo/HP_', - 'name': 'Human Phenotype Ontology', - 'namespacePrefix': 'HP', - 'url': 'http://purl.obolibrary.org/obo/hp.owl', - 'version': datetime.now().strftime('%Y-%m-%d'), }, { 'id': 'omim', 'iriPrefix': 'https://www.omim.org/entry/', From 6eb78773cec7b864b5ecb3905be1ed824960fb4d Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 17:09:30 -0400 Subject: [PATCH 15/20] fix count --- vlm/test_vlm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlm/test_vlm.py b/vlm/test_vlm.py index d39e606074..fb74c60b0b 100644 --- a/vlm/test_vlm.py +++ b/vlm/test_vlm.py @@ -166,7 +166,7 @@ async def test_match_details(self, mocked_responses): 'exists': True, 'id': 'TestVLM', 'setType': 'Family', - 'resultsCount': 5, + 'resultsCount': 7, 'results': [{ 'id': 'I_0_0', 'pedigree': { From b33babc722b01b8d8a559876a5b2c36ccab26ab4 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 17:15:14 -0400 Subject: [PATCH 16/20] clean up --- vlm/test_vlm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/vlm/test_vlm.py b/vlm/test_vlm.py index fb74c60b0b..9d64ddf050 100644 --- a/vlm/test_vlm.py +++ b/vlm/test_vlm.py @@ -849,7 +849,6 @@ async def test_match_details(self, mocked_responses): 'setType': 'Family' }, ] - self.maxDiff = None await self._test_match_endpoint('match_details', mocked_responses, meta, results, only_37_results, empty_results) async def _test_match_endpoint(self, path, mocked_responses, meta, results, only_37_results, empty_results): From c5b9bfdbe309602d5e6911a57bba7d47498f7154 Mon Sep 17 00:00:00 2001 From: hanars Date: Mon, 10 Aug 2026 18:01:15 -0400 Subject: [PATCH 17/20] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- vlm/match.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlm/match.py b/vlm/match.py index e885cb278f..0f038a8517 100644 --- a/vlm/match.py +++ b/vlm/match.py @@ -192,7 +192,7 @@ async def _get_match_detail_results(match: list[tuple], lift_match: Optional[lis results += [{ 'id': phenopacket['id'], 'proband': phenopacket, - 'relatives': [p for p in phenopackets if p != phenopacket], + 'relatives': [p for p in phenopackets if p is not phenopacket], 'pedigree': {'persons': pedigree}, 'meta_data': {'phenopacket_schema_version': '2.0', 'resources': []}, } for phenopacket in phenopackets] From 42b5e7a375a262d929318562d35a9acea0966da8 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Mon, 10 Aug 2026 18:26:30 -0400 Subject: [PATCH 18/20] correctly count new samples --- seqr/views/apis/anvil_workspace_api.py | 2 +- seqr/views/apis/anvil_workspace_api_tests.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/seqr/views/apis/anvil_workspace_api.py b/seqr/views/apis/anvil_workspace_api.py index 825db188a4..7f8c8abf19 100644 --- a/seqr/views/apis/anvil_workspace_api.py +++ b/seqr/views/apis/anvil_workspace_api.py @@ -256,7 +256,7 @@ def _trigger_add_workspace_data(project, pedigree_records, user, data_path, samp project, individual_records=pedigree_records, user=user, get_update_json=get_pedigree_json, get_individual_db_ids=True, allow_features_update=True, skip_gt_stats_rebuild=True, ) - num_updated_individuals = len(individual_ids) + num_updated_individuals = len(individual_ids - set(previous_loaded_ids or [])) individual_ids.update(previous_loaded_ids or []) # use airflow api to trigger AnVIL dags diff --git a/seqr/views/apis/anvil_workspace_api_tests.py b/seqr/views/apis/anvil_workspace_api_tests.py index 0851d96b9b..e76daeefe1 100644 --- a/seqr/views/apis/anvil_workspace_api_tests.py +++ b/seqr/views/apis/anvil_workspace_api_tests.py @@ -857,7 +857,7 @@ def _assert_valid_operation(self, project, test_add_data=True): self._assert_expected_requests(variables, project, num_samples=14 if test_add_data else 3, status='Loading') self.assert_expected_airtable_headers(-1) - sample_summary = '13 new and 7 re-loaded' if test_add_data else '3 new' + sample_summary = '7 new and 7 re-loaded' if test_add_data else '3 new' self.mock_slack.assert_called_with( SEQR_SLACK_ANVIL_DATA_LOADING_CHANNEL, self._success_slack_message(project, sample_summary, genome_version, variables), @@ -961,7 +961,7 @@ def _test_mv_file_and_triggering_loading_exception(self, url, workspace, sample_ self.mock_slack.assert_has_calls([ mock.call(SEQR_SLACK_LOADING_NOTIFICATION_CHANNEL, slack_message_on_failure), mock.call(SEQR_SLACK_ANVIL_DATA_LOADING_CHANNEL, self._success_slack_message( - project, '3 new' if sample_type == 'WES' else '5 new and 1 re-loaded', genome_version, variables, sample_type, + project, '3 new' if sample_type == 'WES' else '4 new and 1 re-loaded', genome_version, variables, sample_type, )), ]) self._assert_expected_requests( From df4c20e5385939c8168e8fde32d631967efc7e3c Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Wed, 12 Aug 2026 10:41:44 -0400 Subject: [PATCH 19/20] cleaner import for clinvar constants --- clickhouse_search/constants.py | 36 ++++++++++++++++++ .../commands/reload_clinvar_all_variants.py | 11 ++++-- .../reload_clinvar_all_variants_tests.py | 4 +- .../models/reference_data_models.py | 38 +------------------ 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/clickhouse_search/constants.py b/clickhouse_search/constants.py index aaba9464b9..0721e16955 100644 --- a/clickhouse_search/constants.py +++ b/clickhouse_search/constants.py @@ -79,6 +79,42 @@ ('benign', 'Benign/Likely_benign', 'Benign'), ] +CLINVAR_ASSERTIONS = [ + 'Affects', + 'association', + 'association_not_found', + 'confers_sensitivity', + 'drug_response', + 'low_penetrance', + 'not_provided', + 'other', + 'protective', + 'risk_factor', + 'no_classification_for_the_single_variant', + 'no_classifications_from_unflagged_records', +] +CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY = 'Conflicting_classifications_of_pathogenicity' +CLINVAR_DEFAULT_PATHOGENICITY = 'No_pathogenic_assertion' +CLINVAR_PATHOGENICITIES = [ + 'Pathogenic', + 'Pathogenic/Likely_pathogenic', + 'Pathogenic/Likely_pathogenic/Established_risk_allele', + 'Pathogenic/Likely_pathogenic/Likely_risk_allele', + 'Pathogenic/Likely_risk_allele', + 'Likely_pathogenic', + 'Likely_pathogenic/Likely_risk_allele', + 'Established_risk_allele', + 'Likely_risk_allele', + CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY, + 'Uncertain_risk_allele', + 'Uncertain_significance/Uncertain_risk_allele', + 'Uncertain_significance', + CLINVAR_DEFAULT_PATHOGENICITY, + 'Likely_benign', + 'Benign/Likely_benign', + 'Benign', +] + HGMD_KEY = 'hgmd' HGMD_CLASS_FILTERS = [ ('disease_causing', 'DM'), diff --git a/clickhouse_search/management/commands/reload_clinvar_all_variants.py b/clickhouse_search/management/commands/reload_clinvar_all_variants.py index de9793c961..d343e9dd2e 100644 --- a/clickhouse_search/management/commands/reload_clinvar_all_variants.py +++ b/clickhouse_search/management/commands/reload_clinvar_all_variants.py @@ -15,6 +15,9 @@ from clickhouse_backend import models from clickhouse_search.models.reference_data_models import ClinvarAllVariantsGRCh37SnvIndel, ClinvarAllVariantsSnvIndel, ClinvarAllVariantsMito, \ ClinvarMvGRCh37SnvIndel, ClinvarMvSnvIndel, ClinvarMvMito, ClinvarSearchMvGRCh37SnvIndel, ClinvarSearchMvSnvIndel, ClinvarSearchMvMito +from clickhouse_search.constants import \ + CLINVAR_ASSERTIONS as CORE_CLINVAR_ASSERTIONS, CLINVAR_PATHOGENICITIES as CORE_CLINVAR_PATHOGENICITIES, CLINVAR_DEFAULT_PATHOGENICITY as CORE_CLINVAR_DEFAULT_PATHOGENICITY, \ + CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY as CORE_CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY from reference_data.models import DataVersions from seqr.utils.communication_utils import safe_post_to_slack @@ -29,11 +32,11 @@ def replace_spaces_with_underscores(value: Union[list[str], list[tuple[str, int] return [s.replace(' ', '_') for s in value] BATCH_SIZE = 1000 -CLINVAR_ASSERTIONS = replace_underscores_with_spaces(ClinvarAllVariantsSnvIndel.CLINVAR_ASSERTIONS) -CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY = replace_underscores_with_spaces([ClinvarAllVariantsSnvIndel.CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY])[0] +CLINVAR_ASSERTIONS = replace_underscores_with_spaces(CORE_CLINVAR_ASSERTIONS) +CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY = replace_underscores_with_spaces([CORE_CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY])[0] CLINVAR_CONFLICTING_DATA_FROM_SUBMITTERS = 'conflicting data from submitters' -CLINVAR_DEFAULT_PATHOGENICITY = replace_underscores_with_spaces([ClinvarAllVariantsSnvIndel.CLINVAR_DEFAULT_PATHOGENICITY])[0] -CLINVAR_PATHOGENICITIES = replace_underscores_with_spaces(ClinvarAllVariantsSnvIndel.CLINVAR_PATHOGENICITIES) +CLINVAR_DEFAULT_PATHOGENICITY = replace_underscores_with_spaces([CORE_CLINVAR_DEFAULT_PATHOGENICITY])[0] +CLINVAR_PATHOGENICITIES = replace_underscores_with_spaces(CORE_CLINVAR_PATHOGENICITIES) CLINVAR_GOLD_STARS_LOOKUP = { 'no classification for the single variant': 0, 'no classification provided': 0, diff --git a/clickhouse_search/management/tests/reload_clinvar_all_variants_tests.py b/clickhouse_search/management/tests/reload_clinvar_all_variants_tests.py index b7a18267d5..9be4e198d7 100644 --- a/clickhouse_search/management/tests/reload_clinvar_all_variants_tests.py +++ b/clickhouse_search/management/tests/reload_clinvar_all_variants_tests.py @@ -197,7 +197,7 @@ def test_batching(self, mock_logger, mock_safe_post_to_slack): call_command('reload_clinvar_all_variants') mock_logger.assert_called_with('Updating Clinvar ClickHouse tables to 2025-06-30 from 2025-06-23.') self.assertEqual(ClinvarAllVariantsSnvIndel.objects.all().count(), BATCH_SIZE * 2 + 10) - self.assertEqual(ClinvarAllVariantsSnvIndel.objects.first().pathogenicity, ClinvarAllVariantsSnvIndel.CLINVAR_DEFAULT_PATHOGENICITY) + self.assertEqual(ClinvarAllVariantsSnvIndel.objects.first().pathogenicity, 'No_pathogenic_assertion') self.assertIsNone(ClinvarAllVariantsSnvIndel.objects.first().gold_stars) @responses.activate @@ -417,7 +417,7 @@ def test_conflicting_data_from_submitters(self, mock_logger, mock_safe_post_to_s ) call_command('reload_clinvar_all_variants') self.assertEqual(ClinvarAllVariantsSnvIndel.objects.count(), 1) - self.assertEqual(ClinvarAllVariantsSnvIndel.objects.first().pathogenicity, ClinvarAllVariantsSnvIndel.CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY) + self.assertEqual(ClinvarAllVariantsSnvIndel.objects.first().pathogenicity, 'Conflicting_classifications_of_pathogenicity') mock_safe_post_to_slack.assert_called_with( SEQR_SLACK_DATA_ALERTS_NOTIFICATION_CHANNEL, 'Successfully updated Clinvar ClickHouse tables to 2025-06-30.', diff --git a/clickhouse_search/models/reference_data_models.py b/clickhouse_search/models/reference_data_models.py index d129f8de8b..783ff4934e 100644 --- a/clickhouse_search/models/reference_data_models.py +++ b/clickhouse_search/models/reference_data_models.py @@ -6,6 +6,7 @@ from clickhouse_search.backend.fields import Enum8Field, NestedField, UInt32FieldDeltaCodecField, DictKeyForeignKey from clickhouse_search.backend.table_models import FixtureLoadableClickhouseModel, Dictionary, \ RefreshableMaterializedView, RefreshableMaterializedViewMeta +from clickhouse_search.constants import CLINVAR_ASSERTIONS, CLINVAR_PATHOGENICITIES from seqr.utils.xpos_utils import CHROMOSOME_CHOICES from settings import DATABASES, PIPELINE_RUNNER_SERVER @@ -39,43 +40,6 @@ class ReferenceDataDictMeta: class BaseClinvar(FixtureLoadableClickhouseModel): - - CLINVAR_ASSERTIONS = [ - 'Affects', - 'association', - 'association_not_found', - 'confers_sensitivity', - 'drug_response', - 'low_penetrance', - 'not_provided', - 'other', - 'protective', - 'risk_factor', - 'no_classification_for_the_single_variant', - 'no_classifications_from_unflagged_records', - ] - CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY = 'Conflicting_classifications_of_pathogenicity' - CLINVAR_DEFAULT_PATHOGENICITY = 'No_pathogenic_assertion' - CLINVAR_PATHOGENICITIES = [ - 'Pathogenic', - 'Pathogenic/Likely_pathogenic', - 'Pathogenic/Likely_pathogenic/Established_risk_allele', - 'Pathogenic/Likely_pathogenic/Likely_risk_allele', - 'Pathogenic/Likely_risk_allele', - 'Likely_pathogenic', - 'Likely_pathogenic/Likely_risk_allele', - 'Established_risk_allele', - 'Likely_risk_allele', - CLINVAR_CONFLICTING_CLASSICATIONS_OF_PATHOGENICITY, - 'Uncertain_risk_allele', - 'Uncertain_significance/Uncertain_risk_allele', - 'Uncertain_significance', - CLINVAR_DEFAULT_PATHOGENICITY, - 'Likely_benign', - 'Benign/Likely_benign', - 'Benign', - ] - ASSERTIONS_CHOICES = list(enumerate(CLINVAR_ASSERTIONS)) PATHOGENICITY_CHOICES = list(enumerate(CLINVAR_PATHOGENICITIES)) From 236b760e9101cf81f94adf3af9777dba62a6a646 Mon Sep 17 00:00:00 2001 From: Hana Snow Date: Wed, 12 Aug 2026 14:26:07 -0400 Subject: [PATCH 20/20] fix flapping test --- seqr/views/apis/saved_variant_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seqr/views/apis/saved_variant_api.py b/seqr/views/apis/saved_variant_api.py index 9e7b7985c4..68b5a68de8 100644 --- a/seqr/views/apis/saved_variant_api.py +++ b/seqr/views/apis/saved_variant_api.py @@ -321,7 +321,7 @@ def _delete_removed_tags(saved_variants, all_variant_guids, tag_updates, user, c existing_tag_guids = [tag['tagGuid'] for tag in tag_updates if tag.get('tagGuid')] deleted_tag_guids = [] tag_set = _get_tag_set(saved_variants[0], tag_type) - remove_tags = tag_set.exclude(guid__in=existing_tag_guids) + remove_tags = tag_set.order_by('id').exclude(guid__in=existing_tag_guids) if protected_tag_types: remove_tags = remove_tags.exclude(variant_tag_type__name__in=protected_tag_types) if not can_edit: