vfbquery 0.3.4__tar.gz → 0.4.1__tar.gz

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.
Files changed (26) hide show
  1. {vfbquery-0.3.4 → vfbquery-0.4.1}/PKG-INFO +16 -16
  2. {vfbquery-0.3.4 → vfbquery-0.4.1}/README.md +16 -16
  3. {vfbquery-0.3.4 → vfbquery-0.4.1}/setup.py +1 -1
  4. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/test/readme_parser.py +29 -1
  5. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/test/term_info_queries_test.py +58 -0
  6. vfbquery-0.4.1/src/test/test_default_caching.py +173 -0
  7. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/test/test_examples_diff.py +6 -1
  8. vfbquery-0.4.1/src/vfbquery/__init__.py +86 -0
  9. vfbquery-0.4.1/src/vfbquery/cache_enhancements.py +465 -0
  10. vfbquery-0.4.1/src/vfbquery/cached_functions.py +227 -0
  11. vfbquery-0.4.1/src/vfbquery/solr_cache_integration.py +212 -0
  12. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery/solr_fetcher.py +47 -3
  13. vfbquery-0.4.1/src/vfbquery/solr_result_cache.py +659 -0
  14. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery/vfb_queries.py +315 -73
  15. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery.egg-info/PKG-INFO +16 -16
  16. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery.egg-info/SOURCES.txt +5 -0
  17. vfbquery-0.3.4/src/vfbquery/__init__.py +0 -4
  18. {vfbquery-0.3.4 → vfbquery-0.4.1}/LICENSE +0 -0
  19. {vfbquery-0.3.4 → vfbquery-0.4.1}/pyproject.toml +0 -0
  20. {vfbquery-0.3.4 → vfbquery-0.4.1}/setup.cfg +0 -0
  21. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/test/__init__.py +0 -0
  22. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery/term_info_queries.py +0 -0
  23. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery/test_utils.py +0 -0
  24. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery.egg-info/dependency_links.txt +0 -0
  25. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery.egg-info/requires.txt +0 -0
  26. {vfbquery-0.3.4 → vfbquery-0.4.1}/src/vfbquery.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vfbquery
3
- Version: 0.3.4
3
+ Version: 0.4.1
4
4
  Summary: Wrapper for querying VirtualFlyBrain knowledge graph.
5
5
  Home-page: https://github.com/VirtualFlyBrain/VFBquery
6
6
  Author: VirtualFlyBrain
@@ -121,9 +121,9 @@ vfb.get_term_info('FBbt_00003748')
121
121
  },
122
122
  {
123
123
  "id": "VFB_00101385",
124
- "label": "[ME%28R%29 on JRC_FlyEM_Hemibrain](VFB_00101385)",
124
+ "label": "[ME(R) on JRC_FlyEM_Hemibrain](VFB_00101385)",
125
125
  "tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
126
- "thumbnail": "[![ME%28R%29 on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
126
+ "thumbnail": "[![ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
127
127
  },
128
128
  {
129
129
  "id": "VFB_00030810",
@@ -143,8 +143,8 @@ vfb.get_term_info('FBbt_00003748')
143
143
  "count": 4
144
144
  }
145
145
  ],
146
- "IsIndividual": false,
147
- "IsClass": true,
146
+ "IsIndividual": False,
147
+ "IsClass": True,
148
148
  "Examples": {
149
149
  "VFB_00101384": [
150
150
  {
@@ -191,7 +191,7 @@ vfb.get_term_info('FBbt_00003748')
191
191
  }
192
192
  ]
193
193
  },
194
- "IsTemplate": false,
194
+ "IsTemplate": False,
195
195
  "Synonyms": [
196
196
  {
197
197
  "label": "ME",
@@ -1122,7 +1122,7 @@ vfb.get_instances('FBbt_00003748', return_dataframe=False)
1122
1122
  },
1123
1123
  {
1124
1124
  "id": "VFB_00101385",
1125
- "label": "[ME%28R%29 on JRC_FlyEM_Hemibrain](VFB_00101385)",
1125
+ "label": "[ME(R) on JRC_FlyEM_Hemibrain](VFB_00101385)",
1126
1126
  "tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
1127
1127
  "parent": "[medulla](FBbt_00003748)",
1128
1128
  "source": "",
@@ -1130,7 +1130,7 @@ vfb.get_instances('FBbt_00003748', return_dataframe=False)
1130
1130
  "template": "[JRCFIB2018Fum](VFB_00101384)",
1131
1131
  "dataset": "[JRC_FlyEM_Hemibrain painted domains](Xu2020roi)",
1132
1132
  "license": "",
1133
- "thumbnail": "[![ME%28R%29 on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
1133
+ "thumbnail": "[![ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
1134
1134
  },
1135
1135
  {
1136
1136
  "id": "VFB_00030810",
@@ -1152,7 +1152,7 @@ vfb.get_instances('FBbt_00003748', return_dataframe=False)
1152
1152
  "source": "",
1153
1153
  "source_id": "",
1154
1154
  "template": "[JFRC2](VFB_00017894)",
1155
- "dataset": "[BrainName neuropils on adult brain JFRC2 %28Jenett, Shinomya%29](JenettShinomya_BrainName)",
1155
+ "dataset": "[BrainName neuropils on adult brain JFRC2 (Jenett, Shinomya)](JenettShinomya_BrainName)",
1156
1156
  "license": "",
1157
1157
  "thumbnail": "[![medulla on adult brain template JFRC2 aligned to JFRC2](http://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/thumbnail.png 'medulla on adult brain template JFRC2 aligned to JFRC2')](VFB_00017894,VFB_00030624)"
1158
1158
  }
@@ -1234,7 +1234,7 @@ vfb.get_templates(return_dataframe=False)
1234
1234
  "name": "[JFRC2](VFB_00017894)",
1235
1235
  "tags": "Nervous_system|Adult",
1236
1236
  "thumbnail": "[![JFRC2](http://www.virtualflybrain.org/data/VFB/i/0001/7894/VFB_00017894/thumbnail.png 'JFRC2')](VFB_00017894)",
1237
- "dataset": "[FlyLight - GMR GAL4 collection %28Jenett2012%29](Jenett2012)",
1237
+ "dataset": "[FlyLight - GMR GAL4 collection (Jenett2012)](Jenett2012)",
1238
1238
  "license": "[CC-BY-NC-SA](VFBlicense_CC_BY_NC_SA_4_0)"
1239
1239
  },
1240
1240
  {
@@ -1252,7 +1252,7 @@ vfb.get_templates(return_dataframe=False)
1252
1252
  "name": "[L1 larval CNS ssTEM - Cardona/Janelia](VFB_00050000)",
1253
1253
  "tags": "Nervous_system|Larva",
1254
1254
  "thumbnail": "[![L1 larval CNS ssTEM - Cardona/Janelia](http://www.virtualflybrain.org/data/VFB/i/0005/0000/VFB_00050000/thumbnail.png 'L1 larval CNS ssTEM - Cardona/Janelia')](VFB_00050000)",
1255
- "dataset": "[Neurons involved in larval fast escape response - EM %28Ohyama2016%29](Ohyama2015)",
1255
+ "dataset": "[Neurons involved in larval fast escape response - EM (Ohyama2016)](Ohyama2015)",
1256
1256
  "license": "[CC_BY_SA](VFBlicense_CC_BY_SA_4_0)"
1257
1257
  },
1258
1258
  {
@@ -1261,7 +1261,7 @@ vfb.get_templates(return_dataframe=False)
1261
1261
  "name": "[L1 larval CNS ssTEM - Cardona/Janelia](VFB_00050000)",
1262
1262
  "tags": "Nervous_system|Larva",
1263
1263
  "thumbnail": "[![L1 larval CNS ssTEM - Cardona/Janelia](http://www.virtualflybrain.org/data/VFB/i/0005/0000/VFB_00050000/thumbnail.png 'L1 larval CNS ssTEM - Cardona/Janelia')](VFB_00050000)",
1264
- "dataset": "[larval hugin neurons - EM %28Schlegel2016%29](Schlegel2016)",
1264
+ "dataset": "[larval hugin neurons - EM (Schlegel2016)](Schlegel2016)",
1265
1265
  "license": "[CC_BY](VFBlicense_CC_BY_4_0)"
1266
1266
  },
1267
1267
  {
@@ -1270,7 +1270,7 @@ vfb.get_templates(return_dataframe=False)
1270
1270
  "name": "[L3 CNS template - Wood2018](VFB_00049000)",
1271
1271
  "tags": "Nervous_system|Larva",
1272
1272
  "thumbnail": "[![L3 CNS template - Wood2018](http://www.virtualflybrain.org/data/VFB/i/0004/9000/VFB_00049000/thumbnail.png 'L3 CNS template - Wood2018')](VFB_00049000)",
1273
- "dataset": "[L3 Larval CNS Template %28Truman2016%29](Truman2016)",
1273
+ "dataset": "[L3 Larval CNS Template (Truman2016)](Truman2016)",
1274
1274
  "license": "[CC_BY_SA](VFBlicense_CC_BY_SA_4_0)"
1275
1275
  },
1276
1276
  {
@@ -1279,7 +1279,7 @@ vfb.get_templates(return_dataframe=False)
1279
1279
  "name": "[COURT2018VNS](VFB_00100000)",
1280
1280
  "tags": "Nervous_system|Adult|Ganglion",
1281
1281
  "thumbnail": "[![COURT2018VNS](http://www.virtualflybrain.org/data/VFB/i/0010/0000/VFB_00100000/thumbnail.png 'COURT2018VNS')](VFB_00100000)",
1282
- "dataset": "[Adult VNS neuropils %28Court2017%29](Court2017)",
1282
+ "dataset": "[Adult VNS neuropils (Court2017)](Court2017)",
1283
1283
  "license": "[CC_BY_SA](VFBlicense_CC_BY_SA_4_0)"
1284
1284
  },
1285
1285
  {
@@ -1294,7 +1294,7 @@ vfb.get_templates(return_dataframe=False)
1294
1294
  {
1295
1295
  "id": "VFB_00110000",
1296
1296
  "order": 9,
1297
- "name": "[Adult Head %28McKellar2020%29](VFB_00110000)",
1297
+ "name": "[Adult Head (McKellar2020)](VFB_00110000)",
1298
1298
  "tags": "Adult|Anatomy",
1299
1299
  "thumbnail": "[![Adult Head (McKellar2020)](http://www.virtualflybrain.org/data/VFB/i/0011/0000/VFB_00110000/thumbnail.png 'Adult Head (McKellar2020)')](VFB_00110000)",
1300
1300
  "dataset": "[GAL4 lines from McKellar et al., 2020](McKellar2020)",
@@ -1303,7 +1303,7 @@ vfb.get_templates(return_dataframe=False)
1303
1303
  {
1304
1304
  "id": "VFB_00120000",
1305
1305
  "order": 10,
1306
- "name": "[Adult T1 Leg %28Kuan2020%29](VFB_00120000)",
1306
+ "name": "[Adult T1 Leg (Kuan2020)](VFB_00120000)",
1307
1307
  "tags": "Adult|Anatomy",
1308
1308
  "thumbnail": "[![Adult T1 Leg (Kuan2020)](http://www.virtualflybrain.org/data/VFB/i/0012/0000/VFB_00120000/thumbnail.png 'Adult T1 Leg (Kuan2020)')](VFB_00120000)",
1309
1309
  "dataset": "[Millimeter-scale imaging of a Drosophila leg at single-neuron resolution](Kuan2020)",
@@ -101,9 +101,9 @@ vfb.get_term_info('FBbt_00003748')
101
101
  },
102
102
  {
103
103
  "id": "VFB_00101385",
104
- "label": "[ME%28R%29 on JRC_FlyEM_Hemibrain](VFB_00101385)",
104
+ "label": "[ME(R) on JRC_FlyEM_Hemibrain](VFB_00101385)",
105
105
  "tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
106
- "thumbnail": "[![ME%28R%29 on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
106
+ "thumbnail": "[![ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
107
107
  },
108
108
  {
109
109
  "id": "VFB_00030810",
@@ -123,8 +123,8 @@ vfb.get_term_info('FBbt_00003748')
123
123
  "count": 4
124
124
  }
125
125
  ],
126
- "IsIndividual": false,
127
- "IsClass": true,
126
+ "IsIndividual": False,
127
+ "IsClass": True,
128
128
  "Examples": {
129
129
  "VFB_00101384": [
130
130
  {
@@ -171,7 +171,7 @@ vfb.get_term_info('FBbt_00003748')
171
171
  }
172
172
  ]
173
173
  },
174
- "IsTemplate": false,
174
+ "IsTemplate": False,
175
175
  "Synonyms": [
176
176
  {
177
177
  "label": "ME",
@@ -1102,7 +1102,7 @@ vfb.get_instances('FBbt_00003748', return_dataframe=False)
1102
1102
  },
1103
1103
  {
1104
1104
  "id": "VFB_00101385",
1105
- "label": "[ME%28R%29 on JRC_FlyEM_Hemibrain](VFB_00101385)",
1105
+ "label": "[ME(R) on JRC_FlyEM_Hemibrain](VFB_00101385)",
1106
1106
  "tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
1107
1107
  "parent": "[medulla](FBbt_00003748)",
1108
1108
  "source": "",
@@ -1110,7 +1110,7 @@ vfb.get_instances('FBbt_00003748', return_dataframe=False)
1110
1110
  "template": "[JRCFIB2018Fum](VFB_00101384)",
1111
1111
  "dataset": "[JRC_FlyEM_Hemibrain painted domains](Xu2020roi)",
1112
1112
  "license": "",
1113
- "thumbnail": "[![ME%28R%29 on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
1113
+ "thumbnail": "[![ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum](http://www.virtualflybrain.org/data/VFB/i/0010/1385/VFB_00101384/thumbnail.png 'ME(R) on JRC_FlyEM_Hemibrain aligned to JRCFIB2018Fum')](VFB_00101384,VFB_00101385)"
1114
1114
  },
1115
1115
  {
1116
1116
  "id": "VFB_00030810",
@@ -1132,7 +1132,7 @@ vfb.get_instances('FBbt_00003748', return_dataframe=False)
1132
1132
  "source": "",
1133
1133
  "source_id": "",
1134
1134
  "template": "[JFRC2](VFB_00017894)",
1135
- "dataset": "[BrainName neuropils on adult brain JFRC2 %28Jenett, Shinomya%29](JenettShinomya_BrainName)",
1135
+ "dataset": "[BrainName neuropils on adult brain JFRC2 (Jenett, Shinomya)](JenettShinomya_BrainName)",
1136
1136
  "license": "",
1137
1137
  "thumbnail": "[![medulla on adult brain template JFRC2 aligned to JFRC2](http://www.virtualflybrain.org/data/VFB/i/0003/0624/VFB_00017894/thumbnail.png 'medulla on adult brain template JFRC2 aligned to JFRC2')](VFB_00017894,VFB_00030624)"
1138
1138
  }
@@ -1214,7 +1214,7 @@ vfb.get_templates(return_dataframe=False)
1214
1214
  "name": "[JFRC2](VFB_00017894)",
1215
1215
  "tags": "Nervous_system|Adult",
1216
1216
  "thumbnail": "[![JFRC2](http://www.virtualflybrain.org/data/VFB/i/0001/7894/VFB_00017894/thumbnail.png 'JFRC2')](VFB_00017894)",
1217
- "dataset": "[FlyLight - GMR GAL4 collection %28Jenett2012%29](Jenett2012)",
1217
+ "dataset": "[FlyLight - GMR GAL4 collection (Jenett2012)](Jenett2012)",
1218
1218
  "license": "[CC-BY-NC-SA](VFBlicense_CC_BY_NC_SA_4_0)"
1219
1219
  },
1220
1220
  {
@@ -1232,7 +1232,7 @@ vfb.get_templates(return_dataframe=False)
1232
1232
  "name": "[L1 larval CNS ssTEM - Cardona/Janelia](VFB_00050000)",
1233
1233
  "tags": "Nervous_system|Larva",
1234
1234
  "thumbnail": "[![L1 larval CNS ssTEM - Cardona/Janelia](http://www.virtualflybrain.org/data/VFB/i/0005/0000/VFB_00050000/thumbnail.png 'L1 larval CNS ssTEM - Cardona/Janelia')](VFB_00050000)",
1235
- "dataset": "[Neurons involved in larval fast escape response - EM %28Ohyama2016%29](Ohyama2015)",
1235
+ "dataset": "[Neurons involved in larval fast escape response - EM (Ohyama2016)](Ohyama2015)",
1236
1236
  "license": "[CC_BY_SA](VFBlicense_CC_BY_SA_4_0)"
1237
1237
  },
1238
1238
  {
@@ -1241,7 +1241,7 @@ vfb.get_templates(return_dataframe=False)
1241
1241
  "name": "[L1 larval CNS ssTEM - Cardona/Janelia](VFB_00050000)",
1242
1242
  "tags": "Nervous_system|Larva",
1243
1243
  "thumbnail": "[![L1 larval CNS ssTEM - Cardona/Janelia](http://www.virtualflybrain.org/data/VFB/i/0005/0000/VFB_00050000/thumbnail.png 'L1 larval CNS ssTEM - Cardona/Janelia')](VFB_00050000)",
1244
- "dataset": "[larval hugin neurons - EM %28Schlegel2016%29](Schlegel2016)",
1244
+ "dataset": "[larval hugin neurons - EM (Schlegel2016)](Schlegel2016)",
1245
1245
  "license": "[CC_BY](VFBlicense_CC_BY_4_0)"
1246
1246
  },
1247
1247
  {
@@ -1250,7 +1250,7 @@ vfb.get_templates(return_dataframe=False)
1250
1250
  "name": "[L3 CNS template - Wood2018](VFB_00049000)",
1251
1251
  "tags": "Nervous_system|Larva",
1252
1252
  "thumbnail": "[![L3 CNS template - Wood2018](http://www.virtualflybrain.org/data/VFB/i/0004/9000/VFB_00049000/thumbnail.png 'L3 CNS template - Wood2018')](VFB_00049000)",
1253
- "dataset": "[L3 Larval CNS Template %28Truman2016%29](Truman2016)",
1253
+ "dataset": "[L3 Larval CNS Template (Truman2016)](Truman2016)",
1254
1254
  "license": "[CC_BY_SA](VFBlicense_CC_BY_SA_4_0)"
1255
1255
  },
1256
1256
  {
@@ -1259,7 +1259,7 @@ vfb.get_templates(return_dataframe=False)
1259
1259
  "name": "[COURT2018VNS](VFB_00100000)",
1260
1260
  "tags": "Nervous_system|Adult|Ganglion",
1261
1261
  "thumbnail": "[![COURT2018VNS](http://www.virtualflybrain.org/data/VFB/i/0010/0000/VFB_00100000/thumbnail.png 'COURT2018VNS')](VFB_00100000)",
1262
- "dataset": "[Adult VNS neuropils %28Court2017%29](Court2017)",
1262
+ "dataset": "[Adult VNS neuropils (Court2017)](Court2017)",
1263
1263
  "license": "[CC_BY_SA](VFBlicense_CC_BY_SA_4_0)"
1264
1264
  },
1265
1265
  {
@@ -1274,7 +1274,7 @@ vfb.get_templates(return_dataframe=False)
1274
1274
  {
1275
1275
  "id": "VFB_00110000",
1276
1276
  "order": 9,
1277
- "name": "[Adult Head %28McKellar2020%29](VFB_00110000)",
1277
+ "name": "[Adult Head (McKellar2020)](VFB_00110000)",
1278
1278
  "tags": "Adult|Anatomy",
1279
1279
  "thumbnail": "[![Adult Head (McKellar2020)](http://www.virtualflybrain.org/data/VFB/i/0011/0000/VFB_00110000/thumbnail.png 'Adult Head (McKellar2020)')](VFB_00110000)",
1280
1280
  "dataset": "[GAL4 lines from McKellar et al., 2020](McKellar2020)",
@@ -1283,7 +1283,7 @@ vfb.get_templates(return_dataframe=False)
1283
1283
  {
1284
1284
  "id": "VFB_00120000",
1285
1285
  "order": 10,
1286
- "name": "[Adult T1 Leg %28Kuan2020%29](VFB_00120000)",
1286
+ "name": "[Adult T1 Leg (Kuan2020)](VFB_00120000)",
1287
1287
  "tags": "Adult|Anatomy",
1288
1288
  "thumbnail": "[![Adult T1 Leg (Kuan2020)](http://www.virtualflybrain.org/data/VFB/i/0012/0000/VFB_00120000/thumbnail.png 'Adult T1 Leg (Kuan2020)')](VFB_00120000)",
1289
1289
  "dataset": "[Millimeter-scale imaging of a Drosophila leg at single-neuron resolution](Kuan2020)",
@@ -1292,4 +1292,4 @@ vfb.get_templates(return_dataframe=False)
1292
1292
  ],
1293
1293
  "count": 10
1294
1294
  }
1295
- ```
1295
+ ```
@@ -3,7 +3,7 @@ from os import path
3
3
 
4
4
  here = path.abspath(path.dirname(__file__))
5
5
 
6
- __version__ = "0.3.4"
6
+ __version__ = "0.4.1"
7
7
 
8
8
  # Get the long description from the README file
9
9
  with open(path.join(here, 'README.md')) as f:
@@ -27,7 +27,35 @@ def extract_code_blocks(readme_path):
27
27
  # Look for vfb.* calls and extract them
28
28
  vfb_calls = re.findall(r'(vfb\.[^)]*\))', block)
29
29
  if vfb_calls:
30
- processed_python_blocks.extend(vfb_calls)
30
+ # Add force_refresh=True to each call to ensure fresh data in tests
31
+ # Exceptions:
32
+ # - get_templates() doesn't support force_refresh (no SOLR cache)
33
+ # - Performance test terms (FBbt_00003748, VFB_00101567) should use cache
34
+ for call in vfb_calls:
35
+ # Check if this is get_templates() - if so, don't add force_refresh
36
+ if 'get_templates' in call:
37
+ processed_python_blocks.append(call)
38
+ continue
39
+
40
+ # Check if this call uses performance test terms - skip force_refresh for those
41
+ if 'FBbt_00003748' in call or 'VFB_00101567' in call:
42
+ processed_python_blocks.append(call)
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)'
52
+ else:
53
+ # Has parameters: vfb.function(param1, param2)
54
+ modified_call = call[:-1] + ', force_refresh=True)'
55
+ processed_python_blocks.append(modified_call)
56
+ else:
57
+ # Shouldn't happen, but include original call if no parentheses
58
+ processed_python_blocks.append(call)
31
59
 
32
60
  # Process JSON blocks
33
61
  processed_json_blocks = []
@@ -524,6 +524,64 @@ class TermInfoQueriesTest(unittest.TestCase):
524
524
  self.assertFalse("filemeta" in serialized)
525
525
  self.assertFalse("template" in serialized)
526
526
 
527
+ def test_term_info_performance(self):
528
+ """
529
+ Performance test for specific term info queries.
530
+ Tests the execution time for FBbt_00003748 and VFB_00101567.
531
+ """
532
+ import vfbquery as vfb
533
+
534
+ # Test performance for FBbt_00003748 (mushroom body)
535
+ start_time = time.time()
536
+ result_1 = vfb.get_term_info('FBbt_00003748')
537
+ duration_1 = time.time() - start_time
538
+
539
+ # Test performance for VFB_00101567 (individual anatomy)
540
+ start_time = time.time()
541
+ result_2 = vfb.get_term_info('VFB_00101567')
542
+ duration_2 = time.time() - start_time
543
+
544
+ # Print performance metrics for GitHub Actions logs
545
+ print(f"\n" + "="*50)
546
+ print(f"Performance Test Results:")
547
+ print(f"="*50)
548
+ print(f"FBbt_00003748 query took: {duration_1:.4f} seconds")
549
+ print(f"VFB_00101567 query took: {duration_2:.4f} seconds")
550
+ print(f"Total time for both queries: {duration_1 + duration_2:.4f} seconds")
551
+
552
+ # Performance categories
553
+ total_time = duration_1 + duration_2
554
+ if total_time < 1.5:
555
+ performance_level = "🟢 Excellent (< 1.5 seconds)"
556
+ elif total_time < 3.0:
557
+ performance_level = "🟡 Good (1.5-3 seconds)"
558
+ elif total_time < 6.0:
559
+ performance_level = "🟠 Acceptable (3-6 seconds)"
560
+ else:
561
+ performance_level = "🔴 Slow (> 6 seconds)"
562
+
563
+ print(f"Performance Level: {performance_level}")
564
+ print(f"="*50)
565
+
566
+ # Basic assertions to ensure the queries succeeded
567
+ self.assertIsNotNone(result_1, "FBbt_00003748 query returned None")
568
+ self.assertIsNotNone(result_2, "VFB_00101567 query returned None")
569
+
570
+ # Performance assertions - fail if queries take too long
571
+ # These thresholds are based on observed performance characteristics
572
+ max_single_query_time = 3.0 # seconds (increased from 2.0 to account for SOLR cache overhead)
573
+ max_total_time = 6.0 # seconds (2 queries * 3 seconds each)
574
+
575
+ self.assertLess(duration_1, max_single_query_time,
576
+ f"FBbt_00003748 query took {duration_1:.4f}s, exceeding {max_single_query_time}s threshold")
577
+ self.assertLess(duration_2, max_single_query_time,
578
+ f"VFB_00101567 query took {duration_2:.4f}s, exceeding {max_single_query_time}s threshold")
579
+ self.assertLess(duration_1 + duration_2, max_total_time,
580
+ f"Total query time {duration_1 + duration_2:.4f}s exceeds {max_total_time}s threshold")
581
+
582
+ # Log success
583
+ print("Performance test completed successfully!")
584
+
527
585
 
528
586
  class TestVariable:
529
587
 
@@ -0,0 +1,173 @@
1
+ """
2
+ Test VFBquery default caching functionality.
3
+
4
+ These tests ensure that the default 3-month TTL, 2GB memory caching
5
+ system works correctly and provides expected performance benefits.
6
+ """
7
+
8
+ import unittest
9
+ import os
10
+ import time
11
+ from unittest.mock import MagicMock
12
+ import sys
13
+
14
+ # Mock vispy imports before importing vfbquery
15
+ for module in ['vispy', 'vispy.scene', 'vispy.util', 'vispy.util.fonts',
16
+ 'vispy.util.fonts._triage', 'vispy.util.fonts._quartz',
17
+ 'vispy.ext', 'vispy.ext.cocoapy', 'navis', 'navis.plotting',
18
+ 'navis.plotting.vispy', 'navis.plotting.vispy.viewer']:
19
+ sys.modules[module] = MagicMock()
20
+
21
+ # Set environment variables
22
+ os.environ.update({
23
+ 'MPLBACKEND': 'Agg',
24
+ 'VISPY_GL_LIB': 'osmesa',
25
+ 'VISPY_USE_EGL': '0',
26
+ 'VFBQUERY_CACHE_ENABLED': 'true'
27
+ })
28
+
29
+
30
+ class TestDefaultCaching(unittest.TestCase):
31
+ """Test default caching behavior in VFBquery."""
32
+
33
+ def setUp(self):
34
+ """Set up test environment."""
35
+ # Clear any existing cache before each test
36
+ try:
37
+ import vfbquery
38
+ if hasattr(vfbquery, 'clear_vfbquery_cache'):
39
+ vfbquery.clear_vfbquery_cache()
40
+ except ImportError:
41
+ pass
42
+
43
+ def test_caching_enabled_by_default(self):
44
+ """Test that caching is automatically enabled when importing vfbquery."""
45
+ import vfbquery
46
+
47
+ # Check that caching functions are available
48
+ self.assertTrue(hasattr(vfbquery, 'get_vfbquery_cache_stats'))
49
+ self.assertTrue(hasattr(vfbquery, 'enable_vfbquery_caching'))
50
+
51
+ # Check that cache stats show caching is enabled
52
+ stats = vfbquery.get_vfbquery_cache_stats()
53
+ self.assertTrue(stats['enabled'])
54
+ self.assertEqual(stats['cache_ttl_days'], 90.0) # 3 months
55
+ self.assertEqual(stats['memory_cache_limit_mb'], 2048) # 2GB
56
+
57
+ def test_cache_performance_improvement(self):
58
+ """Test that caching provides performance improvement."""
59
+ import vfbquery
60
+
61
+ test_term = 'FBbt_00003748' # medulla
62
+
63
+ # First call (cold - populates cache)
64
+ start_time = time.time()
65
+ result1 = vfbquery.get_term_info(test_term)
66
+ cold_time = time.time() - start_time
67
+
68
+ # Verify we got a result
69
+ self.assertIsNotNone(result1)
70
+ if result1 is not None:
71
+ self.assertIn('Name', result1)
72
+
73
+ # Second call (warm - should hit cache)
74
+ start_time = time.time()
75
+ result2 = vfbquery.get_term_info(test_term)
76
+ warm_time = time.time() - start_time
77
+
78
+ # Verify cache hit
79
+ self.assertIsNotNone(result2)
80
+ self.assertEqual(result1, result2) # Should be identical
81
+
82
+ # Verify performance improvement (warm should be faster)
83
+ self.assertLess(warm_time, cold_time)
84
+
85
+ # Check cache statistics
86
+ stats = vfbquery.get_vfbquery_cache_stats()
87
+ self.assertGreater(stats['hits'], 0) # Should have cache hits
88
+ self.assertGreater(stats['hit_rate_percent'], 0) # Positive hit rate
89
+
90
+ def test_cache_statistics_tracking(self):
91
+ """Test that cache statistics are properly tracked."""
92
+ import vfbquery
93
+
94
+ # Clear cache and get fresh baseline
95
+ vfbquery.clear_vfbquery_cache()
96
+ initial_stats = vfbquery.get_vfbquery_cache_stats()
97
+ initial_items = initial_stats['memory_cache_items']
98
+ initial_total = initial_stats['misses'] + initial_stats['hits']
99
+
100
+ # Make a unique query that won't be cached
101
+ unique_term = 'FBbt_00005106' # Use a different term
102
+ result = vfbquery.get_term_info(unique_term)
103
+ self.assertIsNotNone(result)
104
+
105
+ # Check that stats were updated
106
+ updated_stats = vfbquery.get_vfbquery_cache_stats()
107
+ updated_total = updated_stats['misses'] + updated_stats['hits']
108
+
109
+ self.assertGreaterEqual(updated_stats['memory_cache_items'], initial_items)
110
+ self.assertGreater(updated_total, initial_total) # More total requests
111
+ self.assertGreaterEqual(updated_stats['memory_cache_size_mb'], 0)
112
+
113
+ def test_memory_size_tracking(self):
114
+ """Test that memory usage is properly tracked."""
115
+ import vfbquery
116
+
117
+ # Clear cache to start fresh
118
+ vfbquery.clear_vfbquery_cache()
119
+
120
+ # Cache a few different terms
121
+ test_terms = ['FBbt_00003748', 'VFB_00101567']
122
+
123
+ for term in test_terms:
124
+ vfbquery.get_term_info(term)
125
+ stats = vfbquery.get_vfbquery_cache_stats()
126
+
127
+ # Memory size should be tracked
128
+ self.assertGreaterEqual(stats['memory_cache_size_mb'], 0)
129
+ self.assertLessEqual(stats['memory_cache_size_mb'], stats['memory_cache_limit_mb'])
130
+
131
+ def test_cache_ttl_configuration(self):
132
+ """Test that cache TTL is properly configured."""
133
+ import vfbquery
134
+
135
+ stats = vfbquery.get_vfbquery_cache_stats()
136
+
137
+ # Should be configured for 3 months (90 days)
138
+ self.assertEqual(stats['cache_ttl_days'], 90.0)
139
+ self.assertEqual(stats['cache_ttl_hours'], 2160) # 90 * 24
140
+
141
+ def test_transparent_caching(self):
142
+ """Test that regular VFBquery functions are transparently cached."""
143
+ import vfbquery
144
+
145
+ # Test that get_term_info and get_instances are using cached versions
146
+ test_term = 'FBbt_00003748'
147
+
148
+ # These should work with caching transparently
149
+ term_info = vfbquery.get_term_info(test_term)
150
+ self.assertIsNotNone(term_info)
151
+
152
+ instances = vfbquery.get_instances(test_term, limit=5)
153
+ self.assertIsNotNone(instances)
154
+
155
+ # Cache should show activity
156
+ stats = vfbquery.get_vfbquery_cache_stats()
157
+ self.assertGreater(stats['misses'] + stats['hits'], 0)
158
+
159
+ def test_cache_disable_environment_variable(self):
160
+ """Test that caching can be disabled via environment variable."""
161
+ # This test would need to be run in a separate process to test
162
+ # the environment variable behavior at import time
163
+ # For now, just verify the current state respects the env var
164
+
165
+ cache_enabled = os.getenv('VFBQUERY_CACHE_ENABLED', 'true').lower()
166
+ if cache_enabled not in ('false', '0', 'no', 'off'):
167
+ import vfbquery
168
+ stats = vfbquery.get_vfbquery_cache_stats()
169
+ self.assertTrue(stats['enabled'])
170
+
171
+
172
+ if __name__ == '__main__':
173
+ unittest.main(verbosity=2)
@@ -113,7 +113,12 @@ def remove_nulls(data):
113
113
  new_dict[k] = cleaned
114
114
  return new_dict
115
115
  elif isinstance(data, list):
116
- return [remove_nulls(item) for item in data if remove_nulls(item) not in [None, {}, []]]
116
+ filtered = []
117
+ for item in data:
118
+ cleaned_item = remove_nulls(item)
119
+ if cleaned_item is not None and cleaned_item != {} and cleaned_item != []:
120
+ filtered.append(cleaned_item)
121
+ return filtered
117
122
  return data
118
123
 
119
124
  def main():
@@ -0,0 +1,86 @@
1
+ from .vfb_queries import *
2
+ from .solr_result_cache import get_solr_cache
3
+
4
+ # Caching enhancements (optional import - don't break if dependencies missing)
5
+ try:
6
+ from .cache_enhancements import (
7
+ enable_vfbquery_caching,
8
+ disable_vfbquery_caching,
9
+ clear_vfbquery_cache,
10
+ get_vfbquery_cache_stats,
11
+ set_cache_ttl,
12
+ set_cache_memory_limit,
13
+ set_cache_max_items,
14
+ enable_disk_cache,
15
+ disable_disk_cache,
16
+ get_cache_config,
17
+ CacheConfig
18
+ )
19
+ from .cached_functions import (
20
+ get_term_info_cached,
21
+ get_instances_cached,
22
+ patch_vfbquery_with_caching,
23
+ unpatch_vfbquery_caching
24
+ )
25
+ __caching_available__ = True
26
+
27
+ # Enable caching by default with 3-month TTL and 2GB memory cache
28
+ import os
29
+
30
+ # Check if caching should be disabled via environment variable
31
+ cache_disabled = os.getenv('VFBQUERY_CACHE_ENABLED', 'true').lower() in ('false', '0', 'no', 'off')
32
+
33
+ if not cache_disabled:
34
+ # Enable caching with VFB_connect-like defaults
35
+ enable_vfbquery_caching(
36
+ cache_ttl_hours=2160, # 3 months (90 days)
37
+ memory_cache_size_mb=2048, # 2GB memory cache
38
+ max_items=10000, # Max 10k items as safeguard
39
+ disk_cache_enabled=True # Persistent across sessions
40
+ )
41
+
42
+ # Automatically patch existing functions for transparent caching
43
+ patch_vfbquery_with_caching()
44
+
45
+ print("VFBquery: Caching enabled by default (3-month TTL, 2GB memory)")
46
+ print(" Disable with: export VFBQUERY_CACHE_ENABLED=false")
47
+
48
+ except ImportError:
49
+ __caching_available__ = False
50
+ print("VFBquery: Caching not available (dependencies missing)")
51
+
52
+ # Convenience function for clearing SOLR cache entries
53
+ def clear_solr_cache(query_type: str, term_id: str) -> bool:
54
+ """
55
+ Clear a specific SOLR cache entry to force refresh
56
+
57
+ Args:
58
+ query_type: Type of query ('term_info', 'instances', etc.)
59
+ term_id: Term identifier (e.g., 'FBbt_00003748')
60
+
61
+ Returns:
62
+ True if successfully cleared, False otherwise
63
+
64
+ Example:
65
+ >>> import vfbquery as vfb
66
+ >>> vfb.clear_solr_cache('term_info', 'FBbt_00003748')
67
+ >>> result = vfb.get_term_info('FBbt_00003748') # Will fetch fresh data
68
+ """
69
+ cache = get_solr_cache()
70
+ return cache.clear_cache_entry(query_type, term_id)
71
+
72
+ # SOLR-based result caching (experimental - for cold start optimization)
73
+ try:
74
+ from .solr_cache_integration import (
75
+ enable_solr_result_caching,
76
+ disable_solr_result_caching,
77
+ warmup_solr_cache,
78
+ get_solr_cache_stats as get_solr_cache_stats_func,
79
+ cleanup_solr_cache
80
+ )
81
+ __solr_caching_available__ = True
82
+ except ImportError:
83
+ __solr_caching_available__ = False
84
+
85
+ # Version information
86
+ __version__ = "0.4.1"