From dc397062ad7d4f49c89a3332c6f9637a58d5ac0d Mon Sep 17 00:00:00 2001 From: Ivan Usov <ivan.usov@psi.ch> Date: Thu, 2 Feb 2023 14:22:34 +0100 Subject: [PATCH] Switch to bokeh wrapper for app serving --- pyzebra/app/app_hooks.py | 17 ++++++++ pyzebra/app/cli.py | 74 ++------------------------------- pyzebra/app/handler.py | 31 -------------- pyzebra/app/{app.py => main.py} | 39 ++++++++++++----- scripts/pyzebra-test.sh | 2 +- scripts/pyzebra.sh | 2 +- 6 files changed, 51 insertions(+), 114 deletions(-) create mode 100644 pyzebra/app/app_hooks.py delete mode 100644 pyzebra/app/handler.py rename pyzebra/app/{app.py => main.py} (68%) diff --git a/pyzebra/app/app_hooks.py b/pyzebra/app/app_hooks.py new file mode 100644 index 0000000..5b44192 --- /dev/null +++ b/pyzebra/app/app_hooks.py @@ -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) diff --git a/pyzebra/app/cli.py b/pyzebra/app/cli.py index d411ebd..6a1d56c 100644 --- a/pyzebra/app/cli.py +++ b/pyzebra/app/cli.py @@ -1,77 +1,11 @@ -import argparse -import logging import os - -from bokeh.application.application import Application -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__) +import subprocess +import sys def main(): - """The pyzebra command line interface. - - 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() + app_path = os.path.join(os.path.dirname(os.path.abspath(__file__))) + subprocess.run(["bokeh", "serve", app_path, *sys.argv[1:]], check=True) if __name__ == "__main__": diff --git a/pyzebra/app/handler.py b/pyzebra/app/handler.py deleted file mode 100644 index aa2ec05..0000000 --- a/pyzebra/app/handler.py +++ /dev/null @@ -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 diff --git a/pyzebra/app/app.py b/pyzebra/app/main.py similarity index 68% rename from pyzebra/app/app.py rename to pyzebra/app/main.py index f143db6..b9afa73 100644 --- a/pyzebra/app/app.py +++ b/pyzebra/app/main.py @@ -1,6 +1,6 @@ +import argparse import logging import sys -from io import StringIO from bokeh.io import curdoc from bokeh.layouts import column, row @@ -20,16 +20,33 @@ from pyzebra.app import ( ) doc = curdoc() +doc.title = "pyzebra" -sys.stdout = StringIO() -stdout_textareainput = TextAreaInput(title="print output:") +parser = argparse.ArgumentParser() -bokeh_stream = StringIO() -bokeh_handler = logging.StreamHandler(bokeh_stream) -bokeh_handler.setFormatter(logging.Formatter(logging.BASIC_FORMAT)) -bokeh_logger = logging.getLogger("bokeh") -bokeh_logger.setLevel(logging.WARNING) -bokeh_logger.addHandler(bokeh_handler) +parser.add_argument( + "--anatric-path", type=str, default=pyzebra.ANATRIC_PATH, help="path to anatric executable" +) + +parser.add_argument( + "--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:") @@ -77,13 +94,13 @@ doc.add_root( 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(): - stdout_textareainput.value = sys.stdout.getvalue() + log_textareainput.value = sys.stdout.getvalue() bokeh_log_textareainput.value = bokeh_stream.getvalue() diff --git a/scripts/pyzebra-test.sh b/scripts/pyzebra-test.sh index 30ade45..dea0aae 100644 --- a/scripts/pyzebra-test.sh +++ b/scripts/pyzebra-test.sh @@ -1,4 +1,4 @@ source /opt/miniconda3/etc/profile.d/conda.sh 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 diff --git a/scripts/pyzebra.sh b/scripts/pyzebra.sh index d98acaa..d0a3bcc 100644 --- a/scripts/pyzebra.sh +++ b/scripts/pyzebra.sh @@ -1,4 +1,4 @@ source /opt/miniconda3/etc/profile.d/conda.sh 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 -- GitLab