simphony / simphony-osp

A framework that aims to achieve interoperability between software such as simulation engines, databases and data repositories using a knowledge graph as the common language.
https://simphony.readthedocs.io
Other
16 stars 12 forks source link

SimPhoNy cache mechanism introduced in v4.0.0rc3 incompatible with algorithms using DFS #820

Open kysrpex opened 1 year ago

kysrpex commented 1 year ago

The SimPhoNy caching feature yields an exception when used in combination with a DFS algorithm. A good example is the find function from the simphony_osp.tools.search module in SimPhoNy v4.0.0rc4.

Can be reproduced in SimPhoNy v4.0.0rc4 using a wrapper that has the SimPhoNy caching feature enabled.

from simphony_osp.namespaces import dcat, dcterms, foaf
from simphony_osp.tools import search
from simphony_osp.wrappers import AllegroGraph

session = AllegroGraph(f"<https://****:****@****:****/repositories/***>"); session.locked = True;

with session:
    session.clear()
    session.commit()
    person = foaf.Person()
    dataset = dcat.Dataset()
    dataset[dcterms.creator] = person
    session.commit()

dataset = session.get(oclass=dcat.Dataset).one()
list(search.find(dataset))
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-5-531347a879ca> in <module>
----> 1 list(search.find(dataset))

~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/tools/search.py in _iter(criterion, root, rel, annotation, max_depth, current_depth, visited)
    115 
    116     if current_depth < max_depth:
--> 117         for sub in chain(
    118             *(root.iter(rel=r) for r in rel),
    119             *(root.annotations_iter(rel=r) for r in annotation)

~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/ontology/individual.py in annotations_iter(self, rel, return_rel)
   2014             yield from entities_and_annotations
   2015         else:
-> 2016             yield from map(lambda x: x[0], entities_and_annotations)
   2017 
   2018     # ↑ --------------- ↑

~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/ontology/individual.py in <genexpr>(.0)
   1994                 rel, typing=OntologyAnnotation
   1995             )
-> 1996         entities_and_annotations = (
   1997             (
   1998                 self.session.from_identifier(o),

~/.miniconda3/envs/simphony/lib/python3.8/site-packages/rdflib/graph.py in triples(self, triple)
    464                 yield _s, p, _o
    465         else:
--> 466             for (s, p, o), cg in self.__store.triples((s, p, o), context=self):
    467                 yield s, p, o
    468 

~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/interfaces/interface.py in triples(self, triple_pattern, context, ignore_buffers)
    592             )
    593 
--> 594         yield from ((triple, iter(())) for triple in triple_pool)
    595 
    596     def __len__(self, context: Graph = None, ignore_buffers=False) -> int:

~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/interfaces/interface.py in <genexpr>(.0)
    592             )
    593 
--> 594         yield from ((triple, iter(())) for triple in triple_pool)
    595 
    596     def __len__(self, context: Graph = None, ignore_buffers=False) -> int:

~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/interfaces/interface.py in <genexpr>(.0)
    569         triple_pool = query_method(triple_pattern)
    570         if not ignore_buffers:
--> 571             triple_pool = (
    572                 triple
    573                 for triple in triple_pool

~/.miniconda3/envs/simphony/lib/python3.8/site-packages/rdflib/graph.py in triples(self, triple)
    464                 yield _s, p, _o
    465         else:
--> 466             for (s, p, o), cg in self.__store.triples((s, p, o), context=self):
    467                 yield s, p, o
    468 

~/.miniconda3/envs/simphony/lib/python3.8/site-packages/rdflib/plugins/stores/memory.py in triples(self, triple_pattern, context)
    109                                 pass
    110                         else:  # object unbound
--> 111                             for o in subjectDictionary[p].keys():
    112                                 yield (subject, p, o), self.__contexts()
    113             else:  # given subject not found

RuntimeError: dictionary keys changed during iteration