11import threading
22from datetime import datetime
3- from typing import List , Iterator
3+ from typing import List , Iterator , Dict
44
55import rdflib
66
@@ -29,46 +29,102 @@ def empty(self):
2929prov_logger = ProvLogger ()
3030
3131
32- class RetroProv (RdfWrapper ):
33- def __init__ (self ):
34- super ().__init__ (uri = None , ref_name = 'retroprov' )
35- self .timestamp = datetime .now ()
36-
37-
38- class StepRetroProv (RetroProv ):
39- def __init__ (self , step ):
40- super ().__init__ ()
32+ class StepRetroProv (RdfWrapper ):
33+ def __init__ (self , step = None , step_args :Dict = None , time_start :datetime = None , time_end :datetime = None , output = None ):
34+ super ().__init__ (uri = None , ref_name = 'fairstepprov' )
4135 self .set_attribute (rdflib .RDF .type , namespaces .PPLAN .Activity )
4236 self .step = step
4337 self .step_uri = step .uri
4438
39+ stepbase = rdflib .Namespace (step .uri )
40+
41+ # Bind inputs
42+ for inputvar in step .inputs :
43+ if inputvar .name in step_args :
44+ retrovar = rdflib .BNode (inputvar .name )
45+ self ._rdf .add ( (self .self_ref , namespaces .PROV .used , retrovar ) )
46+ self ._rdf .add ( (retrovar , rdflib .RDF .type , namespaces .PPLAN .Entity ) )
47+ self ._rdf .add ( (retrovar , rdflib .RDFS .label , rdflib .Literal (inputvar .name )) )
48+ self ._rdf .add ( (retrovar , rdflib .RDF .value , rdflib .Literal (step_args [inputvar .name ])) )
49+
50+ if inputvar .uri :
51+ self ._rdf .add ( (retrovar , namespaces .PPLAN .correspondsToVariable , inputvar .uri ) )
52+
53+ # Bind outputs
54+ num_outputs = len (list (step .outputs ))
55+ if num_outputs == 1 :
56+ outvardict = {'out1' : output }
57+ else :
58+ outvardict = {('out' + str (i )): outval for i , outval in enumerate (output ) }
59+
60+ for outputvar in step .outputs :
61+ retrovar = rdflib .BNode (outputvar .name )
62+ if outputvar .name in outvardict :
63+ self ._rdf .add ( (self .self_ref , namespaces .PROV .used , retrovar ) )
64+ self ._rdf .add ( (retrovar , rdflib .RDF .type , namespaces .PPLAN .Entity ) )
65+ self ._rdf .add ( (retrovar , rdflib .RDFS .label , rdflib .Literal (outputvar .name )) )
66+ self ._rdf .add ( (retrovar , rdflib .RDF .value , rdflib .Literal (outvardict [outputvar .name ])) )
67+
68+ if outputvar .uri :
69+ self ._rdf .add ( (retrovar , namespaces .PPLAN .correspondsToVariable , outputvar .uri ) )
70+
71+ # Add times to RDF (if available)
72+ if time_start :
73+ self .set_attribute (namespaces .PROV .startedAtTime , rdflib .Literal (time_start , datatype = rdflib .XSD .dateTime ))
74+ if time_end :
75+ self .set_attribute (namespaces .PROV .endedAtTime , rdflib .Literal (time_end , datatype = rdflib .XSD .dateTime ))
76+
4577 @property
4678 def step_uri (self ):
4779 """Refers to URI of step associated to this provenance.
4880
49- Matches the predicate prov:wasDerivedFrom associated to this retrospective provenance
81+ Matches the predicate pplan:correspondsToStep associated to this retrospective provenance
5082 """
51- return self .get_attribute (namespaces .PROV . wasDerivedFrom )
83+ return self .get_attribute (namespaces .PPLAN . correspondsToStep )
5284
5385 @step_uri .setter
5486 def step_uri (self , value ):
5587 self .set_attribute (namespaces .PPLAN .correspondsToStep , rdflib .URIRef (value ), overwrite = True )
5688
89+ def publish_as_nanopub (self , use_test_server = False , ** kwargs ):
90+ """
91+ Publish this rdf as a nanopublication.
92+
93+ Args:
94+ use_test_server (bool): Toggle using the test nanopub server.
95+ kwargs: Keyword arguments to be passed to [nanopub.Publication.from_assertion](
96+ https://nanopub.readthedocs.io/en/latest/reference/publication.html#
97+ nanopub.publication.Publication.from_assertion).
98+ This allows for more control over the nanopublication RDF.
99+
100+ Returns:
101+ a dictionary with publication info, including 'nanopub_uri', and 'concept_uri'
102+ """
103+ return self ._publish_as_nanopub (use_test_server = use_test_server , ** kwargs )
104+
57105 def __str__ (self ):
58106 """String representation."""
59107 s = f'Step retrospective provenance.\n '
60- s += self ._rdf .serialize (format = 'trig ' ).decode ('utf-8' )
108+ s += self ._rdf .serialize (format = 'turtle ' ).decode ('utf-8' )
61109 return s
62110
63111
64- class WorkflowRetroProv (RetroProv ):
112+ class WorkflowRetroProv (RdfWrapper ):
65113 def __init__ (self , workflow , workflow_uri , step_provs : List [StepRetroProv ]):
66- super ().__init__ ()
67- self .set_attribute (rdflib .RDF .type , namespaces .PPLAN .Bundle )
114+ super ().__init__ (uri = None , ref_name = 'fairworkflowprov' )
115+ self ._rdf .add ((self .self_ref , rdflib .RDF .type , namespaces .PPLAN .Bundle ))
116+ self ._rdf .add ((self .self_ref , rdflib .RDF .type , namespaces .PROV .Collection ))
68117 self .workflow = workflow
69118 self .workflow_uri = workflow_uri
70119 self ._step_provs = step_provs
71120
121+ # Add the Entity links for now (dummy links, if unpublished)
122+ for stepprov in self ._step_provs :
123+ if stepprov .uri :
124+ self ._rdf .add ((self .self_ref , namespaces .PROV .hasMember , rdflib .URIRef (stepprov .uri )))
125+ else :
126+ self ._rdf .add ((self .self_ref , namespaces .PROV .hasMember , rdflib .URIRef ('http://www.example.org/unpublished-entity-' + str (hash (stepprov )))))
127+
72128 @property
73129 def workflow_uri (self ):
74130 """Refers to URI of step associated to this provenance.
@@ -88,8 +144,32 @@ def __iter__(self) -> Iterator[StepRetroProv]:
88144 def __len__ (self ) -> int :
89145 return len (self ._step_provs )
90146
147+ def publish_as_nanopub (self , use_test_server = False , ** kwargs ):
148+ """
149+ Publish this rdf as a nanopublication.
150+
151+ Args:
152+ use_test_server (bool): Toggle using the test nanopub server.
153+ kwargs: Keyword arguments to be passed to [nanopub.Publication.from_assertion](
154+ https://nanopub.readthedocs.io/en/latest/reference/publication.html#
155+ nanopub.publication.Publication.from_assertion).
156+ This allows for more control over the nanopublication RDF.
157+
158+ Returns:
159+ a dictionary with publication info, including 'nanopub_uri', and 'concept_uri'
160+ """
161+
162+ # Clear existing members of this entity (to be replaced with newly published links)
163+ self .remove_attribute (namespaces .PROV .hasMember )
164+
165+ for stepprov in self ._step_provs :
166+ stepprov .publish_as_nanopub (use_test_server = use_test_server , ** kwargs )
167+ self ._rdf .add ((self .self_ref , namespaces .PROV .hasMember , rdflib .URIRef (stepprov .uri )))
168+
169+ return self ._publish_as_nanopub (use_test_server = use_test_server , ** kwargs )
170+
91171 def __str__ (self ):
92172 """String representation."""
93173 s = f'Workflow retrospective provenance.\n '
94- s += self ._rdf .serialize (format = 'trig ' ).decode ('utf-8' )
174+ s += self ._rdf .serialize (format = 'turtle ' ).decode ('utf-8' )
95175 return s
0 commit comments