Source code for libvis.VisWorker
import webbrowser
from legimens import App
from loguru import logger as log
import sys
from libvis import ref
from .helpers.threaded import threaded
from .http_server import create_server as create_http
from .VisVars import VisVars, VisObject
from .interface import add_serializer, serialize_to_vis
[docs]class Vis():
def __init__(self, ws_port = 7700, vis_port=7000
, nb_name=None
, debug=False
, allow_remote=False
):
self.ws_port = ws_port
self.vis_port = vis_port
if debug: log_level = 'DEBUG'
else: log_level = 'ERROR'
self.nb_name = nb_name
self.addr = '0.0.0.0' if allow_remote else 'localhost'
self.app = App(addr=self.addr, port=ws_port)
self.app.vars = VisVars()
self.app._register_child(self.app.vars)
self.app.serialize_value = serialize_to_vis
self.vars = self.app.vars
self.configure_logging(log_level)
self.start()
# -- Starts
[docs] def start(self):
""" Start visualization process.
Main entry point of legimens.
Called upon initialization of this class.
1. Starts an http server with dashboard app on `vis_port`.
2. Starts the legimens app using `Vis.app.run()`.
Raises:
Exception: Something went wrong when starting
http or websocket server in legimens.
"""
try:
self.start_http(self.addr, self.vis_port)
except Exception as e:
print(f"Webapp HTTP server failed to start at {self.addr}:{self.vis_port}."
" To start manually: `Vis.start_http(port)`."
" Error was:", e
, file=sys.stderr)
if not self.app._running:
self.app.run()
else:
print("Legimens app is already running, what are you doing? To stop: `Vis.stop()`")
[docs] def start_http(self, addr=None, port=None):
""" Start the http server on `addr` and `port`. """
if port is None: port=self.vis_port
if addr is None: port=self.addr
self.http_server = create_http(port=port, addr=addr)
self.phttp = threaded( self.http_server.serve_forever, name='http')
print(f'Started libvis app at http://{addr}:{port}')
# --
[docs] def use(self, type_, serializer):
""" Add a serializer to :meth:`libvis.interface.IFC`. """
add_serializer(type_, serializer)
[docs] def watch(self, obj, key, serializer=None):
""" Sets `libvis` to watch an object.
Parameters:
obj: the object to watch, has to be serializable.
key (str): name of the object variable.
serializer (callable): optional function that converts objects of type(obj) to serializable.
For sending updates we can use existing channel created for ``vis.vars``,
but this would introduce overhead. Hence, a new channel is created
by creating a :meth:`libvis.VisVars.VisObject` of type :meth:`legimens.Object`.
It is a wrapper that has single ``body`` attribute.
Legimens will send serialized :meth:`legimens.Object` every ``vis.app._watch_poll_delay`` seconds.
Returns `ref` of the proxy ``VisObject``.
"""
proxy_obj = VisObject(obj)
self.app.watch_obj(proxy_obj)
# it will register. is it bad?
self.vars.__setattr__(key, proxy_obj)
if serializer:
# Note: this will act on *any* object of the same type
self.use(type(obj), serializer)
return ref(proxy_obj)
[docs] def show(self):
""" Open libvis dashboard in browser. """
if self.nb_name:
params = '?p='+self.nb_name
else: params = ''
webbrowser.open_new_tab(
f"http://{self.addr}:{self.vis_port}/{params}"
)
# -- Stops
[docs] def stop_http(self):
""" Stops the http threaded server. """
if hasattr(self, 'phttp'):
if self.phttp.is_alive():
self.http_server.shutdown()
self.http_server.server_close()
self.phttp.join()
else:
print('Warning: no http server to stop.')
[docs] def stop(self):
print("Stopping webapp http server: `Vis.stop_http()`...", end="", flush=True)
self.stop_http()
print(" OK")
print("Stopping websocket server: `Vis.app.stop()`...", end="", flush=True)
self.app.stop()
print(" OK")
# --