Panel regression? (embedding panel in gunicorn+Flask)

@philippjfr

Thanks for the follow-up. This topic mentions using panel 0.10.2 and flask under gunicorn. However, the problem can still be reproduced using just panel and flask, i.e. without the gunicorn layer.

Starting with the bokeh server embed example, flask_embed.py, I stripped out the theme and replaced the bokeh layout with panel’s syntax to yield the following example. This example works as expected in panel 0.9.7 but throws 404 errors in panel 0.10.2

 * Running on http://127.0.0.1:8000/ (Press CTRL+C to quit)
127.0.0.1 - - [18/Jan/2021 08:42:27] "GET / HTTP/1.1" 200 -
INFO:werkzeug:127.0.0.1 - - [18/Jan/2021 08:42:27] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/alerts.css HTTP/1.1" 404 -
INFO:werkzeug:127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/alerts.css HTTP/1.1" 404 -
127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/card.css HTTP/1.1" 404 -
INFO:werkzeug:127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/card.css HTTP/1.1" 404 -
127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/widgets.css HTTP/1.1" 404 -
INFO:werkzeug:127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/widgets.css HTTP/1.1" 404 -
127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/markdown.css HTTP/1.1" 404 -
INFO:werkzeug:127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/markdown.css HTTP/1.1" 404 -
127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/json.css HTTP/1.1" 404 -
INFO:werkzeug:127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/json.css HTTP/1.1" 404 -
127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/dataframe.css HTTP/1.1" 404 -
INFO:werkzeug:127.0.0.1 - - [18/Jan/2021 08:42:27] "GET /static/extensions/panel/css/dataframe.css HTTP/1.1" 404 -
^C^CException ignored in: <module 'threading' from '/Users/monaco/opt/anaconda3/lib/python3.8/threading.py'> 

Here’s the example code and HTML embed template.

flask_embed.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
"""

from threading import Thread

from flask import Flask, render_template
from tornado.ioloop import IOLoop

from bokeh.embed import server_document
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature
from bokeh.server.server import Server

import panel as pn

app = Flask(__name__)


def bkapp(doc):
    df = sea_surface_temperature.copy()
    source = ColumnDataSource(data=df)

    plot = figure(x_axis_type='datetime', y_range=(0, 25), y_axis_label='Temperature (Celsius)',
                  title="Sea Surface Temperature at 43.18, -70.43")
    plot.line('time', 'temperature', source=source)

    def callback(attr, old, new):
        if new == 0:
            data = df
        else:
            data = df.rolling(f"{new}D").mean()
        source.data = ColumnDataSource.from_df(data)

    slider = Slider(start=0, end=30, value=0, step=1, title="Smoothing by N Days")
    slider.on_change('value', callback)

    pn.Column(slider, plot).server_doc(doc)


@app.route('/', methods=['GET'])
def bkapp_page():
    script = server_document('http://localhost:5006/bkapp')
    return render_template("embed.html", script=script, template="Flask")


def bk_worker():
    # Can't pass num_procs > 1 in this configuration. If you need to run multiple
    # processes, see e.g. flask_gunicorn_embed.py
    server = Server({'/bkapp': bkapp}, io_loop=IOLoop(), allow_websocket_origin=["localhost:8000"])
    server.start()
    server.io_loop.start()

Thread(target=bk_worker).start()

if __name__ == '__main__':
    print('Opening single process Flask app with embedded Bokeh application on http://localhost:8000/')
    print()
    print('Multiple connections may block the Bokeh app in this configuration!')
    print('See "flask_gunicorn_embed.py" for one way to run multi-process')
    app.run(port=8000)

embed.html

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Embedding a Bokeh Server With {{ framework }}</title>
</head>

<body>
  <div>
    This Bokeh app below served by a Bokeh server that has been embedded
    in another web app framework. For more information see the section
    <a  target="_blank" href="https://docs.bokeh.org/en/latest/docs/user_guide/server.html#embedding-bokeh-server-as-a-library">Embedding Bokeh Server as a Library</a>
    in the User's Guide.
  </div>
  {{ script|safe }}
</body>
</html>