diff options
author | Matthias Baumgartner <dev@igsor.net> | 2023-01-21 18:27:22 +0100 |
---|---|---|
committer | Matthias Baumgartner <dev@igsor.net> | 2023-01-21 18:27:22 +0100 |
commit | c196d2ce73d8351a18c19bcddd4b06d224e644fc (patch) | |
tree | 19c383d39304c4a08c998ebcb05d1775810034ab | |
parent | 965f4dfe41afd552ed6477c75e1286c14e3580f6 (diff) | |
download | bsfs-c196d2ce73d8351a18c19bcddd4b06d224e644fc.tar.gz bsfs-c196d2ce73d8351a18c19bcddd4b06d224e644fc.tar.bz2 bsfs-c196d2ce73d8351a18c19bcddd4b06d224e644fc.zip |
Fetch in graph including results view
-rw-r--r-- | .pylintrc | 6 | ||||
-rw-r--r-- | bsfs/graph/ac/base.py | 4 | ||||
-rw-r--r-- | bsfs/graph/ac/null.py | 4 | ||||
-rw-r--r-- | bsfs/graph/nodes.py | 137 | ||||
-rw-r--r-- | bsfs/graph/result.py | 112 | ||||
-rw-r--r-- | test/graph/test_nodes.py | 95 | ||||
-rw-r--r-- | test/graph/test_result.py | 392 |
7 files changed, 734 insertions, 16 deletions
@@ -76,10 +76,10 @@ max-attributes=7 max-bool-expr=5 # Maximum number of branch for function / method body. -max-branches=15 +max-branches=20 # Maximum number of locals for function / method body. -max-locals=15 +max-locals=20 # Maximum number of parents for a class (see R0901). max-parents=7 @@ -91,7 +91,7 @@ max-public-methods=20 max-returns=15 # Maximum number of statements in function / method body. -max-statements=50 +max-statements=100 # Minimum number of public methods for a class (see R0903). min-public-methods=1 diff --git a/bsfs/graph/ac/base.py b/bsfs/graph/ac/base.py index 0703e2e..79b09e5 100644 --- a/bsfs/graph/ac/base.py +++ b/bsfs/graph/ac/base.py @@ -72,4 +72,8 @@ class AccessControlBase(abc.ABC): def filter_read(self, node_type: schema.Node, query: ast.filter.FilterExpression) -> ast.filter.FilterExpression: """Re-write a filter *query* to get (i.e., read) *node_type* nodes.""" + @abc.abstractmethod + def fetch_read(self, node_type: schema.Node, query: ast.fetch.FetchExpression) -> ast.fetch.FetchExpression: + """Re-write a fetch *query* to get (i.e, read) values for *node_type* nodes.""" + ## EOF ## diff --git a/bsfs/graph/ac/null.py b/bsfs/graph/ac/null.py index 12b4e87..6a923a5 100644 --- a/bsfs/graph/ac/null.py +++ b/bsfs/graph/ac/null.py @@ -54,4 +54,8 @@ class NullAC(base.AccessControlBase): """Re-write a filter *query* to get (i.e., read) *node_type* nodes.""" return query + def fetch_read(self, node_type: schema.Node, query: ast.fetch.FetchExpression) -> ast.fetch.FetchExpression: + """Re-write a fetch *query* to get (i.e, read) values for *node_type* nodes.""" + return query + ## EOF ## diff --git a/bsfs/graph/nodes.py b/bsfs/graph/nodes.py index 5a93f77..a4ba45f 100644 --- a/bsfs/graph/nodes.py +++ b/bsfs/graph/nodes.py @@ -5,17 +5,20 @@ A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # imports +from collections import abc import time import typing # bsfs imports -from bsfs import schema as _schema +from bsfs import schema as bsc from bsfs.namespace import ns +from bsfs.query import ast, validate from bsfs.triple_store import TripleStoreBase from bsfs.utils import errors, URI, typename # inner-module imports from . import ac +from . import result # exports __all__: typing.Sequence[str] = ( @@ -37,7 +40,7 @@ class Nodes(): _user: URI # node type. - _node_type: _schema.Node + _node_type: bsc.Node # guids of nodes. Can be empty. _guids: typing.Set[URI] @@ -46,13 +49,16 @@ class Nodes(): self, backend: TripleStoreBase, user: URI, - node_type: _schema.Node, + node_type: bsc.Node, guids: typing.Iterable[URI], ): + # set main members self._backend = backend self._user = user self._node_type = node_type self._guids = set(guids) + # create helper instances + # FIXME: Assumes that the schema does not change while the instance is in use! self._ac = ac.NullAC(self._backend, self._user) def __eq__(self, other: typing.Any) -> bool: @@ -72,7 +78,7 @@ class Nodes(): return f'{typename(self)}({self._node_type}, {self._guids})' @property - def node_type(self) -> _schema.Node: + def node_type(self) -> bsc.Node: """Return the node's type.""" return self._node_type @@ -83,7 +89,7 @@ class Nodes(): def set( self, - pred: URI, # FIXME: URI or _schema.Predicate? + pred: URI, # FIXME: URI or bsc.Predicate? value: typing.Any, ) -> 'Nodes': """Set predicate *pred* to *value*.""" @@ -91,7 +97,7 @@ class Nodes(): def set_from_iterable( self, - predicate_values: typing.Iterable[typing.Tuple[URI, typing.Any]], # FIXME: URI or _schema.Predicate? + predicate_values: typing.Iterable[typing.Tuple[URI, typing.Any]], # FIXME: URI or bsc.Predicate? ) -> 'Nodes': """Set mutliple predicate-value pairs at once.""" # TODO: Could group predicate_values by predicate to gain some efficiency @@ -120,6 +126,119 @@ class Nodes(): return self + def get( + self, + *paths: typing.Union[URI, typing.Iterable[URI]], + view: typing.Union[typing.Type[list], typing.Type[dict]] = dict, + **view_kwargs, + ) -> typing.Any: + """Get values or nodes at *paths*. + Return an iterator (view=list) or a dict (view=dict) over the results. + """ + # check args + if len(paths) == 0: + raise AttributeError('expected at least one path, found none') + if view not in (dict, list): + raise ValueError(f'expected dict or list, found {view}') + # process paths: create fetch ast, build name mapping, and find unique paths + schema = self._backend.schema + statements = set() + name2path = {} + unique_paths = set() # paths that result in a single (unique) value + normpath: typing.Tuple[URI, ...] + for idx, path in enumerate(paths): + # normalize path + if isinstance(path, str): + normpath = (URI(path), ) + elif isinstance(path, abc.Iterable): + if not all(isinstance(step, str) for step in path): + raise TypeError(path) + normpath = tuple(URI(step) for step in path) + else: + raise TypeError(path) + # check path's schema consistency + if not all(schema.has_predicate(pred) for pred in normpath): + raise errors.ConsistencyError(f'path is not fully covered by the schema: {path}') + # check path's uniqueness + if all(schema.predicate(pred).unique for pred in normpath): + unique_paths.add(path) + # fetch tail predicate + tail = schema.predicate(normpath[-1]) + # determine tail ast node type + factory = ast.fetch.Node if isinstance(tail.range, bsc.Node) else ast.fetch.Value + # assign name + name = f'fetch{idx}' + name2path[name] = (path, tail) + # create tail ast node + curr: ast.fetch.FetchExpression = factory(tail.uri, name) + # walk towards front + hop: URI + for hop in normpath[-2::-1]: + curr = ast.fetch.Fetch(hop, curr) + # add to fetch query + statements.add(curr) + # aggregate fetch statements + if len(statements) == 1: + fetch = next(iter(statements)) + else: + fetch = ast.fetch.All(*statements) + # add access controls to fetch + fetch = self._ac.fetch_read(self.node_type, fetch) + + # compose filter ast + filter = ast.filter.IsIn(self.guids) # pylint: disable=redefined-builtin + # add access controls to filter + filter = self._ac.filter_read(self.node_type, filter) + + # validate queries + validate.Filter(self._backend.schema)(self.node_type, filter) + validate.Fetch(self._backend.schema)(self.node_type, fetch) + + # process results, convert if need be + def triple_iter(): + # query the backend + triples = self._backend.fetch(self.node_type, filter, fetch) + # process triples + for root, name, raw in triples: + # get node + node = Nodes(self._backend, self._user, self.node_type, {root}) + # get path + path, tail = name2path[name] + # covert raw to value + if isinstance(tail.range, bsc.Node): + value = Nodes(self._backend, self._user, tail.range, {raw}) + else: + value = raw + # emit triple + yield node, path, value + + # simplify by default + view_kwargs['node'] = view_kwargs.get('node', len(self._guids) == 1) + view_kwargs['path'] = view_kwargs.get('path', len(paths) == 1) + view_kwargs['value'] = view_kwargs.get('value', True) + + # return results view + if view == list: + return result.to_list_view( + triple_iter(), + # aggregation args + **view_kwargs, + ) + + if view == dict: + return result.to_dict_view( + triple_iter(), + # context + len(self._guids) == 1, + len(paths) == 1, + unique_paths, + # aggregation args + **view_kwargs, + ) + + raise errors.UnreachableError() # view was already checked + + def __set(self, predicate: URI, value: typing.Any): """ """ @@ -145,7 +264,7 @@ class Nodes(): guids = set(self._ensure_nodes(node_type, guids)) # check value - if isinstance(pred.range, _schema.Literal): + if isinstance(pred.range, bsc.Literal): # check write permissions on existing nodes # As long as the user has write permissions, we don't restrict # the creation or modification of literal values. @@ -160,7 +279,7 @@ class Nodes(): [value], ) - elif isinstance(pred.range, _schema.Node): + elif isinstance(pred.range, bsc.Node): # check value type if not isinstance(value, Nodes): raise TypeError(value) @@ -192,7 +311,7 @@ class Nodes(): else: raise errors.UnreachableError() - def _ensure_nodes(self, node_type: _schema.Node, guids: typing.Iterable[URI]): + def _ensure_nodes(self, node_type: bsc.Node, guids: typing.Iterable[URI]): """ """ # check node existence diff --git a/bsfs/graph/result.py b/bsfs/graph/result.py new file mode 100644 index 0000000..3009801 --- /dev/null +++ b/bsfs/graph/result.py @@ -0,0 +1,112 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +from collections import defaultdict +import typing + +# bsfs imports +from bsfs.utils import URI + +# exports +__all__: typing.Sequence[str] = ( + 'to_list_view', + 'to_dict_view', + ) + + +## code ## + +def to_list_view( + triples, + # aggregators + node: bool, + path: bool, + value: bool, # pylint: disable=unused-argument + ): + """Return an iterator over results. + + Dependent on the *node*, *path*, and *value* flags, + the respective component is omitted. + + """ + if node and path: + return iter(val for _, _, val in triples) + if node: + return iter((pred, val) for _, pred, val in triples) + if path: + return iter((subj, val) for subj, _, val in triples) + return iter((subj, pred, val) for subj, pred, val in triples) + + +def to_dict_view( + triples, + # context + one_node: bool, + one_path: bool, + unique_paths: typing.Set[typing.Union[URI, typing.Iterable[URI]]], + # aggregators + node: bool, + path: bool, + value: bool, + ) -> typing.Any: + """Return a dict of results. + + Note that triples are materialized to create this view. + + The returned structure depends on the *node*, *path*, and *value* flags. + If all flags are set to False, returns a dict(node -> dict(path -> set(values))). + Setting a flag to true omits or simplifies the respective component (if possible). + + """ + # NOTE: To create a dict, we need to materialize or make further assumptions + # (e.g., sorted in a specific order). + + data: typing.Any # disable type checks on data since it's very flexibly typed. + + # FIXME: type of data can be overwritten later on (if value) + + if node and path: + data = set() + elif node ^ path: + data = defaultdict(set) + else: + data = defaultdict(lambda: defaultdict(set)) + + for subj, pred, val in triples: + unique = pred in unique_paths + if node and path: + if value and unique and one_node and one_path: + return val + data.add(val) + elif node: + # remove node from result, group by predicate + if value and unique and one_node: + data[pred] = val + else: + data[pred].add(val) + elif path: + # remove predicate from result, group by node + if value and unique and one_path: + data[subj] = val + else: + data[subj].add(val) + else: + if value and unique: + data[subj][pred] = val + else: + data[subj][pred].add(val) + + # FIXME: Combine multiple Nodes instances into one? + + # convert defaultdict to ordinary dict + if node and path: + return data + if node ^ path: + return dict(data) + return {key: dict(val) for key, val in data.items()} + +## EOF ## diff --git a/test/graph/test_nodes.py b/test/graph/test_nodes.py index 2870f35..a4e07ee 100644 --- a/test/graph/test_nodes.py +++ b/test/graph/test_nodes.py @@ -9,8 +9,8 @@ import rdflib import unittest # bsie imports -from bsfs import schema as _schema -from bsfs.namespace import ns +from bsfs import schema as bsc +from bsfs.namespace import Namespace, ns from bsfs.triple_store.sparql import SparqlStore from bsfs.utils import errors, URI @@ -20,11 +20,13 @@ from bsfs.graph.nodes import Nodes ## code ## +bst = Namespace('http://bsfs.ai/schema/Tag') + class TestNodes(unittest.TestCase): def setUp(self): # initialize backend self.backend = SparqlStore() - self.backend.schema = _schema.from_string(''' + self.backend.schema = bsc.from_string(''' prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> prefix xsd: <http://www.w3.org/2001/XMLSchema#> @@ -67,6 +69,11 @@ class TestNodes(unittest.TestCase): rdfs:range bsfs:User ; bsfs:unique "true"^^xsd:boolean . + bst:label rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Tag ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + bst:representative rdfs:subClassOf bsfs:Predicate ; rdfs:domain bsfs:Tag ; rdfs:range bsfs:Entity ; @@ -89,7 +96,8 @@ class TestNodes(unittest.TestCase): (rdflib.URIRef(ns.bse.filesize), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)), (rdflib.URIRef(ns.bse.tag), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)), (rdflib.URIRef(ns.bse.author), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)), - (rdflib.URIRef('http://bsfs.ai/schema/Tag#representative'), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)), + (rdflib.URIRef(bst.representative), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)), + (rdflib.URIRef(bst.label), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)), } # Nodes constructor args self.user = URI('http://example.com/me') @@ -371,6 +379,85 @@ class TestNodes(unittest.TestCase): (self.p_author.uri, Nodes(self.backend, self.user, self.user_type, {URI('http://example.com/me/user#1234'), URI('http://example.com/me/user#4321')})))) self.assertSetEqual(curr, set(self.backend._graph)) + def test_fetch(self): + # setup: add some instances + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}) \ + .set(ns.bse.comment, 'hello world') \ + .set(ns.bse.filesize, 1234) \ + .set(ns.bse.tag, Nodes(self.backend, self.user, self.tag_type, {'http://example.com/me/tag#1234'})) + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}) \ + .set(ns.bse.filesize, 4321) \ + .set(ns.bse.tag, Nodes(self.backend, self.user, self.tag_type, {'http://example.com/me/tag#4321'})) + Nodes(self.backend, self.user, self.tag_type, {'http://example.com/me/tag#1234'}) \ + .set(bst.label, 'tag_label_1234') + Nodes(self.backend, self.user, self.tag_type, {'http://example.com/me/tag#4321'}) \ + .set(bst.label, 'tag_label_4321') + # setup: get nodes instance + nodes = Nodes(self.backend, self.user, self.ent_type, self.ent_ids) + # must pass at least one path + self.assertRaises(AttributeError, nodes.get) + # view must be list or dict + self.assertRaises(ValueError, nodes.get, ns.bse.filesize, view='hello') + self.assertRaises(ValueError, nodes.get, ns.bse.filesize, view=1234) + self.assertRaises(ValueError, nodes.get, ns.bse.filesize, view=tuple) + # can pass path as URI + self.assertDictEqual(nodes.get(ns.bse.filesize), { + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}): 1234, + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}): 4321, + }) + # can pass path as sequence of URI + self.assertDictEqual(nodes.get((ns.bse.tag, bst.label)), { + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}): {'tag_label_1234'}, + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}): {'tag_label_4321'}, + }) + # get returns the same path that was passed + self.assertCountEqual(list(nodes.get((ns.bse.tag, bst.label), path=False, view=list)), [ + (Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}), (ns.bse.tag, bst.label), 'tag_label_1234'), + (Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}), (ns.bse.tag, bst.label), 'tag_label_4321'), + ]) + self.assertCountEqual(list(nodes.get([ns.bse.tag, bst.label], path=False, view=list)), [ + (Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}), [ns.bse.tag, bst.label], 'tag_label_1234'), + (Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}), [ns.bse.tag, bst.label], 'tag_label_4321'), + ]) + # paths must be URI or sequence thereof + self.assertRaises(TypeError, nodes.get, 1234) + self.assertRaises(TypeError, nodes.get, (ns.bse.tag, 1234)) + self.assertRaises(TypeError, nodes.get, (1234, ns.bse.tag)) + self.assertRaises(errors.ConsistencyError, nodes.get, 'hello world') + self.assertRaises(errors.ConsistencyError, nodes.get, ns.bse.invalid) + self.assertRaises(errors.ConsistencyError, nodes.get, (ns.bse.tag, bst.invalid)) + # can pass multiple paths + self.assertDictEqual(nodes.get(ns.bse.filesize, (ns.bse.tag, bst.label)), { + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}): { + ns.bse.filesize: 1234, + (ns.bse.tag, bst.label): {'tag_label_1234'}, + }, + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}): { + ns.bse.filesize: 4321, + (ns.bse.tag, bst.label): {'tag_label_4321'}, + }, + }) + # get respects view + self.assertDictEqual(nodes.get(ns.bse.filesize, view=dict), { + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}): 1234, + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}): 4321, + }) + self.assertSetEqual(set(nodes.get(ns.bse.filesize, view=list)), { + (Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}), 1234), + (Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}), 4321), + }) + # get returns Nodes instance when fetching a node + self.assertDictEqual(nodes.get(ns.bse.tag), { + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}): + {Nodes(self.backend, self.user, self.tag_type, {'http://example.com/me/tag#1234'})}, + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#4321'}): + {Nodes(self.backend, self.user, self.tag_type, {'http://example.com/me/tag#4321'})}, + }) + # get returns a value when fetching a value and omits missing values + self.assertDictEqual(nodes.get(ns.bse.comment), { + Nodes(self.backend, self.user, self.ent_type, {'http://example.com/me/entity#1234'}): {'hello world'}, + }) + ## main ## diff --git a/test/graph/test_result.py b/test/graph/test_result.py new file mode 100644 index 0000000..89b0da1 --- /dev/null +++ b/test/graph/test_result.py @@ -0,0 +1,392 @@ +""" + +Part of the bsfs test suite. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +import unittest + +# bsie imports +from bsfs import schema as bsc +from bsfs.namespace import ns +from bsfs.utils import URI + +# objects to test +from bsfs.graph.result import to_list_view, to_dict_view + + +## code ## + +class TestListView(unittest.TestCase): + def setUp(self): + self.triples_111 = [('ent#1234', ns.bse.iso, 123)] + self.triples_11U = [('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678')] + self.triples_1M1 = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.t_created, '2010-01-02')] + self.triples_1MU = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678')] + self.triples_N11 = [('ent#1234', ns.bse.iso, 123), + ('ent#4321', ns.bse.iso, 321)] + self.triples_N1U = [('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678'), + ('ent#4321', ns.bse.tag, 'tag#4321')] + self.triples_NM1 = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.t_created, '2010-01-02'), + ('ent#4321', ns.bse.iso, 321), + ('ent#4321', ns.bse.t_created, '2022-02-22')] + self.triples_NMU = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678'), + ('ent#4321', ns.bse.iso, 321), + ('ent#4321', ns.bse.t_created, '2022-02-22')] + + def test_copy(self): + # iterator yields tuples + self.assertIsInstance(list(to_list_view([('subject', 'predicate', 'object')], node=False, path=False, value=False))[0], tuple) + # components are not changed + class Foo(): pass + foo = Foo() + self.assertListEqual(list(to_list_view([('subject', 'predicate', 'object')], node=False, path=False, value=False)), + [('subject', 'predicate', 'object')]) + self.assertListEqual(list(to_list_view([(foo, 'predicate', 'object')], node=False, path=False, value=False)), + [(foo, 'predicate', 'object')]) + self.assertListEqual(list(to_list_view([('subject', foo, 'object')], node=False, path=False, value=False)), + [('subject', foo, 'object')]) + self.assertListEqual(list(to_list_view([('subject', 'predicate', foo)], node=False, path=False, value=False)), + [('subject', 'predicate', foo)]) + + def test_agg_none(self): + self.assertListEqual(list(to_list_view(self.triples_111, node=False, path=False, value=False)), self.triples_111) + self.assertListEqual(list(to_list_view(self.triples_11U, node=False, path=False, value=False)), self.triples_11U) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=False, path=False, value=False)), self.triples_1M1) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=False, path=False, value=False)), self.triples_1MU) + self.assertListEqual(list(to_list_view(self.triples_N11, node=False, path=False, value=False)), self.triples_N11) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=False, path=False, value=False)), self.triples_N1U) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=False, path=False, value=False)), self.triples_NM1) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=False, path=False, value=False)), self.triples_NMU) + + def test_agg_node(self): + self.assertListEqual(list(to_list_view(self.triples_111, node=True, path=False, value=False)), + [(ns.bse.iso, 123)]) + self.assertListEqual(list(to_list_view(self.triples_11U, node=True, path=False, value=False)), + [(ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=True, path=False, value=False)), + [(ns.bse.iso, 123), (ns.bse.t_created, '2010-01-02')]) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=True, path=False, value=False)), + [(ns.bse.iso, 123), (ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_N11, node=True, path=False, value=False)), + [(ns.bse.iso, 123), (ns.bse.iso, 321)]) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=True, path=False, value=False)), + [(ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678'), (ns.bse.tag, 'tag#4321')]) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=True, path=False, value=False)), + [(ns.bse.iso, 123), (ns.bse.t_created, '2010-01-02'), (ns.bse.iso, 321), (ns.bse.t_created, '2022-02-22')]) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=True, path=False, value=False)), + [(ns.bse.iso, 123), (ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678'), (ns.bse.iso, 321), (ns.bse.t_created, '2022-02-22')]) + + def test_agg_path(self): + self.assertListEqual(list(to_list_view(self.triples_111, node=False, path=True, value=False)), + [('ent#1234', 123)]) + self.assertListEqual(list(to_list_view(self.triples_11U, node=False, path=True, value=False)), + [('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=False, path=True, value=False)), + [('ent#1234', 123), ('ent#1234', '2010-01-02')]) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=False, path=True, value=False)), + [('ent#1234', 123), ('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_N11, node=False, path=True, value=False)), + [('ent#1234', 123), ('ent#4321', 321)]) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=False, path=True, value=False)), + [('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678'), ('ent#4321', 'tag#4321')]) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=False, path=True, value=False)), + [('ent#1234', 123), ('ent#1234', '2010-01-02'), ('ent#4321', 321), ('ent#4321', '2022-02-22')]) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=False, path=True, value=False)), + [('ent#1234', 123), ('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678'), ('ent#4321', 321), ('ent#4321', '2022-02-22')]) + + def test_agg_node_path(self): + self.assertListEqual(list(to_list_view(self.triples_111, node=True, path=True, value=False)), + [123]) + self.assertListEqual(list(to_list_view(self.triples_11U, node=True, path=True, value=False)), + ['tag#1234', 'tag#5678']) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=True, path=True, value=False)), + [123, '2010-01-02']) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=True, path=True, value=False)), + [123, 'tag#1234', 'tag#5678']) + self.assertListEqual(list(to_list_view(self.triples_N11, node=True, path=True, value=False)), + [123, 321]) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=True, path=True, value=False)), + ['tag#1234', 'tag#5678', 'tag#4321']) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=True, path=True, value=False)), + [123, '2010-01-02', 321, '2022-02-22']) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=True, path=True, value=False)), + [123, 'tag#1234', 'tag#5678', 321, '2022-02-22']) + + def test_agg_value(self): + # value flag has no effect + self.assertListEqual(list(to_list_view(self.triples_111, node=False, path=False, value=False)), self.triples_111) + self.assertListEqual(list(to_list_view(self.triples_11U, node=False, path=False, value=False)), self.triples_11U) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=False, path=False, value=False)), self.triples_1M1) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=False, path=False, value=False)), self.triples_1MU) + self.assertListEqual(list(to_list_view(self.triples_N11, node=False, path=False, value=False)), self.triples_N11) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=False, path=False, value=False)), self.triples_N1U) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=False, path=False, value=False)), self.triples_NM1) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=False, path=False, value=False)), self.triples_NMU) + + def test_agg_node_value(self): + # value flag has no effect -> same test as test_agg_node + self.assertListEqual(list(to_list_view(self.triples_111, node=True, path=False, value=True)), + [(ns.bse.iso, 123)]) + self.assertListEqual(list(to_list_view(self.triples_11U, node=True, path=False, value=True)), + [(ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=True, path=False, value=True)), + [(ns.bse.iso, 123), (ns.bse.t_created, '2010-01-02')]) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=True, path=False, value=True)), + [(ns.bse.iso, 123), (ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_N11, node=True, path=False, value=True)), + [(ns.bse.iso, 123), (ns.bse.iso, 321)]) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=True, path=False, value=True)), + [(ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678'), (ns.bse.tag, 'tag#4321')]) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=True, path=False, value=True)), + [(ns.bse.iso, 123), (ns.bse.t_created, '2010-01-02'), (ns.bse.iso, 321), (ns.bse.t_created, '2022-02-22')]) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=True, path=False, value=True)), + [(ns.bse.iso, 123), (ns.bse.tag, 'tag#1234'), (ns.bse.tag, 'tag#5678'), (ns.bse.iso, 321), (ns.bse.t_created, '2022-02-22')]) + + def test_agg_path_value(self): + # value flag has no effect -> same test as test_agg_path + self.assertListEqual(list(to_list_view(self.triples_111, node=False, path=True, value=True)), + [('ent#1234', 123)]) + self.assertListEqual(list(to_list_view(self.triples_11U, node=False, path=True, value=True)), + [('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=False, path=True, value=True)), + [('ent#1234', 123), ('ent#1234', '2010-01-02')]) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=False, path=True, value=True)), + [('ent#1234', 123), ('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678')]) + self.assertListEqual(list(to_list_view(self.triples_N11, node=False, path=True, value=True)), + [('ent#1234', 123), ('ent#4321', 321)]) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=False, path=True, value=True)), + [('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678'), ('ent#4321', 'tag#4321')]) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=False, path=True, value=True)), + [('ent#1234', 123), ('ent#1234', '2010-01-02'), ('ent#4321', 321), ('ent#4321', '2022-02-22')]) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=False, path=True, value=True)), + [('ent#1234', 123), ('ent#1234', 'tag#1234'), ('ent#1234', 'tag#5678'), ('ent#4321', 321), ('ent#4321', '2022-02-22')]) + + def test_agg_all(self): + # value flag has no effect -> same test as test_agg_node_path + self.assertListEqual(list(to_list_view(self.triples_111, node=True, path=True, value=True)), + [123]) + self.assertListEqual(list(to_list_view(self.triples_11U, node=True, path=True, value=True)), + ['tag#1234', 'tag#5678']) + self.assertListEqual(list(to_list_view(self.triples_1M1, node=True, path=True, value=True)), + [123, '2010-01-02']) + self.assertListEqual(list(to_list_view(self.triples_1MU, node=True, path=True, value=True)), + [123, 'tag#1234', 'tag#5678']) + self.assertListEqual(list(to_list_view(self.triples_N11, node=True, path=True, value=True)), + [123, 321]) + self.assertListEqual(list(to_list_view(self.triples_N1U, node=True, path=True, value=True)), + ['tag#1234', 'tag#5678', 'tag#4321']) + self.assertListEqual(list(to_list_view(self.triples_NM1, node=True, path=True, value=True)), + [123, '2010-01-02', 321, '2022-02-22']) + self.assertListEqual(list(to_list_view(self.triples_NMU, node=True, path=True, value=True)), + [123, 'tag#1234', 'tag#5678', 321, '2022-02-22']) + + +class TestDictView(unittest.TestCase): + def setUp(self): + self.unique_paths = {ns.bse.iso, ns.bse.t_created} + self.triples_111 = [('ent#1234', ns.bse.iso, 123)] + self.triples_11U = [('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678')] + self.triples_1M1 = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.t_created, '2010-01-02')] + self.triples_1MU = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678')] + self.triples_N11 = [('ent#1234', ns.bse.iso, 123), + ('ent#4321', ns.bse.iso, 321)] + self.triples_N1U = [('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678'), + ('ent#4321', ns.bse.tag, 'tag#4321')] + self.triples_NM1 = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.t_created, '2010-01-02'), + ('ent#4321', ns.bse.iso, 321), + ('ent#4321', ns.bse.t_created, '2022-02-22')] + self.triples_NMU = [('ent#1234', ns.bse.iso, 123), + ('ent#1234', ns.bse.tag, 'tag#1234'), + ('ent#1234', ns.bse.tag, 'tag#5678'), + ('ent#4321', ns.bse.iso, 321), + ('ent#4321', ns.bse.t_created, '2022-02-22')] + + def test_errounous_call(self): + # return set instead of value + self.assertSetEqual(to_dict_view(self.triples_111, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=True), + {123}) + self.assertSetEqual(to_dict_view(self.triples_111, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=True), + {123}) + # one_node mismatch: return set of values instead of value + self.assertDictEqual(to_dict_view(self.triples_111, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.iso: {123}}) + # one_path mismatch: return set of values instead of value + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': {123}}) + # unique_paths mismatch: return set of values instead of value + self.assertSetEqual(to_dict_view(self.triples_111, one_node=True, one_path=False, unique_paths={}, node=True, path=True, value=True), + {123}) + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=False, unique_paths={}, node=True, path=False, value=True), + {ns.bse.iso: {123}}) + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=False, unique_paths={}, node=False, path=True, value=True), + {'ent#1234': {123}}) + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=False, unique_paths={}, node=False, path=False, value=True), + {'ent#1234': {ns.bse.iso: {123}}}) + + def test_agg_none(self): + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.iso: {123}}}) + self.assertDictEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.tag: {'tag#1234', 'tag#5678'}}}) + self.assertDictEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.iso: {123}, ns.bse.t_created: {'2010-01-02'}}}) + self.assertDictEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.iso: {123}, ns.bse.tag: {'tag#1234', 'tag#5678'}}}) + self.assertDictEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.iso: {123}}, 'ent#4321': {ns.bse.iso: {321}}}) + self.assertDictEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.tag: {'tag#1234', 'tag#5678'}}, 'ent#4321': {ns.bse.tag: {'tag#4321'}}}) + self.assertDictEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.iso: {123}, ns.bse.t_created: {'2010-01-02'}}, 'ent#4321': {ns.bse.iso: {321}, ns.bse.t_created: {'2022-02-22'}}}) + self.assertDictEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=False), + {'ent#1234': {ns.bse.iso: {123}, ns.bse.tag: {'tag#1234', 'tag#5678'}}, 'ent#4321': {ns.bse.iso: {321}, ns.bse.t_created: {'2022-02-22'}}}) + + def test_agg_node(self): + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.iso: {123}}) + self.assertDictEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.tag: {'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.iso: {123}, ns.bse.t_created: {'2010-01-02'}}) + self.assertDictEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.iso: {123}, ns.bse.tag: {'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.iso: {123, 321}}) + self.assertDictEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.tag: {'tag#1234', 'tag#5678', 'tag#4321'}}) + self.assertDictEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.iso: {123, 321}, ns.bse.t_created: {'2010-01-02', '2022-02-22'}}) + self.assertDictEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=False), + {ns.bse.iso: {123, 321}, ns.bse.tag: {'tag#1234', 'tag#5678'}, ns.bse.t_created: {'2022-02-22'}}) + + def test_agg_path(self): + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {123}}) + self.assertDictEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {123, '2010-01-02'}}) + self.assertDictEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {123, 'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {123}, 'ent#4321': {321}}) + self.assertDictEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {'tag#1234', 'tag#5678'}, 'ent#4321': {'tag#4321'}}) + self.assertDictEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {123, '2010-01-02'}, 'ent#4321': {321, '2022-02-22'}}) + self.assertDictEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=False), + {'ent#1234': {123, 'tag#1234', 'tag#5678'}, 'ent#4321': {321, '2022-02-22'}}) + + def test_agg_node_path(self): + self.assertSetEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=False), + {123}) + self.assertSetEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=False), + {'tag#1234', 'tag#5678'}) + self.assertSetEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=False), + {123, '2010-01-02'}) + self.assertSetEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=False), + {123, 'tag#1234', 'tag#5678'}) + self.assertSetEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=False), + {123, 321}) + self.assertSetEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=False), + {'tag#1234', 'tag#5678', 'tag#4321'}) + self.assertSetEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=False), + {123, '2010-01-02', 321, '2022-02-22'}) + self.assertSetEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=False), + {123, 'tag#1234', 'tag#5678', 321, '2022-02-22'}) + + def test_agg_value(self): + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.iso: 123}}) + self.assertDictEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.tag: {'tag#1234', 'tag#5678'}}}) + self.assertDictEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.iso: 123, ns.bse.t_created: '2010-01-02'}}) + self.assertDictEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.iso: 123, ns.bse.tag: {'tag#1234', 'tag#5678'}}}) + self.assertDictEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.iso: 123}, 'ent#4321': {ns.bse.iso: 321}}) + self.assertDictEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.tag: {'tag#1234', 'tag#5678'}}, 'ent#4321': {ns.bse.tag: {'tag#4321'}}}) + self.assertDictEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.iso: 123, ns.bse.t_created: '2010-01-02'}, 'ent#4321': {ns.bse.iso: 321, ns.bse.t_created: '2022-02-22'}}) + self.assertDictEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=False, value=True), + {'ent#1234': {ns.bse.iso: 123, ns.bse.tag: {'tag#1234', 'tag#5678'}}, 'ent#4321': {ns.bse.iso: 321, ns.bse.t_created: '2022-02-22'}}) + + def test_agg_node_value(self): + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.iso: 123}) + self.assertDictEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.tag: {'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.iso: 123, ns.bse.t_created: '2010-01-02'}) + self.assertDictEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.iso: 123, ns.bse.tag: {'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.iso: {123, 321}}) + self.assertDictEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.tag: {'tag#1234', 'tag#5678', 'tag#4321'}}) + self.assertDictEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.iso: {123, 321}, ns.bse.t_created: {'2010-01-02', '2022-02-22'}}) + self.assertDictEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=False, value=True), + {ns.bse.iso: {123, 321}, ns.bse.tag: {'tag#1234', 'tag#5678'}, ns.bse.t_created: {'2022-02-22'}}) + + def test_agg_path_value(self): + self.assertDictEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': 123}) + self.assertDictEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': {'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': {123, '2010-01-02'}}) + self.assertDictEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': {123, 'tag#1234', 'tag#5678'}}) + self.assertDictEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': 123, 'ent#4321': 321}) + self.assertDictEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': {'tag#1234', 'tag#5678'}, 'ent#4321': {'tag#4321'}}) + self.assertDictEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': {123, '2010-01-02'}, 'ent#4321': {321, '2022-02-22'}}) + self.assertDictEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=False, path=True, value=True), + {'ent#1234': {123, 'tag#1234', 'tag#5678'}, 'ent#4321': {321, '2022-02-22'}}) + + def test_agg_all(self): + self.assertEqual(to_dict_view(self.triples_111, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=True), + 123) + self.assertSetEqual(to_dict_view(self.triples_11U, one_node=True, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=True), + {'tag#1234', 'tag#5678'}) + self.assertSetEqual(to_dict_view(self.triples_1M1, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=True), + {123, '2010-01-02'}) + self.assertSetEqual(to_dict_view(self.triples_1MU, one_node=True, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=True), + {123, 'tag#1234', 'tag#5678'}) + self.assertSetEqual(to_dict_view(self.triples_N11, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=True), + {123, 321}) + self.assertSetEqual(to_dict_view(self.triples_N1U, one_node=False, one_path=True, unique_paths=self.unique_paths, node=True, path=True, value=True), + {'tag#1234', 'tag#5678', 'tag#4321'}) + self.assertSetEqual(to_dict_view(self.triples_NM1, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=True), + {123, '2010-01-02', 321, '2022-02-22'}) + self.assertSetEqual(to_dict_view(self.triples_NMU, one_node=False, one_path=False, unique_paths=self.unique_paths, node=True, path=True, value=True), + {123, 'tag#1234', 'tag#5678', 321, '2022-02-22'}) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## |