Switch to bokeh wrapper for app serving

This commit is contained in:
usov_i 2023-02-02 14:22:34 +01:00
parent 3458a6c755
commit dc397062ad
6 changed files with 51 additions and 114 deletions

17
pyzebra/app/app_hooks.py Normal file
View File

@ -0,0 +1,17 @@
import logging
import sys
from io import StringIO
def on_server_loaded(_server_context):
formatter = logging.Formatter(
fmt="%(asctime)s %(levelname)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
)
sys.stdout = StringIO()
bokeh_handler = logging.StreamHandler(StringIO())
bokeh_handler.setFormatter(formatter)
bokeh_logger = logging.getLogger("bokeh")
bokeh_logger.setLevel(logging.WARNING)
bokeh_logger.addHandler(bokeh_handler)

View File

@ -1,77 +1,11 @@
import argparse
import logging
import os import os
import subprocess
from bokeh.application.application import Application import sys
from bokeh.application.handlers import ScriptHandler
from bokeh.server.server import Server
from pyzebra import ANATRIC_PATH, SXTAL_REFGEN_PATH
from pyzebra.app.handler import PyzebraHandler
logging.basicConfig(format="%(asctime)s %(message)s", level=logging.INFO)
logger = logging.getLogger(__name__)
def main(): def main():
"""The pyzebra command line interface. app_path = os.path.join(os.path.dirname(os.path.abspath(__file__)))
subprocess.run(["bokeh", "serve", app_path, *sys.argv[1:]], check=True)
This is a wrapper around a bokeh server that provides an interface to launch the application,
bundled with the pyzebra package.
"""
app_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "app.py")
parser = argparse.ArgumentParser(
prog="pyzebra", formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"--port", type=int, default=5006, help="port to listen on for HTTP requests"
)
parser.add_argument(
"--allow-websocket-origin",
metavar="HOST[:PORT]",
type=str,
action="append",
default=None,
help="hostname that can connect to the server websocket",
)
parser.add_argument(
"--anatric-path", type=str, default=ANATRIC_PATH, help="path to anatric executable"
)
parser.add_argument(
"--sxtal-refgen-path",
type=str,
default=SXTAL_REFGEN_PATH,
help="path to Sxtal_Refgen executable",
)
parser.add_argument("--spind-path", type=str, default=None, help="path to spind scripts folder")
parser.add_argument(
"--args",
nargs=argparse.REMAINDER,
default=[],
help="command line arguments for the pyzebra application",
)
args = parser.parse_args()
logger.info(app_path)
pyzebra_handler = PyzebraHandler(args.anatric_path, args.spind_path)
handler = ScriptHandler(filename=app_path, argv=args.args)
server = Server(
{"/": Application(pyzebra_handler, handler)},
port=args.port,
allow_websocket_origin=args.allow_websocket_origin,
)
server.start()
server.io_loop.start()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,31 +0,0 @@
from bokeh.application.handlers import Handler
class PyzebraHandler(Handler):
"""Provides a mechanism for generic bokeh applications to build up new streamvis documents."""
def __init__(self, anatric_path, spind_path):
"""Initialize a pyzebra handler for bokeh applications.
Args:
args (Namespace): Command line parsed arguments.
"""
super().__init__() # no-op
self.anatric_path = anatric_path
self.spind_path = spind_path
def modify_document(self, doc):
"""Modify an application document with pyzebra specific features.
Args:
doc (Document) : A bokeh Document to update in-place
Returns:
Document
"""
doc.title = "pyzebra"
doc.anatric_path = self.anatric_path
doc.spind_path = self.spind_path
return doc

View File

@ -1,6 +1,6 @@
import argparse
import logging import logging
import sys import sys
from io import StringIO
from bokeh.io import curdoc from bokeh.io import curdoc
from bokeh.layouts import column, row from bokeh.layouts import column, row
@ -20,16 +20,33 @@ from pyzebra.app import (
) )
doc = curdoc() doc = curdoc()
doc.title = "pyzebra"
sys.stdout = StringIO() parser = argparse.ArgumentParser()
stdout_textareainput = TextAreaInput(title="print output:")
bokeh_stream = StringIO() parser.add_argument(
bokeh_handler = logging.StreamHandler(bokeh_stream) "--anatric-path", type=str, default=pyzebra.ANATRIC_PATH, help="path to anatric executable"
bokeh_handler.setFormatter(logging.Formatter(logging.BASIC_FORMAT)) )
bokeh_logger = logging.getLogger("bokeh")
bokeh_logger.setLevel(logging.WARNING) parser.add_argument(
bokeh_logger.addHandler(bokeh_handler) "--sxtal-refgen-path",
type=str,
default=pyzebra.SXTAL_REFGEN_PATH,
help="path to Sxtal_Refgen executable",
)
parser.add_argument("--spind-path", type=str, default=None, help="path to spind scripts folder")
args = parser.parse_args()
doc.anatric_path = args.anatric_path
doc.spind_path = args.spind_path
doc.sxtal_refgen_path = args.sxtal_refgen_path
# In app_hooks.py a StreamHandler was added to "bokeh" logger
bokeh_stream = logging.getLogger("bokeh").handlers[0].stream
log_textareainput = TextAreaInput(title="logging output:")
bokeh_log_textareainput = TextAreaInput(title="server output:") bokeh_log_textareainput = TextAreaInput(title="server output:")
@ -77,13 +94,13 @@ doc.add_root(
panel_spind.create(), panel_spind.create(),
] ]
), ),
row(stdout_textareainput, bokeh_log_textareainput, sizing_mode="scale_both"), row(log_textareainput, bokeh_log_textareainput, sizing_mode="scale_both"),
) )
) )
def update_stdout(): def update_stdout():
stdout_textareainput.value = sys.stdout.getvalue() log_textareainput.value = sys.stdout.getvalue()
bokeh_log_textareainput.value = bokeh_stream.getvalue() bokeh_log_textareainput.value = bokeh_stream.getvalue()

View File

@ -1,4 +1,4 @@
source /opt/miniconda3/etc/profile.d/conda.sh source /opt/miniconda3/etc/profile.d/conda.sh
conda activate test conda activate test
python /opt/pyzebra/pyzebra/app/cli.py --port=5010 --allow-websocket-origin=pyzebra.psi.ch:5010 --spind-path=/opt/spind python /opt/pyzebra/pyzebra/app/cli.py --port=5010 --allow-websocket-origin=pyzebra.psi.ch:5010 --args --spind-path=/opt/spind

View File

@ -1,4 +1,4 @@
source /opt/miniconda3/etc/profile.d/conda.sh source /opt/miniconda3/etc/profile.d/conda.sh
conda activate prod conda activate prod
pyzebra --port=80 --allow-websocket-origin=pyzebra.psi.ch:80 --spind-path=/opt/spind pyzebra --port=80 --allow-websocket-origin=pyzebra.psi.ch:80 --args --spind-path=/opt/spind