# -*- 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))