diff options
Diffstat (limited to 'bsfs')
-rw-r--r-- | bsfs/graph/ac/base.py | 12 | ||||
-rw-r--r-- | bsfs/graph/graph.py | 20 | ||||
-rw-r--r-- | bsfs/graph/nodes.py | 58 | ||||
-rw-r--r-- | bsfs/triple_store/sparql.py | 81 |
4 files changed, 89 insertions, 82 deletions
diff --git a/bsfs/graph/ac/base.py b/bsfs/graph/ac/base.py index eef444b..80742d7 100644 --- a/bsfs/graph/ac/base.py +++ b/bsfs/graph/ac/base.py @@ -25,19 +25,19 @@ class AccessControlBase(abc.ABC): """ """ - # - __backend: TripleStoreBase + # The triple store backend. + _backend: TripleStoreBase - # - __user: URI + # The current user. + _user: URI def __init__( self, backend: TripleStoreBase, user: URI, ): - self.__backend = backend - self.__user = URI(user) + self._backend = backend + self._user = URI(user) @abc.abstractmethod def is_protected_predicate(self, pred: schema.Predicate) -> bool: diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py index d5e1b88..71973c2 100644 --- a/bsfs/graph/graph.py +++ b/bsfs/graph/graph.py @@ -27,33 +27,33 @@ class Graph(): """ """ # link to the triple storage backend. - __backend: TripleStoreBase + _backend: TripleStoreBase # user uri. - __user: URI + _user: URI def __init__(self, backend: TripleStoreBase, user: URI): - self.__backend = backend - self.__user = user + self._backend = backend + self._user = user def __hash__(self) -> int: - return hash((type(self), self.__backend, self.__user)) + return hash((type(self), self._backend, self._user)) def __eq__(self, other) -> bool: return isinstance(other, type(self)) \ - and self.__backend == other.__backend \ - and self.__user == other.__user + and self._backend == other._backend \ + and self._user == other._user def __repr__(self) -> str: - return f'{typename(self)}(backend={repr(self.__backend)}, user={self.__user})' + return f'{typename(self)}(backend={repr(self._backend)}, user={self._user})' def __str__(self) -> str: - return f'{typename(self)}({str(self.__backend)}, {self.__user})' + return f'{typename(self)}({str(self._backend)}, {self._user})' @property def schema(self) -> Schema: """Return the store's local schema.""" - return self.__backend.schema + return self._backend.schema """ def nodes(self, node_type: URI, guids: typing.Iterable[URI]) -> _nodes.Nodes: diff --git a/bsfs/graph/nodes.py b/bsfs/graph/nodes.py index 7d2e9b3..7b0e8f4 100644 --- a/bsfs/graph/nodes.py +++ b/bsfs/graph/nodes.py @@ -32,16 +32,16 @@ class Nodes(): """ # triple store backend. - __backend: TripleStoreBase + _backend: TripleStoreBase # user uri. - __user: URI + _user: URI # node type. - __node_type: _schema.Node + _node_type: _schema.Node # guids of nodes. Can be empty. - __guids: typing.Set[URI] + _guids: typing.Set[URI] def __init__( self, @@ -50,37 +50,37 @@ class Nodes(): node_type: _schema.Node, guids: typing.Iterable[URI], ): - self.__backend = backend - self.__user = user - self.__node_type = node_type - self.__guids = set(guids) - self.__ac = ac.NullAC(self.__backend, self.__user) + self._backend = backend + self._user = user + self._node_type = node_type + self._guids = set(guids) + self.__ac = ac.NullAC(self._backend, self._user) def __eq__(self, other: typing.Any) -> bool: return isinstance(other, Nodes) \ - and self.__backend == other.__backend \ - and self.__user == other.__user \ - and self.__node_type == other.__node_type \ - and self.__guids == other.__guids + and self._backend == other._backend \ + and self._user == other._user \ + and self._node_type == other._node_type \ + and self._guids == other._guids def __hash__(self) -> int: - return hash((type(self), self.__backend, self.__user, self.__node_type, tuple(sorted(self.__guids)))) + return hash((type(self), self._backend, self._user, self._node_type, tuple(sorted(self._guids)))) def __repr__(self) -> str: - return f'{typename(self)}({self.__backend}, {self.__user}, {self.__node_type}, {self.__guids})' + return f'{typename(self)}({self._backend}, {self._user}, {self._node_type}, {self._guids})' def __str__(self) -> str: - return f'{typename(self)}({self.__node_type}, {self.__guids})' + return f'{typename(self)}({self._node_type}, {self._guids})' @property def node_type(self) -> _schema.Node: """Return the node's type.""" - return self.__node_type + return self._node_type @property def guids(self) -> typing.Iterator[URI]: """Return all node guids.""" - return iter(self.__guids) + return iter(self._guids) def set( self, @@ -93,7 +93,7 @@ class Nodes(): # insert triples self.__set(pred, value) # save changes - self.__backend.commit() + self._backend.commit() except ( errors.PermissionDeniedError, # tried to set a protected predicate (ns.bsm.t_created) @@ -103,7 +103,7 @@ class Nodes(): ValueError, # multiple values passed to unique predicate ): # revert changes - self.__backend.rollback() + self._backend.rollback() # notify the client raise @@ -123,7 +123,7 @@ class Nodes(): for pred, value in predicate_values: self.__set(pred, value) # save changes - self.__backend.commit() + self._backend.commit() except ( errors.PermissionDeniedError, # tried to set a protected predicate (ns.bsm.t_created) @@ -133,7 +133,7 @@ class Nodes(): ValueError, # multiple values passed to unique predicate ): # revert changes - self.__backend.rollback() + self._backend.rollback() # notify the client raise @@ -148,7 +148,7 @@ class Nodes(): """ """ # get normalized predicate. Raises KeyError if *pred* not in the schema. - pred = self.__backend.schema.predicate(predicate) + pred = self._backend.schema.predicate(predicate) # node_type must be a subclass of the predicate's domain node_type = self.node_type @@ -177,7 +177,7 @@ class Nodes(): # insert literals # TODO: Support passing iterators as values for non-unique predicates - self.__backend.set( + self._backend.set( node_type, guids, pred, @@ -206,7 +206,7 @@ class Nodes(): targets = set(self.__ac.link_to_node(value.node_type, targets)) # insert node links - self.__backend.set( + self._backend.set( node_type, guids, pred, @@ -223,7 +223,7 @@ class Nodes(): ): # check node existence guids = set(guids) - existing = set(self.__backend.exists(node_type, guids)) + existing = set(self._backend.exists(node_type, guids)) # get nodes to be created missing = guids - existing # create nodes if need be @@ -231,10 +231,10 @@ class Nodes(): # check which missing nodes can be created missing = set(self.__ac.createable(node_type, missing)) # create nodes - self.__backend.create(node_type, missing) + self._backend.create(node_type, missing) # add bookkeeping triples - self.__backend.set(node_type, missing, - self.__backend.schema.predicate(ns.bsm.t_created), [time.time()]) + self._backend.set(node_type, missing, + self._backend.schema.predicate(ns.bsm.t_created), [time.time()]) # add permission triples self.__ac.create(node_type, missing) # return available nodes diff --git a/bsfs/triple_store/sparql.py b/bsfs/triple_store/sparql.py index 3eab869..d9ed55a 100644 --- a/bsfs/triple_store/sparql.py +++ b/bsfs/triple_store/sparql.py @@ -10,9 +10,8 @@ import typing import rdflib # bsfs imports -from bsfs.utils import URI -from bsfs.utils import errors -import bsfs.schema as _schema +from bsfs import schema as bsc +from bsfs.utils import errors, URI # inner-module imports from . import base @@ -26,7 +25,7 @@ __all__: typing.Sequence[str] = ( ## code ## -class Transaction(): +class _Transaction(): """Lightweight rdflib transactions for in-memory databases.""" def __init__(self, graph): @@ -58,11 +57,20 @@ class SparqlStore(base.TripleStoreBase): """ """ - def __init__(self, uri: typing.Optional[URI] = None): - super().__init__(uri) - self.graph = rdflib.Graph() - self.transaction = Transaction(self.graph) - self.__schema = _schema.Schema.Empty() + # The rdflib graph. + _graph: rdflib.Graph + + # Current transaction. + _transaction: _Transaction + + # The local schema. + _schema: bsc.Schema + + def __init__(self): + super().__init__(None) + self._graph = rdflib.Graph() + self._transaction = _Transaction(self._graph) + self._schema = bsc.Schema.Empty() @classmethod def Open( @@ -73,15 +81,14 @@ class SparqlStore(base.TripleStoreBase): return cls(None) def commit(self): - self.transaction.commit() + self._transaction.commit() def rollback(self): - self.transaction.rollback() + self._transaction.rollback() @property - def schema(self) -> _schema.Schema: - """Return the current schema.""" - return self.__schema + def schema(self) -> bsc.Schema: + return self._schema @schema.setter def schema(self, schema: _schema.Schema): @@ -106,7 +113,7 @@ class SparqlStore(base.TripleStoreBase): """ # check args: Schema instanace - if not isinstance(schema, _schema.Schema): + if not isinstance(schema, bsc.Schema): raise TypeError(schema) # check compatibility: No contradicting definitions if not self.schema.consistent_with(schema): @@ -124,21 +131,21 @@ class SparqlStore(base.TripleStoreBase): # remove predicate instances for pred in sub.predicates: - for src, trg in self.graph.subject_objects(rdflib.URIRef(pred.uri)): - self.transaction.remove((src, rdflib.URIRef(pred.uri), trg)) + for src, trg in self._graph.subject_objects(rdflib.URIRef(pred.uri)): + self._transaction.remove((src, rdflib.URIRef(pred.uri), trg)) # remove node instances for node in sub.nodes: # iterate through node instances - for inst in self.graph.subjects(rdflib.RDF.type, rdflib.URIRef(node.uri)): + for inst in self._graph.subjects(rdflib.RDF.type, rdflib.URIRef(node.uri)): # remove triples where the instance is in the object position - for src, pred in self.graph.subject_predicates(inst): - self.transaction.remove((src, pred, inst)) + for src, pred in self._graph.subject_predicates(inst): + self._transaction.remove((src, pred, inst)) # remove triples where the instance is in the subject position - for pred, trg in self.graph.predicate_objects(inst): - self.transaction.remove((inst, pred, trg)) + for pred, trg in self._graph.predicate_objects(inst): + self._transaction.remove((inst, pred, trg)) # remove instance - self.transaction.remove((inst, rdflib.RDF.type, rdflib.URIRef(node.uri))) + self._transaction.remove((inst, rdflib.RDF.type, rdflib.URIRef(node.uri))) # NOTE: Nothing to do for literals @@ -146,15 +153,15 @@ class SparqlStore(base.TripleStoreBase): self.commit() # migrate schema - self.__schema = schema + self._schema = schema - def _has_type(self, subject: URI, node_type: _schema.Node) -> bool: + def _has_type(self, subject: URI, node_type: bsc.Node) -> bool: """Return True if *subject* is a node of class *node_type* or a subclass thereof.""" if node_type not in self.schema.nodes(): raise errors.ConsistencyError(f'{node_type} is not defined in the schema') - subject_types = list(self.graph.objects(rdflib.URIRef(subject), rdflib.RDF.type)) + subject_types = list(self._graph.objects(rdflib.URIRef(subject), rdflib.RDF.type)) if len(subject_types) == 0: return False elif len(subject_types) == 1: @@ -170,7 +177,7 @@ class SparqlStore(base.TripleStoreBase): def exists( self, - node_type: _schema.Node, + node_type: bsc.Node, guids: typing.Iterable[URI], ): """ @@ -179,7 +186,7 @@ class SparqlStore(base.TripleStoreBase): def create( self, - node_type: _schema.Node, + node_type: bsc.Node, guids: typing.Iterable[URI], ): """ @@ -195,13 +202,13 @@ class SparqlStore(base.TripleStoreBase): # FIXME: node exists and may have a different type! ignore? raise? report? continue # add node - self.transaction.add((guid, rdflib.RDF.type, rdflib.URIRef(node_type.uri))) + self._transaction.add((guid, rdflib.RDF.type, rdflib.URIRef(node_type.uri))) def set( self, - node_type: _schema.Node, # FIXME: is the node_type even needed? Couldn't I infer from the predicate? + node_type: bsc.Node, guids: typing.Iterable[URI], - predicate: _schema.Predicate, + predicate: bsc.Predicate, values: typing.Iterable[typing.Any], ): # check node_type @@ -218,7 +225,7 @@ class SparqlStore(base.TripleStoreBase): return if predicate.unique and len(values) != 1: raise ValueError(values) - if isinstance(predicate.range, _schema.Node): + if isinstance(predicate.range, bsc.Node): values = set(values) # materialize to safeguard against iterators passed as argument inconsistent = {val for val in values if not self._has_type(val, predicate.range)} # catches nodes that don't exist and nodes that have an inconsistent type @@ -236,18 +243,18 @@ class SparqlStore(base.TripleStoreBase): for guid, value in itertools.product(guids, values): guid = rdflib.URIRef(guid) # convert value - if isinstance(predicate.range, _schema.Literal): + if isinstance(predicate.range, bsc.Literal): value = rdflib.Literal(value, datatype=rdflib.URIRef(predicate.range.uri)) - elif isinstance(predicate.range, _schema.Node): + elif isinstance(predicate.range, bsc.Node): value = rdflib.URIRef(value) else: raise errors.UnreachableError() # clear triples for unique predicates if predicate.unique: - for obj in self.graph.objects(guid, pred): + for obj in self._graph.objects(guid, pred): if obj != value: - self.transaction.remove((guid, pred, obj)) + self._transaction.remove((guid, pred, obj)) # add triple - self.transaction.add((guid, pred, value)) + self._transaction.add((guid, pred, value)) ## EOF ## |