def create_relation_type(self, id=None, origins=None, destinations=None, supertypes=(), label=None): """ I create a new relation type in this model. :param id: see :ref:`ktbs-resource-creation` :param origins: explain. :param destinations: explain. :param supertypes: explain. :param label: explain. :rtype: `RelationTypeMixin`:class: """ # redefining built-in 'id' #pylint: disable=W0622 if id is None and label is None: raise ValueError("id or label must be supplied") uri = mint_uri_from_label(label, self, id) with self.edit(_trust=True) as graph: base_uri = self.uri graph_add = graph.add graph_add((uri, RDF.type, KTBS.RelationType)) if label is not None: graph_add((uri, SKOS.prefLabel, Literal(label))) if origins is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(origins, basestring) or isinstance( origins, ObselTypeMixin): warn( "Model abstract API has changed: you should provide an *iterable* of origins" ) origins = [origins] for origin in origins: origin_uri = coerce_to_uri(origin, self.uri) graph_add((uri, _HAS_REL_ORIGIN, origin_uri)) if destinations is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(destinations, basestring) or isinstance( destinations, ObselTypeMixin): warn( "Model abstract API has changed: you should provide an *iterable* of destinations" ) destinations = [destinations] for destination in destinations: destination_uri = coerce_to_uri(destination, self.uri) graph_add((uri, _HAS_REL_DESTINATION, destination_uri)) for i in supertypes: graph_add((uri, KTBS.hasSuperRelationType, coerce_to_uri(i, base_uri))) ret = self.factory(uri, [KTBS.RelationType]) assert isinstance(ret, RelationTypeMixin) return ret
def create_attribute_type(self, id=None, obsel_types=None, data_types=None, value_is_list=False, label=None): """ I create a new obsel type in this model. :param id: see :ref:`ktbs-resource-creation` :param obsel_types: explain. :param data_types: explain. :param value_is_list: explain. :param label: explain. :rtype: `AttributeTypeMixin`:class: """ # redefining built-in 'id' #pylint: disable=W0622 if id is None and label is None: raise ValueError("id or label must be supplied") uri = mint_uri_from_label(label, self, id) with self.edit(_trust=True) as graph: base_uri = self.uri graph_add = graph.add graph_add((uri, RDF.type, KTBS.AttributeType)) if label is not None: graph_add((uri, SKOS.prefLabel, Literal(label))) if obsel_types is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(obsel_types, basestring) or isinstance( obsel_types, ObselTypeMixin): warn( "Model abstract API has changed: you should provide an *iterable* of obsel_types" ) obsel_types = [obsel_types] for obsel_type in obsel_types: obsel_type_uri = coerce_to_uri(obsel_type, base_uri) graph_add((uri, _HAS_ATT_OBSELTYPE, obsel_type_uri)) if data_types is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(data_types, basestring): warn( "Model abstract API has changed: you should provide an *iterable* of data_types" ) data_types = [data_types] for data_type in data_types: data_type_uri = coerce_to_uri(data_type, base_uri) graph_add((uri, _HAS_ATT_DATATYPE, data_type_uri)) # TODO SOON make use of value_is_list # ... in the meantime, we lure pylint into ignoring it: _ = value_is_list ret = self.factory(uri, [KTBS.AttributeType]) assert isinstance(ret, AttributeTypeMixin) return ret
def create_model(self, id=None, parents=None, label=None, graph=None): """Create a new model in this trace base. :param id: see :ref:`ktbs-resource-creation` :param parents: either None, or an iterable of models from which this model inherits :param label: explain. :param graph: see :ref:`ktbs-resource-creation` :rtype: `~.tace_model.TraceModelMixin`:class: """ # redefining built-in 'id' #pylint: disable-msg=W0622 trust = graph is None and id is None node = coerce_to_node(id, self.uri) if parents is None: parents = () # abstract API allows None if graph is None: graph = Graph() graph.add((self.uri, KTBS.contains, node)) graph.add((node, RDF.type, KTBS.TraceModel)) if label: graph.add((node, SKOS.prefLabel, Literal(label))) for parent in parents: parent = coerce_to_uri(parent, self.uri) graph.add((node, KTBS.hasParentModel, parent)) uris = self.post_graph(graph, None, trust, node, KTBS.TraceModel) assert len(uris) == 1 return self.factory(uris[0], [KTBS.TraceModel])
def del_source_trace(self, val): """I break the link between this trace and one of its source traces """ source_uri = coerce_to_uri(val) # do not trust edit, as there are many verifications to make with self.edit() as editable: editable.remove((self.uri, KTBS.hasSource, source_uri))
def remove_origin(self, origin): """ I remove an obsel type from this attribute. """ origin_uri = coerce_to_uri(origin) with self.edit(_trust=True) as editable: editable.remove((self.uri, _HAS_REL_ORIGIN, origin_uri))
def create_obsel_type(self, id=None, supertypes=(), label=None): """ I create a new obsel type in this model. :param id: see :ref:`ktbs-resource-creation` :param supertypes: explain. :param label: explain. :rtype: `ObselTypeMixin`:class: """ # redefining built-in 'id' #pylint: disable=W0622 if id is None and label is None: raise ValueError("id or label must be supplied") uri = mint_uri_from_label(label, self, id) with self.edit(_trust=True) as graph: base_uri = self.uri graph_add = graph.add graph_add((uri, RDF.type, KTBS.ObselType)) if label is not None: graph_add((uri, SKOS.prefLabel, Literal(label))) for i in supertypes: graph_add( (uri, KTBS.hasSuperObselType, coerce_to_uri(i, base_uri))) ret = self.factory(uri, [KTBS.ObselType]) assert isinstance(ret, ObselTypeMixin) return ret
def remove_parent(self, model): """ I remove model as a parent model to this model. """ with self.edit(_trust=True) as graph: graph.remove((self.uri, KTBS.hasParentModel, coerce_to_uri(model, self.uri)))
def mint_uri_from_label(label, target, uri=None, suffix=""): """ Mint a URI for a resource posted to `target` based on `label`. :param label: the label for the resource to create :param target: the resource "containing" the resource to create :param uri: if provided, will be used instead (must be fresh) :param suffix: if provided, will be added to the end of the URI :return: a URI not present in `target.state` :rtype: rdflib.URIRef :raise: InvalidDataError if `uri` is provided and not acceptable """ if uri is not None: uri = coerce_to_uri(uri, target.uri) if not check_new(target.state, uri): raise InvalidDataError("URI already in use <%s>" % uri) if not uri.startswith(target.uri): raise InvalidDataError( "URI is wrong <%s> (did you forget a leading '#'?)" % uri) else: label = label.lower() prefix = target.uri if prefix[-1] != "/": prefix = "%s#" % prefix prefix = "%s%s" % (prefix, _NON_ALPHA.sub("-", label)) uri = URIRef("%s%s" % (prefix, suffix)) if not check_new(target.state, uri): prefix = "%s-" % prefix uri = make_fresh_uri(target.state, prefix, suffix) return uri
def remove_data_type(self, data_type): """ I remove the data type from this attribute. """ data_type_uri = coerce_to_uri(data_type) with self.edit(_trust=True) as editable: editable.remove((self.uri, _HAS_ATT_DATATYPE, data_type_uri))
def add_origin(self, origin): """ I add an obsel type to this attribute. """ origin_uri = coerce_to_uri(origin) with self.edit(_trust=True) as editable: editable.add((self.uri, _HAS_REL_ORIGIN, origin_uri))
def serialize_json_method(graph, method, bindings=None): valconv = ValueConverter(method.uri) valconv_uri = valconv.uri yield u"""{ "@context": "%s", "@id": "%s", "@type": "Method", "hasParentMethod": "%s", "parameter": [""" % ( CONTEXT_URI, method.uri, valconv_uri(coerce_to_uri(method.parent)) ) own_params = method.iter_parameters_with_values(False) yield u",".join( u"\n %s" % dumps("%s=%s" % item) for item in own_params ) + "]" used_by = list(method.state.subjects(KTBS.hasMethod, method.uri)) if used_by: yield u""",\n "isMethodOf": %s""" \ % dumps([ valconv_uri(i) for i in used_by ]) children = list(method.state.subjects(KTBS.hasParentMethod, method.uri)) if children: yield u""",\n "isParentMethodOf": %s""" \ % dumps([ valconv_uri(i) for i in children]) for i in iter_other_arcs(graph, method.uri, valconv): yield i yield u""",\n "inBase": "%s"\n}\n""" % valconv_uri(method.base.uri)
def remove_destination(self, destination): """ I remove an obsel type from this attribute. """ destination_uri = coerce_to_uri(destination) with self.edit(_trust=True) as editable: editable.remove((self.uri, _HAS_REL_DESTINATION, destination_uri))
def remove_obsel_type(self, obsel_type): """ I remove an obsel type from this attribute. """ obsel_type_uri = coerce_to_uri(obsel_type) with self.edit(_trust=True) as editable: editable.remove((self.uri, _HAS_ATT_OBSELTYPE, obsel_type_uri))
def add_obsel_type(self, obsel_type): """ I add an obsel type to this attribute. """ obsel_type_uri = coerce_to_uri(obsel_type) with self.edit(_trust=True) as editable: editable.add((self.uri, _HAS_ATT_OBSELTYPE, obsel_type_uri))
def add_destination(self, destination): """ I add an obsel type to this attribute. """ destination_uri = coerce_to_uri(destination) with self.edit(_trust=True) as editable: editable.add((self.uri, _HAS_REL_DESTINATION, destination_uri))
def create_obsel_type(self, id=None, supertypes=(), label=None): """ I create a new obsel type in this model. :param id: see :ref:`ktbs-resource-creation` :param supertypes: explain. :param label: explain. :rtype: `ObselTypeMixin`:class: """ # redefining built-in 'id' #pylint: disable=W0622 if id is None and label is None: raise ValueError("id or label must be supplied") uri = mint_uri_from_label(label, self, id) with self.edit(_trust=True) as graph: base_uri = self.uri graph_add = graph.add graph_add((uri, RDF.type, KTBS.ObselType)) if label is not None: graph_add((uri, SKOS.prefLabel, Literal(label))) for i in supertypes: graph_add((uri, KTBS.hasSuperObselType, coerce_to_uri(i, base_uri))) ret = self.factory(uri, [KTBS.ObselType]) assert isinstance(ret, ObselTypeMixin) return ret
def add_source_trace(self, val): """I add a source trace to this trace """ source_uri = coerce_to_uri(val) # do not trust edit, as there are many verifications to make with self.edit() as editable: editable.add((self.uri, KTBS.hasSource, source_uri))
def __init__(self, uri, collection, host_graph, host_parameters): # not calling parents __init__ #pylint: disable=W0231 self.uri = coerce_to_uri(uri, collection.uri) self.collection = collection self.host_graph = host_graph self.host_parameters = host_parameters if __debug__: self._readonly_graph = ReadOnlyGraph(host_graph)
def remove_parent(self, model): """ I remove model as a parent model to this model. """ with self.edit(_trust=True) as graph: graph.remove( (self.uri, KTBS.hasParentModel, coerce_to_uri(model, self.uri)))
def set_model(self, model): """I set the model of this trace. model can be a Model or a URI; relative URIs are resolved against this trace's URI. """ model_uri = coerce_to_uri(model, self.uri) with self.edit(_trust=True) as graph: graph.set((self.uri, KTBS.hasModel, model_uri))
def create_attribute_type(self, id=None, obsel_types=None, data_types=None, value_is_list=False, label=None): """ I create a new obsel type in this model. :param id: see :ref:`ktbs-resource-creation` :param obsel_types: explain. :param data_types: explain. :param value_is_list: explain. :param label: explain. :rtype: `AttributeTypeMixin`:class: """ # redefining built-in 'id' #pylint: disable=W0622 if id is None and label is None: raise ValueError("id or label must be supplied") uri = mint_uri_from_label(label, self, id) with self.edit(_trust=True) as graph: base_uri = self.uri graph_add = graph.add graph_add((uri, RDF.type, KTBS.AttributeType)) if label is not None: graph_add((uri, SKOS.prefLabel, Literal(label))) if obsel_types is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(obsel_types, basestring) or isinstance(obsel_types, ObselTypeMixin): warn("Model abstract API has changed: you should provide an *iterable* of obsel_types") obsel_types = [obsel_types] for obsel_type in obsel_types: obsel_type_uri = coerce_to_uri(obsel_type, base_uri) graph_add ((uri, _HAS_ATT_OBSELTYPE, obsel_type_uri)) if data_types is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(data_types, basestring): warn("Model abstract API has changed: you should provide an *iterable* of data_types") data_types = [data_types] for data_type in data_types: data_type_uri = coerce_to_uri(data_type, base_uri) graph_add ((uri, _HAS_ATT_DATATYPE, data_type_uri)) # TODO SOON make use of value_is_list # ... in the meantime, we lure pylint into ignoring it: _ = value_is_list ret = self.factory(uri, [KTBS.AttributeType]) assert isinstance(ret, AttributeTypeMixin) return ret
def create_relation_type(self, id=None, origins=None, destinations=None, supertypes=(), label=None): """ I create a new relation type in this model. :param id: see :ref:`ktbs-resource-creation` :param origins: explain. :param destinations: explain. :param supertypes: explain. :param label: explain. :rtype: `RelationTypeMixin`:class: """ # redefining built-in 'id' #pylint: disable=W0622 if id is None and label is None: raise ValueError("id or label must be supplied") uri = mint_uri_from_label(label, self, id) with self.edit(_trust=True) as graph: base_uri = self.uri graph_add = graph.add graph_add((uri, RDF.type, KTBS.RelationType)) if label is not None: graph_add((uri, SKOS.prefLabel, Literal(label))) if origins is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(origins, basestring) or isinstance(origins, ObselTypeMixin): warn("Model abstract API has changed: you should provide an *iterable* of origins") origins = [origins] for origin in origins: origin_uri = coerce_to_uri(origin, self.uri) graph_add((uri, _HAS_REL_ORIGIN, origin_uri)) if destinations is not None: # TODO remove test below when enough time has passed (2016-03-18) if isinstance(destinations, basestring) or isinstance(destinations, ObselTypeMixin): warn("Model abstract API has changed: you should provide an *iterable* of destinations") destinations = [destinations] for destination in destinations: destination_uri = coerce_to_uri(destination, self.uri) graph_add((uri, _HAS_REL_DESTINATION, destination_uri)) for i in supertypes: graph_add((uri, KTBS.hasSuperRelationType, coerce_to_uri(i, base_uri))) ret = self.factory(uri, [KTBS.RelationType]) assert isinstance(ret, RelationTypeMixin) return ret
def add_data_type(self, data_type): """ I add the data type to this attribute. """ # TODO LATER check data_type? # what kind of datatype do we accept? see ktbs.namespace data_type_uri = coerce_to_uri(data_type) with self.edit(_trust=True) as editable: editable.add((self.uri, _HAS_ATT_DATATYPE, data_type_uri))
def set_method(self, val): """I set the method that this computed trace will use """ method_uri = coerce_to_uri(val) # do not trust edit, as there is many verifications to make with self.edit() as editable: editable.set((self.uri, KTBS.hasMethod, method_uri)) self.force_state_refresh() self.obsel_collection.force_state_refresh()
def get_attribute_value(self, atype): """ I return the value of the given attribut type for this obsel, or None. """ atype = coerce_to_uri(atype, self.uri) ret = self.state.value(self.uri, atype) if isinstance(ret, Literal): ret = ret.toPython() return ret
def get_base(self, id): """ I return the base corresponding to the given URI. :rtype: `~.base.BaseMixin`:class: """ # redefining built-in 'id' #pylint: disable-msg=W0622 base_uri = coerce_to_uri(id, self.uri) return self.factory(base_uri, [KTBS.Base])
def get_builtin_method(self, uri): """I return the built-in method identified by `uri` if supported. :rtype: `~.builtin_method.MethodBuiltinMixin`:class: """ uri = coerce_to_uri(uri) if (self.uri, KTBS.hasBuiltinMethod, uri) in self.state: return universal_factory(uri, [KTBS.BuiltinMethod]) else: return None
def create_stored_trace(self, id=None, model=None, origin=None, default_subject=None, label=None, graph=None): """Create a new store trace in this trace base. :param id: see :ref:`ktbs-resource-creation` :param model: mode of the trace to create (required) :param origin: Typically a timestamp. It can be an opaque string, meaning that the precise time when the trace was collected is not known :param default_subject: The subject to set to new obsels when they do not specifify a subject :param label: explain. :param graph: see :ref:`ktbs-resource-creation` :rtype: `~.trace.StoredTraceMixin`:class: """ # redefining built-in 'id' #pylint: disable=W0622 # We somehow duplicate StoredTrace.complete_new_graph and # StoredTrace.check_new_graph here, but this is required if we want to # be able to set _trust=True below. # Furthermore, the signature of this method makes it significantly # easier to produce a valid graph, so there is a benefit to this # duplication. if model is None: raise ValueError("model is mandatory") trust = graph is None and id is None node = coerce_to_node(id, self.uri) model = coerce_to_uri(model, self.uri) origin_isoformat = getattr(origin, "isoformat", None) if origin_isoformat: origin = origin_isoformat() if graph is None: graph = Graph() graph.add((self.uri, KTBS.contains, node)) graph.add((node, RDF.type, KTBS.StoredTrace)) graph.add((node, KTBS.hasModel, model)) graph.add((node, KTBS.hasOrigin, Literal(origin))) if default_subject is not None: if not isinstance(default_subject, URIRef): default_subject = Literal(default_subject) graph.add((node, KTBS.hasDefaultSubject, default_subject)) if label: graph.add((node, SKOS.prefLabel, Literal(label))) uris = self.post_graph(graph, None, trust, node, KTBS.StoredTrace) assert len(uris) == 1 return self.factory(uris[0], [KTBS.StoredTrace])
def set_parent(self, method): """ I set the parent method. """ method_uri = coerce_to_uri(method, self.uri) # checking that method_uri is a valid parent is a bit tricky # so we leave it to the implementation to check it: # we use an *untrusted* edit context with self.edit() as graph: graph.set((self.uri, KTBS.hasParentMethod, method_uri)) self._ack_change_parameters()
def create_method(self, id=None, parent=None, parameters=None, label=None, graph=None): """Create a new computed trace in this trace base. :param id: see :ref:`ktbs-resource-creation` :param parent: parent method (required) :param parameters: method parameters :param label: explain. :param graph: see :ref:`ktbs-resource-creation` :rtype: `~.method.MethodMixin`:class: """ # redefining built-in 'id' #pylint: disable-msg=W0622 # We somehow duplicate Method.check_new_graph here, but this is # required if we want to be able to set _trust=True below. # Furthermore, the signature of this method makes it significantly # easier to produce a valid graph, so there is a benefit to this # duplication. if parent is None: raise ValueError("parent is mandatory") trust = graph is None and id is None node = coerce_to_node(id, self.uri) parent = coerce_to_uri(parent, self.uri) if parameters is None: parameters = {} if trust: if parent.startswith(self.uri): if not (parent, RDF.type, KTBS.Method) in self.state: raise InvalidDataError("Parent <%s> is not a Method" % parent) else: trust = False # could be built-in, let impl/server check if graph is None: graph = Graph() graph.add((self.uri, KTBS.contains, node)) graph.add((node, RDF.type, KTBS.Method)) graph.add((node, KTBS.hasParentMethod, parent)) for key, value in parameters.iteritems(): if "=" in key: raise ValueError("Parameter name can not contain '=': %s", key) graph.add( (node, KTBS.hasParameter, Literal(u"%s=%s" % (key, value)))) if label: graph.add((node, SKOS.prefLabel, Literal(label))) uris = self.post_graph(graph, None, trust, node, KTBS.Method) assert len(uris) == 1 return self.factory(uris[0], [KTBS.Method])
def add_supertype(self, element=None, element_type=None, super_type=None): """ I add a super type to the element (obsel or relation) type in this model. :param element: ObselType or RelationType or their URI. :param element_type: Type of the concerned element. :param super_type: SuperObselType or SuperRelationType. """ if element is not None: uri = coerce_to_uri(element, self.uri) else: raise ValueError("element must be supplied") base_uri = self.uri with self.edit(_trust=True) as graph: if element_type == KTBS.ObselType: graph.add((uri, KTBS.hasSuperObselType, coerce_to_uri(super_type, base_uri))) if element_type == KTBS.RelationType: graph.add((uri, KTBS.hasSuperRelationType, coerce_to_uri(super_type, base_uri)))
def create_method(self, id=None, parent=None, parameters=None, label=None, graph=None): """Create a new computed trace in this trace base. :param id: see :ref:`ktbs-resource-creation` :param parent: parent method (required) :param parameters: method parameters :param label: explain. :param graph: see :ref:`ktbs-resource-creation` :rtype: `~.method.MethodMixin`:class: """ # redefining built-in 'id' #pylint: disable-msg=W0622 # We somehow duplicate Method.check_new_graph here, but this is # required if we want to be able to set _trust=True below. # Furthermore, the signature of this method makes it significantly # easier to produce a valid graph, so there is a benefit to this # duplication. if parent is None: raise ValueError("parent is mandatory") trust = graph is None and id is None node = coerce_to_node(id, self.uri) parent = coerce_to_uri(parent, self.uri) if parameters is None: parameters = {} if trust: if parent.startswith(self.uri): if not (parent, RDF.type, KTBS.Method) in self.state: raise InvalidDataError("Parent <%s> is not a Method" % parent) else: trust = False # could be built-in, let impl/server check if graph is None: graph = Graph() graph.add((self.uri, KTBS.contains, node)) graph.add((node, RDF.type, KTBS.Method)) graph.add((node, KTBS.hasParentMethod, parent)) for key, value in parameters.iteritems(): if "=" in key: raise ValueError("Parameter name can not contain '=': %s", key) graph.add((node, KTBS.hasParameter, Literal(u"%s=%s" % (key, value)))) if label: graph.add((node, SKOS.prefLabel, Literal(label))) uris = self.post_graph(graph, None, trust, node, KTBS.Method) assert len(uris) == 1 return self.factory(uris[0], [KTBS.Method])
def get_obsel(self, id): """ Return the obsel with the given uri. :param id: the URI of the obsel; may be relative to the URI of the trace :type id: str :rtype: `~.obsel.ObselMixin`:class: """ # Redefining built-in id #pylint: disable-msg=W0622 uri = coerce_to_uri(id, self.uri) ret = self.factory(uri, [KTBS.Obsel]) assert ret is None or isinstance(ret, ObselMixin) return ret
def iter_related_obsels(self, rtype): """ I iter over all obsels pointed by an outgoing relation. """ rtype = coerce_to_uri(rtype, self.uri) query_str = """ SELECT ?related WHERE { <%s> <%s> ?related . ?related <http://liris.cnrs.fr/silex/2009/ktbs#hasTrace> ?t . } """ % (self.uri, rtype) factory = self.factory for related, in self.state.query(query_str): #/!\ returns 1-uples yield factory(related, [KTBS.Obsel])
def iter_relating_obsels(self, rtype): """ I iter over all incoming relation types for this obsel. """ rtype = coerce_to_uri(rtype, self.uri) query_str = """ SELECT ?relating WHERE { ?relating <%s> <%s> . ?relating <http://liris.cnrs.fr/silex/2009/ktbs#hasTrace> ?t . } """ % (rtype, self.uri) factory = self.factory for relating, in self.state.query(query_str): #/!\ returns 1-uples yield factory(relating, [KTBS.Obsel])