|
1 | 1 | import os
|
2 |
| -import unittest |
| 2 | + |
| 3 | +import pytest |
3 | 4 |
|
4 | 5 | import tests.test_index.model.container_test as src_dm
|
5 | 6 | from linkml_runtime.index.object_index import ObjectIndex, ProxyObject
|
|
12 | 13 | DATA = os.path.join(INPUT_DIR, "object-indexer-data.yaml")
|
13 | 14 |
|
14 | 15 |
|
15 |
| -class ObjectIndexerTestCase(unittest.TestCase): |
16 |
| - """ |
17 |
| - tests the data model |
18 |
| - """ |
19 |
| - |
20 |
| - def setUp(self) -> None: |
21 |
| - self.schemaview = SchemaView(SCHEMA) |
22 |
| - obj: src_dm.Container |
23 |
| - self.container = yaml_loader.load(DATA, target_class=src_dm.Container) |
24 |
| - |
25 |
| - def test_object_index(self): |
26 |
| - """checks indexing objects""" |
27 |
| - # domain object |
28 |
| - container = self.container |
29 |
| - frt = container.persons[0].has_familial_relationships[0].type |
30 |
| - self.assertIsInstance(frt, src_dm.FamilialRelationshipType) |
31 |
| - # create an index |
32 |
| - oix = ObjectIndex(container, schemaview=self.schemaview) |
33 |
| - self.assertEqual(0, oix.proxy_object_cache_size) |
34 |
| - self.assertGreater(oix.source_object_cache_size, 4) |
35 |
| - # test basic lookups |
36 |
| - proxy_obj = oix.bless(container) |
37 |
| - # proxy objects mock the domain object class, plus |
38 |
| - # they also instantiate ProxyObject |
39 |
| - self.assertIsInstance(proxy_obj, ProxyObject) |
40 |
| - self.assertIsInstance(proxy_obj, src_dm.Container) |
41 |
| - proxy_obj = oix.bless(container.persons[0]) |
42 |
| - self.assertIsInstance(proxy_obj, ProxyObject) |
43 |
| - self.assertIsInstance(proxy_obj, src_dm.Person) |
44 |
| - v = proxy_obj.name |
45 |
| - self.assertEqual("fred bloggs", v) |
46 |
| - self.assertEqual(33, proxy_obj.age_in_years) |
47 |
| - self.assertCountEqual(["a", "b"], proxy_obj.aliases) |
48 |
| - addr = proxy_obj.current_address |
49 |
| - self.assertIsInstance(addr, ProxyObject) |
50 |
| - self.assertIsInstance(addr, src_dm.Address) |
51 |
| - self.assertEqual("1 oak street", addr.street) |
52 |
| - self.assertIsInstance(proxy_obj.has_familial_relationships, list) |
53 |
| - fr = proxy_obj.has_familial_relationships[0] |
54 |
| - self.assertIsInstance(fr, ProxyObject) |
55 |
| - # test automatic dereferencing; |
56 |
| - # related_to is *not* inlined in the schema |
57 |
| - self.assertEqual("Alison Wu", fr.related_to.name) |
58 |
| - self.assertIsInstance(fr.type, src_dm.FamilialRelationshipType) |
59 |
| - self.assertIsNone(fr.related_to.age_in_years) |
60 |
| - self.assertIsInstance(fr.related_to, ProxyObject) |
61 |
| - self.assertEqual(2, len(proxy_obj.has_medical_history)) |
62 |
| - fr2 = fr.related_to.has_familial_relationships[0] |
63 |
| - self.assertEqual("fred bloggs", fr2.related_to.name) |
64 |
| - self.assertEqual(33, fr2.related_to.age_in_years) |
65 |
| - self.assertIsInstance(fr2.related_to, ProxyObject) |
66 |
| - fr3 = fr2.related_to.has_familial_relationships[0] |
67 |
| - self.assertIsInstance(fr3.related_to, ProxyObject) |
68 |
| - self.assertEqual("Alison Wu", fr3.related_to.name) |
69 |
| - self.assertGreater(oix.proxy_object_cache_size, 1) |
70 |
| - self.assertLess(oix.proxy_object_cache_size, 9) |
71 |
| - oix.clear_proxy_object_cache() |
72 |
| - self.assertEqual(0, oix.proxy_object_cache_size) |
73 |
| - fr = proxy_obj.has_familial_relationships[0].related_to |
74 |
| - # test that attributes are closed |
75 |
| - with self.assertRaises(ValueError): |
76 |
| - v = proxy_obj.fake_attribute |
77 |
| - # test setting attributes, and that this affects shadowed object |
78 |
| - proxy_obj.age_in_years = 44 |
79 |
| - self.assertEqual(44, proxy_obj.age_in_years) |
80 |
| - self.assertEqual(44, self.container.persons[0].age_in_years) |
81 |
| - # test evaluation of expressions |
82 |
| - self.assertEqual(5, oix.eval_expr("5")) |
83 |
| - self.assertEqual(5, oix.eval_expr("2*2+1")) |
84 |
| - self.assertEqual("P:001", oix.eval_expr("persons", container)[0].id) |
85 |
| - self.assertEqual("P:001", oix.eval_expr("persons[0].id", container)) |
86 |
| - self.assertEqual(oix.eval_expr("persons", container), oix.eval_expr("persons")) |
87 |
| - person = oix.eval_expr("persons")[0] |
88 |
| - self.assertIsInstance(oix.bless(container).persons[0], ProxyObject) |
89 |
| - self.assertIsInstance(person, ProxyObject) |
90 |
| - self.assertEqual("1 oak street", oix.eval_expr("current_address.street", person)) |
91 |
| - self.assertEqual("Alison Wu", oix.eval_expr("has_familial_relationships[0].related_to.name", person)) |
92 |
| - # experimental: reverse direction |
93 |
| - self.assertEqual("P:001", oix.eval_expr("persons[0]._parents[0][1].persons[0].id")) |
94 |
| - self.assertEqual("P:001", oix.eval_expr("persons[0].persons__inverse[0].persons[0].id")) |
95 |
| - # test inference |
96 |
| - # infer_all_slot_values(person, self.schemaview, class_name="Person") |
97 |
| - config = Config(use_expressions=True) |
98 |
| - infer_slot_value(person, "description", schemaview=self.schemaview, class_name="Person", config=config) |
99 |
| - self.assertEqual("name: fred bloggs address: 1 oak street", person.description) |
100 |
| - |
101 |
| - |
102 |
| -if __name__ == "__main__": |
103 |
| - unittest.main() |
| 16 | +@pytest.fixture |
| 17 | +def schema_view(): |
| 18 | + """SchemaView instance for container test schema.""" |
| 19 | + return SchemaView(SCHEMA) |
| 20 | + |
| 21 | + |
| 22 | +@pytest.fixture |
| 23 | +def container(): |
| 24 | + """Load container test data.""" |
| 25 | + return yaml_loader.load(DATA, target_class=src_dm.Container) |
| 26 | + |
| 27 | + |
| 28 | +@pytest.fixture |
| 29 | +def object_index(container, schema_view): |
| 30 | + """ObjectIndex instance for testing.""" |
| 31 | + return ObjectIndex(container, schemaview=schema_view) |
| 32 | + |
| 33 | + |
| 34 | +def test_object_index(schema_view, container, object_index): |
| 35 | + """Test object indexing functionality.""" |
| 36 | + # Test domain object |
| 37 | + frt = container.persons[0].has_familial_relationships[0].type |
| 38 | + assert isinstance(frt, src_dm.FamilialRelationshipType) |
| 39 | + |
| 40 | + # Test index initialization |
| 41 | + oix = object_index |
| 42 | + assert oix.proxy_object_cache_size == 0 |
| 43 | + assert oix.source_object_cache_size > 4 |
| 44 | + |
| 45 | + # Test basic lookups |
| 46 | + proxy_obj = oix.bless(container) |
| 47 | + # Proxy objects mock the domain object class, plus they also instantiate ProxyObject |
| 48 | + assert isinstance(proxy_obj, ProxyObject) |
| 49 | + assert isinstance(proxy_obj, src_dm.Container) |
| 50 | + |
| 51 | + proxy_obj = oix.bless(container.persons[0]) |
| 52 | + assert isinstance(proxy_obj, ProxyObject) |
| 53 | + assert isinstance(proxy_obj, src_dm.Person) |
| 54 | + |
| 55 | + # Test basic attributes |
| 56 | + v = proxy_obj.name |
| 57 | + assert v == "fred bloggs" |
| 58 | + assert proxy_obj.age_in_years == 33 |
| 59 | + assert sorted(proxy_obj.aliases) == sorted(["a", "b"]) |
| 60 | + |
| 61 | + # Test address proxy |
| 62 | + addr = proxy_obj.current_address |
| 63 | + assert isinstance(addr, ProxyObject) |
| 64 | + assert isinstance(addr, src_dm.Address) |
| 65 | + assert addr.street == "1 oak street" |
| 66 | + |
| 67 | + # Test familial relationships |
| 68 | + assert isinstance(proxy_obj.has_familial_relationships, list) |
| 69 | + fr = proxy_obj.has_familial_relationships[0] |
| 70 | + assert isinstance(fr, ProxyObject) |
| 71 | + |
| 72 | + # Test automatic dereferencing - related_to is *not* inlined in the schema |
| 73 | + assert fr.related_to.name == "Alison Wu" |
| 74 | + assert isinstance(fr.type, src_dm.FamilialRelationshipType) |
| 75 | + assert fr.related_to.age_in_years is None |
| 76 | + assert isinstance(fr.related_to, ProxyObject) |
| 77 | + assert len(proxy_obj.has_medical_history) == 2 |
| 78 | + |
| 79 | + # Test recursive relationships |
| 80 | + fr2 = fr.related_to.has_familial_relationships[0] |
| 81 | + assert fr2.related_to.name == "fred bloggs" |
| 82 | + assert fr2.related_to.age_in_years == 33 |
| 83 | + assert isinstance(fr2.related_to, ProxyObject) |
| 84 | + |
| 85 | + fr3 = fr2.related_to.has_familial_relationships[0] |
| 86 | + assert isinstance(fr3.related_to, ProxyObject) |
| 87 | + assert fr3.related_to.name == "Alison Wu" |
| 88 | + |
| 89 | + # Test cache behavior |
| 90 | + assert oix.proxy_object_cache_size > 1 |
| 91 | + assert oix.proxy_object_cache_size < 9 |
| 92 | + oix.clear_proxy_object_cache() |
| 93 | + assert oix.proxy_object_cache_size == 0 |
| 94 | + |
| 95 | + # Test that attributes are closed |
| 96 | + with pytest.raises(ValueError): |
| 97 | + v = proxy_obj.fake_attribute |
| 98 | + |
| 99 | + # Test setting attributes affects shadowed object |
| 100 | + proxy_obj.age_in_years = 44 |
| 101 | + assert proxy_obj.age_in_years == 44 |
| 102 | + assert container.persons[0].age_in_years == 44 |
| 103 | + |
| 104 | + # Test evaluation of expressions |
| 105 | + assert oix.eval_expr("5") == 5 |
| 106 | + assert oix.eval_expr("2*2+1") == 5 |
| 107 | + assert oix.eval_expr("persons", container)[0].id == "P:001" |
| 108 | + assert oix.eval_expr("persons[0].id", container) == "P:001" |
| 109 | + assert oix.eval_expr("persons", container) == oix.eval_expr("persons") |
| 110 | + |
| 111 | + person = oix.eval_expr("persons")[0] |
| 112 | + assert isinstance(oix.bless(container).persons[0], ProxyObject) |
| 113 | + assert isinstance(person, ProxyObject) |
| 114 | + assert oix.eval_expr("current_address.street", person) == "1 oak street" |
| 115 | + assert oix.eval_expr("has_familial_relationships[0].related_to.name", person) == "Alison Wu" |
| 116 | + |
| 117 | + # Test experimental reverse direction |
| 118 | + assert oix.eval_expr("persons[0]._parents[0][1].persons[0].id") == "P:001" |
| 119 | + assert oix.eval_expr("persons[0].persons__inverse[0].persons[0].id") == "P:001" |
| 120 | + |
| 121 | + # Test inference |
| 122 | + config = Config(use_expressions=True) |
| 123 | + infer_slot_value(person, "description", schemaview=schema_view, class_name="Person", config=config) |
| 124 | + assert person.description == "name: fred bloggs address: 1 oak street" |
0 commit comments