def test_transitive_dep_null_context_triples_no_imports(custom_bundle): dep_dep_desc = Descriptor.load(''' id: dep_dep includes: - http://example.com/ctx ''') dep_desc = Descriptor.load(''' id: dep dependencies: - dep_dep ''') test_desc = Descriptor.load(''' id: test dependencies: - dep ''') depgraph = ConjunctiveGraph() ctx_graph = depgraph.get_context('http://example.com/ctx') quad = (URIRef('http://example.org/sub'), URIRef('http://example.org/prop'), URIRef('http://example.org/obj'), ctx_graph) depgraph.add(quad) with custom_bundle(dep_dep_desc, graph=depgraph) as depdepbun, \ custom_bundle(dep_desc, bundles_directory=depdepbun.bundles_directory) as depbun, \ custom_bundle(test_desc, bundles_directory=depbun.bundles_directory) as testbun, \ Bundle('test', bundles_directory=testbun.bundles_directory) as bnd: assert set([quad[:3]]) == set(bnd.rdf.triples((None, None, None)))
def test_add_to_graph_not_supported(custom_bundle): dep_desc = Descriptor.load(''' id: dep includes: - http://example.com/ctx ''') test_desc = Descriptor.load(''' id: test dependencies: - dep ''') depgraph = ConjunctiveGraph() ctx_graph = depgraph.get_context('http://example.com/ctx') quad = (URIRef('http://example.org/sub'), URIRef('http://example.org/prop'), URIRef('http://example.org/obj'), ctx_graph) depgraph.add(quad) with custom_bundle(dep_desc, graph=depgraph) as depbun, \ custom_bundle(test_desc, bundles_directory=depbun.bundles_directory) as testbun, \ Bundle('test', bundles_directory=testbun.bundles_directory) as bnd: with pytest.raises(ZODB.POSException.ReadOnlyError): with transaction.manager: bnd.rdf.add((URIRef('http://example.org/sub'), URIRef('http://example.org/prop'), URIRef('http://example.org/obj')))
def test_triples_choices_context_not_included(custom_bundle): dep_desc = Descriptor.load(''' id: dep includes: - http://example.com/ctxg ''') test_desc = Descriptor.load(''' id: test dependencies: - dep ''') depgraph = ConjunctiveGraph() ctx_graph = depgraph.get_context('http://example.com/ctx') quad = (URIRef('http://example.org/sub'), URIRef('http://example.org/prop'), URIRef('http://example.org/obj'), ctx_graph) depgraph.add(quad) with custom_bundle(dep_desc, graph=depgraph) as depbun, \ custom_bundle(test_desc, bundles_directory=depbun.bundles_directory) as testbun, \ Bundle('test', bundles_directory=testbun.bundles_directory) as bnd: match = False for x in bnd.rdf.triples_choices((URIRef('http://example.org/sub'), URIRef('http://example.org/prop'), [URIRef('http://example.org/obj')]), context=ctx_graph): match = True assert not match
def bundle_helper(descriptor, graph=None, bundles_directory=None, homedir=None, **kwargs): ''' Helper for creating bundles for testing. Uses `~owmeta_core.bundle.Installer` to lay out a bundle Parameters ---------- descriptor : Descriptor Describes the bundle graph : rdflib.graph.ConjunctiveGraph, optional Graph from which the bundle contexts will be generated. If not provided, a graph will be created with the triple ``(ex:a, ex:b, ex:c)`` in a context named ``ex:ctx``, where ``ex:`` expands to ``http://example.org/`` bundles_directory : str, optional The directory where the bundles should be installed. If not provided, creates a temporary directory to house the bundles and cleans them up afterwards homedir : str, optional Test home directory. If not provided, one will be created based on test directory ''' res = BundleData() with tempfile.TemporaryDirectory(prefix=__name__ + '.') as testdir: res.testdir = testdir res.test_homedir = homedir or p(res.testdir, 'homedir') res.bundle_source_directory = p(res.testdir, 'bundle_source') res.bundles_directory = bundles_directory or p(res.test_homedir, '.owmeta', 'bundles') if not homedir: os.mkdir(res.test_homedir) os.mkdir(res.bundle_source_directory) if not bundles_directory: os.makedirs(res.bundles_directory) # This is a bit of an integration test since it would be a PITA to maintain the bundle # format separately from the installer res.descriptor = descriptor if graph is None: graph = ConjunctiveGraph() ctxg = graph.get_context(URIRef('http://example.org/ctx')) ctxg.add((URIRef('http://example.org/a'), URIRef('http://example.org/b'), URIRef('http://example.org/c'))) res.installer = Installer(res.bundle_source_directory, res.bundles_directory, graph=graph, **kwargs) res.bundle_directory = res.installer.install(res.descriptor) yield res
def test_quad_not_in_dependency(custom_bundle): dep_desc = Descriptor.load(''' id: dep includes: - http://example.com/ctx ''') test_desc = Descriptor.load(''' id: test dependencies: - dep ''') depgraph = ConjunctiveGraph() ctx_graph = depgraph.get_context('http://example.com/other_ctx') quad = (URIRef('http://example.org/sub'), URIRef('http://example.org/prop'), URIRef('http://example.org/obj'), ctx_graph) depgraph.add(quad) with custom_bundle(dep_desc, graph=depgraph) as depbun, \ custom_bundle(test_desc, bundles_directory=depbun.bundles_directory) as testbun, \ Bundle('test', bundles_directory=testbun.bundles_directory) as bnd: assert quad not in bnd.rdf
class py_drone_graph_core: ''' sample instantiation, d_graph = ldg.py_drone_graph(ontology_myID, load_graph_file) where, 1. ontology_myID, uuid for this drone e.g. "MjlmNmVmZTAtNGU1OS00N2I4LWI3MzYtODZkMDQ0MTRiNzcxCg==" 2. load_graph_file, turtle file or (folder) for db initialization e.g. base.ttl has the following sections, 1. initialization and graph i/o 2. utility functions like generating uuid etc. ''' ################# # class variables ################# g = None # graph Id = None # local drone id files_loaded = False # flag to prevent ontology reload my_host_name = None # host_name BASE = None # base namespace # initialization and graph i/o ############################################# ####################### # class initialization ####################### def __init__(self, ontology_myid, graph_dict, my_base, my_host_name): ''' Args: ontology_myid (str): uuid for this drone graph_dict (dict.): configuration data ''' # save hostname self.my_host_name = my_host_name + '/' # fix base self.BASE = rdflib.Namespace(my_base) # set base id self.Id = ontology_myid # load graph, include ttl to load if required self.setup_graph(graph_dict) ########################## # setup and load graph ########################## def setup_graph(self, graph_dict): ''' Args: graph_dict (dict.): configuration data ''' # get config for graph name, physical db location and it's format # added extraction of load_graph_file self.graph_name = graph_dict.get('name', ontology_db) graph_location = graph_dict.get('db_location', ontology_db_location) graph_file_format = graph_dict.get('file_format', ontology_landrs_file_format) load_graph_file = graph_dict.get('file', ontology_db_file) # test created instances with pyshacl? pshac = graph_dict.get('pyshacl', 'False') if pshac == 'False': self.pyshacl = False else: self.pyshacl = True shacl_filename = graph_dict.get('shacl_filename', '*shape.ttl') ontology_filename = graph_dict.get('ontology_filename', 'ontology.ttl') # other shape files flight_shacl_filename = graph_dict.get('flight_shacl_filename', extra_shape_file) shacl_constraint_filename = graph_dict.get('shacl_constraint_filename', '*shapes.ttl') # added file reload startegy graph_file_reload = graph_dict.get('file_reload', 'False') # does the db exist? reload_db = True if graph_file_reload == 'False' and os.path.isfile(graph_location + '.sqlite'): reload_db = False # check any folders exist os.makedirs(os.path.dirname(graph_location), exist_ok=True) # store location uri = Literal("sqlite:///%(here)s/%(loc)s.sqlite" % { "here": os.getcwd(), "loc": graph_location }) # create store store_ident = URIRef('store_' + self.graph_name) self.store = plugin.get("SQLAlchemy", Store)(identifier=store_ident) # was self.g.open self.store.open(uri, create=True) # and ConjunctiveGraph self.g = ConjunctiveGraph(self.store) # vars for first graph context ident = self.BASE.term(self.graph_name) # create and load graph self.g1 = Graph(self.store, identifier=ident) # vars for shape graph context ident2 = self.BASE.term(self.graph_name + '_shape') # create and load shape graph self.g2 = Graph(self.store, identifier=ident2) # vars for config shape graph context ident3 = self.BASE.term(self.graph_name + '_config') # create and load shape graph self.g_config = Graph(self.store, identifier=ident3) # print graphs print("Graphs") for c in self.g.contexts(): print("-- %s " % c) # add LANDRS and other namespaces, this converts the pythonized names to # something more readable self.g.namespace_manager.bind('landrs', LANDRS) self.g.namespace_manager.bind('sosa', SOSA) #self.g.namespace_manager.bind('base', BASE) #self.g.namespace_manager.bind('qudt-unit-1-1', QUDT_UNIT) self.g.namespace_manager.bind('qudt-1-1', QUDT) self.g.namespace_manager.bind('geo', GEO) self.g.namespace_manager.bind('rdfg', RDFG) # Load graph? if load_graph_file and not self.files_loaded and reload_db: # folder or file? if os.path.isdir(load_graph_file): # get the list of files files_in_graph_folder = os.walk(load_graph_file) print("Folder provided for import.") # loop for (dirpath, dirnames, filenames) in files_in_graph_folder: for file in filenames: file_path = os.path.join(dirpath, file) # each file if turtle if os.path.splitext(file_path)[-1].lower( ) == "." + graph_file_format: if os.path.isfile(file_path): print("file", file_path) self.files_loaded = True # load the individual file try: # test for shacl files, seperate graph if fnmatch.fnmatch( os.path.basename(file_path), shacl_filename): self.g2.load( file_path, format=graph_file_format, publicID=self.my_host_name) else: self.g1.load( file_path, format=graph_file_format, publicID=self.my_host_name) except Exception as ex: print("Could not load graph file: " + str(ex)) else: print("File provided for import.") if os.path.isfile(load_graph_file): self.files_loaded = True # load the file try: self.g1.load(load_graph_file, format=graph_file_format, publicID=self.my_host_name) except Exception as ex: print("Could not load graph file: " + str(ex)) # turn off pyshacl if no seperate shape graph self.pyshacl = False # additional config shape files, folder? if os.path.isdir(flight_shacl_filename): file_list = glob.glob(flight_shacl_filename + shacl_constraint_filename) for fn in file_list: # extract target graph name pos = fn.find(shacl_constraint_filename[1:]) - 1 pos2 = fn.rfind('/') + 1 # set name g_name = fn[pos2:pos] print("file", fn, g_name) # create graph # vars for config shape graph context identn = self.BASE.term(g_name) # create and load shape graph self.g_tmp = Graph(self.store, identifier=identn) # try to create try: self.g_tmp.load(fn, format=graph_file_format, publicID=self.my_host_name) except Exception as ex: print("Could not load shape file: " + str(ex)) # stand alone? elif os.path.isfile(flight_shacl_filename): print("file", flight_shacl_filename) try: self.g_config.load(flight_shacl_filename, format=graph_file_format, publicID=self.my_host_name) except Exception as ex: print("Could not load shape file: " + str(ex)) ############# # create uuid ############# def generate_uuid(self): return base64.urlsafe_b64encode( uuid.uuid4().bytes)[:-2].decode('utf-8') ###################### # dump graph as turtle ###################### def dump_graph(self, id): graph = self.g.get_context(self.BASE.term(id)) if graph: return graph.serialize(format="turtle", base=self.my_host_name) else: return None ####################### # dump graphs as turtle ####################### def list_graphs(self): ret = '@prefix rdfg: <http://www.w3.org/2004/03/trix/rdfg-1/> .\n' + \ '@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n' + \ '@prefix rdflib: <http://rdflib.net/projects#> .\n\n' # loop over graphs and append for c in self.g.contexts(): ret = ret + str(c) + '\n' # return it return ret ########################################### # find namespace for node from uuid # solves problem of having objects created # on ld.landrs.org OR the drone. # Also test existance. ########################################### def find_node_from_uuid(self, uuid, id_type=None): ''' Args: uuid (str): uuid to find Returns: URIRef: node associated with uuid ''' # check drone definition exists and if it is local or on ld.landrs.org id_node = LDLBASE.term(uuid) if not (id_node, RDF.type, id_type) in self.g: # from myself? id_node = self.BASE.term(uuid) if not (id_node, RDF.type, id_type) in self.g: # return info return None # if here, exists and node resolved return id_node ########################################## # recursive drill down through blank nodes ########################################## def blank_node_recursion(self, blnk, grph): # check blank if isinstance(blnk, BNode): # get nodes for sn, pn, on in self.g.triples((blnk, None, None)): grph.add((sn, pn, on)) # recurse self.blank_node_recursion(on, grph) ######################################### # get graph with node and its blank nodes ######################################### def get_graph_with_node(self, id_node): ''' Args: id_node (str): node id to put into graph Returns: graph: graph of id_node ''' node_graph = Graph() # get id's triples for s, p, o in self.g.triples((id_node, None, None)): node_graph.add((s, p, o)) # if associated blank not, get its tripples self.blank_node_recursion(o, node_graph) # return the new graph return node_graph ########################## # get triples for an id ########################## def get_id_data(self, id, json=False): ''' Args: id (str): uuid to query Returns: dict.: query result ''' # dictionary id_data = {} # is the id a local graph? # if so return the graph as turtle g = self.g.get_context(self.BASE.term(id)) if g: # return info return g.serialize(format="turtle", base=self.my_host_name) # id_data # check drone definition exists and if it is local or on ld.landrs.org # we will support ld.landrs.org ids due to potential connectivity problems id_node = self.find_node_from_uuid(id) if not id_node: # return info return {"status": "id: " + id + " not found."} if not json: node_graph = self.get_graph_with_node(id_node) # return info return node_graph.serialize(format="turtle", base=self.my_host_name) # id_data else: # get id's triples for s, p, o in self.g.triples((id_node, None, None)): print("{} is a {}".format(p, o)) id_data.update({p: o}) # return json here return id_data ################################## # routine to convert graph to json ################################## def graph_to_json(self, g): """ Pass in a rdflib.Graph and get back a chunk of JSON using the Talis JSON serialization for RDF: http://n2.talis.com/wiki/RDF_JSON_Specification """ g_json = {} # go through all the triples in the graph for s, p, o in g: # initialize property dictionary if we've got a new subject if not s in g_json.keys(): # if not json.has_key(s): g_json[s] = {} # initialize object list if we've got a new subject-property combo if not p in g_json[s].keys(): # if not json[s].has_key(p): g_json[s][p] = [] # determine the value dictionary for the object v = {'value': o} if isinstance(o, rdflib.URIRef): v['type'] = 'uri' elif isinstance(o, rdflib.BNode): v['type'] = 'bnode' elif isinstance(o, rdflib.Literal): v['type'] = 'literal' if o.language: v['lang'] = o.language if o.datatype: v['datatype'] = o.datatype # add the triple g_json[s][p].append(v) return json.dumps(g_json, indent=4)
class InMemoryStorage(object): def __init__(self): store = IOMemory() self.g = ConjunctiveGraph(store=store) self.g.bind("lada",ns_lada) self.g.bind('data', ns_data) self.g.bind('cube', ns_cube) self.g.bind('qb', ns_cube) self.g.bind('lcd', ns_lcd) self.g.bind('xsd', ns_xsd) self.g.bind('qb4cc', ns_qb4cc) self.g.bind('skos', ns_skos) self.initNs = { 'lada': ns_lada, 'data': ns_data, 'qb': ns_cube, 'lcd': ns_lcd, 'xsd': ns_xsd, 'qb4cc': ns_qb4cc, 'skos': ns_skos } def _concatenate_graphs(self, graphs): source = Graph() for g in graphs: if g in graph_dict: source += self.g.get_context(graph_dict[g]) elif type(g) is URIRef: source += self.g.get_context(g) return source def add_triple(self, triple, context): if context: if type(context) is str: self.g.get_context(graph_dict[context]).add(triple) else: self.g.get_context(context).add(triple) else: self.g.add(triple) def add_graph(self, graph, context): if context: g = None if type(context) is str: g = self.g.get_context(graph_dict[context]) else: g = self.g.get_context(context) g += graph else: self.g += graph def add_file(self, file, format, context): if context: if type(context) is str: self.g.get_context(graph_dict[context]).parse(file, format=format) else: self.g.get_context(context).parse(file, format=format) else: self.g.parse(file, format=format) def query(self, queryString, contexts): if contexts: if type(contexts) is list: return self._concatenate_graphs(contexts).query(queryString, initNs=self.initNs) elif type(contexts) is str: return self.g.get_context(graph_dict[contexts]).query(queryString, initNs=self.initNs) else: return self.g.get_context(contexts).query(queryString, initNs=self.initNs) else: return self.g.query(queryString, initNs=self.initNs) def value(self, subject, predicate, context): if context: if type(context) is str: return self.g.get_context(graph_dict[context]).value(subject, predicate) else: return self.g.get_context(context).value(subject, predicate) else: return self.g.value(subject, predicate) def remove(self, triple_pattern, contexts): if contexts: if type(contexts) is list: self._concatenate_graphs(contexts).remove(triple_pattern) else: self.g.get_context(graph_dict[contexts]).remove(triple_pattern) else: self.g.remove(triple_pattern) def clear(self, context): if context: if type(context) is str: self.g.remove_context(self.g.get_context(graph_dict[context])) else: self.g.remove_context(self.g.get_context(context)) else: self.g.remove( (None, None, None) ) def count_triples(self): c = 0; for s, p, o in self.g: c = c +1; return c def export(self, context): if type(context) is str: self.g.get_context(graph_dict[context]).serialize(context + ".ttl", format="turtle")
class Project: def __init__(self, uri, storePath): if (uri[-1] != "/"): raise SemPipeException("A Module must be a directory and its URI must end with a /") self.n = URIRef(uri) self.g = ConjunctiveGraph('IOMemory') self.storePath = storePath if storePath and os.path.exists(storePath+"/store.nquads"): self.g.parse(storePath + "/store.nq", format='nquads') self.confGraph = self.g.get_context(URIRef("sempipe:confgraph")) #self.storePath = storePath ## Get the Sleepycat plugin. #self.store = plugin.get('Sleepycat', Store)('rdfstore') ## Open previously created store, or create it if it doesn't exist yet #self.g = ConjunctiveGraph(store="Sleepycat", # identifier = URIRef(self.default_graph_uri)) ##path = mkdtemp() #rt = self.g.open(self.storePath, create=False) #if rt == NO_STORE: # # There is no underlying Sleepycat infrastructure, create it # self.g.open(self.storePath, create=True) #else: # assert rt == VALID_STORE, "The underlying store is corrupt" else: #Aggregate graphs self.confGraph = self.g.get_context(URIRef("sempipe:confgraph")) self._loadconf() for graph in self.confGraph.objects(self.n, semp.dataGraph): self.loadData(graph) for updateList in self.confGraph.objects(self.n, semp.update): for updateInstruction in Collection(self.confGraph, updateList): self.updateGraph(str(updateInstruction)) self.commit() # Cache HostedSpaces self.hostedSpaces = [] res = self.confGraph.query(""" SELECT ?baseURI ?mapTo ?index ?htaccess { ?baseURI a semp:HostedSpace ; semp:mapTo ?mapTo ; semp:mapIndexTo ?index ; semp:mapHTAccessTo ?htaccess . } """, initNs={"semp": semp}) for s in res: self.hostedSpaces.append(HostedSpace._make(s)) def __str__(self): return str(self.n) def __repr__(self): return "{0}({1},{2})".format(self.__class__.__name__, repr(self.n), repr(self.storePath)) def _loadconf(self, uri=None): """Loads a graph and all config-graphs it references as configuration graphs @param uri: a URIRef, defaults to self.n+SempPipe.conffilename""" uri = uri or URIRef(self.n + conffilename) if self.g.get_context(uri): print("ConfGraph {} already in database".format(uri), file=sys.stderr) return print("Loading {} as config graph".format(uri), file=sys.stderr) newgraph = self.g.parse(uri, format="n3") self.confGraph += newgraph self.confGraph.add((uri, rdf.type, semp.ConfGraph)) imports = set(newgraph.objects(uri, semp.confGraph)) imports |= set(newgraph.objects(self.n, semp.confGraph)) imports = filter(lambda x: not self.g.get_context(x), imports) #Recursively load additional graphs for imp in imports: self._loadconf(imp) def loadData(self, url): """Loads a data graph""" return parse(self.g, url) def updateGraph(self, sparql): try: self.g.update(sparql) except: raise SemPipeException("Update instruction failed:\n{}".format(str(sparql))) def hostedSpace(self, resource, reverse=False): """Picks the best matching hostedSpace for the given resource. If reverse is set, resource is considered to be a path relative to the buildDir and the corresponding URIRef is returned.""" if reverse: hostedSpaces = filter(lambda s: resource.startswith(self.buildDir + s.mapTo), self.hostedSpaces) else: hostedSpaces = filter(lambda s: resource.startswith(s.baseURI), self.hostedSpaces) # Find the best match, which is the most specific one: try: return max(hostedSpaces, key=lambda s: len(s.baseURI)) except ValueError: raise SemPipeException("No hosted space found for {}".format(resource)) def contentLocation(self, base, ending): if str(base)[-1] == '/': index = self.hostedSpace(base).index return str(base) + index + ending else: return str(base) + ending @property def buildDir(self): return next(self.confGraph.objects(self.n, semp.buildDir)) def buildLocation(self, resource): """Determines the filename in the build directory corresponding to a URI.""" hs = self.hostedSpace(resource) return self.buildDir + hs.mapTo + resource[len(hs.baseURI):] def buildLocationToResource(self, buildLocation): """Determines the filename in the build directory corresponding to a URI.""" if not buildLocation.startswith(self.buildDir): raise SemPipeException("{} is not in buildDir".format(buildLocation)) hs = self.hostedSpace(buildLocation, reverse=True) return URIRef(hs.baseURI + buildLocation[len(self.buildDir + hs.mapTo):]) def copy(self, source, dest): """Publish a resource by copying a file Note that dest is the URI where the resource should be published, the corresponding directory in the build directory is derived automatically.""" dest = self.buildLocation(dest) print("copy {0} to {1}".format(source, dest), file=sys.stderr) directory = dest.rsplit("/",1)[0] directory = fileurl2path(directory) print(" Making shure directory {0} exists".format(directory), file=sys.stderr) os.makedirs(directory, mode=0o777, exist_ok=True) shutil.copy(fileurl2path(source), fileurl2path(dest)) print(" done", file=sys.stderr) def write(self, dest, data): """Publishes a file with contents data""" dest = self.buildLocation(dest) print("writing data to {0}".format(dest), file=sys.stderr) directory = dest.rsplit("/",1)[0] directory = fileurl2path(directory) print(" Making shure directory {0} exists".format(directory), file=sys.stderr) os.makedirs(directory, mode=0o777, exist_ok=True) with open(fileurl2path(dest), mode="wb") as f: f.write(data) print(" done", file=sys.stderr) def buildResource(self, resource): """Looks up the description of the resource and builds it Creates all representations of the resource and adds information to the .htaccess if required. semp:Reource type of a Resource semp:subject What the page is mainly about. This is used by semp:Render to know which one is the root node. semp:source points to a source file semp:representation A variant of the resource, obtainable by content nogtiation semp:content-type indicates the targetted content type semp:buildCommand tells how to build the representation. Use semp:Render to render with fresnel Lenses and an XSLT. Use semp:Raw to just take the surce file. semp:content-type used on a source file or representation to indicate the content type """ representations = self.confGraph.objects(resource, semp.representation) for r in representations: content_type = next(self.confGraph.objects(r, semp["content-type"])) try: source = next(self.confGraph.objects(r, semp.source)) except(StopIteration): source = None try: language = next(self.confGraph.objects(r, semp.language)) except(StopIteration): language = None try: quality = next(self.confGraph.objects(r, semp.quality)) except(StopIteration): quality = None contentLocation = URIRef(self.contentLocation(resource, self.defaultEnding(content_type, language))) if semp.Raw in self.confGraph.objects(r, semp.buildCommand): self.copy(source, contentLocation) elif semp.Render in self.confGraph.objects(r, semp.buildCommand): #fresnelGraph = Graph() #multiparse(fresnelGraph, self.confGraph.objects(r, semp.fresnelGraph)) #instanceGraph = Graph() #parse(instanceGraph, source) #multiparse(instanceGraph, self.confGraph.objects(r, semp.additionalData)) fresnelGraph = self.g instanceGraph = self.g ctx = Fresnel.Context(fresnelGraph=fresnelGraph, instanceGraph=instanceGraph) box = Fresnel.ContainerBox(ctx) box.append(resource) box.select() box.portray() tree = box.transform() #Fresnel.prettify(tree) # results in bad whitespace self.write(contentLocation, etree.tostring(tree,encoding="UTF-8",xml_declaration=True)) elif semp.Serialize in self.confGraph.objects(r, semp.buildCommand): graph = self.g.get_context(resource) self.write(contentLocation, graph.serialize()) else: raise SemPipeException("Failed to produce representation {0} of {1}".format(r, resource)) try: xslt_files = Collection(self.confGraph, next(self.confGraph.objects(r, semp.transformation))) buildloc = self.buildLocation(contentLocation) for xslt_file in xslt_files: command = ["xsltproc", "--output", fileurl2path(buildloc), fileurl2path(str(xslt_file)), fileurl2path(buildloc)] print("Running transformation", *command, file=sys.stderr) subprocess.call(command) except (StopIteration): pass #write typemap typemap = self.typemap(resource) if typemap is not None: self.write(resource, typemap) def typemap(self, resource): """ Returns the contents of a type-map file for all representations of the given resource. Returns None if no typemap is necessary. """ representations = sorted(self.confGraph.objects(resource, semp.representation)) typemap_url = lambda url: str(url).rsplit("/", 1)[-1] typemap = ["URI: {}\n\n".format(typemap_url(resource))] typemap_needed = False for r in representations: content_type = next(self.confGraph.objects(r, semp["content-type"])) try: source = next(self.confGraph.objects(r, semp.source)) except(StopIteration): source = None try: language = next(self.confGraph.objects(r, semp.language)) except(StopIteration): language = None try: quality = next(self.confGraph.objects(r, semp.quality)) except(StopIteration): quality = None contentLocation = URIRef(self.contentLocation(resource, self.defaultEnding(content_type, language))) typemap.append("URI: {}\n".format(typemap_url(contentLocation))) typemap.append("Content-type: {}".format(content_type)) if quality is not None: typemap[-1] += "; q={}\n".format(quality) typemap_needed = True else: typemap[-1] += "\n" if language is not None: typemap.append("Content-language: {}\n".format(language)) typemap.append("\n") if typemap_needed: return "".join(typemap).encode("UTF-8") else: return None def defaultEnding(self, content_type=None, language=None): cts = { "application/rdf+xml": ".rdf", "application/xhtml+xml": ".xhtml", "text/html": ".html", None: "" } if content_type: typeendings = list(self.confGraph.objects(URIRef("http://purl.org/NET/mediatypes/" + content_type), semp.defaultExtension)) if len(typeendings) > 1: raise SemPipeException("ambiguous extension for content-type {} in confGraph.".format(content_type)) elif len(typeendings) < 1: raise SemPipeException("No extension for content-type {} found".format(content_type)) else: typeending = typeendings[0] else: typeending = "" return ("." + language if language else "") + "." + typeending def write_htaccess(self): """Writes all required .htaccess files.""" # First generate the directives for each resource filesinfo = []; resources = self.resources for resource in resources: info = []; filesinfo.append((resource, info)); if self.typemap(resource) is not None: info.append("SetHandler type-map\n") # Generate the .htaccess files htaccessfiles = dict() for resource, info in filter(lambda x: x[1], filesinfo): directory, filename = resource.rsplit("/", 1) ht = htaccessfiles.setdefault(directory, []) ht.append('<Files "{}">\n'.format(filename)) ht += info ht.append('</Files>\n') for directory, ht in htaccessfiles.items(): print("Writing a .htaccess in {}".format(directory), file=sys.stderr) filename = self.hostedSpace(resource).htaccess self.write(directory + "/" + filename, "".join(ht).encode("UTF-8")) def publish(self): import getpass import subprocess """Walks through HostedSpaces and upload the respective files from the build diretory. (Instead we should walk through the build directory. Will be changed later.)""" hostedSpacesQuery = """ SELECT ?space ?method ?command ?invocation WHERE { ?space a semp:HostedSpace . ?space semp:publishMethod ?method . ?method semp:command ?command . ?method semp:invocation ?invocation . }""" askForQuery = """ SELECT ?variable WHERE { { ?method semp:askFor ?variable . } UNION { ?method semp:askForHidden ?variable . } }""" #?hidden #{ ?method semp:askFor ?variable . } #UNION #{ ?method semp:askForHidden ?variable . # BIND ("true"^^xsd:boolean as ?hidden) } for spaceRow in self.confGraph.query(hostedSpacesQuery, initNs={"semp": semp}).bindings: space = spaceRow[Variable("?space")] method = spaceRow[Variable("?method")] answers = dict() for question in self.confGraph.query(askForQuery, initNs={"semp": semp}, initBindings={"method": method}).bindings: answers[question[Variable("?variable")]] = getpass.getpass("{} for method {}".format(question[Variable("?variable")], method)) spacedir = self.buildLocation(space) command = [] for arg in Collection(self.confGraph, spaceRow[Variable("command")]): command.append(str(arg).format("",fileurl2path(spacedir),str(space),**answers)) print("Running {}".format(command[0]), file=sys.stderr) subprocess.call(command) @property def resources(self): return self.confGraph.subjects(rdf.type, semp.Resource) def commit(self): self.g.commit() if self.storePath: self.g.serialize(destination=self.storePath+"/store.nq", format='nquads', encoding='UTF-8') def serialize(self): return self.g.serialize() def close(self): self.g.close()