Source code for tests.test_functions

# -*- coding: utf-8 -*-
# MIT License
#
# Copyright (c) 2018 IRISA, Pierre Vignet
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Contributor(s): Pierre Vignet

"""
This module is used to test functions used during the translation of Biopax
content to cadbiom model.
"""

from __future__ import unicode_literals
from __future__ import print_function

# Standard imports
import pytest

# Custom imports
import biopax2cadbiom.biopax_converter as b2c_bc
from biopax2cadbiom.reactions import get_classes_from_reactants
from biopax2cadbiom.classes import PhysicalEntity
from biopax2cadbiom.commons import DIR_LOGS
from biopax2cadbiom.tools import parse_uri

URI_PREFIX = 'http://simulated/test#'

[docs]@pytest.fixture def simulated_physical_entities(): """Provides simulated entities for merge tests A: Standard Complex with 2 components: X, Y Abis: A copy of A with another uri: must be merged together. Ater: A copy of A but with another uri and a different component: is unique, must be kept. """ pe_A = PhysicalEntity( URI_PREFIX + 'A', 'A', URI_PREFIX + 'anywhere', URI_PREFIX + 'Protein', None, ) pe_A.components_uris.update([URI_PREFIX + 'X', URI_PREFIX + 'Y']) # Duplication of A but with a different URI (Abis) pe_Abis = PhysicalEntity( URI_PREFIX + 'Abis', 'A', # Same name URI_PREFIX + 'anywhere', URI_PREFIX + 'Protein', None, ) pe_Abis.components_uris.update([URI_PREFIX + 'X', URI_PREFIX + 'Y']) # Similar with A but with a different component pe_Ater = PhysicalEntity( URI_PREFIX + 'Ater', 'A', # Same name URI_PREFIX + 'anywhere', URI_PREFIX + 'Protein', None, ) pe_Ater.components_uris.update([URI_PREFIX + 'X', URI_PREFIX + 'W']) return pe_A, pe_Abis, pe_Ater
[docs]@pytest.fixture def classes_and_classes_complexes(): """Generate nested complexes, complexes/classes and classes classes: A (complex), C (protein), D (protein) - A: A1/A2 Complex/class - A1: X Complex - A2: B Complex - B: C,D Complex - C: C1/C2 Class Protein - D: D1/D2/D3 Class Protein """ complexes_names = ('A', 'A1', 'A2', 'B') proteins_names = ('X', 'C', 'C1', 'C2', 'D', 'D1', 'D2', 'D3') complexes = [PhysicalEntity( URI_PREFIX + name, name, URI_PREFIX + 'anywhere', URI_PREFIX + 'Complex', None, ) for name in complexes_names] pe_A, pe_A1, pe_A2, pe_B = complexes proteins = [PhysicalEntity( URI_PREFIX + name, name, URI_PREFIX + 'anywhere', URI_PREFIX + 'Protein', None, ) for name in proteins_names] pe_X, pe_C, pe_C1, pe_C2, pe_D, pe_D1, pe_D2, pe_D3 = proteins # A: Complex/class Complex_9b6a5665172e4e0ba45a78a54dc9d784 members = {pe_A1.uri, pe_A2.uri} pe_A.members = pe_A.membersUsed = members # A1: Simple complex with 1 component (Protein) pe_A1.components_uris.update([pe_X.uri, ]) # A2: Simple complex with 1 component (Complex) Complex_05b98d9de5c95f8b474af2392fb7340b pe_A2.components_uris.update([pe_B.uri, ]) # B: Simple complex with 2 components (Proteins/complexes) Complex_e8f8d16b4143983d88ed67d9ca30512f pe_B.components_uris.update([pe_C.uri, pe_D.uri]) # C: Class with 2 members Protein_4006dc5d1cdd1041441487feb7d19af5 members = {pe_C1.uri, pe_C2.uri} pe_C.members = pe_C.membersUsed = members # D: Class with 3 members Protein_0c60a7787f4970c5856bf6c98dbc4751 members = {pe_D1.uri, pe_D2.uri, pe_D3.uri} pe_D.members = pe_D.membersUsed = members physicalEntities = {entity.uri: entity for entity in complexes} physicalEntities.update({entity.uri: entity for entity in proteins}) return complexes, proteins, physicalEntities
[docs]def test_get_classes_from_reactants(classes_and_classes_complexes): """Test the recursive search of classes in a set of primitives primitives are reactants of a reaction. get_classes_from_reactants() must return the classes in each reactant ordered according to their order of intrication """ complexes, proteins, dictPhysicalEntity = classes_and_classes_complexes primitives = [complex.uri for complex in complexes] + [prot.uri for prot in proteins] print("primitives:", primitives) found = tuple(parse_uri(uri) for uri in get_classes_from_reactants(primitives, dictPhysicalEntity)) # A + A2 + B + C + D expected = ('A', 'C', 'D',) + ('C', 'D',) + ('C', 'D',) + ('C',) + ('D',) assert expected == found
[docs]def test_merge_entities(simulated_physical_entities): """Test the merge of similar entities""" # Get the fixture data pe_A, pe_Abis, pe_Ater = simulated_physical_entities dictPhysicalEntity = { pe_A.uri: pe_A, pe_Abis.uri: pe_Abis, pe_Ater.uri: pe_Ater, } # PS: the first entity in a group, is taken as reference. # Here we expect that pe_A is in first position in the group. expected_dictPhysicalEntity = { pe_A.uri: pe_A, pe_Abis.uri: pe_A, pe_Ater.uri: pe_Ater, } b2c_bc.merge_duplicated_entities(dictPhysicalEntity, DIR_LOGS + '_') # A and Abis must be merged assert dictPhysicalEntity == expected_dictPhysicalEntity
[docs]def test_sort_of_entities(simulated_physical_entities): """Test the sort of entities that is used as a result for the merge .. note:: The sort of all entities must respect lexicographic order of all attributes. => if component URI is not casted into a sorted list, the order is modified, and then, itertools.groupby will be fooled: - ['W', 'X'] < ['X', 'Y'] => True - {'X', 'W'} < {'X', 'Y'} => False .. code-block:: text ['W', 'X'] is < to ['X', 'Y'] Ater;A;['W', 'X'];http://simulated/test#anywhere; A;A;['X', 'Y'];http://simulated/test#anywhere; Abis;A;['X', 'Y'];http://simulated/test#anywhere; If we do not cast set into list: A;A;['Y', 'X'];http://simulated/test#anywhere; Abis;A;['Y', 'X'];http://simulated/test#anywhere; Ater;A;['X', 'W'];http://simulated/test#anywhere; """ # Get the fixture data pe_A, pe_Abis, pe_Ater = simulated_physical_entities dictPhysicalEntity = { pe_A.uri: pe_A, pe_Abis.uri: pe_Abis, pe_Ater.uri: pe_Ater, } # Sort entities on their attributes before group them sorted_entities = sorted(dictPhysicalEntity.itervalues(), key=b2c_bc.sort_callback) expected_sorted_entities = [pe_Ater, pe_A, pe_Abis] def get_uris_from_entities(entities): """Uris are easier to debug than objects""" return [entity.uri for entity in entities] assert (get_uris_from_entities(expected_sorted_entities) == get_uris_from_entities(sorted_entities))