Thanks for your help @Bryan Below is the solution I came up with (some time ago!). It seems to work well but does introduce some dependencies on BokehJS internals. The idea is that a call like:
initialize_bokeh( )
or if using the local development build of the library, like:
initialize_bokeh( “mylibraryjs/dist/mylibraryjs.min.js” )
is made at startup.
It would be nice if something similar (but generic) could be provided as part of the standard API.
version = "0.0.3"
...
@static_vars(initialized=False)
def initialize_bokeh( libs=None, dev=0 ):
"""Initialize `bokeh` for use with the ``mylibraryjs`` extensions.
The ``mylibraryjs`` extensions for Bokeh are built into a stand-alone
external JavaScript file constructed for the specific version of
Bokeh that is being used. The URL or the local path to a locally
built verion must be supplied as the ``libs`` parameter. If ``libs``
is ``None`` then the default is to use the published verison of
``mylibraryjs`` extensions built and installed for `HTTP` access.
Parameters
----------
libs: None or str or list of str
javascript library to load could be a local path, a URL or None.
None is the default in which case it loads the published library
for the current version of ``mylibraryjs`` and ``bokeh``
dev: int, optional
Chrome caches the javascript files. This parameter allows for
specifying `dev` allows for including a development version
for incremental updates to JavaScript from website.
"""
if initialize_bokeh.initialized:
### only initialize once...
return
library_hashes = {
### --------------------------------------------------------------------------------------------------
### Generate hashes with:
### echo `cat mylibraryjs-v0.0.2.0-b2.3.js | openssl dgst -sha384 -binary | openssl base64 -A`
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
### NOTE: with the conversion from Bokeh 2.3.3 to 2.4.1, it seems that the security hashes are no
### longer included in the generated HTML.
### --------------------------------------------------------------------------------------------------
'mylibraryjs-v0.0.2.0-b2.3.js': 'EtB9H3ooIK3inPGx9RsRXeUv/COHtArEjhZUr7P75GBUPl+lAoGH/tqoAc1sV5jD',
'mylibraryjs-v0.0.2.0-b2.3.min.js': 'jAFFXRC9B93jSanS1dmqo+l/3rkcBqM48uTMN+SFcY7GPC/IPeEoI+p+Za5ztkcm',
'mylibraryjs-v0.0.3.0-b2.4.min.js': '23DOS7ISXIG8BRyIsD7vINUllDbo8NDCozIGBy7jGC+M14Z+axfF7j4bruA2ZnzL',
'mylibraryjs-v0.0.3.0-b2.4.js': 'OmIWKy37YXZf973kemdoFd2L/h0I9AY/hsP5PMdk5/g5xlgj16yk6b0cgO01UMxM'
}
mylib = None
mylibraryjs_libs = None
mylibraryjs_url = None
if libs is None:
mylib = "mylibraryjs-v%s.%d-b%s.min.js" % (version,dev,'.'.join(bokeh_version.split('.')[0:2]))
mylibraryjs_url = "https://example.com/download/javascript/mylibraryjs/%s/%s" % (version,mylib)
mylibraryjs_libs = [ mylibraryjs_url ]
else:
mylibraryjs_libs = [ libs ] if type(libs) == str else libs
mylibraryjs_libs = list(map( path_to_url, mylibraryjs_libs ))
from bokeh import resources
resources.JSResources._old_hashes = resources.JSResources.hashes
def hashes( self ):
result = self._old_hashes
if mylib is not None and mylib in library_hashes:
result[mylibraryjs_url] = library_hashes[mylib]
return result
resources.JSResources._old_js_files = resources.JSResources.js_files
def js_files( self ):
result = self._old_js_files
result = result + mylibraryjs_libs
return result
resources.JSResources.hashes = property(hashes)
resources.JSResources.js_files = property(js_files)
initialize_bokeh.initialized = True