vfbquery 0.5.0__py3-none-any.whl → 0.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- test/readme_parser.py +29 -33
- test/term_info_queries_test.py +49 -34
- test/test_default_caching.py +86 -85
- test/test_examples_code.py +7 -0
- test/test_examples_diff.py +95 -172
- test/test_neurons_part_here.py +12 -13
- test/test_query_performance.py +3 -7
- vfbquery/__init__.py +47 -35
- vfbquery/cached_functions.py +772 -131
- vfbquery/owlery_client.py +1 -1
- vfbquery/solr_cache_integration.py +34 -30
- vfbquery/solr_result_cache.py +262 -99
- vfbquery/term_info_queries.py +1 -1
- vfbquery/vfb_queries.py +69 -20
- vfbquery-0.5.2.dist-info/METADATA +2806 -0
- {vfbquery-0.5.0.dist-info → vfbquery-0.5.2.dist-info}/RECORD +19 -18
- {vfbquery-0.5.0.dist-info → vfbquery-0.5.2.dist-info}/WHEEL +1 -1
- vfbquery-0.5.0.dist-info/METADATA +0 -2273
- {vfbquery-0.5.0.dist-info → vfbquery-0.5.2.dist-info}/LICENSE +0 -0
- {vfbquery-0.5.0.dist-info → vfbquery-0.5.2.dist-info}/top_level.txt +0 -0
vfbquery/vfb_queries.py
CHANGED
|
@@ -340,10 +340,25 @@ def encode_markdown_links(df, columns):
|
|
|
340
340
|
return label
|
|
341
341
|
|
|
342
342
|
try:
|
|
343
|
-
#
|
|
344
|
-
# These should NOT be encoded
|
|
343
|
+
# Handle linked images (format: [](link))
|
|
345
344
|
if label.startswith("[](link)
|
|
347
|
+
def secure_image_url(match):
|
|
348
|
+
alt_text = match.group(1)
|
|
349
|
+
image_url = match.group(2)
|
|
350
|
+
title = match.group(3) if match.group(3) else ""
|
|
351
|
+
link = match.group(4)
|
|
352
|
+
secure_url = image_url.replace("http://", "https://")
|
|
353
|
+
if title:
|
|
354
|
+
return f"[]({link})"
|
|
355
|
+
else:
|
|
356
|
+
return f"[]({link})"
|
|
357
|
+
|
|
358
|
+
# Regex to match the entire linked image
|
|
359
|
+
pattern = r'\[\!\[([^\]]+)\]\(([^\'"\s]+)(?:\s+[\'"]([^\'"]*)[\'"])?\)\]\(([^)]+)\)'
|
|
360
|
+
encoded_label = re.sub(pattern, secure_image_url, label)
|
|
361
|
+
return encoded_label
|
|
347
362
|
|
|
348
363
|
# Process regular markdown links - handle multiple links separated by commas
|
|
349
364
|
# Pattern matches [label](url) format
|
|
@@ -356,7 +371,9 @@ def encode_markdown_links(df, columns):
|
|
|
356
371
|
url_part = match.group(2) # The URL part (between ( and ))
|
|
357
372
|
# Encode brackets in the label part only
|
|
358
373
|
label_part_encoded = encode_brackets(label_part)
|
|
359
|
-
|
|
374
|
+
# Ensure URLs use https
|
|
375
|
+
url_part_secure = url_part.replace("http://", "https://")
|
|
376
|
+
return f"[{label_part_encoded}]({url_part_secure})"
|
|
360
377
|
|
|
361
378
|
# Replace all markdown links with their encoded versions
|
|
362
379
|
encoded_label = re.sub(r'\[([^\]]+)\]\(([^\)]+)\)', encode_single_link, label)
|
|
@@ -1268,7 +1285,7 @@ def NeuronRegionConnectivityQuery_to_schema(name, take_default):
|
|
|
1268
1285
|
"default": take_default,
|
|
1269
1286
|
}
|
|
1270
1287
|
preview = 5
|
|
1271
|
-
preview_columns = ["id", "
|
|
1288
|
+
preview_columns = ["id", "region", "presynaptic_terminals", "postsynaptic_terminals", "tags"]
|
|
1272
1289
|
return Query(query=query, label=label, function=function, takes=takes, preview=preview, preview_columns=preview_columns)
|
|
1273
1290
|
|
|
1274
1291
|
|
|
@@ -2713,7 +2730,7 @@ def get_neuron_region_connectivity(short_form: str, return_dataframe=True, limit
|
|
|
2713
2730
|
primary
|
|
2714
2731
|
RETURN
|
|
2715
2732
|
target.short_form AS id,
|
|
2716
|
-
target.label AS
|
|
2733
|
+
target.label AS region,
|
|
2717
2734
|
synapse_counts.`pre` AS presynaptic_terminals,
|
|
2718
2735
|
synapse_counts.`post` AS postsynaptic_terminals,
|
|
2719
2736
|
target.uniqueFacets AS tags
|
|
@@ -2732,7 +2749,7 @@ def get_neuron_region_connectivity(short_form: str, return_dataframe=True, limit
|
|
|
2732
2749
|
|
|
2733
2750
|
headers = {
|
|
2734
2751
|
'id': {'title': 'Region ID', 'type': 'selection_id', 'order': -1},
|
|
2735
|
-
'
|
|
2752
|
+
'region': {'title': 'Brain Region', 'type': 'markdown', 'order': 0},
|
|
2736
2753
|
'presynaptic_terminals': {'title': 'Presynaptic Terminals', 'type': 'number', 'order': 1},
|
|
2737
2754
|
'postsynaptic_terminals': {'title': 'Postsynaptic Terminals', 'type': 'number', 'order': 2},
|
|
2738
2755
|
'tags': {'title': 'Region Types', 'type': 'list', 'order': 3},
|
|
@@ -3070,19 +3087,37 @@ def _owlery_query_to_results(owl_query_string: str, short_form: str, return_data
|
|
|
3070
3087
|
owlery_url = f"{owlery_base}{endpoint}?{urlencode(params)}"
|
|
3071
3088
|
|
|
3072
3089
|
import sys
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3090
|
+
import requests
|
|
3091
|
+
|
|
3092
|
+
# Check if this is a 400 Bad Request (invalid query) vs other errors
|
|
3093
|
+
is_bad_request = isinstance(e, requests.exceptions.HTTPError) and hasattr(e, 'response') and e.response.status_code == 400
|
|
3094
|
+
|
|
3095
|
+
if is_bad_request:
|
|
3096
|
+
# 400 Bad Request means the term isn't valid for this type of query (e.g., anatomical query on expression pattern)
|
|
3097
|
+
# Return 0 results instead of error
|
|
3098
|
+
print(f"INFO: Owlery query returned 400 Bad Request (invalid for this term type): {owl_query_string}", file=sys.stderr)
|
|
3099
|
+
if return_dataframe:
|
|
3100
|
+
return pd.DataFrame()
|
|
3101
|
+
return {
|
|
3102
|
+
"headers": _get_standard_query_headers(),
|
|
3103
|
+
"rows": [],
|
|
3104
|
+
"count": 0
|
|
3105
|
+
}
|
|
3106
|
+
else:
|
|
3107
|
+
# Other errors (500, network issues, etc.) - return error indication
|
|
3108
|
+
print(f"ERROR: Owlery {'instances' if query_instances else 'subclasses'} query failed: {e}", file=sys.stderr)
|
|
3109
|
+
print(f" Full URL: {owlery_url}", file=sys.stderr)
|
|
3110
|
+
print(f" Query string: {owl_query_string}", file=sys.stderr)
|
|
3111
|
+
import traceback
|
|
3112
|
+
traceback.print_exc()
|
|
3113
|
+
# Return error indication with count=-1
|
|
3114
|
+
if return_dataframe:
|
|
3115
|
+
return pd.DataFrame()
|
|
3116
|
+
return {
|
|
3117
|
+
"headers": _get_standard_query_headers(),
|
|
3118
|
+
"rows": [],
|
|
3119
|
+
"count": -1
|
|
3120
|
+
}
|
|
3086
3121
|
|
|
3087
3122
|
|
|
3088
3123
|
def get_anatomy_scrnaseq(anatomy_short_form: str, return_dataframe=True, limit: int = -1):
|
|
@@ -3915,6 +3950,20 @@ def fill_query_results(term_info):
|
|
|
3915
3950
|
result_count = 0
|
|
3916
3951
|
|
|
3917
3952
|
# Store preview results (count is stored at query level, not in preview_results)
|
|
3953
|
+
# Sort rows based on the sort field in headers, default to ID descending if none
|
|
3954
|
+
sort_column = None
|
|
3955
|
+
sort_direction = None
|
|
3956
|
+
for col, info in filtered_headers.items():
|
|
3957
|
+
if 'sort' in info and isinstance(info['sort'], dict):
|
|
3958
|
+
sort_column = col
|
|
3959
|
+
sort_direction = list(info['sort'].values())[0] # e.g., 'Asc' or 'Desc'
|
|
3960
|
+
break
|
|
3961
|
+
if sort_column:
|
|
3962
|
+
reverse = sort_direction == 'Desc'
|
|
3963
|
+
filtered_result.sort(key=lambda x: x.get(sort_column, ''), reverse=reverse)
|
|
3964
|
+
else:
|
|
3965
|
+
# Default to ID descending if no sort specified
|
|
3966
|
+
filtered_result.sort(key=lambda x: x.get('id', ''), reverse=True)
|
|
3918
3967
|
query['preview_results'] = {'headers': filtered_headers, 'rows': filtered_result}
|
|
3919
3968
|
query['count'] = result_count
|
|
3920
3969
|
# print(f"Filtered result: {filtered_result}")
|