Static images with bokeh>=2.4.0 vs bokeh==2.3.3

I use the code below with bokeh==2.3.3 to insert an image in a Div widget (both for macOS and Windows). When upgrading to bokeh >=2.4.0 (I also checked 3.2.2), the test_image.png is still displayed with macOS, but with Windows I get the error

404 GET /test/static/images/test_image.png (::1) 1.00ms

What has to be changed in the code for Windows using bokeh>=2.4.0? I have already checked the changelog and migration guide for bokeh==2.4.0, but was not successful with solving the problem…

Thanks a lot for your support!

from tornado.web import StaticFileHandler
from tornado.ioloop import IOLoop
from bokeh.server.server import Server
from bokeh.models import Div
import os, sys

def make_document(doc):
    d = Div(text="""<img src="./test/static/images/test_image.png" alt="div_image">""")

io_loop = IOLoop.current()

if sys.platform == "win32":
    # Windows
    path = os.path.normpath(os.path.dirname(os.path.abspath(__file__)) + r'/static/images')
    # MacOS
    path = r'./static/images'

server = Server(applications={'/test': make_document}, io_loop=io_loop, port=5001,
                extra_patterns=[(r'/test/static/images/(.*)', StaticFileHandler, {'path': path})])


Have you tried printing the full path that is computed, to verify that it is correct? If it’s not that, any problem or charge is probably actually with Tornado rather than Bokeh itself.

Hi Bryan, thanks a lot for the quick response! Yes, the full path to the png image is correct, I checked it.

I only updated bokeh=2.3.3 to bokeh=2.4.0 (via pip install bokeh==2.4.0) between my two runs, so my guess was to trace it back to the updated bokeh version since anything else remained unchanged (in particular no update of the tornado package and change of code).

I was wondering whether I need to adjust something for

  • Raw string paths in Image property
    Use pathlib.Path instead.

which is mentioned in the 2.4.0 migration guide and played around with it, however without any success. Do you have any suggestions how to proceed?

@bokeh_fan My only suggestion is to try with latest Bokeh version for comparison, or even verify that going back to 2.3.3 on the same machine does actually fix the issue. E.g. another possibility could be some file permission problem on the Windows machine, unrelated to Bokeh. You can also configure a higher log level, that will print out all the pattern registration at the Tornado level.

It is ultimately the Tornado StaticFileHandler that is responsible for serving the file, and also what is generating the 404 error message in the log. As you can see there’s not really much of anything Bokeh itself is doing in between.

@Bryan Thanks a lot for the suggestions! I have already tried the following on the same (Windows) machine:

  • Going back to 2.3.3 → fixes the issue
  • Using latest bokeh version (3.2.2) instead of 2.4.0 → does not fix the issue

I will check your other suggestions…

I would also see what happens with a path other than “static” since Bokeh does attempt to manage a static handler automatically in some cases. Perhaps there is a conflict.

It looks like in 2.4 Bokeh was updated to add a default static path handler at the same prefix you are trying to add:

I don’t think there is any good way to currently configure the path that that StaticHandler points to (i.e. I think you’d need to create your own Application subclass to override app.static_path) so you’d need to propose a GitHub issue for new feature development if you’d like to see that added. Otherwise in the mean time I think you’ll need to use a different endpoint.

Thanks a lot for following up on this topic @Bryan!

I think the feature would be beneficial for some people. Actually my example is based on a post from stack overflow (python - Access static directory when using Bokeh as a library - Stack Overflow) where somebody else asked about this feature. The applied method is also described in in the examples section of bokeh v3.2.2.

I have just tested again my code with MacOS (bokeh==2.3.3, bokeh==2.4.0, bokeh==3.2.2). Everything works fine for each version and there is no issue with StaticHandler. Is this reasonable for you @Bryan as you wrote that I need to use a different endpoint (I suppose this should be the case for both Windows and MacOS then)?

After some debugging, I understand now what you write about app.static_path and using a different endpoint @Bryan. I am not bound to the subdirectory ./static/images so I can move the subdirectory images into the test folder and remove static from any string in my posted code. The picture is then displayed for any mentioned bokeh version with Windows. Perfect!

For MacOS, however, I must not change my posted code (i.e. static needs to remain in the strings, otherwise the picture is not displayed for any mentioned bokeh version). This is confusing, but it works!

Thanks a lot for your support @Bryan, I appreciate it!