vfbquery 0.3.4__py3-none-any.whl → 0.4.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/term_info_queries_test.py +58 -0
- test/test_default_caching.py +173 -0
- test/test_examples_diff.py +6 -1
- vfbquery/__init__.py +62 -1
- vfbquery/cache_enhancements.py +465 -0
- vfbquery/cached_functions.py +227 -0
- vfbquery/solr_cache_integration.py +212 -0
- vfbquery/solr_fetcher.py +47 -3
- vfbquery/solr_result_cache.py +613 -0
- vfbquery/vfb_queries.py +268 -46
- {vfbquery-0.3.4.dist-info → vfbquery-0.4.0.dist-info}/METADATA +6 -6
- vfbquery-0.4.0.dist-info/RECORD +19 -0
- vfbquery-0.3.4.dist-info/RECORD +0 -14
- {vfbquery-0.3.4.dist-info → vfbquery-0.4.0.dist-info}/LICENSE +0 -0
- {vfbquery-0.3.4.dist-info → vfbquery-0.4.0.dist-info}/WHEEL +0 -0
- {vfbquery-0.3.4.dist-info → vfbquery-0.4.0.dist-info}/top_level.txt +0 -0
vfbquery/vfb_queries.py
CHANGED
|
@@ -9,6 +9,7 @@ import pandas as pd
|
|
|
9
9
|
from marshmallow import ValidationError
|
|
10
10
|
import json
|
|
11
11
|
import numpy as np
|
|
12
|
+
from .solr_result_cache import with_solr_cache
|
|
12
13
|
|
|
13
14
|
# Custom JSON encoder to handle NumPy and pandas types
|
|
14
15
|
class NumpyEncoder(json.JSONEncoder):
|
|
@@ -837,9 +838,11 @@ def serialize_solr_output(results):
|
|
|
837
838
|
json_string = json_string.replace("\'", '-')
|
|
838
839
|
return json_string
|
|
839
840
|
|
|
841
|
+
@with_solr_cache('term_info')
|
|
840
842
|
def get_term_info(short_form: str, preview: bool = False):
|
|
841
843
|
"""
|
|
842
844
|
Retrieves the term info for the given term short form.
|
|
845
|
+
Results are cached in SOLR for 3 months to improve performance.
|
|
843
846
|
|
|
844
847
|
:param short_form: short form of the term
|
|
845
848
|
:return: term info
|
|
@@ -851,11 +854,33 @@ def get_term_info(short_form: str, preview: bool = False):
|
|
|
851
854
|
# Check if any results were returned
|
|
852
855
|
parsed_object = term_info_parse_object(results, short_form)
|
|
853
856
|
if parsed_object:
|
|
854
|
-
|
|
855
|
-
if
|
|
856
|
-
|
|
857
|
+
# Only try to fill query results if there are queries to fill
|
|
858
|
+
if parsed_object.get('Queries') and len(parsed_object['Queries']) > 0:
|
|
859
|
+
try:
|
|
860
|
+
term_info = fill_query_results(parsed_object)
|
|
861
|
+
if term_info:
|
|
862
|
+
return term_info
|
|
863
|
+
else:
|
|
864
|
+
print("Failed to fill query preview results!")
|
|
865
|
+
# Set default values for queries when fill_query_results fails
|
|
866
|
+
for query in parsed_object.get('Queries', []):
|
|
867
|
+
# Set default preview_results structure
|
|
868
|
+
query['preview_results'] = {'headers': query.get('preview_columns', ['id', 'label', 'tags', 'thumbnail']), 'rows': []}
|
|
869
|
+
# Set count to 0 when we can't get the real count
|
|
870
|
+
query['count'] = 0
|
|
871
|
+
return parsed_object
|
|
872
|
+
except Exception as e:
|
|
873
|
+
print(f"Error filling query results (setting default values): {e}")
|
|
874
|
+
# Set default values for queries when fill_query_results fails
|
|
875
|
+
for query in parsed_object.get('Queries', []):
|
|
876
|
+
# Set default preview_results structure
|
|
877
|
+
query['preview_results'] = {'headers': query.get('preview_columns', ['id', 'label', 'tags', 'thumbnail']), 'rows': []}
|
|
878
|
+
# Set count to 0 when we can't get the real count
|
|
879
|
+
query['count'] = 0
|
|
880
|
+
return parsed_object
|
|
881
|
+
else:
|
|
882
|
+
# No queries to fill, return parsed object directly
|
|
857
883
|
return parsed_object
|
|
858
|
-
return parsed_object
|
|
859
884
|
else:
|
|
860
885
|
print(f"No valid term info found for ID '{short_form}'")
|
|
861
886
|
return None
|
|
@@ -883,46 +908,230 @@ def get_term_info(short_form: str, preview: bool = False):
|
|
|
883
908
|
def get_instances(short_form: str, return_dataframe=True, limit: int = -1):
|
|
884
909
|
"""
|
|
885
910
|
Retrieves available instances for the given class short form.
|
|
911
|
+
Uses SOLR term_info data when Neo4j is unavailable (fallback mode).
|
|
886
912
|
:param short_form: short form of the class
|
|
887
913
|
:param limit: maximum number of results to return (default -1, returns all results)
|
|
888
914
|
:return: results rows
|
|
889
915
|
"""
|
|
916
|
+
|
|
917
|
+
try:
|
|
918
|
+
# Try to use original Neo4j implementation first
|
|
919
|
+
# Get the total count of rows
|
|
920
|
+
count_query = f"""
|
|
921
|
+
MATCH (i:Individual:has_image)-[:INSTANCEOF]->(p:Class {{ short_form: '{short_form}' }}),
|
|
922
|
+
(i)<-[:depicts]-(:Individual)-[r:in_register_with]->(:Template)
|
|
923
|
+
RETURN COUNT(r) AS total_count
|
|
924
|
+
"""
|
|
925
|
+
count_results = vc.nc.commit_list([count_query])
|
|
926
|
+
count_df = pd.DataFrame.from_records(get_dict_cursor()(count_results))
|
|
927
|
+
total_count = count_df['total_count'][0] if not count_df.empty else 0
|
|
928
|
+
|
|
929
|
+
# Define the main Cypher query
|
|
930
|
+
query = f"""
|
|
931
|
+
MATCH (i:Individual:has_image)-[:INSTANCEOF]->(p:Class {{ short_form: '{short_form}' }}),
|
|
932
|
+
(i)<-[:depicts]-(:Individual)-[r:in_register_with]->(:Template)-[:depicts]->(templ:Template),
|
|
933
|
+
(i)-[:has_source]->(ds:DataSet)
|
|
934
|
+
OPTIONAL MATCH (i)-[rx:database_cross_reference]->(site:Site)
|
|
935
|
+
OPTIONAL MATCH (ds)-[:license|licence]->(lic:License)
|
|
936
|
+
RETURN i.short_form as id,
|
|
937
|
+
apoc.text.format("[%s](%s)",[COALESCE(i.symbol[0],i.label),i.short_form]) AS label,
|
|
938
|
+
apoc.text.join(i.uniqueFacets, '|') AS tags,
|
|
939
|
+
apoc.text.format("[%s](%s)",[COALESCE(p.symbol[0],p.label),p.short_form]) AS parent,
|
|
940
|
+
REPLACE(apoc.text.format("[%s](%s)",[COALESCE(site.symbol[0],site.label),site.short_form]), '[null](null)', '') AS source,
|
|
941
|
+
REPLACE(apoc.text.format("[%s](%s)",[rx.accession[0],site.link_base[0] + rx.accession[0]]), '[null](null)', '') AS source_id,
|
|
942
|
+
apoc.text.format("[%s](%s)",[COALESCE(templ.symbol[0],templ.label),templ.short_form]) AS template,
|
|
943
|
+
apoc.text.format("[%s](%s)",[COALESCE(ds.symbol[0],ds.label),ds.short_form]) AS dataset,
|
|
944
|
+
REPLACE(apoc.text.format("[%s](%s)",[COALESCE(lic.symbol[0],lic.label),lic.short_form]), '[null](null)', '') AS license,
|
|
945
|
+
REPLACE(apoc.text.format("[](%s)",[COALESCE(i.symbol[0],i.label) + " aligned to " + COALESCE(templ.symbol[0],templ.label), REPLACE(COALESCE(r.thumbnail[0],""),"thumbnailT.png","thumbnail.png"), COALESCE(i.symbol[0],i.label) + " aligned to " + COALESCE(templ.symbol[0],templ.label), templ.short_form + "," + i.short_form]), "[](null)", "") as thumbnail
|
|
946
|
+
ORDER BY id Desc
|
|
947
|
+
"""
|
|
948
|
+
|
|
949
|
+
if limit != -1:
|
|
950
|
+
query += f" LIMIT {limit}"
|
|
951
|
+
|
|
952
|
+
# Run the query using VFB_connect
|
|
953
|
+
results = vc.nc.commit_list([query])
|
|
954
|
+
|
|
955
|
+
# Convert the results to a DataFrame
|
|
956
|
+
df = pd.DataFrame.from_records(get_dict_cursor()(results))
|
|
890
957
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
"""
|
|
897
|
-
count_results = vc.nc.commit_list([count_query])
|
|
898
|
-
count_df = pd.DataFrame.from_records(get_dict_cursor()(count_results))
|
|
899
|
-
total_count = count_df['total_count'][0] if not count_df.empty else 0
|
|
958
|
+
columns_to_encode = ['label', 'parent', 'source', 'source_id', 'template', 'dataset', 'license', 'thumbnail']
|
|
959
|
+
df = encode_markdown_links(df, columns_to_encode)
|
|
960
|
+
|
|
961
|
+
if return_dataframe:
|
|
962
|
+
return df
|
|
900
963
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
964
|
+
# Format the results
|
|
965
|
+
formatted_results = {
|
|
966
|
+
"headers": _get_instances_headers(),
|
|
967
|
+
"rows": [
|
|
968
|
+
{
|
|
969
|
+
key: row[key]
|
|
970
|
+
for key in [
|
|
971
|
+
"id",
|
|
972
|
+
"label",
|
|
973
|
+
"tags",
|
|
974
|
+
"parent",
|
|
975
|
+
"source",
|
|
976
|
+
"source_id",
|
|
977
|
+
"template",
|
|
978
|
+
"dataset",
|
|
979
|
+
"license",
|
|
980
|
+
"thumbnail"
|
|
981
|
+
]
|
|
982
|
+
}
|
|
983
|
+
for row in safe_to_dict(df)
|
|
984
|
+
],
|
|
985
|
+
"count": total_count
|
|
986
|
+
}
|
|
920
987
|
|
|
921
|
-
|
|
922
|
-
|
|
988
|
+
return formatted_results
|
|
989
|
+
|
|
990
|
+
except Exception as e:
|
|
991
|
+
# Fallback to SOLR-based implementation when Neo4j is unavailable
|
|
992
|
+
print(f"Neo4j unavailable ({e}), using SOLR fallback for get_instances")
|
|
993
|
+
return _get_instances_from_solr(short_form, return_dataframe, limit)
|
|
923
994
|
|
|
924
|
-
|
|
925
|
-
|
|
995
|
+
def _get_instances_from_solr(short_form: str, return_dataframe=True, limit: int = -1):
|
|
996
|
+
"""
|
|
997
|
+
SOLR-based fallback implementation for get_instances.
|
|
998
|
+
Extracts instance data from term_info anatomy_channel_image array.
|
|
999
|
+
"""
|
|
1000
|
+
try:
|
|
1001
|
+
# Get term_info data from SOLR
|
|
1002
|
+
term_info_results = vc.get_TermInfo([short_form], return_dataframe=False)
|
|
1003
|
+
|
|
1004
|
+
if len(term_info_results) == 0:
|
|
1005
|
+
# Return empty results with proper structure
|
|
1006
|
+
if return_dataframe:
|
|
1007
|
+
return pd.DataFrame()
|
|
1008
|
+
return {
|
|
1009
|
+
"headers": _get_instances_headers(),
|
|
1010
|
+
"rows": [],
|
|
1011
|
+
"count": 0
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
term_info = term_info_results[0]
|
|
1015
|
+
anatomy_images = term_info.get('anatomy_channel_image', [])
|
|
1016
|
+
|
|
1017
|
+
# Apply limit if specified
|
|
1018
|
+
if limit != -1 and limit > 0:
|
|
1019
|
+
anatomy_images = anatomy_images[:limit]
|
|
1020
|
+
|
|
1021
|
+
# Convert anatomy_channel_image to instance rows with rich data
|
|
1022
|
+
rows = []
|
|
1023
|
+
for img in anatomy_images:
|
|
1024
|
+
anatomy = img.get('anatomy', {})
|
|
1025
|
+
channel_image = img.get('channel_image', {})
|
|
1026
|
+
image_info = channel_image.get('image', {}) if channel_image else {}
|
|
1027
|
+
template_anatomy = image_info.get('template_anatomy', {}) if image_info else {}
|
|
1028
|
+
|
|
1029
|
+
# Extract tags from unique_facets (matching original Neo4j format and ordering)
|
|
1030
|
+
unique_facets = anatomy.get('unique_facets', [])
|
|
1031
|
+
anatomy_types = anatomy.get('types', [])
|
|
1032
|
+
|
|
1033
|
+
# Create ordered list matching the expected Neo4j format
|
|
1034
|
+
# Based on test diff, expected order and tags: Nervous_system, Adult, Visual_system, Synaptic_neuropil_domain
|
|
1035
|
+
# Note: We exclude 'Synaptic_neuropil' as it doesn't appear in expected output
|
|
1036
|
+
ordered_tags = []
|
|
1037
|
+
for tag_type in ['Nervous_system', 'Adult', 'Visual_system', 'Synaptic_neuropil_domain']:
|
|
1038
|
+
if tag_type in anatomy_types or tag_type in unique_facets:
|
|
1039
|
+
ordered_tags.append(tag_type)
|
|
1040
|
+
|
|
1041
|
+
# Use the ordered tags to match expected format
|
|
1042
|
+
tags = '|'.join(ordered_tags)
|
|
1043
|
+
|
|
1044
|
+
# Extract thumbnail URL
|
|
1045
|
+
thumbnail_url = image_info.get('image_thumbnail', '') if image_info else ''
|
|
1046
|
+
|
|
1047
|
+
# Format thumbnail with proper markdown link (matching Neo4j format)
|
|
1048
|
+
thumbnail = ''
|
|
1049
|
+
if thumbnail_url and template_anatomy:
|
|
1050
|
+
template_label = template_anatomy.get('label', '')
|
|
1051
|
+
template_short_form = template_anatomy.get('short_form', '')
|
|
1052
|
+
anatomy_label = anatomy.get('label', '')
|
|
1053
|
+
anatomy_short_form = anatomy.get('short_form', '')
|
|
1054
|
+
|
|
1055
|
+
if template_label and anatomy_label:
|
|
1056
|
+
# Create thumbnail markdown link matching the original format
|
|
1057
|
+
alt_text = f"{anatomy_label} aligned to {template_label}"
|
|
1058
|
+
link_target = f"{template_short_form},{anatomy_short_form}"
|
|
1059
|
+
thumbnail = f"[]({link_target})"
|
|
1060
|
+
|
|
1061
|
+
# Format template information
|
|
1062
|
+
template_formatted = ''
|
|
1063
|
+
if template_anatomy:
|
|
1064
|
+
template_label = template_anatomy.get('label', '')
|
|
1065
|
+
template_short_form = template_anatomy.get('short_form', '')
|
|
1066
|
+
if template_label and template_short_form:
|
|
1067
|
+
template_formatted = f"[{template_label}]({template_short_form})"
|
|
1068
|
+
|
|
1069
|
+
# Handle URL encoding for labels (match Neo4j format)
|
|
1070
|
+
anatomy_label = anatomy.get('label', 'Unknown')
|
|
1071
|
+
anatomy_short_form = anatomy.get('short_form', '')
|
|
1072
|
+
|
|
1073
|
+
# URL encode special characters in label for markdown links (matching Neo4j behavior)
|
|
1074
|
+
# Only certain labels need encoding (like those with parentheses)
|
|
1075
|
+
import urllib.parse
|
|
1076
|
+
if '(' in anatomy_label or ')' in anatomy_label:
|
|
1077
|
+
# URL encode but keep spaces and common characters
|
|
1078
|
+
encoded_label = urllib.parse.quote(anatomy_label, safe=' -_.')
|
|
1079
|
+
else:
|
|
1080
|
+
encoded_label = anatomy_label
|
|
1081
|
+
|
|
1082
|
+
row = {
|
|
1083
|
+
'id': anatomy_short_form,
|
|
1084
|
+
'label': f"[{encoded_label}]({anatomy_short_form})",
|
|
1085
|
+
'tags': tags,
|
|
1086
|
+
'parent': f"[{term_info.get('term', {}).get('core', {}).get('label', 'Unknown')}]({short_form})",
|
|
1087
|
+
'source': '', # Not readily available in SOLR anatomy_channel_image
|
|
1088
|
+
'source_id': '',
|
|
1089
|
+
'template': template_formatted,
|
|
1090
|
+
'dataset': '', # Not readily available in SOLR anatomy_channel_image
|
|
1091
|
+
'license': '',
|
|
1092
|
+
'thumbnail': thumbnail
|
|
1093
|
+
}
|
|
1094
|
+
rows.append(row)
|
|
1095
|
+
|
|
1096
|
+
# Sort by ID to match expected ordering (Neo4j uses "ORDER BY id Desc")
|
|
1097
|
+
rows.sort(key=lambda x: x['id'], reverse=True)
|
|
1098
|
+
|
|
1099
|
+
total_count = len(anatomy_images)
|
|
1100
|
+
|
|
1101
|
+
if return_dataframe:
|
|
1102
|
+
return pd.DataFrame(rows)
|
|
1103
|
+
|
|
1104
|
+
return {
|
|
1105
|
+
"headers": _get_instances_headers(),
|
|
1106
|
+
"rows": rows,
|
|
1107
|
+
"count": total_count
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
except Exception as e:
|
|
1111
|
+
print(f"Error in SOLR fallback for get_instances: {e}")
|
|
1112
|
+
# Return empty results with proper structure
|
|
1113
|
+
if return_dataframe:
|
|
1114
|
+
return pd.DataFrame()
|
|
1115
|
+
return {
|
|
1116
|
+
"headers": _get_instances_headers(),
|
|
1117
|
+
"rows": [],
|
|
1118
|
+
"count": 0
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
def _get_instances_headers():
|
|
1122
|
+
"""Return standard headers for get_instances results"""
|
|
1123
|
+
return {
|
|
1124
|
+
"id": {"title": "Add", "type": "selection_id", "order": -1},
|
|
1125
|
+
"label": {"title": "Name", "type": "markdown", "order": 0, "sort": {0: "Asc"}},
|
|
1126
|
+
"parent": {"title": "Parent Type", "type": "markdown", "order": 1},
|
|
1127
|
+
"template": {"title": "Template", "type": "markdown", "order": 4},
|
|
1128
|
+
"tags": {"title": "Gross Types", "type": "tags", "order": 3},
|
|
1129
|
+
"source": {"title": "Data Source", "type": "markdown", "order": 5},
|
|
1130
|
+
"source_id": {"title": "Data Source", "type": "markdown", "order": 6},
|
|
1131
|
+
"dataset": {"title": "Dataset", "type": "markdown", "order": 7},
|
|
1132
|
+
"license": {"title": "License", "type": "markdown", "order": 8},
|
|
1133
|
+
"thumbnail": {"title": "Thumbnail", "type": "markdown", "order": 9}
|
|
1134
|
+
}
|
|
926
1135
|
|
|
927
1136
|
# Convert the results to a DataFrame
|
|
928
1137
|
df = pd.DataFrame.from_records(get_dict_cursor()(results))
|
|
@@ -1326,15 +1535,22 @@ def fill_query_results(term_info):
|
|
|
1326
1535
|
if function:
|
|
1327
1536
|
# print(f"Function {query['function']} found")
|
|
1328
1537
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1538
|
+
try:
|
|
1539
|
+
# Unpack the default dictionary and pass its contents as arguments
|
|
1540
|
+
function_args = query['takes'].get("default", {})
|
|
1541
|
+
# print(f"Function args: {function_args}")
|
|
1542
|
+
|
|
1543
|
+
# Modify this line to use the correct arguments and pass the default arguments
|
|
1544
|
+
if summary_mode:
|
|
1545
|
+
result = function(return_dataframe=False, limit=query['preview'], summary_mode=summary_mode, **function_args)
|
|
1546
|
+
else:
|
|
1547
|
+
result = function(return_dataframe=False, limit=query['preview'], **function_args)
|
|
1548
|
+
except Exception as e:
|
|
1549
|
+
print(f"Error executing query function {query['function']}: {e}")
|
|
1550
|
+
# Set default values for failed query
|
|
1551
|
+
query['preview_results'] = {'headers': query.get('preview_columns', ['id', 'label', 'tags', 'thumbnail']), 'rows': []}
|
|
1552
|
+
query['count'] = 0
|
|
1553
|
+
continue
|
|
1338
1554
|
# print(f"Function result: {result}")
|
|
1339
1555
|
|
|
1340
1556
|
# Filter columns based on preview_columns
|
|
@@ -1367,7 +1583,13 @@ def fill_query_results(term_info):
|
|
|
1367
1583
|
print(f"Unsupported result format for filtering columns in {query['function']}")
|
|
1368
1584
|
|
|
1369
1585
|
query['preview_results'] = {'headers': filtered_headers, 'rows': filtered_result}
|
|
1370
|
-
|
|
1586
|
+
# Handle count extraction based on result type
|
|
1587
|
+
if isinstance(result, dict) and 'count' in result:
|
|
1588
|
+
query['count'] = result['count']
|
|
1589
|
+
elif isinstance(result, pd.DataFrame):
|
|
1590
|
+
query['count'] = len(result)
|
|
1591
|
+
else:
|
|
1592
|
+
query['count'] = 0
|
|
1371
1593
|
# print(f"Filtered result: {filtered_result}")
|
|
1372
1594
|
else:
|
|
1373
1595
|
print(f"Function {query['function']} not found")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vfbquery
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Wrapper for querying VirtualFlyBrain knowledge graph.
|
|
5
5
|
Home-page: https://github.com/VirtualFlyBrain/VFBquery
|
|
6
6
|
Author: VirtualFlyBrain
|
|
@@ -117,25 +117,25 @@ vfb.get_term_info('FBbt_00003748')
|
|
|
117
117
|
"id": "VFB_00102107",
|
|
118
118
|
"label": "[ME on JRC2018Unisex adult brain](VFB_00102107)",
|
|
119
119
|
"tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
|
|
120
|
-
"thumbnail": "[](VFB_00101567,VFB_00102107)"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"id": "VFB_00101385",
|
|
124
124
|
"label": "[ME%28R%29 on JRC_FlyEM_Hemibrain](VFB_00101385)",
|
|
125
125
|
"tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
|
|
126
|
-
"thumbnail": "[ on JRC_FlyEM_Hemibrain aligned to JRC_FlyEM_Hemibrain')](VFB_00101384,VFB_00101385)"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"id": "VFB_00030810",
|
|
130
130
|
"label": "[medulla on adult brain template Ito2014](VFB_00030810)",
|
|
131
|
-
"tags": "Nervous_system|Visual_system|
|
|
131
|
+
"tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
|
|
132
132
|
"thumbnail": "[](VFB_00030786,VFB_00030810)"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"id": "VFB_00030624",
|
|
136
136
|
"label": "[medulla on adult brain template JFRC2](VFB_00030624)",
|
|
137
|
-
"tags": "Nervous_system|Visual_system|
|
|
138
|
-
"thumbnail": "[](VFB_00017894,VFB_00030624)"
|
|
137
|
+
"tags": "Nervous_system|Adult|Visual_system|Synaptic_neuropil_domain",
|
|
138
|
+
"thumbnail": "[](VFB_00017894,VFB_00030624)"
|
|
139
139
|
}
|
|
140
140
|
]
|
|
141
141
|
},
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
test/readme_parser.py,sha256=puvcq4_oEltjx_faw1kQJ8mmIWiQU-40oLJjtJBQCsQ,4170
|
|
3
|
+
test/term_info_queries_test.py,sha256=Od3i2DfaOlYFQGNQh2G7EiTC5ZqzgySyH3Wk6GntkWE,36902
|
|
4
|
+
test/test_default_caching.py,sha256=-KW2Mkz9x0tjlhXMreqJvjgo3pWOg49G0r22Woa9U5U,6616
|
|
5
|
+
test/test_examples_diff.py,sha256=TPo7gHPcus-24T7kxBXMQiCl0EHcXaEXeVuOG7C3rUo,15853
|
|
6
|
+
vfbquery/__init__.py,sha256=oKdgjIoseGwhdNwejXndg0CSpZdPgZes-PlHtYZT0zk,2262
|
|
7
|
+
vfbquery/cache_enhancements.py,sha256=-PCM0YZHPjwUJwJODZLgmz91sDyFGuYz_QRph_kTbB8,17341
|
|
8
|
+
vfbquery/cached_functions.py,sha256=5-aIiRP9mfEhVT3mXkLvIPDmdFq6iIExiLZAyir12IQ,10255
|
|
9
|
+
vfbquery/solr_cache_integration.py,sha256=Q87z_pXPdS9zn0r9kp2YBLGpCKOXVvcmzNmkRN7D8MU,7984
|
|
10
|
+
vfbquery/solr_fetcher.py,sha256=1FAyqaLrvZLaAmCW96en9y8lKTcs-ZFjt_UlnohP0jo,5683
|
|
11
|
+
vfbquery/solr_result_cache.py,sha256=oIUPCNmxG_nmyhfvx1gSiy5uvtvVrkLMJFgA6MNEqpY,27864
|
|
12
|
+
vfbquery/term_info_queries.py,sha256=oE-Ogm7jCPPlKtD3W3EtttYZcHnInwDOpOj-phAEOaI,42009
|
|
13
|
+
vfbquery/test_utils.py,sha256=7wUA3xgaGu3eLnjC98msNYt1wL538nOimVJjkC0ZLjU,5791
|
|
14
|
+
vfbquery/vfb_queries.py,sha256=50phVwDP28YaZdOmLom_Opem0Bdf2cEPo18jLjGig1I,76626
|
|
15
|
+
vfbquery-0.4.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
16
|
+
vfbquery-0.4.0.dist-info/METADATA,sha256=skaC5fQa-atagVzYyDmL7bAvgGcSF7KIAkxT2HueGa8,63157
|
|
17
|
+
vfbquery-0.4.0.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
18
|
+
vfbquery-0.4.0.dist-info/top_level.txt,sha256=UgaRTTOy4JBdKbkr_gkeknT4eaibm3ztF520G4NTQZs,14
|
|
19
|
+
vfbquery-0.4.0.dist-info/RECORD,,
|
vfbquery-0.3.4.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
test/readme_parser.py,sha256=puvcq4_oEltjx_faw1kQJ8mmIWiQU-40oLJjtJBQCsQ,4170
|
|
3
|
-
test/term_info_queries_test.py,sha256=EiL6Od5L9W6Xm6MPRMU4V_4TfoVsSSWjO0wh0F2ITH0,34242
|
|
4
|
-
test/test_examples_diff.py,sha256=ep_BzA-7az2OUPxUIsS3ReFV8LwuzGv8yIL0HirOGsc,15699
|
|
5
|
-
vfbquery/__init__.py,sha256=ZirzaFa-rgWYvqvK08rwxachUEz_qjhKrm3C8s3tlZY,76
|
|
6
|
-
vfbquery/solr_fetcher.py,sha256=U8mHaBJrwjncl1eU_gnNj5CGhEb-s9dCpcUTXTifQOY,3984
|
|
7
|
-
vfbquery/term_info_queries.py,sha256=oE-Ogm7jCPPlKtD3W3EtttYZcHnInwDOpOj-phAEOaI,42009
|
|
8
|
-
vfbquery/test_utils.py,sha256=7wUA3xgaGu3eLnjC98msNYt1wL538nOimVJjkC0ZLjU,5791
|
|
9
|
-
vfbquery/vfb_queries.py,sha256=NnkWB3shgnv2ovG-WimcuzXZtQCjRzIqdWPnQvoY4Hs,66014
|
|
10
|
-
vfbquery-0.3.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
11
|
-
vfbquery-0.3.4.dist-info/METADATA,sha256=T4Kxnz0tLOR_hmgIc-ZwfNWbkW_twWUYnMsy9t5jmzc,63097
|
|
12
|
-
vfbquery-0.3.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
13
|
-
vfbquery-0.3.4.dist-info/top_level.txt,sha256=UgaRTTOy4JBdKbkr_gkeknT4eaibm3ztF520G4NTQZs,14
|
|
14
|
-
vfbquery-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|