diff --git a/CHANGELOG.md b/CHANGELOG.md index ee41293..8a74e3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] + ### Fixed - `prov:generatedBy` in output graphs now refers to a plugin IRI instead of a literal @@ -13,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed - Keep original output ("No explanations found.") if no inconsistencies found with Validate plugin +- Provenance data in output graphs now includes plugin parameter settings ## [1.0.0beta1] 2024-07-01 diff --git a/cmem_plugin_reason/plugin_reason.py b/cmem_plugin_reason/plugin_reason.py index 969c81f..f9f2578 100644 --- a/cmem_plugin_reason/plugin_reason.py +++ b/cmem_plugin_reason/plugin_reason.py @@ -25,12 +25,11 @@ ROBOT, create_xml_catalog_file, get_graphs_tree, + post_provenance, remove_temp, send_result, ) -PLUGIN_IRI = "https://plugin.eccenca.com/cmem-plugin-reason/reason" - @Plugin( label="Reason", @@ -268,7 +267,6 @@ def reason(self, graphs: dict) -> None: f"--language-annotation rdfs:comment " f'"Reasoning result set of <{self.data_graph_iri}> and ' f'<{self.ontology_graph_iri}>" en ' - f'--link-annotation prov:wasGeneratedBy "{PLUGIN_IRI}/{self.reasoner}" ' f'--link-annotation prov:wasDerivedFrom "{self.data_graph_iri}" ' f"--link-annotation prov:wasDerivedFrom " f'"{self.ontology_graph_iri}" ' @@ -292,4 +290,9 @@ def execute(self, inputs: tuple, context: ExecutionContext) -> None: # noqa: AR self.reason(graphs) setup_cmempy_user_access(context.user) send_result(self.result_graph_iri, Path(self.temp) / "result.ttl") + post_provenance( + self.result_graph_iri, + "cmem_plugin_reason-plugin_reason-ReasonPlugin", + context, + ) remove_temp(self) diff --git a/cmem_plugin_reason/plugin_validate.py b/cmem_plugin_reason/plugin_validate.py index c158e9f..8920676 100644 --- a/cmem_plugin_reason/plugin_validate.py +++ b/cmem_plugin_reason/plugin_validate.py @@ -32,12 +32,11 @@ ROBOT, create_xml_catalog_file, get_graphs_tree, + post_provenance, remove_temp, send_result, ) -PLUGIN_IRI = "https://plugin.eccenca.com/cmem-plugin-reason/validate" - @Plugin( label="Validate", @@ -152,7 +151,6 @@ def validate(self, graphs: dict) -> None: f'--language-annotation rdfs:label "Ontology Validation Result {utctime}" en ' f"--language-annotation rdfs:comment " f'"Ontology validation of <{self.ontology_graph_iri}>" en ' - f'--link-annotation prov:wasGeneratedBy "{PLUGIN_IRI}/{self.reasoner}" ' f'--link-annotation prov:wasDerivedFrom "{self.ontology_graph_iri}" ' f'--typed-annotation dc:created "{utctime}" xsd:dateTime ' f'--output "{self.temp}/output.ttl"' @@ -175,25 +173,6 @@ def make_resource(self, context: ExecutionContext) -> None: replace=True, ) - def post_provenance(self, plugin_id: str, context: ExecutionContext) -> None: - """TODO: Post provenance with query""" - plugin_iri = f"http://dataintegration.eccenca.com/{context.task.project_id()}/{context.task.task_id()}" - project_graph = f"http://di.eccenca.com/project/{context.task.project_id()}" - construct = f""" - PREFIX dif: - CONSTRUCT {{ - GRAPH <{self.output_graph_iri}> {{ - <{self.output_graph_iri}> prov:generatedBy <{plugin_iri}> . - <{plugin_iri}> a . - <{plugin_iri}> ?p ?o . - }} - }} - FROM <{project_graph}> - WHERE {{ - <{plugin_iri}> ?p ?o . - FILTER((STRSTARTS(STR(?p), 'https://vocab.eccenca.com/di/functions/param_')) - }}""" # noqa: F841 - def execute(self, inputs: tuple, context: ExecutionContext) -> Entities | None: # noqa: ARG002 """Run the workflow operator.""" setup_cmempy_user_access(context.user) @@ -205,6 +184,12 @@ def execute(self, inputs: tuple, context: ExecutionContext) -> Entities | None: if self.produce_graph: setup_cmempy_user_access(context.user) send_result(self.output_graph_iri, Path(self.temp) / "output.ttl") + post_provenance( + self.output_graph_iri, + "cmem_plugin_reason-plugin_validate-ValidatePlugin", + context, + ) + if self.write_md: setup_cmempy_user_access(context.user) self.make_resource(context) diff --git a/cmem_plugin_reason/utils.py b/cmem_plugin_reason/utils.py index 627b637..cb7561c 100644 --- a/cmem_plugin_reason/utils.py +++ b/cmem_plugin_reason/utils.py @@ -8,10 +8,11 @@ from xml.etree.ElementTree import Element, SubElement, tostring from cmem.cmempy.dp.proxy.graph import get_graph_import_tree, post_streamed +from cmem.cmempy.dp.proxy.update import post from cmem_plugin_base.dataintegration.description import PluginParameter from cmem_plugin_base.dataintegration.parameter.choice import ChoiceParameterType from cmem_plugin_base.dataintegration.parameter.graph import GraphParameterType -from cmem_plugin_base.dataintegration.plugins import WorkflowPlugin +from cmem_plugin_base.dataintegration.plugins import ExecutionContext, WorkflowPlugin from cmem_plugin_base.dataintegration.types import IntParameterType from defusedxml import minidom @@ -115,3 +116,27 @@ def remove_temp(plugin: WorkflowPlugin) -> None: rmtree(plugin.temp) except (OSError, FileNotFoundError) as err: plugin.log.warning(f"Cannot remove directory {plugin.temp} ({err})") + + +def post_provenance(graph: str, plugin_id: str, context: ExecutionContext) -> None: + """Insert provenance""" + plugin_iri = ( + f"http://dataintegration.eccenca.com/{context.task.project_id()}/{context.task.task_id()}" + ) + project_graph = f"http://di.eccenca.com/project/{context.task.project_id()}" + query = f""" + INSERT {{ + GRAPH <{graph}> {{ + <{graph}> <{plugin_iri}> . + <{plugin_iri}> a . + <{plugin_iri}> ?p ?o . + }} + }} + WHERE {{ + GRAPH <{project_graph}> {{ + <{plugin_iri}> ?p ?o . + FILTER(STRSTARTS(STR(?p), "https://vocab.eccenca.com/di/functions/param_")) + }} + }}""" + + post(query=query) diff --git a/tests/test_elk.ttl b/tests/test_elk.ttl index 21dc22b..0bac834 100644 --- a/tests/test_elk.ttl +++ b/tests/test_elk.ttl @@ -12,8 +12,7 @@ owl:imports vocab: ; rdfs:comment "Reasoning result set of and "@en ; prov:wasDerivedFrom - , ; - prov:wasGeneratedBy . + , . ################################################################# # Individuals diff --git a/tests/test_emr.ttl b/tests/test_emr.ttl index 22130a0..2ddd71a 100644 --- a/tests/test_emr.ttl +++ b/tests/test_emr.ttl @@ -12,8 +12,7 @@ owl:imports vocab: ; rdfs:comment "Reasoning result set of and "@en ; prov:wasDerivedFrom - , ; - prov:wasGeneratedBy . + , . ################################################################# # Individuals diff --git a/tests/test_hermit.ttl b/tests/test_hermit.ttl index 376fcf9..a81aaf7 100644 --- a/tests/test_hermit.ttl +++ b/tests/test_hermit.ttl @@ -12,8 +12,7 @@ owl:imports vocab: ; rdfs:comment "Reasoning result set of and "@en ; prov:wasDerivedFrom - , ; - prov:wasGeneratedBy . + , . ################################################################# # Individuals diff --git a/tests/test_jfact.ttl b/tests/test_jfact.ttl index 6f8a857..a81aaf7 100644 --- a/tests/test_jfact.ttl +++ b/tests/test_jfact.ttl @@ -12,8 +12,7 @@ owl:imports vocab: ; rdfs:comment "Reasoning result set of and "@en ; prov:wasDerivedFrom - , ; - prov:wasGeneratedBy . + , . ################################################################# # Individuals diff --git a/tests/test_structural.ttl b/tests/test_structural.ttl index ce025bf..587f20b 100644 --- a/tests/test_structural.ttl +++ b/tests/test_structural.ttl @@ -12,8 +12,7 @@ owl:imports vocab: ; rdfs:comment "Reasoning result set of and "@en ; prov:wasDerivedFrom - , ; - prov:wasGeneratedBy . + , . ################################################################# # Individuals diff --git a/tests/test_validate_output.ttl b/tests/test_validate_output.ttl index 4b777ad..b9b5886 100644 --- a/tests/test_validate_output.ttl +++ b/tests/test_validate_output.ttl @@ -7,8 +7,7 @@ a owl:Ontology ; rdfs:comment "Ontology validation of "@en ; - prov:wasDerivedFrom ; - prov:wasGeneratedBy . + prov:wasDerivedFrom . a owl:NamedIndividual, . diff --git a/tests/test_whelk.ttl b/tests/test_whelk.ttl index eccd0d9..2247138 100644 --- a/tests/test_whelk.ttl +++ b/tests/test_whelk.ttl @@ -12,8 +12,7 @@ owl:imports vocab: ; rdfs:comment "Reasoning result set of and "@en ; prov:wasDerivedFrom - , ; - prov:wasGeneratedBy . + , . ################################################################# # Individuals