Mercurial > code > home > repos > collector
changeset 13:bfd95926be6e default tip
initial port to starlette. missing some disconnect & cleanup functionality
author | drewp@bigasterisk.com |
---|---|
date | Sat, 26 Nov 2022 14:13:51 -0800 |
parents | 032e59be8fe9 |
children | |
files | collector.py deploy.yaml merge.py patchsink.py patchsource.py pdm.lock pyproject.toml src/CollectorState.ts vite.config.ts |
diffstat | 9 files changed, 283 insertions(+), 373 deletions(-) [+] |
line wrap: on
line diff
--- a/collector.py Fri Nov 25 20:58:08 2022 -0800 +++ b/collector.py Sat Nov 26 14:13:51 2022 -0800 @@ -7,48 +7,29 @@ - filter out unneeded stmts from the sources - give a time resolution and concatenate any patches that come faster than that res """ +import asyncio import json import logging import time from typing import Dict, List, Optional, Set, Union -import cyclone.sse -import cyclone.web -from docopt import docopt from patchablegraph.patchablegraph import jsonFromPatch -from patchablegraph.patchsource import PatchSource, ReconnectingPatchSource from prometheus_client import Summary -from prometheus_client.exposition import generate_latest -from prometheus_client.registry import REGISTRY from rdfdb.patch import Patch from rdflib import Namespace, URIRef -from standardservice.logsetup import enableTwistedLog, log -from twisted.internet import defer, reactor + +from starlette.applications import Starlette +from starlette.requests import Request +from starlette.responses import JSONResponse +from starlette.routing import Route +from starlette_exporter import PrometheusMiddleware, handle_metrics from collector_config import config from merge import SourceUri, ActiveStatements, LocalStatements -from patchsink import PatchSink - -import cyclone.sse -def py3_sendEvent(self, message, event=None, eid=None, retry=None): - - if isinstance(message, dict): - message = cyclone.sse.escape.json_encode(message) - if isinstance(message, str): - message = message.encode("utf-8") - assert isinstance(message, bytes) - if eid: - self.transport.write(b"id: %s\n" % eid) - if event: - self.transport.write(b"event: %s\n" % event) - if retry: - self.transport.write(b"retry: %s\n" % retry) - self.transport.write(b"data: %s\n\n" % message) - - -cyclone.sse.SSEHandler.sendEvent = py3_sendEvent - - +from patchsink import PatchSink, PatchSinkResponse +from patchsource import PatchSource +logging.basicConfig(level=logging.DEBUG) +log=logging.getLogger() ROOM = Namespace("http://projects.bigasterisk.com/room/") COLLECTOR = SourceUri(URIRef('http://bigasterisk.com/sse_collector/')) @@ -57,14 +38,6 @@ SEND_UPDATE_PATCH_CALLS = Summary("send_update_patch_calls", 'calls') -class Metrics(cyclone.web.RequestHandler): - - def get(self): - self.add_header('content-type', 'text/plain') - self.write(generate_latest(REGISTRY)) - - - class GraphClients(object): """ All the active PatchSources and SSEHandlers @@ -76,20 +49,20 @@ """ def __init__(self): - self.clients: Dict[SourceUri, Union[PatchSource, ReconnectingPatchSource]] = {} # (COLLECTOR is not listed) - self.handlers: Set[PatchSink] = set() + self.clients: Dict[SourceUri, PatchSource] = {} # (COLLECTOR is not listed) + self.handlers: Set[PatchSinkResponse] = set() self.statements: ActiveStatements = ActiveStatements() self._localStatements = LocalStatements(self._onPatch) def state(self) -> Dict: return { - 'clients': sorted([ps.state() for ps in self.clients.values()], key=lambda r: r['reconnectedPatchSource']['url']), + 'clients': sorted([ps.state() for ps in self.clients.values()], key=lambda r: r['url']), 'sseHandlers': sorted([h.state() for h in self.handlers], key=lambda r: (r['streamId'], r['created'])), 'statements': self.statements.state(), } - def _sourcesForHandler(self, handler: PatchSink) -> List[SourceUri]: + def _sourcesForHandler(self, handler: PatchSinkResponse) -> List[SourceUri]: streamId = handler.streamId matches = [s for s in config['streams'] if s['id'] == streamId] if len(matches) != 1: @@ -107,14 +80,14 @@ self._sendUpdatePatch() - if log.isEnabledFor(logging.DEBUG): + if 0 and log.isEnabledFor(logging.DEBUG): self.statements.pprintTable() if source != COLLECTOR: self._localStatements.setSourceState(source, ROOM['fullGraphReceived'] if fullGraph else ROOM['patchesReceived']) @SEND_UPDATE_PATCH_CALLS.time() - def _sendUpdatePatch(self, handler: Optional[PatchSink] = None): + def _sendUpdatePatch(self, handler: Optional[PatchSinkResponse] = None): """ send a patch event out this handler to bring it up to date with self.statements @@ -129,7 +102,7 @@ # reduce loops here- prepare all patches at once for h in selected: period = .9 - if 'Raspbian' in h.request.headers.get('user-agent', ''): + if 'Raspbian' in h.user_agent: period = 5 if h.lastPatchSentTime > now - period: continue @@ -142,12 +115,12 @@ # it up into multiple sends, although there's no # guarantee at all since any single stmt could be any # length. - h.sendEvent(message=jsonFromPatch(p), event=b'patch') + h.sendEvent(message=jsonFromPatch(p), event='patch') h.lastPatchSentTime = now else: log.debug('nothing to send to %s', h) - def addSseHandler(self, handler: PatchSink): + def addSseHandler(self, handler: PatchSinkResponse): log.info('addSseHandler %r %r', handler, handler.streamId) # fail early if id doesn't match @@ -159,14 +132,14 @@ if source not in self.clients and source != COLLECTOR: log.debug('connect to patch source %s', source) self._localStatements.setSourceState(source, ROOM['connect']) - self.clients[source] = ReconnectingPatchSource(source, - listener=lambda p, fullGraph, source=source: self._onPatch(source, p, fullGraph), - reconnectSecs=10) + self.clients[source] = PatchSource(source, + listener=lambda p, fullGraph, source=source: self._onPatch(source, p, fullGraph), + reconnectSecs=10) log.debug('bring new client up to date') self._sendUpdatePatch(handler) - def removeSseHandler(self, handler: PatchSink): + def removeSseHandler(self, handler: PatchSinkResponse): log.info('removeSseHandler %r', handler) self.statements.discardHandler(handler) for source in self._sourcesForHandler(handler): @@ -204,50 +177,32 @@ garbage.add(stmt) -class State(cyclone.web.RequestHandler): - - @GET_STATE_CALLS.time() - def get(self) -> None: - try: - state = self.settings.graphClients.state() - msg = json.dumps({'graphClients': state}, indent=2, default=lambda obj: '<unserializable>') - log.info(msg) - self.write(msg) - except Exception: - import traceback - traceback.print_exc() - raise - - -class GraphList(cyclone.web.RequestHandler): - - def get(self) -> None: - self.write(json.dumps(config['streams'])) +@GET_STATE_CALLS.time() +def State(request: Request) -> JSONResponse: + state = request.app.state.graphClients.state() + msg = json.dumps({'graphClients': state}, indent=2, default=lambda obj: '<unserializable>') + log.info(msg) + return JSONResponse({'graphClients': state}) -if __name__ == '__main__': - arg = docopt(""" - Usage: sse_collector.py [options] +def GraphList(request: Request) -> JSONResponse: + return JSONResponse(config['streams']) - -v Verbose - -i Info level only - """) - - if True: - enableTwistedLog() - log.setLevel(logging.DEBUG if arg['-v'] else logging.INFO) - defer.setDebugging(True) - +def main(): graphClients = GraphClients() - reactor.listenTCP( - 9072, - cyclone.web.Application( # - handlers=[ - (r'/state', State), - (r'/graph/', GraphList), - (r'/graph/(.+)', PatchSink), - (r'/metrics', Metrics), - ], graphClients=graphClients), - interface='::') - reactor.run() + app = Starlette( + debug=True, + routes=[ + Route('/state', State), + Route('/graph/', GraphList), + Route('/graph/{stream_id:str}', PatchSink), + ]) + app.state.graphClients = graphClients + + app.add_middleware(PrometheusMiddleware, app_name='collector') + app.add_route("/metrics", handle_metrics) + return app + + +app = main() \ No newline at end of file
--- a/deploy.yaml Fri Nov 25 20:58:08 2022 -0800 +++ b/deploy.yaml Sat Nov 26 14:13:51 2022 -0800 @@ -15,10 +15,10 @@ proxy_buffering off; server { access_log /dev/stderr main; - location = /collector/state { proxy_pass http://127.0.0.1:9072/state; } - location /collector/graph/ { proxy_pass http://127.0.0.1:9072/graph/; } - location = /collector/metrics { proxy_pass http://127.0.0.1:9072/metrics; } - location = /metrics { proxy_pass http://127.0.0.1:9072/metrics; } + location = /collector/state { proxy_pass http://127.0.0.1:8001/state; } + location /collector/graph/ { proxy_pass http://127.0.0.1:8001/graph/; } + location = /collector/metrics { proxy_pass http://127.0.0.1:8001/metrics; } + location = /metrics { proxy_pass http://127.0.0.1:8001/metrics; } location = /collector/vite-ws { proxy_pass http://127.0.0.1:8002/collector/vite-ws; @@ -61,11 +61,13 @@ command: - pdm - run - - python - - collector.py - - "-v" + - uvicorn + - --port=8001 + - --host=0.0.0.0 + - collector:app + - --reload ports: - - containerPort: 9072 + - containerPort: 8001 - name: view image: bang5:5000/collector_image @@ -73,8 +75,7 @@ - pnpx - vite - --mode=dev - - --logLevel=info - - --debug + # - --debug ports: - containerPort: 8002 ---
--- a/merge.py Fri Nov 25 20:58:08 2022 -0800 +++ b/merge.py Sat Nov 26 14:13:51 2022 -0800 @@ -1,3 +1,4 @@ +import logging import collections from typing import Callable, Dict, List, Optional, Sequence, Set, Tuple, Union, NewType from prometheus_client import Summary @@ -5,16 +6,19 @@ from rdfdb.patch import Patch from rdflib import Namespace, URIRef from rdflib.term import Node -from standardservice.logsetup import enableTwistedLog, log -from patchsink import PatchSink +log = logging.getLogger() LOCAL_STATEMENTS_PATCH_CALLS = Summary("local_statements_patch_calls", 'calls') MAKE_SYNC_PATCH_CALLS = Summary("make_sync_patch_calls", 'calls') REPLACE_SOURCE_STATEMENTS_CALLS = Summary("replace_source_statements_calls", 'calls') +# we deal with PatchSourceResponse in here, but only as objs to __contains__ and compare. +from patchsink import PatchSinkResponse +OutputHandler = Union[PatchSinkResponse, type(None)] # A patchsink.PatchSinkResponse, but make type error if we try to look in it + SourceUri = NewType('SourceUri', URIRef) Statement = Tuple[Node, Node, Node, Node] -StatementTable = Dict[Statement, Tuple[Set[SourceUri], Set[PatchSink]]] +StatementTable = Dict[Statement, Tuple[Set[SourceUri], Set[OutputHandler]]] ROOM = Namespace("http://projects.bigasterisk.com/room/") COLLECTOR = SourceUri(URIRef('http://bigasterisk.com/sse_collector/')) @@ -111,7 +115,7 @@ print("%03d. %-80s from %s to %s" % (i, abbrevStmt(stmt), [abbrevTerm(s) for s in sources], handlers)) @MAKE_SYNC_PATCH_CALLS.time() - def makeSyncPatch(self, handler: PatchSink, sources: Set[SourceUri]): + def makeSyncPatch(self, handler: OutputHandler, sources: Set[SourceUri]): # todo: this could run all handlers at once, which is how we # use it anyway adds = [] @@ -172,7 +176,7 @@ self.applySourcePatch(source, Patch(addQuads=newStmts, delQuads=[])) - def discardHandler(self, handler: PatchSink): + def discardHandler(self, handler: OutputHandler): with self.postDeleteStatements() as garbage: for stmt, (sources, handlers) in self.table.items(): handlers.discard(handler)
--- a/patchsink.py Fri Nov 25 20:58:08 2022 -0800 +++ b/patchsink.py Sat Nov 26 14:13:51 2022 -0800 @@ -1,43 +1,82 @@ +"""sends patches out an SSE response to a collector client who wants a collection of graphs""" import time -from typing import Dict +from typing import Dict, Any, Optional +import asyncio +from starlette.requests import Request +from sse_starlette.sse import EventSourceResponse +import logging +import queue +log = logging.getLogger('writer') -import cyclone.sse -import cyclone.web +async def iq(q): + while True: + elem = await q.get() + yield elem -class PatchSink(cyclone.sse.SSEHandler): - _handlerSerial = 0 +class PatchSinkResponse(EventSourceResponse): - def __init__(self, application: cyclone.web.Application, request): - cyclone.sse.SSEHandler.__init__(self, application, request) - self.bound = False + def __init__( + self, + + status_code: int = 200, + headers: Optional[Dict] = None, + ping: Optional[int] = None, + user_agent="", + stream_id: Optional[str] = None, + ) -> None: + self.q = asyncio.Queue() + EventSourceResponse.__init__(self, iq(self.q), status_code, headers, ping=ping) self.created = time.time() - self.graphClients = self.settings.graphClients - - self._serial = PatchSink._handlerSerial - PatchSink._handlerSerial += 1 - self.lastPatchSentTime: float = 0.0 - - def __repr__(self) -> str: - return '<Handler #%s>' % self._serial + self.user_agent = user_agent + self.lastPatchSentTime = 0.0 + self.streamId = stream_id + + def sendEvent(self, message: str, event: str): + self.q.put_nowait(dict(data=message, event=event)) def state(self) -> Dict: return { 'created': round(self.created, 2), 'ageHours': round((time.time() - self.created) / 3600, 2), 'streamId': self.streamId, - 'remoteIp': self.request.remote_ip, # wrong, need some forwarded-for thing - 'foafAgent': self.request.headers.get('X-Foaf-Agent'), - 'userAgent': self.request.headers.get('user-agent'), + # 'remoteIp': self.request.remote_ip, # wrong, need some forwarded-for thing + # 'foafAgent': self.request.headers.get('X-Foaf-Agent'), + # 'userAgent': self.request.headers.get('user-agent'), } - def bind(self, *args, **kwargs): - self.streamId = args[0] + +async def PatchSink(request: Request) -> PatchSinkResponse: + log.debug(f"PatchSink for {request.path_params['stream_id']=}") + + ret= PatchSinkResponse( ping=30, user_agent=request.headers['user-agent'], stream_id=request.path_params['stream_id']) + request.app.state.graphClients.addSseHandler(ret) + return ret + + +# class PatchSink_old: +# _handlerSerial = 0 + +# def __init__(self, application: cyclone.web.Application, request): +# cyclone.sse.SSEHandler.__init__(self, application, request) +# self.bound = False +# self.created = time.time() +# self.graphClients = self.settings.graphClients - self.graphClients.addSseHandler(self) - # If something goes wrong with addSseHandler, I don't want to - # try removeSseHandler. - self.bound = True +# self._serial = PatchSink._handlerSerial +# PatchSink._handlerSerial += 1 +# self.lastPatchSentTime: float = 0.0 + +# def __repr__(self) -> str: +# return '<Handler #%s>' % self._serial - def unbind(self) -> None: - if self.bound: - self.graphClients.removeSseHandler(self) +# def bind(self, *args, **kwargs): +# self.streamId = args[0] + +# self.graphClients.addSseHandler(self) +# # If something goes wrong with addSseHandler, I don't want to +# # try removeSseHandler. +# self.bound = True + +# def unbind(self) -> None: +# if self.bound: +# self.graphClients.removeSseHandler(self)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/patchsource.py Sat Nov 26 14:13:51 2022 -0800 @@ -0,0 +1,82 @@ +"""consumes another server's SSE stream of graph patches""" +import time +import asyncio +from aiohttp_sse_client import client as sse_client +from typing import Protocol, Dict, cast +from rdflib import ConjunctiveGraph +from rdflib.parser import StringInputSource +from rdfdb.patch import Patch +import logging + +log = logging.getLogger('reader') +from patchablegraph.patchablegraph import patchFromJson, JsonSerializedPatch + + +class _Listener(Protocol): + + def __call__( + self, + p: Patch, + fullGraph: bool, # True if the patch is the initial full graph. + ) -> None: + ... + + +class PatchSource: + + def __init__(self, url: str, listener: _Listener, reconnectSecs=60, agent='unset'): + + self.url = url + + self._listener = listener + self.reconnectSecs = reconnectSecs + self.agent = agent + + self._reconnnect() + + def _reconnnect(self): + self._fullGraphReceived = None + self._patchesReceived = 0 + log.debug(f'sse_client.EventSource {self.url=}') + self._eventSource = sse_client.EventSource(self.url, on_error=self._onError) + self.task = asyncio.create_task(self._spin()) + + async def _spin(self): + log.info(f'_spin {self.url}') + async with self._eventSource as es: + async for ev in es: + log.info(f'spin got ev {str(ev)[:100]}') + if ev.type == 'patch': + p = patchFromJson(cast(JsonSerializedPatch, ev.data)) + self._listener(p, fullGraph=False) + self._latestPatchTime = time.time() + self._patchesReceived += 1 + elif ev.type == 'fullGraph': + + g = ConjunctiveGraph() + g.parse(StringInputSource(ev.data), format='json-ld') + p = Patch(addGraph=g) + self._listener(p, fullGraph=True) + + self._fullGraphReceived = True + self._fullGraphTime = time.time() + self._patchesReceived += 1 + + def _onError(self, *args): + raise ValueError(repr(args)) + + def state(self) -> Dict: + return { + 'url': self.url, + 'fullGraphReceived': self._fullGraphReceived, + 'patchesReceived': self._patchesReceived, + 'time': { + 'open': getattr(self, '_startReadTime', None), + 'fullGraph': getattr(self, '_fullGraphTime', None), + 'latestPatch': getattr(self, '_latestPatchTime', None), + }, + 'closed': self._eventSource is None, + } + + def stop(self): + print('stop ps pls')
--- a/pdm.lock Fri Nov 25 20:58:08 2022 -0800 +++ b/pdm.lock Sat Nov 26 14:13:51 2022 -0800 @@ -14,6 +14,17 @@ ] [[package]] +name = "aiohttp-sse-client" +version = "0.2.1" +summary = "A Server-Sent Event python client base on aiohttp" +dependencies = [ + "aiohttp>=3", + "attrs", + "multidict", + "yarl", +] + +[[package]] name = "aiosignal" version = "1.3.1" requires_python = ">=3.7" @@ -62,15 +73,6 @@ ] [[package]] -name = "automat" -version = "22.10.0" -summary = "Self-service finite-state machines for the programmer on the go." -dependencies = [ - "attrs>=19.2.0", - "six", -] - -[[package]] name = "cffi" version = "1.15.1" summary = "Foreign Function Interface for Python calling C code." @@ -85,9 +87,19 @@ summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." [[package]] -name = "constantly" -version = "15.1.0" -summary = "Symbolic constants in Python" +name = "click" +version = "8.1.3" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +dependencies = [ + "colorama; platform_system == \"Windows\"", +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." [[package]] name = "cryptography" @@ -99,26 +111,18 @@ ] [[package]] -name = "cyclone" -version = "1.3" -summary = "Non-blocking web server for Python. Tornado API as a Twisted protocol." -dependencies = [ - "pyOpenSSL==19.0.0", - "twisted==19.2.1", -] - -[[package]] -name = "docopt" -version = "0.6.2" -summary = "Pythonic argument parser, that will make you smile" - -[[package]] name = "frozenlist" version = "1.3.3" requires_python = ">=3.7" summary = "A list-like structure which implements collections.abc.MutableSequence" [[package]] +name = "h11" +version = "0.14.0" +requires_python = ">=3.7" +summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" + +[[package]] name = "hyperlink" version = "21.0.0" requires_python = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -134,11 +138,6 @@ summary = "Internationalized Domain Names in Applications (IDNA)" [[package]] -name = "incremental" -version = "22.10.0" -summary = "\"A small library that versions your Python projects.\"" - -[[package]] name = "isodate" version = "0.6.1" summary = "An ISO 8601 date/time/duration parser and formatter" @@ -172,46 +171,12 @@ summary = "Python client for the Prometheus monitoring system." [[package]] -name = "psutil" -version = "5.9.4" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -summary = "Cross-platform lib for process and system monitoring in Python." - -[[package]] -name = "pyasn1" -version = "0.4.8" -summary = "ASN.1 types and codecs" - -[[package]] -name = "pyasn1-modules" -version = "0.2.8" -summary = "A collection of ASN.1-based protocols modules." -dependencies = [ - "pyasn1<0.5.0,>=0.4.6", -] - -[[package]] name = "pycparser" version = "2.21" requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" summary = "C parser in Python" [[package]] -name = "pyhamcrest" -version = "2.0.4" -requires_python = ">=3.6" -summary = "Hamcrest framework for matcher objects" - -[[package]] -name = "pyopenssl" -version = "22.1.0" -requires_python = ">=3.6" -summary = "Python wrapper module around the OpenSSL library" -dependencies = [ - "cryptography<39,>=38.0.0", -] - -[[package]] name = "pyparsing" version = "3.0.9" requires_python = ">=3.6.8" @@ -251,26 +216,6 @@ ] [[package]] -name = "scales" -version = "1.0.9" -summary = "Stats for Python processes" -dependencies = [ - "six", -] - -[[package]] -name = "service-identity" -version = "21.1.0" -summary = "Service identity verification for pyOpenSSL & cryptography." -dependencies = [ - "attrs>=19.1.0", - "cryptography", - "pyasn1", - "pyasn1-modules", - "six", -] - -[[package]] name = "setuptools" version = "65.6.3" requires_python = ">=3.7" @@ -298,16 +243,6 @@ ] [[package]] -name = "standardservice" -version = "0.6.0" -summary = "" -dependencies = [ - "psutil", - "scales", - "twisted", -] - -[[package]] name = "starlette" version = "0.22.0" requires_python = ">=3.7" @@ -326,31 +261,22 @@ ] [[package]] -name = "twisted" -version = "19.2.1" -summary = "An asynchronous networking framework written in Python" -dependencies = [ - "Automat>=0.3.0", - "PyHamcrest>=1.9.0", - "attrs>=17.4.0", - "constantly>=15.1", - "hyperlink>=17.1.1", - "incremental>=16.10.1", - "zope.interface>=4.4.2", -] - -[[package]] -name = "twisted-sse" -version = "0.3.0" -summary = "" - -[[package]] name = "txaio" version = "22.2.1" requires_python = ">=3.6" summary = "Compatibility API between asyncio/Twisted/Trollius" [[package]] +name = "uvicorn" +version = "0.20.0" +requires_python = ">=3.7" +summary = "The lightning-fast ASGI server." +dependencies = [ + "click>=7.0", + "h11>=0.8", +] + +[[package]] name = "yarl" version = "1.8.1" requires_python = ">=3.7" @@ -360,18 +286,9 @@ "multidict>=4.0", ] -[[package]] -name = "zope.interface" -version = "5.5.2" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -summary = "Interfaces for Python" -dependencies = [ - "setuptools", -] - [metadata] lock_version = "4.0" -content_hash = "sha256:7071c9c49f9bcacd4c21a3d47b9779515fb2338cc1a392f73d5402c18131badc" +content_hash = "sha256:8067acc73a57fb7b85629040185ecbba1e4ebd28c00c13effd2a0d13f4849da1" [metadata.files] "aiohttp 3.8.3" = [ @@ -463,6 +380,10 @@ {url = "https://files.pythonhosted.org/packages/fe/e1/401b3fac5bfaa8cef6d7fd541c8a573907565c662f2d5891cc9a0c0124b7/aiohttp-3.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:512bd5ab136b8dc0ffe3fdf2dfb0c4b4f49c8577f6cae55dca862cd37a4564e2"}, {url = "https://files.pythonhosted.org/packages/ff/4f/62d9859b7d4e6dc32feda67815c5f5ab4421e6909e48cbc970b6a40d60b7/aiohttp-3.8.3.tar.gz", hash = "sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269"}, ] +"aiohttp-sse-client 0.2.1" = [ + {url = "https://files.pythonhosted.org/packages/25/c9/ad514e70a549db22e118f0366c0bb38c5a90cb407978cb6c3d1482760889/aiohttp_sse_client-0.2.1-py2.py3-none-any.whl", hash = "sha256:42c81ee9213e9fc8bc412b063bac3a813e02e75250c4c8049222234d41c9b024"}, + {url = "https://files.pythonhosted.org/packages/71/c3/4825c5f37909a70c8018924b3d521847dd7acf1fce7e1054574bafed2271/aiohttp-sse-client-0.2.1.tar.gz", hash = "sha256:5004e29271624af586158dc7166cb0687a7a5997aab5b808f4b53400e1b72e3b"}, +] "aiosignal 1.3.1" = [ {url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, {url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, @@ -486,10 +407,6 @@ "autobahn 22.7.1" = [ {url = "https://files.pythonhosted.org/packages/c5/b5/c92d6640fd55cbbdd97c05800ab534d84197f7b485d89a9df981ab67cce3/autobahn-22.7.1.tar.gz", hash = "sha256:8b462ea2e6aad6b4dc0ed45fb800b6cbfeb0325e7fe6983907f122f2be4a1fe9"}, ] -"automat 22.10.0" = [ - {url = "https://files.pythonhosted.org/packages/29/90/64aabce6c1b820395452cc5472b8f11cd98320f40941795b8069aef4e0e0/Automat-22.10.0-py2.py3-none-any.whl", hash = "sha256:c3164f8742b9dc440f3682482d32aaff7bb53f71740dd018533f9de286b64180"}, - {url = "https://files.pythonhosted.org/packages/7a/7b/9c3d26d8a0416eefbc0428f168241b32657ca260fb7ef507596ff5c2f6c4/Automat-22.10.0.tar.gz", hash = "sha256:e56beb84edad19dcc11d30e8d9b895f75deeb5ef5e96b84a467066b3b84bb04e"}, -] "cffi 1.15.1" = [ {url = "https://files.pythonhosted.org/packages/00/05/23a265a3db411b0bfb721bf7a116c7cecaf3eb37ebd48a6ea4dfb0a3244d/cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, {url = "https://files.pythonhosted.org/packages/03/7b/259d6e01a6083acef9d3c8c88990c97d313632bb28fa84d6ab2bb201140a/cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, @@ -560,9 +477,13 @@ {url = "https://files.pythonhosted.org/packages/a1/34/44964211e5410b051e4b8d2869c470ae8a68ae274953b1c7de6d98bbcf94/charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, {url = "https://files.pythonhosted.org/packages/db/51/a507c856293ab05cdc1db77ff4bc1268ddd39f29e7dc4919aa497f0adbec/charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] -"constantly 15.1.0" = [ - {url = "https://files.pythonhosted.org/packages/95/f1/207a0a478c4bb34b1b49d5915e2db574cadc415c9ac3a7ef17e29b2e8951/constantly-15.1.0.tar.gz", hash = "sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"}, - {url = "https://files.pythonhosted.org/packages/b9/65/48c1909d0c0aeae6c10213340ce682db01b48ea900a7d9fce7a7910ff318/constantly-15.1.0-py2.py3-none-any.whl", hash = "sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d"}, +"click 8.1.3" = [ + {url = "https://files.pythonhosted.org/packages/59/87/84326af34517fca8c58418d148f2403df25303e02736832403587318e9e8/click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, + {url = "https://files.pythonhosted.org/packages/c2/f1/df59e28c642d583f7dacffb1e0965d0e00b218e0186d7858ac5233dce840/click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, +] +"colorama 0.4.6" = [ + {url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] "cryptography 38.0.3" = [ {url = "https://files.pythonhosted.org/packages/13/dd/a9608b7aebe5d2dc0c98a4b2090a6b815628efa46cc1c046b89d8cd25f4c/cryptography-38.0.3.tar.gz", hash = "sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd"}, @@ -592,13 +513,6 @@ {url = "https://files.pythonhosted.org/packages/ee/a7/dfa6e33efa9f7448554560d4e7debf5cefbbdc9bc677c13824a0bc777d78/cryptography-38.0.3-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6ab9516b85bebe7aa83f309bacc5f44a61eeb90d0b4ec125d2d003ce41932d36"}, {url = "https://files.pythonhosted.org/packages/fe/44/e5f4e5040491130f58d3ffbc3d21e917cced3e13faa126530109c18dee2e/cryptography-38.0.3-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320"}, ] -"cyclone 1.3" = [ - {url = "https://files.pythonhosted.org/packages/0a/2d/d3a939924f41c36c91996365f3f9bb8a3da2449a76cfe97a2183611d04b1/cyclone-1.3.tar.gz", hash = "sha256:6e5ec576c719240180d56e6e8f83bb474ab52ca3e56ed6417a90f60fd0bf562b"}, - {url = "https://files.pythonhosted.org/packages/8e/78/fd66d26885eca6c1f0b40c1e5386563d5a7bfdb41d2aa6158707dd926b7f/cyclone-1.3-py3-none-any.whl", hash = "sha256:adc1c8736bafc668f1f55236d1919cfb96c1f377831361deb73d633f0c1db779"}, -] -"docopt 0.6.2" = [ - {url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, -] "frozenlist 1.3.3" = [ {url = "https://files.pythonhosted.org/packages/01/a3/a3c18bfd7bd2a56831b985140f98eb6dda684a2d8b2a54b1077b45c7f9d9/frozenlist-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8"}, {url = "https://files.pythonhosted.org/packages/03/00/febbfd2ec244a0f91707bd879afe6aa278e337dc41cd9d0d25260e6da38e/frozenlist-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef"}, @@ -675,6 +589,10 @@ {url = "https://files.pythonhosted.org/packages/fa/a1/d0822eb2f827f209c8fcf19ff1c9eb30ae08e25b710cf432b1013ea23429/frozenlist-1.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91"}, {url = "https://files.pythonhosted.org/packages/fd/b8/9ed4ed37b2c3269660a86a10a09b2fe49dbbd6973ac684804ece7b51b63f/frozenlist-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816"}, ] +"h11 0.14.0" = [ + {url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] "hyperlink 21.0.0" = [ {url = "https://files.pythonhosted.org/packages/3a/51/1947bd81d75af87e3bb9e34593a4cf118115a8feb451ce7a69044ef1412e/hyperlink-21.0.0.tar.gz", hash = "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b"}, {url = "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl", hash = "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4"}, @@ -683,10 +601,6 @@ {url = "https://files.pythonhosted.org/packages/8b/e1/43beb3d38dba6cb420cefa297822eac205a277ab43e5ba5d5c46faf96438/idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, {url = "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, ] -"incremental 22.10.0" = [ - {url = "https://files.pythonhosted.org/packages/77/51/8073577012492fcd15628e811db585f447c500fa407e944ab3a18ec55fb7/incremental-22.10.0-py2.py3-none-any.whl", hash = "sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51"}, - {url = "https://files.pythonhosted.org/packages/86/42/9e87f04fa2cd40e3016f27a4b4572290e95899c6dce317e2cdb580f3ff09/incremental-22.10.0.tar.gz", hash = "sha256:912feeb5e0f7e0188e6f42241d2f450002e11bbc0937c65865045854c24c0bd0"}, -] "isodate 0.6.1" = [ {url = "https://files.pythonhosted.org/packages/b6/85/7882d311924cbcfc70b1890780763e36ff0b140c7e51c110fc59a532f087/isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, {url = "https://files.pythonhosted.org/packages/db/7a/c0a56c7d56c7fa723988f122fa1f1ccf8c5c4ccc48efad0d214b49e5b1af/isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, @@ -759,42 +673,10 @@ {url = "https://files.pythonhosted.org/packages/2e/5e/4225463cdac1098aac718b1d8adf8f9dc3d6aaea55f4f85a2f7d572b4f7c/prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"}, {url = "https://files.pythonhosted.org/packages/ae/ae/04b27ea04f67f91f10b1379d8fd6729c41ac0bcefbb0af603850b3fa32e0/prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"}, ] -"psutil 5.9.4" = [ - {url = "https://files.pythonhosted.org/packages/1d/80/e1502ba4ff65390bd17b4612010762075f64f5a0e7c28e889c4820bd95a9/psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"}, - {url = "https://files.pythonhosted.org/packages/25/6e/ba97809175c90cbdcd33b470e466ebf0854d15d1506e605cc0ddd284d5b6/psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"}, - {url = "https://files.pythonhosted.org/packages/3d/7d/d05864a69e452f003c0d77e728e155a89a2a26b09e64860ddd70ad64fb26/psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"}, - {url = "https://files.pythonhosted.org/packages/3e/af/fe14b984e8b0f778d502d387b789d846cb2fcc3989f63be942741266d8c8/psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"}, - {url = "https://files.pythonhosted.org/packages/53/ae/536719016fe9399187dbf52cdc65aef942f82b75924495918a2f701bcb77/psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"}, - {url = "https://files.pythonhosted.org/packages/5a/37/ef88eed265d93bc28c681316f68762c5e04167519e5627a0187c8878b409/psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"}, - {url = "https://files.pythonhosted.org/packages/60/f8/b92fecd5297edcecda825a04dfde7cb0a2ecd178eb976cb5a7956e375c6a/psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"}, - {url = "https://files.pythonhosted.org/packages/6e/c8/784968329c1c67c28cce91991ef9af8a8913aa5a3399a6a8954b1380572f/psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"}, - {url = "https://files.pythonhosted.org/packages/79/26/f026804298b933b11640cc2d15155a545805df732e5ead3a2ad7cf45a38b/psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"}, - {url = "https://files.pythonhosted.org/packages/89/a8/dd2f0866a7e87de751fb5f7c6eca99cbb953c81be76e1814ab3c8c3b0908/psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"}, - {url = "https://files.pythonhosted.org/packages/8e/6b/9a3a5471b74d92dc85bfd71a7f7a55e013b258d86b4c3826ace9d49f7b8c/psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"}, - {url = "https://files.pythonhosted.org/packages/99/9c/7a5761f9d2e79e6f781db5b25eeb9e74c2dc533bc52ee4749cb055a32ce9/psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"}, - {url = "https://files.pythonhosted.org/packages/a5/73/35cea01aad1baf901c915dc95ea33a2f271c8ff8cf2f1c73b7f591f1bdf1/psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"}, - {url = "https://files.pythonhosted.org/packages/ec/be/b8df2071eda861e65a1b2cec35770bb1f4523737e84a10aa41c53e39e9bc/psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"}, -] -"pyasn1 0.4.8" = [ - {url = "https://files.pythonhosted.org/packages/62/1e/a94a8d635fa3ce4cfc7f506003548d0a2447ae76fd5ca53932970fe3053f/pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, - {url = "https://files.pythonhosted.org/packages/a4/db/fffec68299e6d7bad3d504147f9094830b704527a7fc098b721d38cc7fa7/pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, -] -"pyasn1-modules 0.2.8" = [ - {url = "https://files.pythonhosted.org/packages/88/87/72eb9ccf8a58021c542de2588a867dbefc7556e14b2866d1e40e9e2b587e/pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, - {url = "https://files.pythonhosted.org/packages/95/de/214830a981892a3e286c3794f41ae67a4495df1108c3da8a9f62159b9a9d/pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, -] "pycparser 2.21" = [ {url = "https://files.pythonhosted.org/packages/5e/0b/95d387f5f4433cb0f53ff7ad859bd2c6051051cebbb564f139a999ab46de/pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, {url = "https://files.pythonhosted.org/packages/62/d5/5f610ebe421e85889f2e55e33b7f9a6795bd982198517d912eb1c76e1a53/pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, ] -"pyhamcrest 2.0.4" = [ - {url = "https://files.pythonhosted.org/packages/b1/9a/588f086b64ace8d2e9843d8551e9068b2570c3c51b06cb49a107303f8700/pyhamcrest-2.0.4.tar.gz", hash = "sha256:b5d9ce6b977696286cf232ce2adf8969b4d0b045975b0936ac9005e84e67e9c1"}, - {url = "https://files.pythonhosted.org/packages/fe/58/96afda21aa47a5b4de8f050a90c8e0f394c142a0edae251199fe873d2970/pyhamcrest-2.0.4-py3-none-any.whl", hash = "sha256:60a41d4783b9d56c9ec8586635d2301db5072b3ea8a51c32dd03c408ae2b0f79"}, -] -"pyopenssl 22.1.0" = [ - {url = "https://files.pythonhosted.org/packages/00/3f/ea5cfb789dddb327e6d2cf9377c36d9d8607af85530af0e7001165587ae7/pyOpenSSL-22.1.0-py3-none-any.whl", hash = "sha256:b28437c9773bb6c6958628cf9c3bebe585de661dba6f63df17111966363dd15e"}, - {url = "https://files.pythonhosted.org/packages/e7/2f/c6d89edac75482f11e231b644e365d31d5479b7b727734e6a8f3d00decd5/pyOpenSSL-22.1.0.tar.gz", hash = "sha256:7a83b7b272dd595222d672f5ce29aa030f1fb837630ef229f62e72e395ce8968"}, -] "pyparsing 3.0.9" = [ {url = "https://files.pythonhosted.org/packages/6c/10/a7d0fa5baea8fe7b50f448ab742f26f52b80bfca85ac2be9d35cdd9a3246/pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {url = "https://files.pythonhosted.org/packages/71/22/207523d16464c40a0310d2d4d8926daffa00ac1f5b1576170a32db749636/pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, @@ -810,13 +692,6 @@ {url = "https://files.pythonhosted.org/packages/29/92/da92898b2aab0da78207afc9c035a71bedef3544966374c44e9627d761c5/rdflib_jsonld-0.6.2-py2.py3-none-any.whl", hash = "sha256:011afe67672353ca9978ab9a4bee964dff91f14042f2d8a28c22a573779d2f8b"}, {url = "https://files.pythonhosted.org/packages/cd/1a/627de985dffc11b486eb07be86dc9a16c25b4877905f5f6a0be3633addb0/rdflib-jsonld-0.6.2.tar.gz", hash = "sha256:107cd3019d41354c31687e64af5e3fd3c3e3fa5052ce635f5ce595fd31853a63"}, ] -"scales 1.0.9" = [ - {url = "https://files.pythonhosted.org/packages/08/85/b4a3933f227889b536a76c7ed5a0708ae5f63fe20f81d09a725228349e81/scales-1.0.9.tar.gz", hash = "sha256:8b6930f7d4bf115192290b44c757af5e254e3fcfcb75ff9a51f5c96a404e2753"}, -] -"service-identity 21.1.0" = [ - {url = "https://files.pythonhosted.org/packages/09/2e/26ade69944773df4748c19d3053e025b282f48de02aad84906d34a29d28b/service-identity-21.1.0.tar.gz", hash = "sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34"}, - {url = "https://files.pythonhosted.org/packages/93/5a/5e93f280ec7be676b5a57f305350f439d31ced168bca04e6ffa64b575664/service_identity-21.1.0-py2.py3-none-any.whl", hash = "sha256:f0b0caac3d40627c3c04d7a51b6e06721857a0e10a8775f2d1d7e72901b3a7db"}, -] "setuptools 65.6.3" = [ {url = "https://files.pythonhosted.org/packages/b6/21/cb9a8d0b2c8597c83fce8e9c02884bce3d4951e41e807fc35791c6b23d9a/setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, {url = "https://files.pythonhosted.org/packages/ef/e3/29d6e1a07e8d90ace4a522d9689d03e833b67b50d1588e693eec15f26251/setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, @@ -833,9 +708,6 @@ {url = "https://files.pythonhosted.org/packages/3f/98/538914a5ec084ba4f8c1327266925b0d37a344b0840769e506a17a8ab47e/sse-starlette-1.2.1.tar.gz", hash = "sha256:52760a16ed6380be53a2acca9173de17442f4165716f93679182e82ddd5c8a01"}, {url = "https://files.pythonhosted.org/packages/c0/2f/d7dc1386c2a3fb9729bfc7117c753659457a094c9c17d524dd5e584742a6/sse_starlette-1.2.1-py3-none-any.whl", hash = "sha256:22116035906cb332ed3c5cb2d495af58fd55350de20866ecdc247db7fd69f2ef"}, ] -"standardservice 0.6.0" = [ - {url = "https://projects.bigasterisk.com/standardservice/standardservice-0.6.0.tar.gz", hash = "sha256:0f1926ac396287a9aedfa964bd4a8ca651f18e18796ed3f1eba140270ffa4b83"}, -] "starlette 0.22.0" = [ {url = "https://files.pythonhosted.org/packages/1d/4e/30eda84159d5b3ad7fe663c40c49b16dd17436abe838f10a56c34bee44e8/starlette-0.22.0-py3-none-any.whl", hash = "sha256:b5eda991ad5f0ee5d8ce4c4540202a573bb6691ecd0c712262d0bc85cf8f2c50"}, {url = "https://files.pythonhosted.org/packages/f7/ff/64bd3362f80e81402f21e0f1ba55f8801cd899ad3f2a1bcc4a94d284c786/starlette-0.22.0.tar.gz", hash = "sha256:b092cbc365bea34dd6840b42861bdabb2f507f8671e642e8272d2442e08ea4ff"}, @@ -844,16 +716,14 @@ {url = "https://files.pythonhosted.org/packages/3a/7b/2a88fc15c7314dccfb5addb019ed84700e7ede87d328b3f6386c37f27024/starlette_exporter-0.14.0.tar.gz", hash = "sha256:8e64d7b13ad072b1e916458510c68ff9c5eaafaf5b8b5a61c929eaee16c410c4"}, {url = "https://files.pythonhosted.org/packages/50/55/59c632e6b2180bdf84d4e86dd0ad5171b646ae605e28b5aa789d09058a1d/starlette_exporter-0.14.0-py3-none-any.whl", hash = "sha256:69443e326e3b306f6fbec3da9dfc9c5ab555d4e0e0adc3372b879fbc409994e6"}, ] -"twisted 19.2.1" = [ - {url = "https://files.pythonhosted.org/packages/79/59/035de19362320e632301ed7bbde23e4c8cd6fc5e2f1cf8d354cdba857854/Twisted-19.2.1.tar.bz2", hash = "sha256:fa2c04c2d68a9be7fc3975ba4947f653a57a656776f24be58ff0fe4b9aaf3e52"}, -] -"twisted-sse 0.3.0" = [ - {url = "https://projects.bigasterisk.com/twisted-sse/twisted_sse-0.3.0.tar.gz", hash = "sha256:4a112f1157901463666b24f5f38adaef83d7fbd58aa67eabcdd7ca0156624484"}, -] "txaio 22.2.1" = [ {url = "https://files.pythonhosted.org/packages/6d/4b/28313388dfb2bdedb71b35b900459c56ba08ccb7ad2885487df037808c06/txaio-22.2.1.tar.gz", hash = "sha256:2e4582b70f04b2345908254684a984206c0d9b50e3074a24a4c55aba21d24d01"}, {url = "https://files.pythonhosted.org/packages/77/97/001a2b89b07d0a1b17137e0ef33277ad16747a7b8391146bfc880890322b/txaio-22.2.1-py2.py3-none-any.whl", hash = "sha256:41223af4a9d5726e645a8ee82480f413e5e300dd257db94bc38ae12ea48fb2e5"}, ] +"uvicorn 0.20.0" = [ + {url = "https://files.pythonhosted.org/packages/95/3c/9f4650ff609370456f796bb96a355dcddef1ded67e05d1b4eb3481088329/uvicorn-0.20.0.tar.gz", hash = "sha256:a4e12017b940247f836bc90b72e725d7dfd0c8ed1c51eb365f5ba30d9f5127d8"}, + {url = "https://files.pythonhosted.org/packages/96/f3/f39ac8ac3bdf356b4934b8f7e56173e96681f67ef0cd92bd33a5059fae9e/uvicorn-0.20.0-py3-none-any.whl", hash = "sha256:c3ed1598a5668208723f2bb49336f4509424ad198d6ab2615b7783db58d919fd"}, +] "yarl 1.8.1" = [ {url = "https://files.pythonhosted.org/packages/02/83/af04c6a34e9011e1620ae918e223869adcc5de855ae2e89fd77fabfee626/yarl-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85cba594433915d5c9a0d14b24cfba0339f57a2fff203a5d4fd070e593307d0b"}, {url = "https://files.pythonhosted.org/packages/02/df/0d3ae329942cb26c96ac5a4e9164a1d440ffd067331c6886b5ce0729b17a/yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"}, @@ -915,41 +785,3 @@ {url = "https://files.pythonhosted.org/packages/ff/44/52161d5de9fc136e78e2e0663f2b386807f128b246f397817f4d4ae2e4f2/yarl-1.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b51530877d3ad7a8d47b2fff0c8df3b8f3b8deddf057379ba50b13df2a5eae"}, {url = "https://files.pythonhosted.org/packages/ff/c0/ddcd9c883887a67c2d241fc807111fc2be840dcc5513067ddd59abfed933/yarl-1.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d93a049d29df172f48bcb09acf9226318e712ce67374f893b460b42cc1380ae"}, ] -"zope.interface 5.5.2" = [ - {url = "https://files.pythonhosted.org/packages/01/3a/8e57724eeb9b75d366f0c11b24080c69e12f0b3bfe4dc771336f21271c99/zope.interface-5.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d514c269d1f9f5cd05ddfed15298d6c418129f3f064765295659798349c43e6f"}, - {url = "https://files.pythonhosted.org/packages/01/45/9ff2b9281597da5fcf84995ca18cde71abf248c98bfc7c6bdee60af87dbb/zope.interface-5.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5334e2ef60d3d9439c08baedaf8b84dc9bb9522d0dacbc10572ef5609ef8db6d"}, - {url = "https://files.pythonhosted.org/packages/05/0b/ff478275c63e1b910c0605b0fdbb004cdf6730d17169fffb2ebe6a10fc44/zope.interface-5.5.2-cp27-cp27m-win_amd64.whl", hash = "sha256:65c3c06afee96c654e590e046c4a24559e65b0a87dbff256cd4bd6f77e1a33f9"}, - {url = "https://files.pythonhosted.org/packages/05/2a/c863bd1e146b66795067677d7ba51290824c19e53f2c99bd0da36d545c43/zope.interface-5.5.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4087e253bd3bbbc3e615ecd0b6dd03c4e6a1e46d152d3be6d2ad08fbad742dcc"}, - {url = "https://files.pythonhosted.org/packages/06/cf/57513c4915d6288854694f2323d2d15d3fd39e7c7b5c744ebe81b62fcb77/zope.interface-5.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8a2ffadefd0e7206adc86e492ccc60395f7edb5680adedf17a7ee4205c530df4"}, - {url = "https://files.pythonhosted.org/packages/0f/9f/9e08ab4398974406a431be5a9ae4f83603d6d4e208ba276840f6192ec132/zope.interface-5.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7579960be23d1fddecb53898035a0d112ac858c3554018ce615cefc03024e46d"}, - {url = "https://files.pythonhosted.org/packages/12/78/83d8b9893d1a3933d772b2b2a542146f5d1465fc770c7618efb4bc1e265e/zope.interface-5.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fb68d212efd057596dee9e6582daded9f8ef776538afdf5feceb3059df2d2e7b"}, - {url = "https://files.pythonhosted.org/packages/1a/ba/ca524f2f7184346e93bae317580c4906bc2e81bdac6e3b68b64c632a7df0/zope.interface-5.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:765d703096ca47aa5d93044bf701b00bbce4d903a95b41fff7c3796e747b1f1d"}, - {url = "https://files.pythonhosted.org/packages/2b/26/2dd8687863272cab8c34908b18c98c32f8cb6d3da6e23896622c1a8a4a2e/zope.interface-5.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:404d1e284eda9e233c90128697c71acffd55e183d70628aa0bbb0e7a3084ed8b"}, - {url = "https://files.pythonhosted.org/packages/2e/d3/3be31d3433e4df8901857e1a62e87cc69d17f91116fbc45e2b3662ca8c27/zope.interface-5.5.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:008b0b65c05993bb08912f644d140530e775cf1c62a072bf9340c2249e613c32"}, - {url = "https://files.pythonhosted.org/packages/2f/2d/fa6e7f296f9580feff6c2003e70601f111318e032f37f7266bc0a56abc48/zope.interface-5.5.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:17ebf6e0b1d07ed009738016abf0d0a0f80388e009d0ac6e0ead26fc162b3b9c"}, - {url = "https://files.pythonhosted.org/packages/31/01/297bd775394c46e051d3201c6600adfaf72c346d6201062bb61227615d64/zope.interface-5.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dbaeb9cf0ea0b3bc4b36fae54a016933d64c6d52a94810a63c00f440ecb37dd7"}, - {url = "https://files.pythonhosted.org/packages/38/6f/fbfb7dde38be7e5644bb342c4c7cdc444cd5e2ffbd70d091263b3858a8cb/zope.interface-5.5.2.tar.gz", hash = "sha256:bfee1f3ff62143819499e348f5b8a7f3aa0259f9aca5e0ddae7391d059dce671"}, - {url = "https://files.pythonhosted.org/packages/48/fa/25d98f89f07e4524e465d4d5ca4164a443628eae0548f1ec085ea0ed2889/zope.interface-5.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f98d4bd7bbb15ca701d19b93263cc5edfd480c3475d163f137385f49e5b3a3a7"}, - {url = "https://files.pythonhosted.org/packages/4e/61/e873d7006cd71df28319b2a2826fe1863b761d112598344920e383c58dcb/zope.interface-5.5.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:a2ad597c8c9e038a5912ac3cf166f82926feff2f6e0dabdab956768de0a258f5"}, - {url = "https://files.pythonhosted.org/packages/51/af/60b486a1b09497343c08924cf43577f759532e0d8d85ff578c32233b10e5/zope.interface-5.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:0fb497c6b088818e3395e302e426850f8236d8d9f4ef5b2836feae812a8f699c"}, - {url = "https://files.pythonhosted.org/packages/5a/0d/37e87563031b0f35e8002428f7fd27275660c64ff4ebceca0fca8996afc9/zope.interface-5.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:7e66f60b0067a10dd289b29dceabd3d0e6d68be1504fc9d0bc209cf07f56d189"}, - {url = "https://files.pythonhosted.org/packages/5e/2e/1b0e9120ada342584ab82a4889a0c5dd21bd8846c356c2d5ccd2eb46db0f/zope.interface-5.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:959697ef2757406bff71467a09d940ca364e724c534efbf3786e86eee8591452"}, - {url = "https://files.pythonhosted.org/packages/84/5d/88c886d8d6f738d7b291ac3e4162be94c960e7b0fb74ba2886685eff4762/zope.interface-5.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:a16025df73d24795a0bde05504911d306307c24a64187752685ff6ea23897cb0"}, - {url = "https://files.pythonhosted.org/packages/8a/76/a58e11281d2a014fd9b42e7b5fc71e083f686cc9a55d0300af8b3819b5c2/zope.interface-5.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0980d44b8aded808bec5059018d64692f0127f10510eca71f2f0ace8fb11188"}, - {url = "https://files.pythonhosted.org/packages/9b/c9/5bf7b7f4c26f1b92bd836a5a764337689d06dfdd8852204e6b396029369d/zope.interface-5.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d692374b578360d36568dd05efb8a5a67ab6d1878c29c582e37ddba80e66c396"}, - {url = "https://files.pythonhosted.org/packages/9c/8f/cbe5432a50a4cf0492574c1e9328c39f034d36fc86e4d3040443c3287e1c/zope.interface-5.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e74a578172525c20d7223eac5f8ad187f10940dac06e40113d62f14f3adb1e8f"}, - {url = "https://files.pythonhosted.org/packages/a8/cc/c5ad39d8a2207c360d5b68708788984651f8e975e3bebfe8ddd38592d02f/zope.interface-5.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604cdba8f1983d0ab78edc29aa71c8df0ada06fb147cea436dc37093a0100a4e"}, - {url = "https://files.pythonhosted.org/packages/b1/71/5fe40e244f8dae4f06608778a92027cf154a9a4242aca088326da508103e/zope.interface-5.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:e1574980b48c8c74f83578d1e77e701f8439a5d93f36a5a0af31337467c08fcf"}, - {url = "https://files.pythonhosted.org/packages/b4/d5/1af2b1af567f428a09864c965778f00d8a550a86eabf6b1cd3b22e31a251/zope.interface-5.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:655796a906fa3ca67273011c9805c1e1baa047781fca80feeb710328cdbed87f"}, - {url = "https://files.pythonhosted.org/packages/bf/0e/fc2272397b7fd6a907c9c8c8ed310749db0b451ce5ca5cf90de1ac01c166/zope.interface-5.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9d783213fab61832dbb10d385a319cb0e45451088abd45f95b5bb88ed0acca1a"}, - {url = "https://files.pythonhosted.org/packages/c1/d6/b1bec1e7f059f87905d78882821800340d74d58e190e38390f808a6ecd3e/zope.interface-5.5.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6e972493cdfe4ad0411fd9abfab7d4d800a7317a93928217f1a5de2bb0f0d87a"}, - {url = "https://files.pythonhosted.org/packages/c9/85/fd79a02eb965734bc4f5fd03b99b23bf34b42bc5b3665a42abbc0256248a/zope.interface-5.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:311196634bb9333aa06f00fc94f59d3a9fddd2305c2c425d86e406ddc6f2260d"}, - {url = "https://files.pythonhosted.org/packages/d0/75/c80af74b361cedd35bdfb45ade9c22320d3431722186ff8ab1614df80059/zope.interface-5.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d169ccd0756c15bbb2f1acc012f5aab279dffc334d733ca0d9362c5beaebe88e"}, - {url = "https://files.pythonhosted.org/packages/d2/0a/87528a07ce42929cb655398b2df292d2bc7183447b89967cff54b3db89a1/zope.interface-5.5.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:0217a9615531c83aeedb12e126611b1b1a3175013bbafe57c702ce40000eb9a0"}, - {url = "https://files.pythonhosted.org/packages/ed/c9/265a39c9933aef7cea402c25fb80f6455407d74ed761816496166f55d05a/zope.interface-5.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc26c8d44472e035d59d6f1177eb712888447f5799743da9c398b0339ed90b1b"}, - {url = "https://files.pythonhosted.org/packages/f4/3d/81815c8ad716c8a87dc4913472a1fe6fd51e185cb3812f556686049a3497/zope.interface-5.5.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6373d7eb813a143cb7795d3e42bd8ed857c82a90571567e681e1b3841a390d16"}, - {url = "https://files.pythonhosted.org/packages/f5/06/e5db832d195b33853227dfb8e89ccbc707afed7a097f4b1829387a953ad2/zope.interface-5.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:696f3d5493eae7359887da55c2afa05acc3db5fc625c49529e84bd9992313296"}, - {url = "https://files.pythonhosted.org/packages/f5/34/68ae976ee0f0accfc8845107210dcc4c7636f71998e056757c41ac5e5f55/zope.interface-5.5.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3218ab1a7748327e08ef83cca63eea7cf20ea7e2ebcb2522072896e5e2fceedf"}, - {url = "https://files.pythonhosted.org/packages/fb/a7/4e2a58146d909115e102ce4038e3e8672f566174c55d8fa75325151b11fb/zope.interface-5.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e945de62917acbf853ab968d8916290548df18dd62c739d862f359ecd25842a6"}, - {url = "https://files.pythonhosted.org/packages/ff/a1/788d02d891a5abdf842eec244b432891f56f5c23cb30504c35f70b588b85/zope.interface-5.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:40f4065745e2c2fa0dff0e7ccd7c166a8ac9748974f960cd39f63d2c19f9231f"}, -]
--- a/pyproject.toml Fri Nov 25 20:58:08 2022 -0800 +++ b/pyproject.toml Sat Nov 26 14:13:51 2022 -0800 @@ -6,18 +6,16 @@ {name = "", email = ""}, ] dependencies = [ - "docopt>=0.6.2", "prometheus-client>=0.14.1", "rdflib>=6.1.1", "rdflib-jsonld>=0.6.2", - "service-identity>=21.1.0", - "twisted>=19.2.1", - "cyclone>=1.3", - "pyopenssl>=22.0.0", - "twisted-sse>=0.3.0", - "standardservice>=0.6.0", "patchablegraph>=1.5.0", "rdfdb>=0.24.0", + "starlette>=0.22.0", + "starlette-exporter>=0.14.0", + "uvicorn>=0.20.0", + "sse-starlette>=1.2.1", + "aiohttp-sse-client>=0.2.1", ] requires-python = ">=3.10" license = {text = "MIT"}
--- a/src/CollectorState.ts Fri Nov 25 20:58:08 2022 -0800 +++ b/src/CollectorState.ts Sat Nov 26 14:13:51 2022 -0800 @@ -44,7 +44,7 @@ render() { const sourcesTable = (clients: Array<any>) => { const clientRow = (client: any) => { - const d = client.reconnectedPatchSource; + const d = client; const now = Date.now() / 1000; const dispSec = (sec: number) => Math.abs(sec) > now - 1