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.
@@ -0,0 +1,204 @@
1
+ import unittest
2
+ import sys
3
+ import os
4
+
5
+ # Add src to path for imports
6
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'src'))
7
+
8
+ from vfbquery.vfb_queries import get_neurons_with_part_in, get_term_info
9
+
10
+
11
+ class NeuronsPartHereTest(unittest.TestCase):
12
+ """Test suite for NeuronsPartHere query implementation"""
13
+
14
+ def setUp(self):
15
+ """Set up test fixtures"""
16
+ self.medulla_id = 'FBbt_00003748'
17
+ # Expected count based on VFB data (as of test creation)
18
+ # Allowing tolerance for data updates
19
+ self.expected_count = 471
20
+ self.count_tolerance = 5 # Allow ±5 for data updates
21
+
22
+ def test_neurons_part_here_returns_results(self):
23
+ """Test that NeuronsPartHere query returns results for medulla"""
24
+ print("\n" + "=" * 80)
25
+ print("Testing NeuronsPartHere query - Basic functionality")
26
+ print("=" * 80)
27
+
28
+ results_df = get_neurons_with_part_in(
29
+ self.medulla_id,
30
+ return_dataframe=True,
31
+ limit=-1
32
+ )
33
+
34
+ self.assertIsNotNone(results_df, "Results should not be None")
35
+ self.assertGreater(len(results_df), 0, "Should return at least one result")
36
+
37
+ print(f"✓ Query returned {len(results_df)} neuron classes")
38
+
39
+ def test_neurons_part_here_result_count(self):
40
+ """Test that NeuronsPartHere returns expected number of results for medulla"""
41
+ print("\n" + "=" * 80)
42
+ print(f"Testing NeuronsPartHere result count (expected ~{self.expected_count})")
43
+ print("=" * 80)
44
+
45
+ results_df = get_neurons_with_part_in(
46
+ self.medulla_id,
47
+ return_dataframe=True,
48
+ limit=-1
49
+ )
50
+
51
+ actual_count = len(results_df)
52
+ count_diff = abs(actual_count - self.expected_count)
53
+
54
+ print(f"Expected: {self.expected_count} results")
55
+ print(f"Actual: {actual_count} results")
56
+ print(f"Difference: {count_diff}")
57
+
58
+ # Allow some tolerance for data updates
59
+ self.assertLessEqual(
60
+ count_diff,
61
+ self.count_tolerance,
62
+ f"Result count {actual_count} differs from expected {self.expected_count} by more than {self.count_tolerance}"
63
+ )
64
+
65
+ if count_diff > 0:
66
+ print(f"⚠ Count differs by {count_diff} (within tolerance of {self.count_tolerance})")
67
+ else:
68
+ print(f"✓ Exact count match: {actual_count}")
69
+
70
+ def test_neurons_part_here_result_structure(self):
71
+ """Test that results have the expected structure with required columns"""
72
+ print("\n" + "=" * 80)
73
+ print("Testing NeuronsPartHere result structure")
74
+ print("=" * 80)
75
+
76
+ results_df = get_neurons_with_part_in(
77
+ self.medulla_id,
78
+ return_dataframe=True,
79
+ limit=5
80
+ )
81
+
82
+ # Check required columns
83
+ required_columns = ['id', 'label', 'tags', 'thumbnail']
84
+ for col in required_columns:
85
+ self.assertIn(col, results_df.columns, f"Column '{col}' should be present")
86
+
87
+ print(f"✓ All required columns present: {', '.join(required_columns)}")
88
+
89
+ # Check that we have data in the columns
90
+ first_row = results_df.iloc[0]
91
+ self.assertIsNotNone(first_row['id'], "ID should not be None")
92
+ self.assertIsNotNone(first_row['label'], "Label should not be None")
93
+
94
+ print(f"✓ Sample result: {first_row['label']}")
95
+
96
+ def test_neurons_part_here_has_examples(self):
97
+ """Test that neuron class results include example images (thumbnails)"""
98
+ print("\n" + "=" * 80)
99
+ print("Testing NeuronsPartHere includes example images")
100
+ print("=" * 80)
101
+
102
+ results_df = get_neurons_with_part_in(
103
+ self.medulla_id,
104
+ return_dataframe=True,
105
+ limit=10
106
+ )
107
+
108
+ # Count how many results have thumbnails
109
+ has_thumbnails = results_df['thumbnail'].notna().sum()
110
+ total_results = len(results_df)
111
+
112
+ print(f"Results with thumbnails: {has_thumbnails}/{total_results}")
113
+
114
+ # At least some results should have thumbnails (example instances)
115
+ self.assertGreater(
116
+ has_thumbnails,
117
+ 0,
118
+ "At least some neuron classes should have example images"
119
+ )
120
+
121
+ # Show example thumbnails
122
+ sample_with_thumbnail = results_df[results_df['thumbnail'].notna()].iloc[0]
123
+ print(f"\n✓ Example with thumbnail:")
124
+ print(f" {sample_with_thumbnail['label']}")
125
+ print(f" Thumbnail: {sample_with_thumbnail['thumbnail'][:100]}...")
126
+
127
+ def test_neurons_part_here_preview_in_term_info(self):
128
+ """Test that NeuronsPartHere query appears with preview results in term_info"""
129
+ print("\n" + "=" * 80)
130
+ print("Testing NeuronsPartHere preview results in term_info")
131
+ print("=" * 80)
132
+
133
+ term_info = get_term_info(self.medulla_id, preview=True)
134
+
135
+ self.assertIsNotNone(term_info, "term_info should not be None")
136
+ self.assertIn('Queries', term_info, "term_info should have Queries")
137
+
138
+ # Find NeuronsPartHere query
139
+ neurons_part_here_query = None
140
+ for query in term_info.get('Queries', []):
141
+ if query.get('query') == 'NeuronsPartHere':
142
+ neurons_part_here_query = query
143
+ break
144
+
145
+ self.assertIsNotNone(
146
+ neurons_part_here_query,
147
+ "NeuronsPartHere query should be present in term_info"
148
+ )
149
+
150
+ print(f"✓ NeuronsPartHere query found")
151
+ print(f" Label: {neurons_part_here_query.get('label', 'Unknown')}")
152
+ print(f" Preview limit: {neurons_part_here_query.get('preview', 0)}")
153
+
154
+ # Check preview results
155
+ preview_results = neurons_part_here_query.get('preview_results', {})
156
+ preview_rows = preview_results.get('rows', [])
157
+
158
+ self.assertGreater(
159
+ len(preview_rows),
160
+ 0,
161
+ "Preview results should be populated"
162
+ )
163
+
164
+ print(f" Preview results: {len(preview_rows)} items")
165
+
166
+ # Check that preview results include thumbnails
167
+ with_thumbnails = sum(1 for row in preview_rows if row.get('thumbnail', ''))
168
+ print(f" Results with example images: {with_thumbnails}/{len(preview_rows)}")
169
+
170
+ self.assertGreater(
171
+ with_thumbnails,
172
+ 0,
173
+ "At least some preview results should have example images"
174
+ )
175
+
176
+ print(f"\n✓ Preview includes example images")
177
+
178
+ def test_neurons_part_here_limit_parameter(self):
179
+ """Test that the limit parameter works correctly"""
180
+ print("\n" + "=" * 80)
181
+ print("Testing NeuronsPartHere limit parameter")
182
+ print("=" * 80)
183
+
184
+ limit = 10
185
+ results_df = get_neurons_with_part_in(
186
+ self.medulla_id,
187
+ return_dataframe=True,
188
+ limit=limit
189
+ )
190
+
191
+ actual_count = len(results_df)
192
+
193
+ self.assertLessEqual(
194
+ actual_count,
195
+ limit,
196
+ f"Result count {actual_count} should not exceed limit {limit}"
197
+ )
198
+
199
+ print(f"✓ Limit parameter working: requested {limit}, got {actual_count}")
200
+
201
+
202
+ if __name__ == '__main__':
203
+ # Run tests with verbose output
204
+ unittest.main(verbosity=2)
@@ -0,0 +1,282 @@
1
+ """
2
+ Tests for newly implemented Owlery-based queries:
3
+ - NeuronsSynaptic
4
+ - NeuronsPresynapticHere
5
+ - NeuronsPostsynapticHere
6
+ - ComponentsOf
7
+ - PartsOf
8
+ - SubclassesOf
9
+ """
10
+
11
+ import unittest
12
+ from vfbquery.vfb_queries import (
13
+ get_neurons_with_synapses_in,
14
+ get_neurons_with_presynaptic_terminals_in,
15
+ get_neurons_with_postsynaptic_terminals_in,
16
+ get_components_of,
17
+ get_parts_of,
18
+ get_subclasses_of,
19
+ get_term_info
20
+ )
21
+
22
+
23
+ class TestNeuronsSynaptic(unittest.TestCase):
24
+ """Tests for NeuronsSynaptic query"""
25
+
26
+ def setUp(self):
27
+ self.medulla_id = 'FBbt_00003748' # medulla - synaptic neuropil
28
+
29
+ def test_neurons_synaptic_returns_results(self):
30
+ """Test that NeuronsSynaptic query returns results for medulla"""
31
+ result = get_neurons_with_synapses_in(
32
+ self.medulla_id,
33
+ return_dataframe=False
34
+ )
35
+
36
+ self.assertIsNotNone(result)
37
+ self.assertIn('headers', result)
38
+ self.assertIn('rows', result)
39
+ self.assertIn('count', result)
40
+
41
+ def test_neurons_synaptic_has_expected_columns(self):
42
+ """Test that result has expected column structure"""
43
+ result = get_neurons_with_synapses_in(
44
+ self.medulla_id,
45
+ return_dataframe=False
46
+ )
47
+
48
+ headers = result['headers']
49
+ self.assertIn('id', headers)
50
+ self.assertIn('label', headers)
51
+ self.assertIn('tags', headers)
52
+ self.assertIn('thumbnail', headers)
53
+
54
+ def test_neurons_synaptic_in_term_info(self):
55
+ """Test that NeuronsSynaptic appears in term_info queries"""
56
+ term_info = get_term_info(self.medulla_id, preview=True)
57
+
58
+ self.assertIn('Queries', term_info) # Note: Capital 'Q'
59
+ query_labels = [q['label'] for q in term_info['Queries']]
60
+
61
+ # Check if our query is present
62
+ expected_label = f"Neurons with synaptic terminals in {term_info['Name']}"
63
+ self.assertIn(expected_label, query_labels)
64
+
65
+
66
+ class TestNeuronsPresynapticHere(unittest.TestCase):
67
+ """Tests for NeuronsPresynapticHere query"""
68
+
69
+ def setUp(self):
70
+ self.medulla_id = 'FBbt_00003748' # medulla - synaptic neuropil
71
+
72
+ def test_neurons_presynaptic_returns_results(self):
73
+ """Test that NeuronsPresynapticHere query returns results for medulla"""
74
+ result = get_neurons_with_presynaptic_terminals_in(
75
+ self.medulla_id,
76
+ return_dataframe=False
77
+ )
78
+
79
+ self.assertIsNotNone(result)
80
+ self.assertIn('headers', result)
81
+ self.assertIn('rows', result)
82
+ self.assertIn('count', result)
83
+
84
+ def test_neurons_presynaptic_has_expected_columns(self):
85
+ """Test that result has expected column structure"""
86
+ result = get_neurons_with_presynaptic_terminals_in(
87
+ self.medulla_id,
88
+ return_dataframe=False
89
+ )
90
+
91
+ headers = result['headers']
92
+ self.assertIn('id', headers)
93
+ self.assertIn('label', headers)
94
+ self.assertIn('tags', headers)
95
+ self.assertIn('thumbnail', headers)
96
+
97
+ def test_neurons_presynaptic_in_term_info(self):
98
+ """Test that NeuronsPresynapticHere appears in term_info queries"""
99
+ term_info = get_term_info(self.medulla_id, preview=True)
100
+
101
+ self.assertIn('Queries', term_info) # Note: Capital 'Q'
102
+ query_labels = [q['label'] for q in term_info['Queries']]
103
+
104
+ # Check if our query is present
105
+ expected_label = f"Neurons with presynaptic terminals in {term_info['Name']}"
106
+ self.assertIn(expected_label, query_labels)
107
+
108
+
109
+ class TestNeuronsPostsynapticHere(unittest.TestCase):
110
+ """Tests for NeuronsPostsynapticHere query"""
111
+
112
+ def setUp(self):
113
+ self.medulla_id = 'FBbt_00003748' # medulla - synaptic neuropil
114
+
115
+ def test_neurons_postsynaptic_returns_results(self):
116
+ """Test that NeuronsPostsynapticHere query returns results for medulla"""
117
+ result = get_neurons_with_postsynaptic_terminals_in(
118
+ self.medulla_id,
119
+ return_dataframe=False
120
+ )
121
+
122
+ self.assertIsNotNone(result)
123
+ self.assertIn('headers', result)
124
+ self.assertIn('rows', result)
125
+ self.assertIn('count', result)
126
+
127
+ def test_neurons_postsynaptic_has_expected_columns(self):
128
+ """Test that result has expected column structure"""
129
+ result = get_neurons_with_postsynaptic_terminals_in(
130
+ self.medulla_id,
131
+ return_dataframe=False
132
+ )
133
+
134
+ headers = result['headers']
135
+ self.assertIn('id', headers)
136
+ self.assertIn('label', headers)
137
+ self.assertIn('tags', headers)
138
+ self.assertIn('thumbnail', headers)
139
+
140
+ def test_neurons_postsynaptic_in_term_info(self):
141
+ """Test that NeuronsPostsynapticHere appears in term_info queries"""
142
+ term_info = get_term_info(self.medulla_id, preview=True)
143
+
144
+ self.assertIn('Queries', term_info) # Note: Capital 'Q'
145
+ query_labels = [q['label'] for q in term_info['Queries']]
146
+
147
+ # Check if our query is present
148
+ expected_label = f"Neurons with postsynaptic terminals in {term_info['Name']}"
149
+ self.assertIn(expected_label, query_labels)
150
+
151
+
152
+ class TestComponentsOf(unittest.TestCase):
153
+ """Tests for ComponentsOf query"""
154
+
155
+ def setUp(self):
156
+ self.clone_id = 'FBbt_00110369' # adult SLPpm4 lineage clone
157
+
158
+ def test_components_of_returns_results(self):
159
+ """Test that ComponentsOf query returns results for clone"""
160
+ result = get_components_of(
161
+ self.clone_id,
162
+ return_dataframe=False
163
+ )
164
+
165
+ self.assertIsNotNone(result)
166
+ self.assertIn('headers', result)
167
+ self.assertIn('rows', result)
168
+ self.assertIn('count', result)
169
+
170
+ def test_components_of_has_expected_columns(self):
171
+ """Test that result has expected column structure"""
172
+ result = get_components_of(
173
+ self.clone_id,
174
+ return_dataframe=False
175
+ )
176
+
177
+ headers = result['headers']
178
+ self.assertIn('id', headers)
179
+ self.assertIn('label', headers)
180
+ self.assertIn('tags', headers)
181
+ self.assertIn('thumbnail', headers)
182
+
183
+ def test_components_of_in_term_info(self):
184
+ """Test that ComponentsOf appears in term_info queries"""
185
+ term_info = get_term_info(self.clone_id, preview=True)
186
+
187
+ self.assertIn('Queries', term_info) # Note: Capital 'Q'
188
+ query_labels = [q['label'] for q in term_info['Queries']]
189
+
190
+ # Check if our query is present
191
+ expected_label = f"Components of {term_info['Name']}"
192
+ self.assertIn(expected_label, query_labels)
193
+
194
+
195
+ class TestPartsOf(unittest.TestCase):
196
+ """Tests for PartsOf query"""
197
+
198
+ def setUp(self):
199
+ self.medulla_id = 'FBbt_00003748' # medulla - any Class
200
+
201
+ def test_parts_of_returns_results(self):
202
+ """Test that PartsOf query returns results for medulla"""
203
+ result = get_parts_of(
204
+ self.medulla_id,
205
+ return_dataframe=False
206
+ )
207
+
208
+ self.assertIsNotNone(result)
209
+ self.assertIn('headers', result)
210
+ self.assertIn('rows', result)
211
+ self.assertIn('count', result)
212
+
213
+ def test_parts_of_has_expected_columns(self):
214
+ """Test that result has expected column structure"""
215
+ result = get_parts_of(
216
+ self.medulla_id,
217
+ return_dataframe=False
218
+ )
219
+
220
+ headers = result['headers']
221
+ self.assertIn('id', headers)
222
+ self.assertIn('label', headers)
223
+ self.assertIn('tags', headers)
224
+ self.assertIn('thumbnail', headers)
225
+
226
+ def test_parts_of_in_term_info(self):
227
+ """Test that PartsOf appears in term_info queries"""
228
+ term_info = get_term_info(self.medulla_id, preview=True)
229
+
230
+ self.assertIn('Queries', term_info) # Note: Capital 'Q'
231
+ query_labels = [q['label'] for q in term_info['Queries']]
232
+
233
+ # Check if our query is present
234
+ expected_label = f"Parts of {term_info['Name']}"
235
+ self.assertIn(expected_label, query_labels)
236
+
237
+
238
+ class TestSubclassesOf(unittest.TestCase):
239
+ """Tests for SubclassesOf query"""
240
+
241
+ def setUp(self):
242
+ self.wedge_pn_id = 'FBbt_00048516' # wedge projection neuron (>45 subclasses)
243
+
244
+ def test_subclasses_of_returns_results(self):
245
+ """Test that SubclassesOf query returns results for wedge projection neuron"""
246
+ result = get_subclasses_of(
247
+ self.wedge_pn_id,
248
+ return_dataframe=False
249
+ )
250
+
251
+ self.assertIsNotNone(result)
252
+ self.assertIn('headers', result)
253
+ self.assertIn('rows', result)
254
+ self.assertIn('count', result)
255
+
256
+ def test_subclasses_of_has_expected_columns(self):
257
+ """Test that result has expected column structure"""
258
+ result = get_subclasses_of(
259
+ self.wedge_pn_id,
260
+ return_dataframe=False
261
+ )
262
+
263
+ headers = result['headers']
264
+ self.assertIn('id', headers)
265
+ self.assertIn('label', headers)
266
+ self.assertIn('tags', headers)
267
+ self.assertIn('thumbnail', headers)
268
+
269
+ def test_subclasses_of_in_term_info(self):
270
+ """Test that SubclassesOf appears in term_info queries"""
271
+ term_info = get_term_info(self.wedge_pn_id, preview=True)
272
+
273
+ self.assertIn('Queries', term_info) # Note: Capital 'Q'
274
+ query_labels = [q['label'] for q in term_info['Queries']]
275
+
276
+ # Check if our query is present
277
+ expected_label = f"Subclasses of {term_info['Name']}"
278
+ self.assertIn(expected_label, query_labels)
279
+
280
+
281
+ if __name__ == '__main__':
282
+ unittest.main()
@@ -0,0 +1,101 @@
1
+ """
2
+ Unit tests for publication and transgene queries.
3
+
4
+ This tests:
5
+ 1. get_terms_for_pub - Terms referencing a publication
6
+ 2. get_transgene_expression_here - Complex transgene expression query
7
+
8
+ Test terms:
9
+ - DOI_10_7554_eLife_04577 - Example publication
10
+ - FBbt_00003748 - mushroom body (for transgene expression)
11
+ """
12
+
13
+ import unittest
14
+ import sys
15
+ import os
16
+
17
+ # Add src directory to path
18
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
19
+
20
+ from vfbquery.vfb_queries import (
21
+ get_terms_for_pub,
22
+ get_transgene_expression_here,
23
+ TermsForPub_to_schema,
24
+ TransgeneExpressionHere_to_schema
25
+ )
26
+
27
+
28
+ class PublicationTransgeneQueriesTest(unittest.TestCase):
29
+ """Test cases for publication and transgene queries"""
30
+
31
+ def setUp(self):
32
+ """Set up test fixtures"""
33
+ self.pub_term = 'DOI_10_7554_eLife_04577' # Example publication
34
+ self.anatomy_term = 'FBbt_00003748' # mushroom body
35
+
36
+ def test_get_terms_for_pub(self):
37
+ """Test get_terms_for_pub query"""
38
+ result = get_terms_for_pub(self.pub_term, return_dataframe=True, limit=10)
39
+ self.assertIsNotNone(result, "Result should not be None")
40
+
41
+ import pandas as pd
42
+ if isinstance(result, pd.DataFrame) and len(result) > 0:
43
+ print(f"\n✓ Found {len(result)} terms for publication {self.pub_term}")
44
+ self.assertIn('id', result.columns)
45
+ self.assertIn('label', result.columns)
46
+
47
+ def test_get_terms_for_pub_formatted(self):
48
+ """Test get_terms_for_pub with formatted output"""
49
+ result = get_terms_for_pub(self.pub_term, return_dataframe=False, limit=5)
50
+ self.assertIsNotNone(result)
51
+
52
+ if isinstance(result, dict):
53
+ self.assertIn('headers', result)
54
+ self.assertIn('rows', result)
55
+
56
+ def test_get_transgene_expression_here(self):
57
+ """Test get_transgene_expression_here query"""
58
+ result = get_transgene_expression_here(self.anatomy_term, return_dataframe=True, limit=10)
59
+ self.assertIsNotNone(result, "Result should not be None")
60
+
61
+ import pandas as pd
62
+ if isinstance(result, pd.DataFrame) and len(result) > 0:
63
+ print(f"\n✓ Found {len(result)} transgene expressions in {self.anatomy_term}")
64
+ self.assertIn('id', result.columns)
65
+
66
+ def test_get_transgene_expression_formatted(self):
67
+ """Test get_transgene_expression_here with formatted output"""
68
+ result = get_transgene_expression_here(self.anatomy_term, return_dataframe=False, limit=5)
69
+ self.assertIsNotNone(result)
70
+
71
+ if isinstance(result, dict):
72
+ self.assertIn('headers', result)
73
+ self.assertIn('rows', result)
74
+
75
+ def test_schema_functions_exist(self):
76
+ """Test that publication/transgene schema functions exist and are callable"""
77
+ schema_functions = [
78
+ TermsForPub_to_schema,
79
+ TransgeneExpressionHere_to_schema
80
+ ]
81
+
82
+ for func in schema_functions:
83
+ self.assertTrue(callable(func), f"{func.__name__} should be callable")
84
+
85
+ def test_limit_parameter(self):
86
+ """Test that limit parameter works correctly"""
87
+ result = get_terms_for_pub(self.pub_term, return_dataframe=True, limit=3)
88
+
89
+ import pandas as pd
90
+ if isinstance(result, pd.DataFrame) and len(result) > 0:
91
+ self.assertLessEqual(len(result), 3, "Result should respect limit parameter")
92
+
93
+ def test_empty_results_handling(self):
94
+ """Test that queries handle empty results gracefully"""
95
+ # Use a term unlikely to have references
96
+ result = get_terms_for_pub('INVALID_PUB_123', return_dataframe=True, limit=5)
97
+ self.assertIsNotNone(result)
98
+
99
+
100
+ if __name__ == '__main__':
101
+ unittest.main()