Skip to content

Commit ac5ada2

Browse files
committed
Merge feature/standardise-term-links-reports: standardise VFB term links to /reports permalinks (v1.15.0)
2 parents b9c08a8 + 2ea7115 commit ac5ada2

4 files changed

Lines changed: 45 additions & 21 deletions

File tree

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
here = path.abspath(path.dirname(__file__))
55

6-
__version__ = "1.14.12"
6+
__version__ = "1.15.0"
77

88
# Get the long description from the README file
99
with open(path.join(here, 'README.md')) as f:

src/test/term_info_queries_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,13 +487,13 @@ def test_term_info_serialization_template(self):
487487
self.assertTrue("filemeta" in serialized)
488488
self.assertEqual(3, len(serialized["filemeta"]))
489489
self.assertEqual({'obj': {'local': '/MeshFiles(OBJ)/my_id_(my_name).obj',
490-
'url': 'https://v2.virtualflybrain.org/data/VFB/i/0020/0000/VFB_00200000/volume_man.obj'}},
490+
'url': 'https://virtualflybrain.org/data/VFB/i/0020/0000/VFB_00200000/volume_man.obj'}},
491491
serialized["filemeta"][0])
492492
self.assertEqual({'wlz': {'local': '/Slices(WOOLZ)/my_id_(my_name).wlz',
493-
'url': 'https://v2.virtualflybrain.org/data/VFB/i/0020/0000/VFB_00200000/volume.wlz'}},
493+
'url': 'https://virtualflybrain.org/data/VFB/i/0020/0000/VFB_00200000/volume.wlz'}},
494494
serialized["filemeta"][1])
495495
self.assertEqual({'nrrd': {'local': '/SignalFiles(NRRD)/my_id_(my_name).nrrd',
496-
'url': 'https://v2.virtualflybrain.org/data/VFB/i/0020/0000/VFB_00200000/volume.nrrd'}},
496+
'url': 'https://virtualflybrain.org/data/VFB/i/0020/0000/VFB_00200000/volume.nrrd'}},
497497
serialized["filemeta"][2])
498498
self.assertTrue("template" in serialized)
499499
self.assertEqual("[JRC2018UnisexVNC](VFB_00200000)", serialized["template"])

src/vfbquery/term_info_queries.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,12 +1069,14 @@ def get_secure_data_url(data_url: str) -> str:
10691069

10701070
def get_secure_data_v2_url(data_url: str) -> str:
10711071
"""
1072-
Generates a secure data v2 url from the given url
1072+
Generates a secure, canonical data url from the given url: forces https and
1073+
rewrites the www data host to the environment-independent virtualflybrain.org
1074+
host, consistent with VFB term permalinks.
10731075
:param data_url: data url to secure
1074-
:return: secured v2 url
1076+
:return: secured data url
10751077
"""
10761078
return data_url.replace("http://", "https://").replace("https://www.virtualflybrain.org/data/",
1077-
"https://v2.virtualflybrain.org/data/")
1079+
"https://virtualflybrain.org/data/")
10781080

10791081

10801082
def serialize_term_info_to_json(vfb_term: VfbTerminfo, show_types=False) -> str:

src/vfbquery/vfb_queries.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@ def get_dict_cursor():
6464
# Replace VfbConnect with SimpleVFBConnect
6565
vc = SimpleVFBConnect()
6666

67+
# ---------------------------------------------------------------------------
68+
# Canonical VFB term link
69+
# ---------------------------------------------------------------------------
70+
# Public, environment-independent permalink base for a VFB term. This resolves
71+
# to the term's report page outside the app and is recognised as an internal
72+
# link by the v2 query-results table (MarkdownLinkComponent parses the
73+
# short_form out of the `/reports/<id>` path). Never hard-code an app URL such
74+
# as https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=<id> into
75+
# query output -- that pins results to one deployment. Build every VFB term
76+
# link from here (or via the helpers below) so the form is defined in one place.
77+
VFB_REPORT_BASE = "https://virtualflybrain.org/reports/"
78+
79+
80+
def vfb_report_url(short_form: str) -> str:
81+
"""Public permalink for a VFB term id, e.g. .../reports/VFB_00101567."""
82+
return f"{VFB_REPORT_BASE}{short_form}"
83+
84+
85+
def vfb_term_link(label: str, short_form: str) -> str:
86+
"""Markdown link for a VFB term: [label](https://virtualflybrain.org/reports/<id>)."""
87+
return f"[{label}]({vfb_report_url(short_form)})"
88+
89+
6790
def initialize_vfb_connect():
6891
"""
6992
Initialize VFB_connect by triggering the lazy load of the vfb and nc properties.
@@ -4777,7 +4800,7 @@ def get_similar_morphology(neuron_short_form: str, return_dataframe=True, limit:
47774800
}}) END AS types, primary, channel_image, nblast
47784801
RETURN
47794802
primary.short_form AS id,
4780-
'[' + primary.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + primary.short_form + ')' AS name,
4803+
'[' + primary.label + ']({VFB_REPORT_BASE}' + primary.short_form + ')' AS name,
47814804
apoc.text.join(coalesce(primary.uniqueFacets, []), '|') AS tags,
47824805
nblast.NBLAST_score[0] AS score,
47834806
types,
@@ -4835,7 +4858,7 @@ def get_similar_morphology_part_of(neuron_short_form: str, return_dataframe=True
48354858
WITH primary, nblast, channel, ri, templ, technique
48364859
OPTIONAL MATCH (primary)-[:INSTANCEOF]->(typ:Class) WITH CASE WHEN typ IS NULL THEN [] ELSE collect({{short_form: typ.short_form, label: coalesce(typ.label, ''), iri: typ.iri, types: labels(typ), symbol: coalesce(typ.symbol[0], '')}}) END AS types, primary, nblast, channel, ri, templ, technique
48374860
RETURN primary.short_form AS id,
4838-
'[' + primary.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + primary.short_form + ')' AS name,
4861+
'[' + primary.label + ']({VFB_REPORT_BASE}' + primary.short_form + ')' AS name,
48394862
apoc.text.join(coalesce(primary.uniqueFacets, []), '|') AS tags,
48404863
nblast.NBLAST_score[0] AS score,
48414864
types,
@@ -4866,7 +4889,7 @@ def get_similar_morphology_part_of_exp(expression_short_form: str, return_datafr
48664889
WITH primary, nblast, channel, ri, templ, technique
48674890
OPTIONAL MATCH (primary)-[:INSTANCEOF]->(typ:Class) WITH CASE WHEN typ IS NULL THEN [] ELSE collect({{short_form: typ.short_form, label: coalesce(typ.label, ''), iri: typ.iri, types: labels(typ), symbol: coalesce(typ.symbol[0], '')}}) END AS types, primary, nblast, channel, ri, templ, technique
48684891
RETURN primary.short_form AS id,
4869-
'[' + primary.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + primary.short_form + ')' AS name,
4892+
'[' + primary.label + ']({VFB_REPORT_BASE}' + primary.short_form + ')' AS name,
48704893
apoc.text.join(coalesce(primary.uniqueFacets, []), '|') AS tags,
48714894
nblast.NBLAST_score[0] AS score,
48724895
types,
@@ -4897,7 +4920,7 @@ def get_similar_morphology_nb(neuron_short_form: str, return_dataframe=True, lim
48974920
WITH primary, nblast, channel, ri, templ, technique
48984921
OPTIONAL MATCH (primary)-[:INSTANCEOF]->(typ:Class) WITH CASE WHEN typ IS NULL THEN [] ELSE collect({{short_form: typ.short_form, label: coalesce(typ.label, ''), iri: typ.iri, types: labels(typ), symbol: coalesce(typ.symbol[0], '')}}) END AS types, primary, nblast, channel, ri, templ, technique
48994922
RETURN primary.short_form AS id,
4900-
'[' + primary.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + primary.short_form + ')' AS name,
4923+
'[' + primary.label + ']({VFB_REPORT_BASE}' + primary.short_form + ')' AS name,
49014924
apoc.text.join(coalesce(primary.uniqueFacets, []), '|') AS tags,
49024925
nblast.neuronbridge_score[0] AS score,
49034926
types,
@@ -4943,7 +4966,7 @@ def get_similar_morphology_nb_exp(expression_short_form: str, return_dataframe=T
49434966
RETURN ri, templ, technique
49444967
}}
49454968
RETURN primary.short_form AS id,
4946-
'[' + primary.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + primary.short_form + ')' AS name,
4969+
'[' + primary.label + ']({VFB_REPORT_BASE}' + primary.short_form + ')' AS name,
49474970
apoc.text.join(coalesce(primary.uniqueFacets, []), '|') AS tags,
49484971
nblast.neuronbridge_score[0] AS score,
49494972
type,
@@ -4989,7 +5012,7 @@ def get_painted_domains(template_short_form: str, return_dataframe=True, limit:
49895012
total_count = get_dict_cursor()(count_results)[0]['count'] if count_results else 0
49905013

49915014
main_query = f"""MATCH (n:Template {{short_form:'{template_short_form}'}})<-[:depicts]-(:Template)<-[r:in_register_with]-(dc:Individual)-[:depicts]->(di:Individual)-[:INSTANCEOF]->(d:Class) WHERE EXISTS(r.index)
4992-
RETURN DISTINCT di.short_form AS id, '[' + di.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + di.short_form + ')' AS name, coalesce(di.description[0], d.description[0]) AS description, COLLECT(DISTINCT d.label) AS type, replace(r.folder[0],'http:','https:') + '/thumbnailT.png' AS thumbnail"""
5015+
RETURN DISTINCT di.short_form AS id, '[' + di.label + ']({VFB_REPORT_BASE}' + di.short_form + ')' AS name, coalesce(di.description[0], d.description[0]) AS description, COLLECT(DISTINCT d.label) AS type, replace(r.folder[0],'http:','https:') + '/thumbnailT.png' AS thumbnail"""
49935016
if limit != -1: main_query += f" LIMIT {limit}"
49945017

49955018
results = vc.nc.commit_list([main_query])
@@ -5143,16 +5166,15 @@ def get_template_roi_tree(template_short_form: str, return_dataframe=False):
51435166
def _node_summary_md(class_id, class_label, painted_list, parent_label):
51445167
parts = [
51455168
f"**{class_label or class_id}** "
5146-
f"([{class_id}](http://virtualflybrain.org/reports/{class_id}))",
5169+
f"({vfb_term_link(class_id, class_id)})",
51475170
"",
51485171
]
51495172
if parent_label:
51505173
parts.append(f"Part of: *{parent_label}*.")
51515174
parts.append("")
51525175
if painted_list:
51535176
ind_lines = [
5154-
f"[{p.get('individual_label') or p.get('individual_id')}]"
5155-
f"(http://virtualflybrain.org/reports/{p.get('individual_id')})"
5177+
vfb_term_link(p.get('individual_label') or p.get('individual_id'), p.get('individual_id'))
51565178
for p in painted_list if p.get('individual_id')
51575179
]
51585180
if ind_lines:
@@ -5190,7 +5212,7 @@ def _build(node_id, ancestors, parent_label):
51905212
summary_md = (
51915213
f"## ROI tree for **{template_label}**\n\n"
51925214
f"Anatomy root: "
5193-
f"[{root_label or root_id}](http://virtualflybrain.org/reports/{root_id}) "
5215+
f"{vfb_term_link(root_label or root_id, root_id)} "
51945216
f"({root_id}).\n\n"
51955217
f"{painted_class_count} painted region"
51965218
f"{'s' if painted_class_count != 1 else ''} "
@@ -5260,7 +5282,7 @@ def get_dataset_images(dataset_short_form: str, return_dataframe=True, limit: in
52605282
OPTIONAL MATCH (primary)-[:INSTANCEOF]->(typ:Class)
52615283
OPTIONAL MATCH (channel)-[:is_specified_output_of]->(technique:Class)
52625284
RETURN primary.short_form AS id,
5263-
'[' + primary.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + primary.short_form + ')' AS name,
5285+
'[' + primary.label + ']({VFB_REPORT_BASE}' + primary.short_form + ')' AS name,
52645286
apoc.text.join(coalesce(primary.uniqueFacets, []), '|') AS tags,
52655287
typ.label AS type,
52665288
REPLACE(apoc.text.format("[%s](%s)",[COALESCE(template.symbol[0],template.label),template.short_form]), '[null](null)', '') AS template,
@@ -5286,7 +5308,7 @@ def get_all_aligned_images(template_short_form: str, return_dataframe=True, limi
52865308
OPTIONAL MATCH (di)-[:INSTANCEOF]->(typ:Class)
52875309
OPTIONAL MATCH (channel)-[:is_specified_output_of]->(technique:Class)
52885310
RETURN DISTINCT di.short_form AS id,
5289-
'[' + di.label + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + di.short_form + ')' AS name,
5311+
'[' + di.label + ']({VFB_REPORT_BASE}' + di.short_form + ')' AS name,
52905312
apoc.text.join(coalesce(di.uniqueFacets, []), '|') AS tags,
52915313
typ.label AS type,
52925314
REPLACE(apoc.text.format("[%s](%s)",[COALESCE(templ.symbol[0],templ.label),templ.short_form]), '[null](null)', '') AS template,
@@ -5358,7 +5380,7 @@ def _dataset_return_clause(ds_var: str = "ds") -> str:
53585380
return f"""
53595381
RETURN
53605382
{ds_var}.short_form AS id,
5361-
'[' + coalesce({ds_var}.label, {ds_var}.short_form) + '](https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id=' + {ds_var}.short_form + ')' AS name,
5383+
'[' + coalesce({ds_var}.label, {ds_var}.short_form) + ']({VFB_REPORT_BASE}' + {ds_var}.short_form + ')' AS name,
53625384
pubs,
53635385
apoc.text.join(coalesce({ds_var}.uniqueFacets, []), '|') AS tags,
53645386
license,
@@ -6288,7 +6310,7 @@ def build(node_id, depth):
62886310
# Render display text and HTML
62896311
# ------------------------------------------------------------------
62906312

6291-
VFB_BASE = 'https://v2.virtualflybrain.org/org.geppetto.frontend/geppetto?id='
6313+
VFB_BASE = VFB_REPORT_BASE
62926314
DEFAULT_MAX_SIBLINGS = 10 # truncate large sibling groups in text display
62936315

62946316
def _text_tree(node, prefix='', is_last=True, is_root=True, max_siblings=DEFAULT_MAX_SIBLINGS):

0 commit comments

Comments
 (0)