diff --git a/src/test/test_examples_order.py b/src/test/test_examples_order.py new file mode 100644 index 0000000..0ed22b6 --- /dev/null +++ b/src/test/test_examples_order.py @@ -0,0 +1,41 @@ +"""Available Images order: a template's own domain image leads.""" +import unittest + +from vfbquery.vfb_queries import order_template_examples + + +class OrderTemplateExamplesTest(unittest.TestCase): + + def test_indexed_image_first_then_newest_id(self): + # FBbt_00003748 on JRC2018U: the painted domain VFB_00102107 has the + # oldest id but is the only image indexed to the template. + records = [ + {"id": "VFB_00107fo8"}, + {"id": "VFB_00102107", "index": 3}, + {"id": "VFB_001091st"}, + {"id": "VFB_00108iwp"}, + ] + self.assertEqual( + [r["id"] for r in order_template_examples(records)], + ["VFB_00102107", "VFB_001091st", "VFB_00108iwp", "VFB_00107fo8"]) + + def test_several_indexed_images_ascend_by_index(self): + records = [ + {"id": "VFB_0000000a", "index": 7}, + {"id": "VFB_0000000b"}, + {"id": "VFB_0000000c", "index": 0}, + {"id": "VFB_0000000d", "index": 2}, + ] + self.assertEqual( + [r["id"] for r in order_template_examples(records)], + ["VFB_0000000c", "VFB_0000000d", "VFB_0000000a", "VFB_0000000b"]) + + def test_no_index_keeps_id_descending(self): + records = [{"id": "VFB_00000001"}, {"id": "VFB_00000003"}, {"id": "VFB_00000002"}] + self.assertEqual( + [r["id"] for r in order_template_examples(records)], + ["VFB_00000003", "VFB_00000002", "VFB_00000001"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/src/vfbquery/vfb_queries.py b/src/vfbquery/vfb_queries.py index 1482fc1..f9fcb4f 100644 --- a/src/vfbquery/vfb_queries.py +++ b/src/vfbquery/vfb_queries.py @@ -360,6 +360,17 @@ def __init__(self, id, label, thumbnail=None, thumbnail_transparent=None, nrrd=N self.type_label = type_label self.type_id = type_id +def order_template_examples(records): + """Order one template's Examples so its own domain images come first. + + An image with an index is a domain in that template's label volume, so it + belongs to the template and leads the Available Images carousel, by index + ascending. Everything else follows, newest id first as before. + """ + by_id = sorted(records, key=lambda r: r["id"], reverse=True) + return sorted(by_id, key=lambda r: (r.get("index") is None, r.get("index") or 0)) + + class ImageSchema(Schema): id = fields.String(required=True) label = fields.String(required=True) @@ -963,11 +974,13 @@ def term_info_parse_object(results, short_form): for key in vars(image.channel_image.image).keys(): if "image_" in key and not ("thumbnail" in key or "folder" in key) and len(vars(image.channel_image.image)[key]) > 1: record[key.replace("image_","")] = vars(image.channel_image.image)[key].replace("http://","https://") + image_index = getattr(image.channel_image.image, "index", None) + if image_index: + record["index"] = int(image_index[0]) images[image.channel_image.image.template_anatomy.short_form].append(record) - # Sort each template's images by id in descending order (newest first) for template_key in images: - images[template_key] = sorted(images[template_key], key=lambda x: x["id"], reverse=True) + images[template_key] = order_template_examples(images[template_key]) termInfo["Examples"] = images # Add techniques to termInfo for Individuals