from modelverse_state import status import sys from collections import defaultdict import os import rdflib import cPickle as pickle # Work around Python 2 where a 'big integer' automatically becomes a long if sys.version > '3': # pragma: no cover integer_types = (int,) primitive_types = (int, float, str, bool) else: # pragma: no cover integer_types = (int, long) primitive_types = (int, long, float, str, bool, unicode) complex_primitives = frozenset(["if", "while", "assign", "call", "break", "continue", "return","resolve","access", "constant", "input", "output", "declare", "global"]) def instance_to_string(value): return value["value"] def string_to_instance(value): return {'value': value} class ModelverseState(object): def __init__(self, bootfile = None): self.graph = rdflib.Graph() self.parse(bootfile) self.root = 0 self.GC = True self.to_delete = set() def parse(self, filename): triplestore = filename + ".n3" try: if os.path.getmtime(triplestore) > os.path.getmtime(filename): self.graph.parse(filename, format="n3") else: raise Exception("Invalid triplestore") except Exception as e: # We have to parse the file and create the pickle symbols = {} def resolve(symb): try: return int(symb) except: if symb[0] == "?": derefs = symb[1:].split("/") v, _ = self.read_dict(symbols["root"], "__hierarchy") for deref in derefs: v, _ = self.read_dict(v, deref) return v else: return symbols[symb] with open(filename, 'r') as f: for line in f: element_type, constructor = line.split(None, 1) name, values = constructor.split("(", 1) name = name.split()[0] values, _ = values.rsplit(")", 1) if element_type == "Node": if values == "": symbols[name], status = self.create_node() else: value = values if value in complex_primitives: value = string_to_instance(value) else: value = eval(value) symbols[name], status = self.create_nodevalue(value) elif element_type == "Edge": values = [v.split()[0] for v in values.split(",")] symbols[name], status = self.create_edge(resolve(values[0]), resolve(values[1])) else: raise Exception("Unknown element type: %s" % element_type) if status != 100: raise Exception("Failed to process line for reason %s: %s" % (status, line)) # Creation successful, now also create a pickle self.graph.serialize(triplestore, format="n3") #TODO this loses information about the root! return symbols["root"] def read_root(self): return (self.root, status.SUCCESS) def create_node(self): return (rdflib.BNode(), status.SUCCESS) def create_edge(self, source, target): if not isinstance(source, rdflib.BNode): return (None, status.FAIL_CE_SOURCE) if not isinstance(target, rdflib.BNode): return (None, status.FAIL_CE_TARGET) edge = rdflib.BNode() self.graph.add((edge, "hasSource", source)) self.graph.add((edge, "hasTarget", target)) return (edge, status.SUCCESS) def is_valid_datavalue(self, value): if isinstance(value, dict): if "value" in value and value["value"] in complex_primitives: return True else: return False elif not isinstance(value, primitive_types): return False elif isinstance(value, integer_types) and not (-2**63 <= value <= 2**64 - 1): return False return True def create_nodevalue(self, value): if not self.is_valid_datavalue(value): return (None, status.FAIL_CNV_OOB) node = rdflib.BNode() self.graph.add((node, "hasValue", rdflib.Literal(value))) return (node, status.SUCCESS) def create_dict(self, source, data, destination): if not isinstance(source, rdflib.BNode): return (None, status.FAIL_CDICT_SOURCE) if not isinstance(target, rdflib.BNode): return (None, status.FAIL_CDICT_TARGET) if not self.is_valid_datavalue(data): return (None, status.FAIL_CDICT_OOB) n = self.create_nodevalue(data)[0] e = self.create_edge(source, destination)[0] self.create_edge(e, n) return (None, status.SUCCESS) def read_value(self, node): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_RV_UNKNOWN) result = self.graph.query( """ SELECT ?value WHERE { %s "hasValue" ?value. } """ % node if len(result) == 0: return (None, status.FAIL_RV_NO_VALUE) return (result[0], status.SUCCESS) def read_outgoing(self, elem): if not isinstance(elem, rdflib.BNode): return (None, status.FAIL_RO_UNKNOWN) result = self.graph.query( """ SELECT ?link WHERE { %s "hasTarget" ?link. } """ % elem return (list(result), status.SUCCESS) def read_incoming(self, elem): if not isinstance(elem, rdflib.BNode): return (None, status.FAIL_RI_UNKNOWN) result = self.graph.query( """ SELECT ?link WHERE { %s "hasSource" ?link. } """ % elem return (list(result), status.SUCCESS) def read_edge(self, edge): result = self.graph.query( """ SELECT ?source, ?target WHERE { %s "hasSource" ?source; "hasTarget" ?target. } """ % edge if len(result) == 0: return ([None, None], status.FAIL_RE_UNKNOWN) else: return (list(result), status.SUCCESS) def read_dict(self, node, value): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_RDICT_UNKNWON) if not self.is_valid_datavalue(value): return (None, status.FAIL_RDICT_OOB) result = self.graph.query( """ SELECT ?value WHERE { ?main_edge "hasSource" %s; "hasTarget" ?value_node. ?attr_edge "hasSource" ?main_edge; "hasTarget" ?attr_node. ?attr_node "hasValue" %s. ?value_node "hasValue" ?value. } """ % (node, value) if len(result) == 0: return (None, status.FAIL_RDICT_NOT_FOUND) return (result[0], status.SUCCESS) def read_dict_keys(self, node): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_RDICT_UNKNWON) result = self.graph.query( """ SELECT ?key WHERE { ?main_edge "hasSource" %s. ?attr_edge "hasSource" ?main_edge; "hasTarget" ?key. } """ return (list(result), status.SUCCESS) def read_dict_edge(self, node, value): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_RDICTE_UNKNOWN) if not self.is_valid_datavalue(value): return (None, status.FAIL_RDICTE_OOB) result = self.graph.query( """ SELECT ?main_edge WHERE { ?main_edge "hasSource" %s; "hasTarget" ?value_node. ?attr_edge "hasSource" ?main_edge; "hasTarget" ?attr_node. ?attr_node "hasValue" %s. } """ % (node, value) if len(result) == 0: return (None, status.FAIL_RDICTE_NOT_FOUND) return (result[0], status.SUCCESS) def read_dict_node(self, node, value_node): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_RDICTN_UNKNOWN) result = self.graph.query( """ SELECT ?value WHERE { ?main_edge "hasSource" %s; "hasTarget" ?value_node. ?attr_edge "hasSource" ?main_edge; "hasTarget" %s. ?value_node "hasValue" ?value. } """ % (node, value) if len(result) == 0: return (None, status.FAIL_RDICTN_NOT_FOUND) return (result[0], status.SUCCESS) def read_dict_node_edge(self, node, value_node): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_RDICTNE_UNKNOWN) result = self.graph.query( """ SELECT ?main_edge WHERE { ?main_edge "hasSource" %s. ?attr_edge "hasSource" ?main_edge; "hasTarget" %s. } """ % (node, value) if len(result) == 0: return (None, status.FAIL_RDICTNE_NOT_FOUND) return (result[0], status.SUCCESS) def read_reverse_dict(self, node, value): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_RRDICT_UNKNOWN) if not self.is_valid_datavalue(value): return (None, status.FAIL_RRDICT_OOB) result = self.graph.query( """ SELECT ?main_edge WHERE { ?main_edge "hasTarget" %s. ?attr_edge "hasSource" ?main_edge; "hasTarget" ?value_node. ?value_node "hasValue" %s. } """ % (node, value) return (list(result), status.SUCCESS) def delete_node(self, node): if node == self.root: return (None, status.FAIL_DN_UNKNOWN) if not isinstance(node, rdflib.BNode): return (None, status.FAIL_DN_UNKNOWN) # Remove its value if it exists self.graph.remove((node, None, None)) # Get all edges connecting this result = self.graph.query( """ SELECT ?edge WHERE { { ?edge "hasTarget" %s. } UNION { ?edge "hasSource" %s. } } """ # ... and remove them for e in result: self.delete_edge(e) return (None, status.SUCCESS) def delete_edge(self, edge): if not isinstance(node, rdflib.BNode): return (None, status.FAIL_DN_UNKNOWN) # Remove its links self.graph.remove((node, None, None)) # Get all edges connecting this result = self.graph.query( """ SELECT ?edge WHERE { { ?edge "hasTarget" %s. } UNION { ?edge "hasSource" %s. } } """ # ... and remove them for e in result: self.delete_edge(e) return (None, status.SUCCESS) def garbage_collect(self): pass def purge(self): pass