From e8492489098ef5f8566214e083cd2c2d1d449f5a Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Thu, 8 Dec 2022 16:36:19 +0100 Subject: sparql triple store and graph (nodes, mostly) --- bsfs/graph/graph.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 bsfs/graph/graph.py (limited to 'bsfs/graph/graph.py') diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py new file mode 100644 index 0000000..06271f6 --- /dev/null +++ b/bsfs/graph/graph.py @@ -0,0 +1,65 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +import typing + +# bsfs imports +from bsfs.schema import Schema +from bsfs.triple_store import TripleStoreBase +from bsfs.utils import URI, typename + +# inner-module imports +from . import nodes + +# exports +__all__: typing.Sequence[str] = ( + 'Graph', + ) + + +## code ## + +class Graph(): + """ + """ + # link to the triple storage backend. + __backend: TripleStoreBase + + # user uri. + __user: URI + + def __init__(self, backend: TripleStoreBase, user: URI): + self.__backend = backend + self.__user = user + + def __hash__(self) -> int: + 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 + + def __repr__(self) -> str: + return f'{typename(self)}(backend={repr(self.__backend)}, user={self.__user})' + + def __str__(self) -> str: + return f'{typename(self)}({str(self.__backend)}, {self.__user})' + + @property + def schema(self) -> Schema: + """Return the store's local schema.""" + return self.__backend.schema + + def nodes(self, node_type: URI, guids: typing.Iterable[URI]) -> nodes.Nodes: + """ + """ + node_type = self.schema.node(node_type) + # NOTE: Nodes constructor materializes guids. + return nodes.Nodes(self.__backend, self.__user, node_type, guids) + +## EOF ## -- cgit v1.2.3 From ebc3ccb5fdce950649bfcbf18f88ecb4a9dbcad0 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 18 Dec 2022 13:53:34 +0100 Subject: import fixes --- bsfs/graph/graph.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bsfs/graph/graph.py') diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py index 06271f6..d5e1b88 100644 --- a/bsfs/graph/graph.py +++ b/bsfs/graph/graph.py @@ -13,7 +13,7 @@ from bsfs.triple_store import TripleStoreBase from bsfs.utils import URI, typename # inner-module imports -from . import nodes +from . import nodes as _nodes # exports __all__: typing.Sequence[str] = ( @@ -55,11 +55,11 @@ class Graph(): """Return the store's local schema.""" return self.__backend.schema - def nodes(self, node_type: URI, guids: typing.Iterable[URI]) -> nodes.Nodes: """ + def nodes(self, node_type: URI, guids: typing.Iterable[URI]) -> _nodes.Nodes: """ node_type = self.schema.node(node_type) # NOTE: Nodes constructor materializes guids. - return nodes.Nodes(self.__backend, self.__user, node_type, guids) + return _nodes.Nodes(self._backend, self._user, type_, guids) ## EOF ## -- cgit v1.2.3 From edd5390b6db1550f6a80a46f0eaf5f3916997532 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 18 Dec 2022 14:06:58 +0100 Subject: information hiding --- bsfs/graph/graph.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'bsfs/graph/graph.py') 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: -- cgit v1.2.3 From 3165c3609a5061135ff7393747f8dc3f7f7abe0c Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 18 Dec 2022 14:07:56 +0100 Subject: graph schema migration --- bsfs/graph/graph.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'bsfs/graph/graph.py') diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py index 71973c2..4a36ff6 100644 --- a/bsfs/graph/graph.py +++ b/bsfs/graph/graph.py @@ -5,6 +5,7 @@ A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # imports +import os import typing # bsfs imports @@ -35,6 +36,8 @@ class Graph(): def __init__(self, backend: TripleStoreBase, user: URI): self._backend = backend self._user = user + # ensure Graph schema requirements + self.migrate(self._backend.schema) def __hash__(self) -> int: return hash((type(self), self._backend, self._user)) @@ -55,7 +58,28 @@ class Graph(): """Return the store's local schema.""" return self._backend.schema + def migrate(self, schema: Schema, append: bool = True) -> 'Graph': + """Migrate the current schema to a new *schema*. + + Appends to the current schema by default; control this via *append*. + The `Graph` may add additional classes to the schema that are required for its interals. + """ + # check args + if not isinstance(schema, Schema): + raise TypeError(schema) + # append to current schema + if append: + schema = schema + self._backend.schema + # add Graph schema requirements + with open(os.path.join(os.path.dirname(__file__), 'schema.nt'), mode='rt', encoding='UTF-8') as ifile: + schema = schema + Schema.from_string(ifile.read()) + # migrate schema in backend + # FIXME: consult access controls! + self._backend.schema = schema + # return self + return self + def nodes(self, node_type: URI, guids: typing.Iterable[URI]) -> _nodes.Nodes: """ node_type = self.schema.node(node_type) -- cgit v1.2.3 From e19c8f9d0818a147832df0945188ea14de9c7690 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 18 Dec 2022 14:15:18 +0100 Subject: documentation, types, and style fixes --- bsfs/graph/graph.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'bsfs/graph/graph.py') diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py index 4a36ff6..87f7a31 100644 --- a/bsfs/graph/graph.py +++ b/bsfs/graph/graph.py @@ -25,8 +25,15 @@ __all__: typing.Sequence[str] = ( ## code ## class Graph(): + """The Graph class is + + The Graph class provides a convenient interface to query and access a graph. + Since it logically builds on the concept of graphs it is easier to + navigate than raw triple stores. Naturally, it uses a triple store + as *backend*. It also controls actions via access permissions to a *user*. + """ - """ + # link to the triple storage backend. _backend: TripleStoreBase @@ -81,8 +88,14 @@ class Graph(): return self def nodes(self, node_type: URI, guids: typing.Iterable[URI]) -> _nodes.Nodes: + """Return nodes *guids* of type *node_type* as a `bsfs.graph.Nodes` instance. + + Note that the *guids* need not to exist (however, the *node_type* has + to be part of the schema). Inexistent guids will be created (using + *node_type*) once some data is assigned to them. + """ - node_type = self.schema.node(node_type) + type_ = self.schema.node(node_type) # NOTE: Nodes constructor materializes guids. return _nodes.Nodes(self._backend, self._user, type_, guids) -- cgit v1.2.3 From 8ed8dbb4010a9a75cf6e61d185327825fe783776 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sun, 18 Dec 2022 14:16:40 +0100 Subject: Graph.node interface --- bsfs/graph/graph.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'bsfs/graph/graph.py') diff --git a/bsfs/graph/graph.py b/bsfs/graph/graph.py index 87f7a31..b7b9f1c 100644 --- a/bsfs/graph/graph.py +++ b/bsfs/graph/graph.py @@ -99,4 +99,15 @@ class Graph(): # NOTE: Nodes constructor materializes guids. return _nodes.Nodes(self._backend, self._user, type_, guids) + def node(self, node_type: URI, guid: URI) -> _nodes.Nodes: + """Return node *guid* of type *node_type* as a `bsfs.graph.Nodes` instance. + + Note that the *guids* need not to exist (however, the *node_type* has + to be part of the schema). An inexistent guid will be created (using + *node_type*) once some data is assigned to them. + + """ + type_ = self.schema.node(node_type) + return _nodes.Nodes(self._backend, self._user, type_, {guid}) + ## EOF ## -- cgit v1.2.3