|
| 1 | +# noinspection PyPackageRequirements |
| 2 | +import pytest as pt |
| 3 | +import json |
| 4 | +import typing as t |
| 5 | +import kegg_pull.pathway_organizer as po |
| 6 | +import dev.utils as u |
| 7 | + |
| 8 | + |
| 9 | +def test_load_from_kegg_warning(mocker, caplog): |
| 10 | + get_mock: mocker.MagicMock = _get_get_mock(mocker=mocker) |
| 11 | + parse_hierarchy_spy: mocker.MagicMock = mocker.spy(po.PathwayOrganizer, '_parse_hierarchy') |
| 12 | + pathway_org: po.PathwayOrganizer = po.PathwayOrganizer.load_from_kegg(top_level_nodes={'invalid-top-level-node'}) |
| 13 | + get_mock.assert_called_once_with(entry_ids=['br:br08901'], entry_field='json') |
| 14 | + u.assert_warning( |
| 15 | + message='Top level node name "invalid-top-level-node" is not recognized and will be ignored. Valid values are: "Cellular ' |
| 16 | + 'Processes, Drug Development, Environmental Information Processing, Genetic Information Processing, ' |
| 17 | + 'Human Diseases, Metabolism, Organismal Systems"', caplog=caplog) |
| 18 | + parse_hierarchy_spy.assert_called_once_with(pathway_org, level=1, raw_hierarchy_nodes=[], parent_name=None) |
| 19 | + assert pathway_org.hierarchy_nodes == dict() |
| 20 | + |
| 21 | + |
| 22 | +def _get_get_mock(mocker): |
| 23 | + def get_mock(**_) -> mocker.MagicMock: |
| 24 | + with open('dev/test_data/pathway-organizer/pathway-hierarchy.json', 'r') as file_: |
| 25 | + text_body_mock: str = file_.read() |
| 26 | + kegg_response_mock = mocker.MagicMock(text_body=text_body_mock) |
| 27 | + return kegg_response_mock |
| 28 | + return mocker.patch('kegg_pull.pathway_organizer.r.KEGGrest.get', wraps=get_mock) |
| 29 | + |
| 30 | + |
| 31 | +test_load_from_kegg_data = [ |
| 32 | + (None, None, 'all-nodes.json'), |
| 33 | + ({'Metabolism', 'Genetic Information Processing'}, None, 'top-level-nodes.json'), |
| 34 | + (None, {'Genetic Information Processing', 'Global and overview maps', '00010 Glycolysis / Gluconeogenesis'}, 'filter-nodes.json')] |
| 35 | + |
| 36 | + |
| 37 | +@pt.mark.parametrize('top_level_nodes,filter_nodes,hierarchy_nodes_file', test_load_from_kegg_data) |
| 38 | +def test_load_from_kegg(mocker, top_level_nodes: set, filter_nodes: set, hierarchy_nodes_file: str): |
| 39 | + get_mock: mocker.MagicMock = _get_get_mock(mocker=mocker) |
| 40 | + pathway_organizer = po.PathwayOrganizer.load_from_kegg(top_level_nodes=top_level_nodes, filter_nodes=filter_nodes) |
| 41 | + get_mock.assert_called_once_with(entry_ids=['br:br08901'], entry_field='json') |
| 42 | + if top_level_nodes is not None: |
| 43 | + actual_top_level_nodes = {node_key for node_key, node_val in pathway_organizer.hierarchy_nodes.items() if node_val['level'] == 1} |
| 44 | + assert actual_top_level_nodes == top_level_nodes |
| 45 | + if filter_nodes is not None: |
| 46 | + for filter_node in filter_nodes: |
| 47 | + assert filter_node not in pathway_organizer.hierarchy_nodes.keys() |
| 48 | + expected_hierarchy_nodes: dict = _get_expected_hierarchy_nodes(hierarchy_nodes_file=hierarchy_nodes_file) |
| 49 | + assert pathway_organizer.hierarchy_nodes == expected_hierarchy_nodes |
| 50 | + |
| 51 | + |
| 52 | +def _get_expected_hierarchy_nodes(hierarchy_nodes_file: str) -> dict: |
| 53 | + with open(f'dev/test_data/pathway-organizer/{hierarchy_nodes_file}') as file: |
| 54 | + expected_hierarchy_nodes: dict = json.load(file) |
| 55 | + return expected_hierarchy_nodes |
| 56 | + |
| 57 | + |
| 58 | +def test_save_to_json(mocker, json_file_path: str): |
| 59 | + u.mock_non_instantiable(mocker=mocker) |
| 60 | + pathway_organizer = po.PathwayOrganizer() |
| 61 | + pathway_organizer.hierarchy_nodes = _get_expected_hierarchy_nodes(hierarchy_nodes_file='top-level-nodes.json') |
| 62 | + pathway_organizer.save_to_json(file_path=json_file_path) |
| 63 | + u.test_save_to_json(json_file_path=json_file_path, expected_saved_json_object=pathway_organizer.hierarchy_nodes) |
| 64 | + |
| 65 | + |
| 66 | +def test_load_from_json(json_file_path: str): |
| 67 | + expected_hierarchy_nodes: dict = _get_expected_hierarchy_nodes(hierarchy_nodes_file='top-level-nodes.json') |
| 68 | + u.test_load_from_json( |
| 69 | + json_file_path=json_file_path, saved_object=expected_hierarchy_nodes, method=po.PathwayOrganizer.load_from_json, |
| 70 | + expected_loaded_object=expected_hierarchy_nodes, loaded_object_attribute='hierarchy_nodes') |
| 71 | + |
| 72 | + |
| 73 | +test_invalid_load_from_json_data = [ |
| 74 | + 1, 'a', [], [1, 2], ['a', 'b'], [[], []], [[1], [2]], [['a'], ['b']], [{}, {}], [{'a': {}, 'b': []}], {}, {'a': []}, {'a': {}}, |
| 75 | + {'a': {'b': 1}}, {'a': {'name': 'b'}}, {'a': {'level': 1, 'b': 'c'}}, |
| 76 | + {'a': {'name': 'b', 'level': 1, 'parent': 'c', 'children': None, 'entry_id': 'x'}, |
| 77 | + '': {'name': 'b', 'level': 1, 'parent': 'c', 'children': ['d'], 'entry_id': None}}, |
| 78 | + {'a': {'name': 'b', 'level': 1, 'parent': 'c', 'children': None, 'entry_id': None, 'x': 'y'}}, |
| 79 | + {'a': {'name': 2, 'level': 1, 'parent': 'c', 'children': None, 'entry_id': None}}, |
| 80 | + {'a': {'name': '', 'level': 1, 'parent': 'c', 'children': None, 'entry_id': None}}, |
| 81 | + {'a': {'name': None, 'level': 1, 'parent': 'c', 'children': None, 'entry_id': None}}, |
| 82 | + {'a': {'name': 'b', 'level': '1', 'parent': 'c', 'children': None, 'entry_id': None}}, |
| 83 | + {'a': {'name': 'b', 'level': None, 'parent': 'c', 'children': None, 'entry_id': None}}, |
| 84 | + {'a': {'name': 'b', 'level': 0, 'parent': 'c', 'children': None, 'entry_id': None}}, |
| 85 | + {'a': {'name': 'b', 'level': 1, 'parent': '', 'children': None, 'entry_id': None}}, |
| 86 | + {'a': {'name': 'b', 'level': 1, 'parent': 2, 'children': None, 'entry_id': None}}, |
| 87 | + {'a': {'name': 'b', 'level': 1, 'parent': 'c', 'children': [], 'entry_id': None}}, |
| 88 | + {'a': {'name': 'b', 'level': 1, 'parent': 'c', 'children': [1], 'entry_id': None}}, |
| 89 | + {'a': {'name': 'b', 'level': 1, 'parent': 'c', 'children': [''], 'entry_id': None}}, |
| 90 | + {'a': {'name': 'b', 'level': 1, 'parent': 'c', 'children': ['a'], 'entry_id': 1}}, |
| 91 | + {'a': {'name': 'b', 'level': 1, 'parent': 'c', 'children': ['a'], 'entry_id': ''}}] |
| 92 | + |
| 93 | + |
| 94 | +@pt.mark.parametrize('invalid_json_object', test_invalid_load_from_json_data) |
| 95 | +def test_invalid_load_from_json(caplog, json_file_path: str, invalid_json_object: list | dict | int | float | str): |
| 96 | + expected_error_message = f'Failed to load the hierarchy nodes. The pathway organizer JSON file at {json_file_path} is ' \ |
| 97 | + f'corrupted and will need to be re-created.' |
| 98 | + u.test_invalid_load_from_json( |
| 99 | + json_file_path=json_file_path, invalid_json_object=invalid_json_object, method=po.PathwayOrganizer.load_from_json, |
| 100 | + expected_error_message=expected_error_message, caplog=caplog) |
0 commit comments