vfbquery 0.4.0__py3-none-any.whl → 0.5.0__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 +35 -1
- test/term_info_queries_test.py +11 -11
- test/test_dataset_template_queries.py +138 -0
- test/test_default_caching.py +15 -11
- 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 +204 -0
- test/test_new_owlery_queries.py +282 -0
- test/test_publication_transgene_queries.py +101 -0
- test/test_query_performance.py +743 -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 +22 -1
- vfbquery/neo4j_client.py +120 -0
- vfbquery/owlery_client.py +463 -0
- vfbquery/solr_fetcher.py +1 -1
- vfbquery/solr_result_cache.py +238 -53
- vfbquery/vfb_queries.py +2969 -638
- {vfbquery-0.4.0.dist-info → vfbquery-0.5.0.dist-info}/METADATA +1023 -65
- vfbquery-0.5.0.dist-info/RECORD +39 -0
- vfbquery-0.4.0.dist-info/RECORD +0 -19
- {vfbquery-0.4.0.dist-info → vfbquery-0.5.0.dist-info}/LICENSE +0 -0
- {vfbquery-0.4.0.dist-info → vfbquery-0.5.0.dist-info}/WHEEL +0 -0
- {vfbquery-0.4.0.dist-info → vfbquery-0.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for the ImagesNeurons query.
|
|
3
|
+
|
|
4
|
+
This tests the ImagesNeurons query which retrieves individual neuron images
|
|
5
|
+
(instances) with parts in a synaptic neuropil or domain.
|
|
6
|
+
|
|
7
|
+
Test term: FBbt_00007401 (antennal lobe) - a synaptic neuropil
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import unittest
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
# Add src directory to path
|
|
15
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
|
|
16
|
+
|
|
17
|
+
from vfbquery.vfb_queries import (
|
|
18
|
+
get_images_neurons,
|
|
19
|
+
ImagesNeurons_to_schema,
|
|
20
|
+
get_term_info
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ImagesNeuronsTest(unittest.TestCase):
|
|
25
|
+
"""Test cases for ImagesNeurons query"""
|
|
26
|
+
|
|
27
|
+
def setUp(self):
|
|
28
|
+
"""Set up test fixtures"""
|
|
29
|
+
self.test_term = 'FBbt_00007401' # antennal lobe - synaptic neuropil with individual images
|
|
30
|
+
|
|
31
|
+
def test_get_images_neurons_execution(self):
|
|
32
|
+
"""Test that get_images_neurons executes and returns results"""
|
|
33
|
+
result = get_images_neurons(self.test_term, return_dataframe=True, limit=3)
|
|
34
|
+
|
|
35
|
+
# Should return a DataFrame
|
|
36
|
+
self.assertIsNotNone(result, "Result should not be None")
|
|
37
|
+
|
|
38
|
+
# Check result type - handle both DataFrame and dict (from cache)
|
|
39
|
+
import pandas as pd
|
|
40
|
+
if isinstance(result, pd.DataFrame):
|
|
41
|
+
# DataFrame result
|
|
42
|
+
if len(result) > 0:
|
|
43
|
+
print(f"\n✓ Found {len(result)} individual neuron images for {self.test_term}")
|
|
44
|
+
|
|
45
|
+
# Verify DataFrame has expected columns
|
|
46
|
+
self.assertIn('id', result.columns, "Result should have 'id' column")
|
|
47
|
+
self.assertIn('label', result.columns, "Result should have 'label' column")
|
|
48
|
+
|
|
49
|
+
# Print first few results for verification
|
|
50
|
+
print("\nSample results:")
|
|
51
|
+
for idx, row in result.head(3).iterrows():
|
|
52
|
+
print(f" - {row.get('label', 'N/A')} ({row.get('id', 'N/A')})")
|
|
53
|
+
else:
|
|
54
|
+
print(f"\n⚠ No individual neuron images found for {self.test_term} (this may be expected)")
|
|
55
|
+
elif isinstance(result, dict):
|
|
56
|
+
# Dict result (from cache)
|
|
57
|
+
count = result.get('count', 0)
|
|
58
|
+
rows = result.get('rows', [])
|
|
59
|
+
print(f"\n✓ Found {count} total individual neuron images for {self.test_term} (showing {len(rows)})")
|
|
60
|
+
if rows:
|
|
61
|
+
print("\nSample results:")
|
|
62
|
+
for row in rows[:3]:
|
|
63
|
+
print(f" - {row.get('label', 'N/A')} ({row.get('id', 'N/A')})")
|
|
64
|
+
else:
|
|
65
|
+
self.fail(f"Unexpected result type: {type(result)}")
|
|
66
|
+
|
|
67
|
+
def test_images_neurons_schema(self):
|
|
68
|
+
"""Test that ImagesNeurons_to_schema generates correct schema"""
|
|
69
|
+
name = "antennal lobe"
|
|
70
|
+
take_default = {"short_form": self.test_term}
|
|
71
|
+
|
|
72
|
+
schema = ImagesNeurons_to_schema(name, take_default)
|
|
73
|
+
|
|
74
|
+
# Verify schema structure
|
|
75
|
+
self.assertEqual(schema.query, "ImagesNeurons")
|
|
76
|
+
self.assertEqual(schema.label, f"Images of neurons with some part in {name}")
|
|
77
|
+
self.assertEqual(schema.function, "get_images_neurons")
|
|
78
|
+
self.assertEqual(schema.preview, 5)
|
|
79
|
+
self.assertIn("id", schema.preview_columns)
|
|
80
|
+
self.assertIn("label", schema.preview_columns)
|
|
81
|
+
|
|
82
|
+
print(f"\n✓ Schema generated correctly")
|
|
83
|
+
print(f" Query: {schema.query}")
|
|
84
|
+
print(f" Label: {schema.label}")
|
|
85
|
+
print(f" Function: {schema.function}")
|
|
86
|
+
|
|
87
|
+
def test_term_info_integration(self):
|
|
88
|
+
"""Test that ImagesNeurons query appears in term_info for synaptic neuropils"""
|
|
89
|
+
term_info = get_term_info(self.test_term, preview=True)
|
|
90
|
+
|
|
91
|
+
# Should have queries
|
|
92
|
+
self.assertIn('Queries', term_info, "term_info should have 'Queries' key")
|
|
93
|
+
|
|
94
|
+
# Look for ImagesNeurons query
|
|
95
|
+
query_names = [q['query'] for q in term_info['Queries']]
|
|
96
|
+
print(f"\n✓ Queries available for {self.test_term}: {query_names}")
|
|
97
|
+
|
|
98
|
+
if 'ImagesNeurons' in query_names:
|
|
99
|
+
images_query = next(q for q in term_info['Queries'] if q['query'] == 'ImagesNeurons')
|
|
100
|
+
print(f"✓ ImagesNeurons query found: {images_query['label']}")
|
|
101
|
+
|
|
102
|
+
# Verify preview results if available
|
|
103
|
+
if 'preview_results' in images_query:
|
|
104
|
+
preview = images_query['preview_results']
|
|
105
|
+
# Handle both 'data' and 'rows' keys
|
|
106
|
+
data_key = 'data' if 'data' in preview else 'rows'
|
|
107
|
+
if data_key in preview and len(preview[data_key]) > 0:
|
|
108
|
+
print(f" Preview has {len(preview[data_key])} individual neuron images")
|
|
109
|
+
print(f" Sample: {preview[data_key][0]}")
|
|
110
|
+
else:
|
|
111
|
+
print(f"⚠ ImagesNeurons query not found in term_info")
|
|
112
|
+
print(f" Available queries: {query_names}")
|
|
113
|
+
print(f" SuperTypes: {term_info.get('SuperTypes', [])}")
|
|
114
|
+
|
|
115
|
+
def test_images_neurons_preview(self):
|
|
116
|
+
"""Test preview results format"""
|
|
117
|
+
result = get_images_neurons(self.test_term, return_dataframe=False, limit=5)
|
|
118
|
+
|
|
119
|
+
# Should be a dict with specific structure
|
|
120
|
+
self.assertIsInstance(result, dict, "Result should be a dictionary")
|
|
121
|
+
self.assertIn('rows', result, "Result should have 'rows' key")
|
|
122
|
+
self.assertIn('headers', result, "Result should have 'headers' key")
|
|
123
|
+
self.assertIn('count', result, "Result should have 'count' key")
|
|
124
|
+
|
|
125
|
+
if result['count'] > 0:
|
|
126
|
+
print(f"\n✓ Preview format validated")
|
|
127
|
+
print(f" Total count: {result['count']}")
|
|
128
|
+
print(f" Returned rows: {len(result['rows'])}")
|
|
129
|
+
print(f" Headers: {list(result['headers'].keys())}")
|
|
130
|
+
else:
|
|
131
|
+
print(f"\n⚠ No results in preview (this may be expected)")
|
|
132
|
+
|
|
133
|
+
def test_multiple_terms(self):
|
|
134
|
+
"""Test query with multiple synaptic neuropil terms"""
|
|
135
|
+
test_terms = [
|
|
136
|
+
('FBbt_00007401', 'antennal lobe'),
|
|
137
|
+
('FBbt_00003982', 'medulla'), # another synaptic neuropil
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
print("\n✓ Testing ImagesNeurons with multiple terms:")
|
|
141
|
+
for term_id, term_name in test_terms:
|
|
142
|
+
try:
|
|
143
|
+
result = get_images_neurons(term_id, return_dataframe=True, limit=10)
|
|
144
|
+
count = len(result) if result is not None else 0
|
|
145
|
+
print(f" - {term_name} ({term_id}): {count} individual neuron images")
|
|
146
|
+
except Exception as e:
|
|
147
|
+
print(f" - {term_name} ({term_id}): Error - {e}")
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
if __name__ == '__main__':
|
|
151
|
+
# Run tests with verbose output
|
|
152
|
+
unittest.main(verbosity=2)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test suite for ImagesThatDevelopFrom query.
|
|
3
|
+
|
|
4
|
+
This query uses Owlery instances endpoint to find individual neuron images
|
|
5
|
+
that develop from a specified neuroblast.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import unittest
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
# Add src to path for imports
|
|
13
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
14
|
+
|
|
15
|
+
from vfbquery.vfb_queries import (
|
|
16
|
+
get_images_that_develop_from,
|
|
17
|
+
get_term_info,
|
|
18
|
+
ImagesThatDevelopFrom_to_schema
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestImagesThatDevelopFrom(unittest.TestCase):
|
|
23
|
+
"""Test cases for ImagesThatDevelopFrom query functionality."""
|
|
24
|
+
|
|
25
|
+
def setUp(self):
|
|
26
|
+
"""Set up test fixtures."""
|
|
27
|
+
# FBbt_00001419 is neuroblast MNB - has 336 neuron images that develop from it
|
|
28
|
+
self.test_neuroblast = "FBbt_00001419" # neuroblast MNB
|
|
29
|
+
|
|
30
|
+
def test_schema_generation(self):
|
|
31
|
+
"""Test that the schema function generates correct Query object."""
|
|
32
|
+
schema = ImagesThatDevelopFrom_to_schema("test neuroblast", {"short_form": self.test_neuroblast})
|
|
33
|
+
|
|
34
|
+
self.assertEqual(schema.query, "ImagesThatDevelopFrom")
|
|
35
|
+
self.assertEqual(schema.function, "get_images_that_develop_from")
|
|
36
|
+
self.assertIn("test neuroblast", schema.label)
|
|
37
|
+
self.assertEqual(schema.preview, 5)
|
|
38
|
+
self.assertIn("id", schema.preview_columns)
|
|
39
|
+
self.assertIn("thumbnail", schema.preview_columns)
|
|
40
|
+
|
|
41
|
+
def test_get_images_that_develop_from_execution(self):
|
|
42
|
+
"""Test that the query executes without errors."""
|
|
43
|
+
try:
|
|
44
|
+
# Execute query with limit to keep test fast
|
|
45
|
+
result = get_images_that_develop_from(self.test_neuroblast, return_dataframe=True, limit=10)
|
|
46
|
+
|
|
47
|
+
# Result should be either a DataFrame or dict
|
|
48
|
+
self.assertIsNotNone(result)
|
|
49
|
+
|
|
50
|
+
# If we get results, check structure
|
|
51
|
+
if hasattr(result, 'empty'): # DataFrame
|
|
52
|
+
if not result.empty:
|
|
53
|
+
self.assertIn('id', result.columns)
|
|
54
|
+
self.assertIn('label', result.columns)
|
|
55
|
+
elif isinstance(result, dict): # Dict format
|
|
56
|
+
# Check for either 'data' or 'rows' key
|
|
57
|
+
self.assertTrue('data' in result or 'rows' in result,
|
|
58
|
+
"Result dict should have 'data' or 'rows' key")
|
|
59
|
+
|
|
60
|
+
print(f"\n✅ ImagesThatDevelopFrom query executed successfully")
|
|
61
|
+
if isinstance(result, dict):
|
|
62
|
+
count = result.get('count', len(result.get('rows', result.get('data', []))))
|
|
63
|
+
print(f" Result count: {count} neurons")
|
|
64
|
+
elif hasattr(result, 'shape'):
|
|
65
|
+
print(f" Result count: {len(result)} neurons")
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
self.fail(f"Query execution failed: {str(e)}")
|
|
69
|
+
|
|
70
|
+
def test_return_dataframe_parameter(self):
|
|
71
|
+
"""Test that return_dataframe parameter works correctly."""
|
|
72
|
+
# Test with return_dataframe=True
|
|
73
|
+
df_result = get_images_that_develop_from(self.test_neuroblast, return_dataframe=True, limit=5)
|
|
74
|
+
|
|
75
|
+
# Test with return_dataframe=False
|
|
76
|
+
dict_result = get_images_that_develop_from(self.test_neuroblast, return_dataframe=False, limit=5)
|
|
77
|
+
|
|
78
|
+
# Both should return valid results
|
|
79
|
+
self.assertIsNotNone(df_result)
|
|
80
|
+
self.assertIsNotNone(dict_result)
|
|
81
|
+
|
|
82
|
+
def test_limit_parameter(self):
|
|
83
|
+
"""Test that limit parameter restricts results."""
|
|
84
|
+
limited_result = get_images_that_develop_from(self.test_neuroblast, return_dataframe=True, limit=3)
|
|
85
|
+
|
|
86
|
+
self.assertIsNotNone(limited_result)
|
|
87
|
+
|
|
88
|
+
# If results exist, should respect limit
|
|
89
|
+
if hasattr(limited_result, '__len__') and len(limited_result) > 0:
|
|
90
|
+
self.assertLessEqual(len(limited_result), 3)
|
|
91
|
+
|
|
92
|
+
def test_term_info_integration(self):
|
|
93
|
+
"""Test that ImagesThatDevelopFrom appears in term_info for neuroblasts."""
|
|
94
|
+
# Get term info for a neuroblast
|
|
95
|
+
term_info = get_term_info(self.test_neuroblast, preview=False)
|
|
96
|
+
|
|
97
|
+
self.assertIsNotNone(term_info)
|
|
98
|
+
|
|
99
|
+
# Check if ImagesThatDevelopFrom query is in the queries list
|
|
100
|
+
# Note: This will only appear if the term has the correct supertypes
|
|
101
|
+
queries = term_info.get('Queries', [])
|
|
102
|
+
query_names = [q.get('query') for q in queries if isinstance(q, dict)]
|
|
103
|
+
|
|
104
|
+
# ImagesThatDevelopFrom should appear for neuroblasts
|
|
105
|
+
if 'Neuroblast' in term_info.get('SuperTypes', []):
|
|
106
|
+
self.assertIn('ImagesThatDevelopFrom', query_names,
|
|
107
|
+
"ImagesThatDevelopFrom should be available for neuroblast terms")
|
|
108
|
+
print(f"\n✓ ImagesThatDevelopFrom query found in term_info for {self.test_neuroblast}")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if __name__ == '__main__':
|
|
112
|
+
unittest.main(verbosity=2)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Test suite for LineageClonesIn query.
|
|
4
|
+
|
|
5
|
+
Tests the query that finds lineage clones that overlap with a synaptic neuropil.
|
|
6
|
+
This implements the LineageClonesIn query from the VFB XMI specification.
|
|
7
|
+
|
|
8
|
+
Test cases:
|
|
9
|
+
1. Query execution with known neuropil
|
|
10
|
+
2. Schema generation and validation
|
|
11
|
+
3. Term info integration
|
|
12
|
+
4. Preview results validation
|
|
13
|
+
5. Cache functionality
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import unittest
|
|
17
|
+
import sys
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
# Add the src directory to the path
|
|
21
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
22
|
+
|
|
23
|
+
from vfbquery.vfb_queries import (
|
|
24
|
+
get_lineage_clones_in,
|
|
25
|
+
LineageClonesIn_to_schema,
|
|
26
|
+
get_term_info
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LineageClonesInTest(unittest.TestCase):
|
|
31
|
+
"""Test suite for LineageClonesIn query"""
|
|
32
|
+
|
|
33
|
+
def setUp(self):
|
|
34
|
+
"""Set up test fixtures"""
|
|
35
|
+
# Example synaptic neuropil: adult antennal lobe (FBbt_00007401)
|
|
36
|
+
self.test_neuropil = "FBbt_00007401" # antennal lobe
|
|
37
|
+
|
|
38
|
+
def test_query_execution(self):
|
|
39
|
+
"""Test that the query executes successfully"""
|
|
40
|
+
print(f"\n=== Testing LineageClonesIn query execution ===")
|
|
41
|
+
|
|
42
|
+
# Execute the query
|
|
43
|
+
result = get_lineage_clones_in(self.test_neuropil, return_dataframe=False, limit=5)
|
|
44
|
+
|
|
45
|
+
# Validate result structure
|
|
46
|
+
self.assertIsNotNone(result, "Query should return a result")
|
|
47
|
+
self.assertIsInstance(result, dict, "Result should be a dictionary")
|
|
48
|
+
|
|
49
|
+
# Check for expected keys
|
|
50
|
+
if result:
|
|
51
|
+
print(f"Query returned {len(result.get('data', []))} results")
|
|
52
|
+
|
|
53
|
+
# Validate data structure
|
|
54
|
+
if 'data' in result and len(result['data']) > 0:
|
|
55
|
+
first_result = result['data'][0]
|
|
56
|
+
self.assertIn('id', first_result, "Result should contain 'id' field")
|
|
57
|
+
self.assertIn('label', first_result, "Result should contain 'label' field")
|
|
58
|
+
print(f"First result: {first_result.get('label', 'N/A')} ({first_result.get('id', 'N/A')})")
|
|
59
|
+
else:
|
|
60
|
+
print("No results found (this is OK if no clones overlap this neuropil)")
|
|
61
|
+
|
|
62
|
+
def test_schema_generation(self):
|
|
63
|
+
"""Test schema function generates correct structure"""
|
|
64
|
+
print(f"\n=== Testing LineageClonesIn schema generation ===")
|
|
65
|
+
|
|
66
|
+
test_name = "Test Neuropil"
|
|
67
|
+
test_takes = {"short_form": self.test_neuropil}
|
|
68
|
+
|
|
69
|
+
schema = LineageClonesIn_to_schema(test_name, test_takes)
|
|
70
|
+
|
|
71
|
+
# Validate schema structure
|
|
72
|
+
self.assertIsNotNone(schema, "Schema should not be None")
|
|
73
|
+
self.assertEqual(schema.query, "LineageClonesIn", "Query name should match")
|
|
74
|
+
self.assertEqual(schema.label, f"Lineage clones found in {test_name}", "Label should be formatted correctly")
|
|
75
|
+
self.assertEqual(schema.function, "get_lineage_clones_in", "Function name should match")
|
|
76
|
+
self.assertEqual(schema.preview, 5, "Preview should be 10")
|
|
77
|
+
|
|
78
|
+
# Check preview columns
|
|
79
|
+
expected_columns = ["id", "label", "tags", "thumbnail"]
|
|
80
|
+
self.assertEqual(schema.preview_columns, expected_columns, f"Preview columns should be {expected_columns}")
|
|
81
|
+
|
|
82
|
+
print(f"Schema generated successfully: {schema.label}")
|
|
83
|
+
|
|
84
|
+
def test_term_info_integration(self):
|
|
85
|
+
"""Test that query appears in term info for appropriate terms"""
|
|
86
|
+
print(f"\n=== Testing term info integration ===")
|
|
87
|
+
|
|
88
|
+
# Get term info for a synaptic neuropil
|
|
89
|
+
term_info = get_term_info(self.test_neuropil, preview=False)
|
|
90
|
+
|
|
91
|
+
self.assertIsNotNone(term_info, "Term info should not be None")
|
|
92
|
+
self.assertIn("Queries", term_info, "Term info should contain Queries")
|
|
93
|
+
|
|
94
|
+
# Check if our query is present
|
|
95
|
+
queries = term_info.get("Queries", [])
|
|
96
|
+
query_names = [q.get('query') for q in queries]
|
|
97
|
+
|
|
98
|
+
print(f"Available queries for {self.test_neuropil}: {query_names}")
|
|
99
|
+
|
|
100
|
+
# For synaptic neuropils, this query should be available
|
|
101
|
+
if "Synaptic_neuropil" in term_info.get("SuperTypes", []) or \
|
|
102
|
+
"Synaptic_neuropil_domain" in term_info.get("SuperTypes", []):
|
|
103
|
+
self.assertIn("LineageClonesIn", query_names,
|
|
104
|
+
"LineageClonesIn should be available for Synaptic_neuropil")
|
|
105
|
+
print("✓ Query correctly appears for Synaptic_neuropil type")
|
|
106
|
+
else:
|
|
107
|
+
print(f"Warning: {self.test_neuropil} does not have Synaptic_neuropil type")
|
|
108
|
+
print(f"SuperTypes: {term_info.get('SuperTypes', [])}")
|
|
109
|
+
|
|
110
|
+
def test_preview_results(self):
|
|
111
|
+
"""Test that preview results are properly formatted"""
|
|
112
|
+
print(f"\n=== Testing preview results ===")
|
|
113
|
+
|
|
114
|
+
# Get term info with preview enabled
|
|
115
|
+
term_info = get_term_info(self.test_neuropil, preview=True)
|
|
116
|
+
|
|
117
|
+
self.assertIsNotNone(term_info, "Term info should not be None")
|
|
118
|
+
|
|
119
|
+
# Find our query in the results
|
|
120
|
+
queries = term_info.get("Queries", [])
|
|
121
|
+
clones_query = None
|
|
122
|
+
for q in queries:
|
|
123
|
+
if q.get('query') == "LineageClonesIn":
|
|
124
|
+
clones_query = q
|
|
125
|
+
break
|
|
126
|
+
|
|
127
|
+
if clones_query:
|
|
128
|
+
print(f"Found LineageClonesIn query")
|
|
129
|
+
|
|
130
|
+
# Check if preview_results exist
|
|
131
|
+
if clones_query.get('preview_results'):
|
|
132
|
+
preview = clones_query['preview_results']
|
|
133
|
+
data_key = 'data' if 'data' in preview else 'rows'
|
|
134
|
+
print(f"Preview contains {len(preview.get(data_key, []))} results")
|
|
135
|
+
|
|
136
|
+
# Validate preview structure
|
|
137
|
+
self.assertIn(data_key, preview, f"Preview should contain '{data_key}' key")
|
|
138
|
+
self.assertIn('headers', preview, "Preview should contain 'headers' key")
|
|
139
|
+
|
|
140
|
+
# Check first result if available
|
|
141
|
+
if preview.get(data_key) and len(preview[data_key]) > 0:
|
|
142
|
+
first_result = preview[data_key][0]
|
|
143
|
+
print(f"First preview result: {first_result.get('label', 'N/A')}")
|
|
144
|
+
|
|
145
|
+
# Validate required fields
|
|
146
|
+
self.assertIn('id', first_result, "Preview result should have 'id'")
|
|
147
|
+
self.assertIn('label', first_result, "Preview result should have 'label'")
|
|
148
|
+
else:
|
|
149
|
+
print("No preview results available (this is OK if no clones overlap this neuropil)")
|
|
150
|
+
else:
|
|
151
|
+
print("LineageClonesIn query not found in term info")
|
|
152
|
+
|
|
153
|
+
def test_with_different_neuropils(self):
|
|
154
|
+
"""Test with multiple synaptic neuropil types"""
|
|
155
|
+
print(f"\n=== Testing with different neuropils ===")
|
|
156
|
+
|
|
157
|
+
test_neuropils = [
|
|
158
|
+
("FBbt_00007401", "antennal lobe"),
|
|
159
|
+
("FBbt_00003982", "medulla"),
|
|
160
|
+
("FBbt_00003679", "mushroom body"),
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
for neuropil_id, neuropil_name in test_neuropils:
|
|
164
|
+
print(f"\nTesting {neuropil_name} ({neuropil_id})...")
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
result = get_lineage_clones_in(neuropil_id, return_dataframe=False, limit=3)
|
|
168
|
+
|
|
169
|
+
if result and 'data' in result:
|
|
170
|
+
print(f" ✓ Query successful, found {len(result['data'])} results")
|
|
171
|
+
else:
|
|
172
|
+
print(f" ✓ Query successful, no results found")
|
|
173
|
+
|
|
174
|
+
except Exception as e:
|
|
175
|
+
print(f" ✗ Query failed: {str(e)}")
|
|
176
|
+
# Don't fail the test, just log the error
|
|
177
|
+
# raise
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def run_tests():
|
|
181
|
+
"""Run the test suite"""
|
|
182
|
+
suite = unittest.TestLoader().loadTestsFromTestCase(LineageClonesInTest)
|
|
183
|
+
runner = unittest.TextTestRunner(verbosity=2)
|
|
184
|
+
result = runner.run(suite)
|
|
185
|
+
return result.wasSuccessful()
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
if __name__ == '__main__':
|
|
189
|
+
success = run_tests()
|
|
190
|
+
sys.exit(0 if success else 1)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for NBLAST similarity queries.
|
|
3
|
+
|
|
4
|
+
This tests all 6 NBLAST-related queries:
|
|
5
|
+
1. get_similar_morphology - NBLAST matches
|
|
6
|
+
2. get_similar_morphology_part_of - NBLASTexp to expression patterns
|
|
7
|
+
3. get_similar_morphology_part_of_exp - Reverse NBLASTexp
|
|
8
|
+
4. get_similar_morphology_nb - NeuronBridge matches
|
|
9
|
+
5. get_similar_morphology_nb_exp - NeuronBridge for expression patterns
|
|
10
|
+
6. get_similar_morphology_userdata - User upload NBLAST from SOLR
|
|
11
|
+
|
|
12
|
+
Test terms:
|
|
13
|
+
- VFB_00101567 - has NBLAST matches
|
|
14
|
+
- VFB_00050000 - example neuron with NBLASTexp
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import unittest
|
|
18
|
+
import sys
|
|
19
|
+
import os
|
|
20
|
+
|
|
21
|
+
# Add src directory to path
|
|
22
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
|
|
23
|
+
|
|
24
|
+
from vfbquery.vfb_queries import (
|
|
25
|
+
get_similar_morphology,
|
|
26
|
+
get_similar_morphology_part_of,
|
|
27
|
+
get_similar_morphology_part_of_exp,
|
|
28
|
+
get_similar_morphology_nb,
|
|
29
|
+
get_similar_morphology_nb_exp,
|
|
30
|
+
get_similar_morphology_userdata,
|
|
31
|
+
SimilarMorphologyTo_to_schema,
|
|
32
|
+
SimilarMorphologyToPartOf_to_schema,
|
|
33
|
+
SimilarMorphologyToPartOfexp_to_schema,
|
|
34
|
+
SimilarMorphologyToNB_to_schema,
|
|
35
|
+
SimilarMorphologyToNBexp_to_schema,
|
|
36
|
+
SimilarMorphologyToUserData_to_schema
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class NBLASTQueriesTest(unittest.TestCase):
|
|
41
|
+
"""Test cases for NBLAST similarity queries"""
|
|
42
|
+
|
|
43
|
+
def setUp(self):
|
|
44
|
+
"""Set up test fixtures"""
|
|
45
|
+
self.nblast_term = 'VFB_00101567' # Has NBLAST matches
|
|
46
|
+
self.neuron_term = 'VFB_00050000' # Example neuron
|
|
47
|
+
|
|
48
|
+
def test_get_similar_morphology(self):
|
|
49
|
+
"""Test get_similar_morphology query"""
|
|
50
|
+
result = get_similar_morphology(self.nblast_term, return_dataframe=True, limit=5)
|
|
51
|
+
self.assertIsNotNone(result, "Result should not be None")
|
|
52
|
+
|
|
53
|
+
import pandas as pd
|
|
54
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
55
|
+
print(f"\n✓ Found {len(result)} NBLAST matches for {self.nblast_term}")
|
|
56
|
+
self.assertIn('id', result.columns)
|
|
57
|
+
self.assertIn('label', result.columns)
|
|
58
|
+
self.assertIn('score', result.columns)
|
|
59
|
+
|
|
60
|
+
def test_get_similar_morphology_formatted(self):
|
|
61
|
+
"""Test get_similar_morphology with formatted output"""
|
|
62
|
+
result = get_similar_morphology(self.nblast_term, return_dataframe=False, limit=3)
|
|
63
|
+
self.assertIsNotNone(result)
|
|
64
|
+
|
|
65
|
+
if isinstance(result, dict):
|
|
66
|
+
self.assertIn('headers', result)
|
|
67
|
+
self.assertIn('rows', result)
|
|
68
|
+
|
|
69
|
+
def test_get_similar_morphology_part_of(self):
|
|
70
|
+
"""Test get_similar_morphology_part_of (NBLASTexp)"""
|
|
71
|
+
result = get_similar_morphology_part_of(self.neuron_term, return_dataframe=True, limit=5)
|
|
72
|
+
self.assertIsNotNone(result)
|
|
73
|
+
|
|
74
|
+
import pandas as pd
|
|
75
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
76
|
+
print(f"\n✓ Found {len(result)} NBLASTexp matches for {self.neuron_term}")
|
|
77
|
+
|
|
78
|
+
def test_get_similar_morphology_part_of_exp(self):
|
|
79
|
+
"""Test get_similar_morphology_part_of_exp (reverse NBLASTexp)"""
|
|
80
|
+
result = get_similar_morphology_part_of_exp(self.neuron_term, return_dataframe=True, limit=5)
|
|
81
|
+
self.assertIsNotNone(result)
|
|
82
|
+
|
|
83
|
+
import pandas as pd
|
|
84
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
85
|
+
print(f"\n✓ Found {len(result)} reverse NBLASTexp matches")
|
|
86
|
+
|
|
87
|
+
def test_get_similar_morphology_nb(self):
|
|
88
|
+
"""Test get_similar_morphology_nb (NeuronBridge)"""
|
|
89
|
+
result = get_similar_morphology_nb(self.neuron_term, return_dataframe=True, limit=5)
|
|
90
|
+
self.assertIsNotNone(result)
|
|
91
|
+
|
|
92
|
+
import pandas as pd
|
|
93
|
+
if isinstance(result, pd.DataFrame) and len(result) > 0:
|
|
94
|
+
print(f"\n✓ Found {len(result)} NeuronBridge matches")
|
|
95
|
+
self.assertIn('score', result.columns)
|
|
96
|
+
|
|
97
|
+
def test_get_similar_morphology_nb_exp(self):
|
|
98
|
+
"""Test get_similar_morphology_nb_exp (NeuronBridge for expression)"""
|
|
99
|
+
result = get_similar_morphology_nb_exp(self.neuron_term, return_dataframe=True, limit=5)
|
|
100
|
+
self.assertIsNotNone(result)
|
|
101
|
+
|
|
102
|
+
def test_schema_functions_exist(self):
|
|
103
|
+
"""Test that all NBLAST schema functions exist and are callable"""
|
|
104
|
+
schema_functions = [
|
|
105
|
+
SimilarMorphologyTo_to_schema,
|
|
106
|
+
SimilarMorphologyToPartOf_to_schema,
|
|
107
|
+
SimilarMorphologyToPartOfexp_to_schema,
|
|
108
|
+
SimilarMorphologyToNB_to_schema,
|
|
109
|
+
SimilarMorphologyToNBexp_to_schema,
|
|
110
|
+
SimilarMorphologyToUserData_to_schema
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
for func in schema_functions:
|
|
114
|
+
self.assertTrue(callable(func), f"{func.__name__} should be callable")
|
|
115
|
+
|
|
116
|
+
def test_empty_results_handling(self):
|
|
117
|
+
"""Test that queries handle empty results gracefully"""
|
|
118
|
+
# Use a term unlikely to have NBLAST matches
|
|
119
|
+
result = get_similar_morphology('FBbt_00000001', return_dataframe=True, limit=5)
|
|
120
|
+
self.assertIsNotNone(result)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
if __name__ == '__main__':
|
|
124
|
+
unittest.main()
|