vfbquery 0.4.1__py3-none-any.whl → 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- test/readme_parser.py +29 -27
- test/term_info_queries_test.py +46 -34
- test/test_dataset_template_queries.py +138 -0
- test/test_default_caching.py +89 -84
- test/test_examples_code.py +7 -0
- test/test_examples_diff.py +95 -172
- test/test_expression_overlaps.py +183 -0
- test/test_expression_pattern_fragments.py +123 -0
- test/test_images_neurons.py +152 -0
- test/test_images_that_develop_from.py +112 -0
- test/test_lineage_clones_in.py +190 -0
- test/test_nblast_queries.py +124 -0
- test/test_neuron_classes_fasciculating.py +187 -0
- test/test_neuron_inputs.py +193 -0
- test/test_neuron_neuron_connectivity.py +89 -0
- test/test_neuron_region_connectivity.py +117 -0
- test/test_neurons_part_here.py +203 -0
- test/test_new_owlery_queries.py +282 -0
- test/test_publication_transgene_queries.py +101 -0
- test/test_query_performance.py +739 -0
- test/test_similar_morphology.py +177 -0
- test/test_tracts_nerves_innervating.py +188 -0
- test/test_transcriptomics.py +223 -0
- vfbquery/__init__.py +47 -35
- vfbquery/cached_functions.py +772 -131
- vfbquery/neo4j_client.py +120 -0
- vfbquery/owlery_client.py +463 -0
- vfbquery/solr_cache_integration.py +34 -30
- vfbquery/solr_fetcher.py +1 -1
- vfbquery/solr_result_cache.py +338 -36
- vfbquery/term_info_queries.py +1 -1
- vfbquery/vfb_queries.py +2969 -627
- vfbquery-0.5.1.dist-info/METADATA +2806 -0
- vfbquery-0.5.1.dist-info/RECORD +40 -0
- vfbquery-0.4.1.dist-info/METADATA +0 -1315
- vfbquery-0.4.1.dist-info/RECORD +0 -19
- {vfbquery-0.4.1.dist-info → vfbquery-0.5.1.dist-info}/LICENSE +0 -0
- {vfbquery-0.4.1.dist-info → vfbquery-0.5.1.dist-info}/WHEEL +0 -0
- {vfbquery-0.4.1.dist-info → vfbquery-0.5.1.dist-info}/top_level.txt +0 -0
test/readme_parser.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import json
|
|
3
|
+
import ast
|
|
3
4
|
import os.path
|
|
4
5
|
|
|
5
6
|
def extract_code_blocks(readme_path):
|
|
@@ -24,6 +25,9 @@ def extract_code_blocks(readme_path):
|
|
|
24
25
|
# Process Python blocks to extract vfb calls
|
|
25
26
|
processed_python_blocks = []
|
|
26
27
|
for block in python_blocks:
|
|
28
|
+
# Skip blocks that contain import statements
|
|
29
|
+
if 'import' in block:
|
|
30
|
+
continue
|
|
27
31
|
# Look for vfb.* calls and extract them
|
|
28
32
|
vfb_calls = re.findall(r'(vfb\.[^)]*\))', block)
|
|
29
33
|
if vfb_calls:
|
|
@@ -32,29 +36,17 @@ def extract_code_blocks(readme_path):
|
|
|
32
36
|
# - get_templates() doesn't support force_refresh (no SOLR cache)
|
|
33
37
|
# - Performance test terms (FBbt_00003748, VFB_00101567) should use cache
|
|
34
38
|
for call in vfb_calls:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
continue
|
|
44
|
-
|
|
45
|
-
# Check if the call already has parameters
|
|
46
|
-
if '(' in call and ')' in call:
|
|
47
|
-
# Insert force_refresh=True before the closing parenthesis
|
|
48
|
-
# Handle both cases: with and without existing parameters
|
|
49
|
-
if call.rstrip(')').endswith('('):
|
|
50
|
-
# No parameters: vfb.function()
|
|
51
|
-
modified_call = call[:-1] + 'force_refresh=True)'
|
|
39
|
+
if 'FBbt_00003748' in call:
|
|
40
|
+
# Add force_refresh for medulla calls
|
|
41
|
+
if '(' in call and ')' in call:
|
|
42
|
+
if 'force_refresh' not in call:
|
|
43
|
+
modified_call = call[:-1] + ', force_refresh=True)'
|
|
44
|
+
processed_python_blocks.append(modified_call)
|
|
45
|
+
else:
|
|
46
|
+
processed_python_blocks.append(call)
|
|
52
47
|
else:
|
|
53
|
-
|
|
54
|
-
modified_call = call[:-1] + ', force_refresh=True)'
|
|
55
|
-
processed_python_blocks.append(modified_call)
|
|
48
|
+
processed_python_blocks.append(call)
|
|
56
49
|
else:
|
|
57
|
-
# Shouldn't happen, but include original call if no parentheses
|
|
58
50
|
processed_python_blocks.append(call)
|
|
59
51
|
|
|
60
52
|
# Process JSON blocks
|
|
@@ -63,9 +55,6 @@ def extract_code_blocks(readme_path):
|
|
|
63
55
|
try:
|
|
64
56
|
# Clean up the JSON text
|
|
65
57
|
json_text = block.strip()
|
|
66
|
-
# Convert Python boolean literals to JSON booleans using regex
|
|
67
|
-
json_text = re.sub(r'\bTrue\b', 'true', json_text)
|
|
68
|
-
json_text = re.sub(r'\bFalse\b', 'false', json_text)
|
|
69
58
|
# Parse the JSON and add to results
|
|
70
59
|
json_obj = json.loads(json_text)
|
|
71
60
|
processed_json_blocks.append(json_obj)
|
|
@@ -89,6 +78,16 @@ def generate_python_file(python_blocks, output_path):
|
|
|
89
78
|
for block in python_blocks:
|
|
90
79
|
f.write(f'results.append({block})\n')
|
|
91
80
|
|
|
81
|
+
def generate_code_strings_file(python_blocks, output_path):
|
|
82
|
+
"""
|
|
83
|
+
Generates a Python file containing the extracted code blocks as strings in a results list.
|
|
84
|
+
"""
|
|
85
|
+
with open(output_path, 'w') as f:
|
|
86
|
+
f.write('results = [\n')
|
|
87
|
+
for block in python_blocks:
|
|
88
|
+
f.write(f' "{block}",\n')
|
|
89
|
+
f.write(']\n')
|
|
90
|
+
|
|
92
91
|
def generate_json_file(json_blocks, output_path):
|
|
93
92
|
"""
|
|
94
93
|
Generates a Python file containing the extracted JSON blocks as a Python list.
|
|
@@ -107,12 +106,13 @@ def generate_json_file(json_blocks, output_path):
|
|
|
107
106
|
|
|
108
107
|
f.write(python_list)
|
|
109
108
|
|
|
110
|
-
def process_readme(readme_path, python_output_path, json_output_path):
|
|
109
|
+
def process_readme(readme_path, python_output_path, code_strings_output_path, json_output_path):
|
|
111
110
|
"""
|
|
112
111
|
Process the README file and generate the test files.
|
|
113
112
|
"""
|
|
114
113
|
python_blocks, json_blocks = extract_code_blocks(readme_path)
|
|
115
114
|
generate_python_file(python_blocks, python_output_path)
|
|
115
|
+
generate_code_strings_file(python_blocks, code_strings_output_path)
|
|
116
116
|
generate_json_file(json_blocks, json_output_path)
|
|
117
117
|
|
|
118
118
|
return len(python_blocks), len(json_blocks)
|
|
@@ -122,10 +122,12 @@ if __name__ == "__main__":
|
|
|
122
122
|
readme_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'README.md')
|
|
123
123
|
python_blocks, json_blocks = extract_code_blocks(readme_path)
|
|
124
124
|
|
|
125
|
-
python_path = os.path.join(os.path.dirname(
|
|
126
|
-
|
|
125
|
+
python_path = os.path.join(os.path.dirname(__file__), 'test_examples.py')
|
|
126
|
+
code_strings_path = os.path.join(os.path.dirname(__file__), 'test_examples_code.py')
|
|
127
|
+
json_path = os.path.join(os.path.dirname(__file__), 'test_results.py')
|
|
127
128
|
|
|
128
129
|
generate_python_file(python_blocks, python_path)
|
|
130
|
+
generate_code_strings_file(python_blocks, code_strings_path)
|
|
129
131
|
generate_json_file(json_blocks, json_path)
|
|
130
132
|
|
|
131
133
|
print(f"Extracted {len(python_blocks)} Python blocks and {len(json_blocks)} JSON blocks")
|
test/term_info_queries_test.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
import time
|
|
3
|
-
from
|
|
4
|
-
from
|
|
3
|
+
from vfbquery.term_info_queries import deserialize_term_info, deserialize_term_info_from_dict, process
|
|
4
|
+
from vfbquery.solr_fetcher import SolrTermInfoFetcher
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class TermInfoQueriesTest(unittest.TestCase):
|
|
@@ -10,6 +10,12 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
10
10
|
self.vc = SolrTermInfoFetcher()
|
|
11
11
|
self.variable = TestVariable("my_id", "my_name")
|
|
12
12
|
|
|
13
|
+
def get_term_info_or_skip(self, term_id):
|
|
14
|
+
try:
|
|
15
|
+
return self.vc.get_TermInfo([term_id], return_dataframe=False, summary=False)[0]
|
|
16
|
+
except Exception as e:
|
|
17
|
+
self.skipTest(f"SOLR server not available: {e}")
|
|
18
|
+
|
|
13
19
|
def test_term_info_deserialization(self):
|
|
14
20
|
terminfo_json = """
|
|
15
21
|
{"term": {"core": {"iri": "http://purl.obolibrary.org/obo/FBbt_00048514", "symbol": "BM-Taste", "types": ["Entity", "Adult", "Anatomy", "Cell", "Class", "Mechanosensory_system", "Nervous_system", "Neuron", "Sensory_neuron"], "short_form": "FBbt_00048514", "unique_facets": ["Adult", "Mechanosensory_system", "Nervous_system", "Sensory_neuron"], "label": "labial taste bristle mechanosensory neuron"}, "description": ["Any mechanosensory neuron (FBbt:00005919) that has sensory dendrite in some labellar taste bristle (FBbt:00004162)."], "comment": []}, "query": "Get JSON for Neuron Class", "version": "3d2a474", "parents": [{"symbol": "", "iri": "http://purl.obolibrary.org/obo/FBbt_00048508", "types": ["Entity", "Anatomy", "Cell", "Class", "Mechanosensory_system", "Nervous_system", "Neuron", "Sensory_neuron"], "short_form": "FBbt_00048508", "unique_facets": ["Mechanosensory_system", "Nervous_system", "Sensory_neuron"], "label": "mechanosensory neuron of chaeta"}, {"symbol": "", "iri": "http://purl.obolibrary.org/obo/FBbt_00051420", "types": ["Entity", "Adult", "Anatomy", "Cell", "Class", "Mechanosensory_system", "Nervous_system", "Neuron", "Sensory_neuron"], "short_form": "FBbt_00051420", "unique_facets": ["Adult", "Mechanosensory_system", "Nervous_system", "Sensory_neuron"], "label": "adult mechanosensory neuron"}, {"symbol": "", "iri": "http://purl.obolibrary.org/obo/FBbt_00048029", "types": ["Entity", "Adult", "Anatomy", "Cell", "Class", "Nervous_system", "Neuron", "Sensory_neuron"], "short_form": "FBbt_00048029", "unique_facets": ["Adult", "Nervous_system", "Sensory_neuron"], "label": "labellar taste bristle sensory neuron"}], "relationships": [{"relation": {"iri": "http://purl.obolibrary.org/obo/BFO_0000050", "label": "is part of", "type": "part_of"}, "object": {"symbol": "", "iri": "http://purl.obolibrary.org/obo/FBbt_00005892", "types": ["Entity", "Adult", "Anatomy", "Class", "Nervous_system"], "short_form": "FBbt_00005892", "unique_facets": ["Adult", "Nervous_system"], "label": "adult peripheral nervous system"}}], "xrefs": [], "anatomy_channel_image": [], "pub_syn": [{"synonym": {"scope": "has_exact_synonym", "label": "labellar taste bristle mechanosensitive neuron", "type": ""}, "pub": {"core": {"symbol": "", "iri": "http://flybase.org/reports/Unattributed", "types": ["Entity", "Individual", "pub"], "short_form": "Unattributed", "unique_facets": ["pub"], "label": ""}, "FlyBase": "", "PubMed": "", "DOI": ""}}, {"synonym": {"scope": "has_exact_synonym", "label": "labellar taste bristle mechanosensitive neuron", "type": ""}, "pub": {"core": {"symbol": "", "iri": "http://flybase.org/reports/Unattributed", "types": ["Entity", "Individual", "pub"], "short_form": "Unattributed", "unique_facets": ["pub"], "label": ""}, "FlyBase": "", "PubMed": "", "DOI": ""}}, {"synonym": {"scope": "has_exact_synonym", "label": "labial taste bristle mechanosensitive neuron", "type": ""}, "pub": {"core": {"symbol": "", "iri": "http://flybase.org/reports/Unattributed", "types": ["Entity", "Individual", "pub"], "short_form": "Unattributed", "unique_facets": ["pub"], "label": ""}, "FlyBase": "", "PubMed": "", "DOI": ""}}], "def_pubs": [{"core": {"symbol": "", "iri": "http://flybase.org/reports/FBrf0242472", "types": ["Entity", "Individual", "pub"], "short_form": "FBrf0242472", "unique_facets": ["pub"], "label": "Zhou et al., 2019, Sci. Adv. 5(5): eaaw5141"}, "FlyBase": "", "PubMed": "31131327", "DOI": "10.1126/sciadv.aaw5141"}], "targeting_splits": []}
|
|
@@ -40,12 +46,12 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
40
46
|
def test_term_info_deserialization_from_dict(self):
|
|
41
47
|
import pkg_resources
|
|
42
48
|
print("vfb_connect version:", pkg_resources.get_distribution("vfb_connect").version)
|
|
43
|
-
vfbTerm = self.
|
|
49
|
+
vfbTerm = self.get_term_info_or_skip('FBbt_00048514')
|
|
44
50
|
start_time = time.time()
|
|
45
51
|
terminfo = deserialize_term_info_from_dict(vfbTerm)
|
|
46
52
|
print("--- %s seconds ---" % (time.time() - start_time))
|
|
47
|
-
print("vfbTerm:", vfbTerm)
|
|
48
|
-
print("terminfo:", terminfo)
|
|
53
|
+
# print("vfbTerm:", vfbTerm)
|
|
54
|
+
# print("terminfo:", terminfo)
|
|
49
55
|
# Add debug for unique_facets
|
|
50
56
|
if hasattr(terminfo.term.core, 'unique_facets'):
|
|
51
57
|
print("unique_facets:", terminfo.term.core.unique_facets)
|
|
@@ -84,7 +90,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
84
90
|
self.assertEqual("33657409", labellar_hmsn_entry.pub.PubMed)
|
|
85
91
|
|
|
86
92
|
def test_term_info_serialization_individual_anatomy(self):
|
|
87
|
-
term_info_dict = self.
|
|
93
|
+
term_info_dict = self.get_term_info_or_skip('VFB_00010001')
|
|
88
94
|
print(term_info_dict)
|
|
89
95
|
start_time = time.time()
|
|
90
96
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -133,7 +139,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
133
139
|
'reference': '[VFB_00017894,VFB_00010001]'} in serialized["thumbnail"])
|
|
134
140
|
|
|
135
141
|
def test_term_info_serialization_class(self):
|
|
136
|
-
term_info_dict = self.
|
|
142
|
+
term_info_dict = self.get_term_info_or_skip('FBbt_00048531')
|
|
137
143
|
print(term_info_dict)
|
|
138
144
|
start_time = time.time()
|
|
139
145
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -176,7 +182,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
176
182
|
self.assertFalse("downloads_label" in serialized)
|
|
177
183
|
|
|
178
184
|
def test_term_info_serialization_neuron_class(self):
|
|
179
|
-
term_info_dict = self.
|
|
185
|
+
term_info_dict = self.get_term_info_or_skip('FBbt_00048999')
|
|
180
186
|
print(term_info_dict)
|
|
181
187
|
start_time = time.time()
|
|
182
188
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -234,7 +240,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
234
240
|
self.assertFalse("template" in serialized)
|
|
235
241
|
|
|
236
242
|
def test_term_info_serialization_neuron_class2(self):
|
|
237
|
-
term_info_dict = self.
|
|
243
|
+
term_info_dict = self.get_term_info_or_skip('FBbt_00047030')
|
|
238
244
|
print(term_info_dict)
|
|
239
245
|
start_time = time.time()
|
|
240
246
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -303,7 +309,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
303
309
|
self.assertFalse("template" in serialized)
|
|
304
310
|
|
|
305
311
|
def test_term_info_serialization_split_class(self):
|
|
306
|
-
term_info_dict = self.
|
|
312
|
+
term_info_dict = self.get_term_info_or_skip('VFBexp_FBtp0124468FBtp0133404')
|
|
307
313
|
print(term_info_dict)
|
|
308
314
|
start_time = time.time()
|
|
309
315
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -330,18 +336,21 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
330
336
|
|
|
331
337
|
self.assertTrue("relationships" in serialized)
|
|
332
338
|
self.assertEqual(2, len(serialized["relationships"]))
|
|
333
|
-
|
|
339
|
+
expected_rel_1 = "has hemidriver [P{VT043927-GAL4.DBD}](FBtp0124468)"
|
|
340
|
+
expected_rel_2 = "has hemidriver [P{VT017491-p65.AD}](FBtp0133404)"
|
|
341
|
+
self.assertIn(expected_rel_1, serialized["relationships"])
|
|
342
|
+
self.assertIn(expected_rel_2, serialized["relationships"])
|
|
334
343
|
|
|
335
344
|
self.assertFalse("related_individuals" in serialized)
|
|
336
345
|
self.assertTrue("xrefs" in serialized)
|
|
337
346
|
self.assertEqual(2, len(serialized["xrefs"]))
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
347
|
+
expected_xref = {'icon': 'https://www.virtualflybrain.org/data/VFB/logos/fly_light_color.png',
|
|
348
|
+
'label': '[P{VT043927-GAL4.DBD} ∩ P{VT017491-p65.AD} expression pattern on '
|
|
349
|
+
'Driver Line on the FlyLight Split-GAL4 Site]'
|
|
350
|
+
'(http://splitgal4.janelia.org/cgi-bin/view_splitgal4_imagery.cgi?line=SS50574)',
|
|
351
|
+
'site': '[FlyLightSplit]'
|
|
352
|
+
'(http://splitgal4.janelia.org/cgi-bin/view_splitgal4_imagery.cgi?line=SS50574) '}
|
|
353
|
+
self.assertIn(expected_xref, serialized["xrefs"])
|
|
345
354
|
|
|
346
355
|
self.assertTrue("examples" in serialized)
|
|
347
356
|
self.assertFalse("thumbnail" in serialized)
|
|
@@ -357,7 +366,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
357
366
|
self.assertFalse("template" in serialized)
|
|
358
367
|
|
|
359
368
|
def test_term_info_serialization_dataset(self):
|
|
360
|
-
term_info_dict = self.
|
|
369
|
+
term_info_dict = self.get_term_info_or_skip('Ito2013')
|
|
361
370
|
print(term_info_dict)
|
|
362
371
|
start_time = time.time()
|
|
363
372
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -395,7 +404,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
395
404
|
self.assertTrue("clone of Ito 2013" in sample_example["name"])
|
|
396
405
|
|
|
397
406
|
def test_term_info_serialization_license(self):
|
|
398
|
-
term_info_dict = self.
|
|
407
|
+
term_info_dict = self.get_term_info_or_skip('VFBlicense_CC_BY_NC_3_0')
|
|
399
408
|
print(term_info_dict)
|
|
400
409
|
start_time = time.time()
|
|
401
410
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -430,7 +439,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
430
439
|
self.assertFalse("template" in serialized)
|
|
431
440
|
|
|
432
441
|
def test_term_info_serialization_template(self):
|
|
433
|
-
term_info_dict = self.
|
|
442
|
+
term_info_dict = self.get_term_info_or_skip('VFB_00200000')
|
|
434
443
|
print(term_info_dict)
|
|
435
444
|
start_time = time.time()
|
|
436
445
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -458,7 +467,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
458
467
|
self.assertFalse("examples" in serialized)
|
|
459
468
|
self.assertTrue("thumbnail" in serialized)
|
|
460
469
|
self.assertEqual(1, len(serialized["thumbnail"]))
|
|
461
|
-
self.assertEqual({'data': '
|
|
470
|
+
self.assertEqual({'data': 'https://www.virtualflybrain.org/data/VFB/i/0020/0000/VFB_00200000/thumbnailT.png',
|
|
462
471
|
'format': 'PNG',
|
|
463
472
|
'name': 'JRC2018UnisexVNC',
|
|
464
473
|
'reference': 'VFB_00200000'}, serialized["thumbnail"][0])
|
|
@@ -486,7 +495,7 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
486
495
|
self.assertEqual("[JRC2018UnisexVNC](VFB_00200000)", serialized["template"])
|
|
487
496
|
|
|
488
497
|
def test_term_info_serialization_pub(self):
|
|
489
|
-
term_info_dict = self.
|
|
498
|
+
term_info_dict = self.get_term_info_or_skip('FBrf0243986')
|
|
490
499
|
print(term_info_dict)
|
|
491
500
|
start_time = time.time()
|
|
492
501
|
serialized = process(term_info_dict, self.variable)
|
|
@@ -531,15 +540,18 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
531
540
|
"""
|
|
532
541
|
import vfbquery as vfb
|
|
533
542
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
+
try:
|
|
544
|
+
# Test performance for FBbt_00003748 (mushroom body)
|
|
545
|
+
start_time = time.time()
|
|
546
|
+
result_1 = vfb.get_term_info('FBbt_00003748')
|
|
547
|
+
duration_1 = time.time() - start_time
|
|
548
|
+
|
|
549
|
+
# Test performance for VFB_00101567 (individual anatomy)
|
|
550
|
+
start_time = time.time()
|
|
551
|
+
result_2 = vfb.get_term_info('VFB_00101567')
|
|
552
|
+
duration_2 = time.time() - start_time
|
|
553
|
+
except Exception as e:
|
|
554
|
+
self.skipTest(f"SOLR server not available: {e}")
|
|
543
555
|
|
|
544
556
|
# Print performance metrics for GitHub Actions logs
|
|
545
557
|
print(f"\n" + "="*50)
|
|
@@ -569,8 +581,8 @@ class TermInfoQueriesTest(unittest.TestCase):
|
|
|
569
581
|
|
|
570
582
|
# Performance assertions - fail if queries take too long
|
|
571
583
|
# These thresholds are based on observed performance characteristics
|
|
572
|
-
max_single_query_time =
|
|
573
|
-
max_total_time =
|
|
584
|
+
max_single_query_time = 5.0 # seconds (increased from 2.0 to account for SOLR cache overhead)
|
|
585
|
+
max_total_time = 10.0 # seconds (2 queries * 5 seconds each)
|
|
574
586
|
|
|
575
587
|
self.assertLess(duration_1, max_single_query_time,
|
|
576
588
|
f"FBbt_00003748 query took {duration_1:.4f}s, exceeding {max_single_query_time}s threshold")
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for dataset and template queries.
|
|
3
|
+
|
|
4
|
+
This tests all 5 dataset/template-related queries:
|
|
5
|
+
1. get_painted_domains - Template painted anatomy domains
|
|
6
|
+
2. get_dataset_images - Images in a dataset
|
|
7
|
+
3. get_all_aligned_images - All images aligned to template
|
|
8
|
+
4. get_aligned_datasets - All datasets aligned to template
|
|
9
|
+
5. get_all_datasets - All available datasets
|
|
10
|
+
|
|
11
|
+
Test terms:
|
|
12
|
+
- VFBc_00050000 - Adult Brain template
|
|
13
|
+
- VFBc_00101384 - Example dataset
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import unittest
|
|
17
|
+
import sys
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
# Add src directory to path
|
|
21
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
|
|
22
|
+
|
|
23
|
+
from vfbquery.vfb_queries import (
|
|
24
|
+
get_painted_domains,
|
|
25
|
+
get_dataset_images,
|
|
26
|
+
get_all_aligned_images,
|
|
27
|
+
get_aligned_datasets,
|
|
28
|
+
get_all_datasets,
|
|
29
|
+
PaintedDomains_to_schema,
|
|
30
|
+
DatasetImages_to_schema,
|
|
31
|
+
AllAlignedImages_to_schema,
|
|
32
|
+
AlignedDatasets_to_schema,
|
|
33
|
+
AllDatasets_to_schema
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DatasetTemplateQueriesTest(unittest.TestCase):
|
|
38
|
+
"""Test cases for dataset and template queries"""
|
|
39
|
+
|
|
40
|
+
def setUp(self):
|
|
41
|
+
"""Set up test fixtures"""
|
|
42
|
+
self.template_term = 'VFBc_00050000' # Adult Brain template
|
|
43
|
+
self.dataset_term = 'VFBc_00101384' # Example dataset
|
|
44
|
+
|
|
45
|
+
def test_get_painted_domains(self):
|
|
46
|
+
"""Test get_painted_domains query"""
|
|
47
|
+
result = get_painted_domains(self.template_term, return_dataframe=True, limit=10)
|
|
48
|
+
self.assertIsNotNone(result, "Result should not be None")
|
|
49
|
+
|
|
50
|
+
import pandas as pd
|
|
51
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
52
|
+
print(f"\n✓ Found {len(result)} painted domains for {self.template_term}")
|
|
53
|
+
self.assertIn('id', result.columns)
|
|
54
|
+
self.assertIn('label', result.columns)
|
|
55
|
+
self.assertIn('thumbnail', result.columns)
|
|
56
|
+
|
|
57
|
+
def test_get_painted_domains_formatted(self):
|
|
58
|
+
"""Test get_painted_domains with formatted output"""
|
|
59
|
+
result = get_painted_domains(self.template_term, return_dataframe=False, limit=5)
|
|
60
|
+
self.assertIsNotNone(result)
|
|
61
|
+
|
|
62
|
+
if isinstance(result, dict):
|
|
63
|
+
self.assertIn('headers', result)
|
|
64
|
+
self.assertIn('rows', result)
|
|
65
|
+
|
|
66
|
+
def test_get_dataset_images(self):
|
|
67
|
+
"""Test get_dataset_images query"""
|
|
68
|
+
result = get_dataset_images(self.dataset_term, return_dataframe=True, limit=10)
|
|
69
|
+
self.assertIsNotNone(result)
|
|
70
|
+
|
|
71
|
+
import pandas as pd
|
|
72
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
73
|
+
print(f"\n✓ Found {len(result)} images in dataset {self.dataset_term}")
|
|
74
|
+
self.assertIn('id', result.columns)
|
|
75
|
+
|
|
76
|
+
def test_get_all_aligned_images(self):
|
|
77
|
+
"""Test get_all_aligned_images query"""
|
|
78
|
+
result = get_all_aligned_images(self.template_term, return_dataframe=True, limit=10)
|
|
79
|
+
self.assertIsNotNone(result)
|
|
80
|
+
|
|
81
|
+
import pandas as pd
|
|
82
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
83
|
+
print(f"\n✓ Found {len(result)} aligned images for {self.template_term}")
|
|
84
|
+
|
|
85
|
+
def test_get_aligned_datasets(self):
|
|
86
|
+
"""Test get_aligned_datasets query"""
|
|
87
|
+
result = get_aligned_datasets(self.template_term, return_dataframe=True, limit=10)
|
|
88
|
+
self.assertIsNotNone(result)
|
|
89
|
+
|
|
90
|
+
import pandas as pd
|
|
91
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
92
|
+
print(f"\n✓ Found {len(result)} aligned datasets for {self.template_term}")
|
|
93
|
+
|
|
94
|
+
def test_get_all_datasets(self):
|
|
95
|
+
"""Test get_all_datasets query (no parameters)"""
|
|
96
|
+
result = get_all_datasets(return_dataframe=True, limit=20)
|
|
97
|
+
self.assertIsNotNone(result)
|
|
98
|
+
|
|
99
|
+
import pandas as pd
|
|
100
|
+
if isinstance(result, pd.DataFrame):
|
|
101
|
+
print(f"\n✓ Found {len(result)} total datasets")
|
|
102
|
+
self.assertGreater(len(result), 0, "Should find at least some datasets")
|
|
103
|
+
self.assertIn('id', result.columns)
|
|
104
|
+
self.assertIn('name', result.columns)
|
|
105
|
+
|
|
106
|
+
def test_get_all_datasets_formatted(self):
|
|
107
|
+
"""Test get_all_datasets with formatted output"""
|
|
108
|
+
result = get_all_datasets(return_dataframe=False, limit=10)
|
|
109
|
+
self.assertIsNotNone(result)
|
|
110
|
+
|
|
111
|
+
if isinstance(result, dict):
|
|
112
|
+
self.assertIn('headers', result)
|
|
113
|
+
self.assertIn('rows', result)
|
|
114
|
+
|
|
115
|
+
def test_schema_functions_exist(self):
|
|
116
|
+
"""Test that all dataset/template schema functions exist and are callable"""
|
|
117
|
+
schema_functions = [
|
|
118
|
+
PaintedDomains_to_schema,
|
|
119
|
+
DatasetImages_to_schema,
|
|
120
|
+
AllAlignedImages_to_schema,
|
|
121
|
+
AlignedDatasets_to_schema,
|
|
122
|
+
AllDatasets_to_schema
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
for func in schema_functions:
|
|
126
|
+
self.assertTrue(callable(func), f"{func.__name__} should be callable")
|
|
127
|
+
|
|
128
|
+
def test_limit_parameter(self):
|
|
129
|
+
"""Test that limit parameter works correctly"""
|
|
130
|
+
result = get_all_datasets(return_dataframe=True, limit=5)
|
|
131
|
+
|
|
132
|
+
import pandas as pd
|
|
133
|
+
if isinstance(result, pd.DataFrame):
|
|
134
|
+
self.assertLessEqual(len(result), 5, "Result should respect limit parameter")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == '__main__':
|
|
138
|
+
unittest.main()
|