question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[FEATURE] Enable the Server to serve apps at sub urls like /gallery/image-classifier

See original GitHub issue

My Pain

Normally I combine many subapps into one major app and I would like to use the url to structure these logically. And sometimes there is also an underlying REST API url structure I would like to mimic.

For example at awesome-panel.org i have a gallery of apps that I would like to my users to be able to bookmark and share deep links to.

I can use panel.Serve which uses the bokeh Server to serve apps at different urls. This works fine for / and /gallery but for sub pathnames like /gallery/image-classifier this does not work because of a 404 error (Static assets not found).

Solution

Enable serving apps a sub pathnames like /gallery/image-classifier.

Bokeh Example

from bokeh.layouts import column
from bokeh.models import Slider
from bokeh.server.server import Server


def get_app(title="My App"):
    def bkapp(doc):
        slider = Slider(start=0, end=30, value=0, step=1, title=title)

        doc.add_root(column(slider))

    return bkapp


applications = {
    "/": get_app("Welcom"),
    "/resources": get_app("Resources"),
    "/about": get_app("About"),
    "/gallery": get_app("Gallery"),
    "/gallery/bootstrap-dashboard": get_app("Bootstrap Dashboard"),
    "/gallery/image-classifier": get_app("Image Classifier"),
}

# Setting num_procs here means we can't touch the IOLoop before now, we must
# let Server handle that. If you need to explicitly handle IOLoops then you
# will need to use the lower level BaseServer class.
server = Server(applications)
server.start()

if __name__ == "__main__":
    print("Opening Bokeh application on http://localhost:5006/")

    server.io_loop.add_callback(server.show, "/")
    server.io_loop.start()

image

image

image

$ c:/repos/private/awesome-panel/.venv/Scripts/python.exe c:/repos/private/awesome-panel/scripts/issues/issue_bo
keh_serve.py
Opening Bokeh application on http://localhost:5006/
WARNING:tornado.access:404 GET /gallery/static/js/bokeh.min.js?v=ac90935137e13ae0b2c6583f2e1f3fe8 (::1) 1.00ms
WARNING:tornado.access:404 GET /gallery/static/js/bokeh-widgets.min.js?v=bbfecfaf62fc48a3f557280273185467 (::1) 3.00ms
WARNING:tornado.access:404 GET /gallery/static/js/bokeh-tables.min.js?v=35738715f747a3f5672b245db261f9bc (::1) 3.00ms
WARNING:tornado.access:404 GET /gallery/static/js/bokeh-gl.min.js?v=817fa55a6e55d1e469275e21c9b77565 (::1) 3.00ms

Additional Context

Maybe the fix is as simple as changing the boker.server.urls for the StaticHandler see https://docs.bokeh.org/en/latest/docs/reference/server/urls.html.

You can discuss whether this should be posted as a bug or a feature request.

FIRST REQUESTED FOR PANEL AS https://github.com/holoviz/panel/issues/1075. BUT IT WAS SUGGESTED TO REQUEST THIS FOR BOKEH.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:18 (17 by maintainers)

github_iconTop GitHub Comments

3reactions
asmodehncommented, Dec 14, 2020

Chiming in because I am in a similar situation, stitching multiple bokeh applications, in a tornado server, and finding out that static urls don’t work as I would naively expect.

Specifically I wanted to add details for others who might be in a similar situation :

Another option would be to in fact add additional static handlers to serve resources at per-app “static” routes. Maybe that is actually simpler/more reasonable.

This advice is usable as an immediate workaround by a user, and it worked for me (bokeh 2.2.3) roughly like so :


from tornado.web import StaticFileHandler

from bokeh.application import Application as BokehApplication
from bokeh.server.server import Server as BokehServer
from bokeh.application.handlers import Handler as BokehHandler

class MyHandler(BokehHandler):
    ...

BokehServer(
        applications={
                ...
                f"/sub/myurl": BokehApplication(MyHandler())
                ...
        },
        # standard tornado things
        extra_patterns=[
            ('/sub/static/(.*)', StaticFileHandler, {'path': os.path.normpath(os.path.dirname(bokeh.server.__file__) + '/static/')}),
        ],
    )
2reactions
bryevdvcommented, Apr 9, 2021

@MarcSkovMadsen @asmodehn I will need your help to make this happen. Here is a diff that seems to work as needed:

diff --git a/bokeh/server/tornado.py b/bokeh/server/tornado.py
index cc10b68d4..43edc954e 100644
--- a/bokeh/server/tornado.py
+++ b/bokeh/server/tornado.py
@@ -382,14 +382,13 @@ class BokehTornado(TornadoApplication):

             all_patterns.extend(app_patterns)

-            # add a per-app static path if requested by the application
+            # if the app requests a custom static path, use that, otherwise add Bokeh's standard static handler
+            route = self._prefix
+            route += "/static/(.*)" if key == "/" else  key + "/static/(.*)"
             if app.static_path is not None:
-                if key == "/":
-                    route = "/static/(.*)"
-                else:
-                    route = key + "/static/(.*)"
-                route = self._prefix + route
                 all_patterns.append((route, StaticFileHandler, { "path" : app.static_path }))
+            else:
+                all_patterns.append((route, StaticHandler, {}))

         for p in extra_patterns + toplevel_patterns:
             if p[1] == RootHandler:

I don’t like this 100% since it’s already possible for e.g. directory-style apps to add a custom static directory, and we can’t break that feature. So we can only add the default static handler when that isn’t the case, which is a bit clunky. But it seems like unlikely that your case would run into this existing feature, so things should work out.

What I need: I need both of you to test with this patch and confirm that it does, in fact, meet all your needs and requirements. Then, ideally, one or both of you can submit the PR to add it and I can help work through the remaining parts (docs, fixing up tests) in the PR. Like many OSS projects, we are resource-constrained, and I can guarantee things will go faster with extra help.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Material Design App Template for Panel (and Bokeh)
Hi All I've started to contribute a Material Design App Template for ... this one [FEATURE] Enable the Server to serve apps at...
Read more >
Configure an environment for apps for SharePoint Server
To configure app URLs​​ In Central Administration, click Apps. On the Apps page, click Configure App URLs. In the App domain box, type...
Read more >
bokeh Changelog - pyup.io
9671 [component: server] [FEATURE] Enable the Server to serve apps at sub urls like /gallery/image-classifier - 9961 [component: docs] Ref Docs need sidebar ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found