diff --git a/src/test/test_term_info_parity.py b/src/test/test_term_info_parity.py index fca8135..fe56c83 100644 --- a/src/test/test_term_info_parity.py +++ b/src/test/test_term_info_parity.py @@ -151,6 +151,35 @@ def test_license_term_info_does_not_5xx(self): "License term_info failed validity check") self.assertIn("License", result.get("SuperTypes", [])) + # --- Gap E: a term's own licence (`license`) must reach Licenses{} ----- + # DataSet term info returns has_license on the term itself as `license` + # (QueryLibrary.dataset_term_info), not as `dataset_license`. The + # serialiser only read `dataset_license`, so every dataset page rendered + # without a License row even though the edge was in the KB. + def test_dataset_own_license_reaches_licenses(self): + ti = self._parse("Cachero2010") + licenses = ti.get("Licenses", {}) + self.assertTrue(licenses, "DataSet own licence dropped from Licenses{}") + lic = licenses[0] + self.assertTrue(lic.get("short_form", "").startswith("VFBlicense"), + f"unexpected licence short_form: {lic.get('short_form')}") + self.assertTrue(lic.get("label"), "licence label missing") + self.assertTrue(lic.get("iri"), "licence iri missing") + + def test_dataset_own_license_has_no_self_source(self): + # The dataset is its own source, so leave source empty rather than + # rendering a Source row that links back to the same page. + lic = self._parse("Cachero2010").get("Licenses", {})[0] + self.assertEqual("", lic.get("source", "")) + self.assertEqual("", lic.get("source_iri", "")) + + def test_dataset_license_still_attributes_source_on_images(self): + # The dataset_license path is unchanged: an image/template still gets + # its licence via the dataset it came from, with that dataset as source. + licenses = self._parse("VFB_00101567").get("Licenses", {}) + self.assertTrue(licenses, "template lost its inherited licence") + self.assertTrue(licenses[0].get("source"), "inherited licence lost its source") + if __name__ == "__main__": unittest.main() diff --git a/src/vfbquery/vfb_queries.py b/src/vfbquery/vfb_queries.py index 9b7a166..db00572 100644 --- a/src/vfbquery/vfb_queries.py +++ b/src/vfbquery/vfb_queries.py @@ -963,9 +963,34 @@ def term_info_parse_object(results, short_form): record['icon'] = dataset_license.license.icon record['source_iri'] = dataset_license.dataset.core.iri record['source'] = dataset_license.dataset.core.label - licenses[idx] = record + licenses[idx] = record termInfo["Licenses"] = licenses - + elif vfbTerm.license and len(vfbTerm.license) > 0: + # Terms that carry a licence directly rather than inheriting one + # from the dataset they came from. DataSet term info (see + # QueryLibrary.dataset_term_info) returns has_license on the term + # itself as `license`, with no `dataset_license`, so without this + # branch every dataset page loses its License row. + # Mirrors the fallback in term_info_queries.VFBTerm.get_license() + # and the legacy Java serialiser (VFBProcessTermInfoJson.getLicense). + # Deliberately elif, not a merge: the query library populates one or + # the other per term type, and if a term ever carried both, the + # inherited dataset licence wins -- same precedence as get_license(). + licenses = {} + for idx, lcns in enumerate(vfbTerm.license): + record = {} + record['iri'] = lcns.core.iri + record['short_form'] = lcns.core.short_form + record['label'] = lcns.core.label + record['icon'] = lcns.icon + # No source dataset to attribute: the term is its own source, + # and an empty source keeps the panel from rendering a Source + # row that links back to the page you are already on. + record['source_iri'] = '' + record['source'] = '' + licenses[idx] = record + termInfo["Licenses"] = licenses + if vfbTerm.template_channel and vfbTerm.template_channel.channel.short_form: termInfo["IsTemplate"] = True images = {}