aboutsummaryrefslogtreecommitdiffstats
path: root/bsfs
diff options
context:
space:
mode:
authorMatthias Baumgartner <dev@igsor.net>2022-12-18 14:06:58 +0100
committerMatthias Baumgartner <dev@igsor.net>2022-12-18 14:06:58 +0100
commitedd5390b6db1550f6a80a46f0eaf5f3916997532 (patch)
tree090caad31d0bbcc63fa1473a7b44baa02b785982 /bsfs
parentebc3ccb5fdce950649bfcbf18f88ecb4a9dbcad0 (diff)
downloadbsfs-edd5390b6db1550f6a80a46f0eaf5f3916997532.tar.gz
bsfs-edd5390b6db1550f6a80a46f0eaf5f3916997532.tar.bz2
bsfs-edd5390b6db1550f6a80a46f0eaf5f3916997532.zip
information hiding
Diffstat (limited to 'bsfs')
-rw-r--r--bsfs/graph/ac/base.py12
-rw-r--r--bsfs/graph/graph.py20
-rw-r--r--bsfs/graph/nodes.py58
-rw-r--r--bsfs/triple_store/sparql.py81
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 ##