Mercurial > code > home > repos > patchablegraph
diff patchablegraph.py @ 4:dc4f852d0d70
reformat and add some types
author | drewp@bigasterisk.com |
---|---|
date | Wed, 24 Nov 2021 19:47:35 -0800 |
parents | 703adc4f78b1 |
children | 1b6718a54c00 |
line wrap: on
line diff
--- a/patchablegraph.py Wed Nov 24 19:47:06 2021 -0800 +++ b/patchablegraph.py Wed Nov 24 19:47:35 2021 -0800 @@ -20,18 +20,23 @@ differences between RDF graphs """ -import json, logging, itertools, html +import html +import itertools +import json +import logging +from typing import Callable, List, Optional, cast +import cyclone.sse +import cyclone.web +from cycloneerr import PrettyErrorHandler from prometheus_client import Counter, Gauge, Summary from rdfdb.grapheditapi import GraphEditApi +from rdfdb.patch import Patch +from rdfdb.rdflibpatch import inGraph, patchQuads from rdflib import ConjunctiveGraph from rdflib.namespace import NamespaceManager from rdflib.parser import StringInputSource from rdflib.plugins.serializers.jsonld import from_rdf -import cyclone.sse -from cycloneerr import PrettyErrorHandler -from rdfdb.patch import Patch -from rdfdb.rdflibpatch import patchQuads, inGraph log = logging.getLogger('patchablegraph') @@ -46,20 +51,24 @@ def _graphFromQuads2(q): g = ConjunctiveGraph() #g.addN(q) # no effect on nquad output - for s,p,o,c in q: - g.get_context(c).add((s,p,o)) # kind of works with broken rdflib nquad serializer code + for s, p, o, c in q: + g.get_context(c).add((s, p, o)) # kind of works with broken rdflib nquad serializer code #g.store.add((s,p,o), c) # no effect on nquad output return g -def jsonFromPatch(p): - return json.dumps({'patch': { - 'adds': from_rdf(_graphFromQuads2(p.addQuads)), - 'deletes': from_rdf(_graphFromQuads2(p.delQuads)), - }}) -patchAsJson = jsonFromPatch # deprecated name + +def jsonFromPatch(p: Patch) -> str: + return json.dumps( + {'patch': { + 'adds': from_rdf(_graphFromQuads2(p.addQuads)), + 'deletes': from_rdf(_graphFromQuads2(p.delQuads)), + }}) -def patchFromJson(j): +patchAsJson = jsonFromPatch # deprecated name + + +def patchFromJson(j: str) -> Patch: body = json.loads(j)['patch'] a = ConjunctiveGraph() a.parse(StringInputSource(json.dumps(body['adds']).encode('utf8')), format='json-ld') @@ -67,28 +76,34 @@ d.parse(StringInputSource(json.dumps(body['deletes']).encode('utf8')), format='json-ld') return Patch(addGraph=a, delGraph=d) -def graphAsJson(g): + +def graphAsJson(g: ConjunctiveGraph) -> str: # This is not the same as g.serialize(format='json-ld')! That # version omits literal datatypes. return json.dumps(from_rdf(g)) + _graphsInProcess = itertools.count() + + class PatchableGraph(GraphEditApi): """ Master graph that you modify with self.patch, and we get the updates to all current listeners. """ - def __init__(self): - self._graph = ConjunctiveGraph() - self._observers = [] - scales.init(self, '/patchableGraph%s' % next(_graphsInProcess)) - _serialize = scales.PmfStat('serialize') - def serialize(self, *arg, **kw): - with self._serialize.time(): - return self._graph.serialize(*arg, **kw) + def __init__(self, label: Optional[str] = None): + self._graph = ConjunctiveGraph() + self._observers: List[Callable[[str], None]] = [] + if label is None: + label = f'patchableGraph{next(_graphsInProcess)}' + self.label = label - def patch(self, p): + def serialize(self, *arg, **kw) -> bytes: + with SERIALIZE_CALLS.labels(graph=self.label).time(): + return cast(bytes, self._graph.serialize(*arg, **kw)) + + def patch(self, p: Patch): with PATCH_CALLS.labels(graph=self.label).time(): # assuming no stmt is both in p.addQuads and p.delQuads. dels = set([q for q in p.delQuads if inGraph(q, self._graph)]) @@ -96,30 +111,27 @@ minimizedP = Patch(addQuads=adds, delQuads=dels) if minimizedP.isNoop(): return - patchQuads(self._graph, - deleteQuads=dels, - addQuads=adds, - perfect=False) # true? + patchQuads(self._graph, deleteQuads=dels, addQuads=adds, perfect=False) # true? for ob in self._observers: ob(patchAsJson(p)) STATEMENT_COUNT.labels(graph=self.label).set(len(self._graph)) - def asJsonLd(self): + def asJsonLd(self) -> str: return graphAsJson(self._graph) - def addObserver(self, onPatch): + def addObserver(self, onPatch: Callable[[str], None]): self._observers.append(onPatch) OBSERVERS_CURRENT.labels(graph=self.label).set(len(self._observers)) OBSERVERS_ADDED.labels(graph=self.label).inc() - def removeObserver(self, onPatch): + def removeObserver(self, onPatch: Callable[[str], None]): try: self._observers.remove(onPatch) except ValueError: pass self._currentObservers = len(self._observers) - def setToGraph(self, newGraph): + def setToGraph(self, newGraph: ConjunctiveGraph): self.patch(Patch.fromDiff(self._graph, newGraph)) @@ -127,6 +139,7 @@ class CycloneGraphHandler(PrettyErrorHandler, cyclone.web.RequestHandler): + def initialize(self, masterGraph: PatchableGraph): self.masterGraph = masterGraph @@ -227,6 +240,7 @@ response to send 'x-accel-buffering: no', per http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering """ + def __init__(self, application, request, masterGraph): cyclone.sse.SSEHandler.__init__(self, application, request) self.masterGraph = masterGraph