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