Error when trying to subclass Bokeh.models.Div

Hello, I’m trying to extend a bokeh class. Here’s some sample code:

class TestDiv(Div):
    def __init__(self):
        super(Div, self).__init__(text="")
        __implementation__ = JavaScript("")

I can instantiate this all right:

TestDiv()

# returns TestDiv(	id = '1002', …)

however, when i try to display it using bokeh.potting.show, I get this error:

show(TestDiv())

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 show(TestDiv())

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/showing.py:144, in show(obj, browser, new, notebook_handle, notebook_url, **kwargs)
    141 state = curstate()
    143 if isinstance(obj, LayoutDOM):
--> 144     return _show_with_state(obj, state, browser, new, notebook_handle=notebook_handle)
    146 def is_application(obj: Any) -> TypeGuard[Application]:
    147     return getattr(obj, '_is_a_bokeh_application_class', False)

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/showing.py:195, in _show_with_state(obj, state, browser, new, notebook_handle)
    192     shown = True
    194 if state.file or not shown:
--> 195     _show_file_with_state(obj, state, new, controller)
    197 return comms_handle

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/showing.py:176, in _show_file_with_state(obj, state, new, controller)
    172 def _show_file_with_state(obj: LayoutDOM, state: State, new: BrowserTarget, controller: BrowserLike) -> None:
    173     '''
    174 
    175     '''
--> 176     filename = save(obj, state=state)
    177     controller.open("file:// style="color:rgb(175,0,0)">" + filename, new=NEW_PARAM[new])

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/saving.py:98, in save(obj, filename, resources, title, template, state)
     95 theme = state.document.theme
     97 filename, resources, title = _get_save_args(state, filename, resources, title)
---> 98 _save_helper(obj, filename, resources, title, template, theme)
     99 return abspath(filename)

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/saving.py:164, in _save_helper(obj, filename, resources, title, template, theme)
    160 '''
    161 
    162 '''
    163 from ..embed import file_html
--> 164 html = file_html(obj, resources, title=title, template=template or FILE, theme=theme)
    166 with open(filename, mode="w", encoding="utf-8") as f:
    167     f.write(html)

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/embed/standalone.py:348, in file_html(models, resources, title, template, template_variables, theme, suppress_callback_warning, _always_new)
    346 (docs_json, render_items) = standalone_docs_json_and_render_items(models_seq, suppress_callback_warning=suppress_callback_warning)
    347 title = _title_from_models(models_seq, title)
--> 348 bundle = bundle_for_objs_and_resources([doc], resources)
    349 return html_page_for_render_items(bundle, docs_json, render_items, title=title,
    350                                   template=template, template_variables=template_variables)

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/embed/bundle.py:220, in bundle_for_objs_and_resources(objs, resources)
    217     css_raw.extend(css_resources.css_raw)
    219 if js_resources:
--> 220     extensions = _bundle_extensions(objs, js_resources)
    221     mode = js_resources.mode if resources is not None else "inline"
    222     if mode == "inline":

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/embed/bundle.py:298, in _bundle_extensions(objs, resources)
    296 names.add(name)
    297 module = __import__(name)
--> 298 this_file = abspath(module.__file__)
    299 base_dir = dirname(this_file)
    300 dist_dir = join(base_dir, "dist")

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/posixpath.py:374, in abspath(path)
    372 def abspath(path):
    373     """Return an absolute path."""
--> 374     path = os.fspath(path)
    375     if not isabs(path):
    376         if isinstance(path, bytes):

TypeError: expected str, bytes or os.PathLike object, not NoneType

any help appreciated!

show tries to auto-generate a filename for the saved HTML file if you don’t provide one, e.g. from a current script filename. But that’s not always possible, and it can’t handle whatever your situation is (you have not said… ipython console session maybe?) You will ned to provide your own filename to use via output_file or else call save and then open the resulting file yourself with the stdlib webbroswer module.

hi @Bryan thanks for the response! i want to use this within a bokeh server app, so using output_file isn’t an option.

my situation now is testing this in a jupyter notebook, but eventually i want this component to be used in a bokeh server app

is there some workaround here?

and you’re right in that i get this error only when i call output_notebook

FYI output_notebook should work but you have to call output_notebook after the extension is defined. (The output_notebook is exactly the action that “loads” the extension JS into the browser runtime)

still no luck I’m afraid:

from bokeh.io import output_notebook
from pycore.ui import TestDiv # this is where I define TestDiv, see above for class
from bokeh.plotting import show

TestDiv()
output_notebook()

throws this error:

TypeError                                 Traceback (most recent call last)
Input In [2], in <cell line: 2>()
      1 TestDiv()
----> 2 output_notebook()

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/output.py:124, in output_notebook(resources, verbose, hide_banner, load_timeout, notebook_type)
    122 # verify notebook_type first in curstate().output_notebook
    123 curstate().output_notebook(notebook_type)
--> 124 run_notebook_hook(notebook_type, "load", resources, verbose, hide_banner, load_timeout)

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/notebook.py:357, in run_notebook_hook(notebook_type, action, *args, **kwargs)
    355 if _HOOKS[notebook_type][action] is None:
    356     raise RuntimeError(f"notebook hook for {notebook_type!r} did not install {action!r} action")
--> 357 return _HOOKS[notebook_type][action](*args, **kwargs)

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/io/notebook.py:468, in load_notebook(resources, verbose, hide_banner, load_timeout)
    464     html = None
    466 _NOTEBOOK_LOADED = resources
--> 468 bundle = bundle_for_objs_and_resources(None, resources)
    470 nb_js = _loading_js(bundle, element_id, load_timeout, register_mime=True)
    471 jl_js = _loading_js(bundle, element_id, load_timeout, register_mime=False)

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/embed/bundle.py:220, in bundle_for_objs_and_resources(objs, resources)
    217     css_raw.extend(css_resources.css_raw)
    219 if js_resources:
--> 220     extensions = _bundle_extensions(objs, js_resources)
    221     mode = js_resources.mode if resources is not None else "inline"
    222     if mode == "inline":

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/embed/bundle.py:298, in _bundle_extensions(objs, resources)
    296 names.add(name)
    297 module = __import__(name)
--> 298 this_file = abspath(module.__file__)
    299 base_dir = dirname(this_file)
    300 dist_dir = join(base_dir, "dist")

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/posixpath.py:374, in abspath(path)
    372 def abspath(path):
    373     """Return an absolute path."""
--> 374     path = os.fspath(path)
    375     if not isabs(path):
    376         if isinstance(path, bytes):

TypeError: expected str, bytes or os.PathLike object, not NoneType

looks like this is the issue:

File ~/opt/anaconda3/envs/isxtools/lib/python3.8/site-packages/bokeh/embed/bundle.py:298, in _bundle_extensions(objs, resources)
    296 names.add(name)
    297 module = __import__(name)
--> 298 this_file = abspath(module.__file__)

is there some way to give some dummy path to objects that inherit from Div?

@sg-s I am not sure why it is trying to load any file at all, unless maybe your implementation is in a sidecar .js file? I can’t really speculate further without a complete Minimal Reproducible Example to actually run directly and investigate.

yes, i should have put the pieces together. here is a minimum reproducible example:

i have a file called test.py which looks like:

from bokeh.models import Div
from bokeh.util.compiler import JavaScript


class TestDiv(Div):
    def __init__(self):
        super(Div, self).__init__(text="")
        __implementation__ = JavaScript("")

then, in a jupyter notebook, i have this:

from bokeh.io import output_notebook
from bokeh.plotting import show
from test import TestDiv

output_notebook(hide_banner=True)

print(TestDiv())

show(TestDiv())

i get this output:

TestDiv(id='1012', ...) 

Javascript Error: Model 'test.TestDiv' does not exist. This could be due to a widget or a custom model not being registered before first usage.

i realize this is differnet from the error i had initially, but i still can’t figure out why i get this. i found this thread but couldn’t find anything that helps

I’m using Bokeh v2.4.3, on macOS. this error is on multiple browsers (Safari, Chrome, FF)

i don’t see any errors in the JS console

@sg-s where is the JavaScript implementation? I would regard a custom extensions with no implementation as undefined behavior. There is no automatic inheritance on the JS side, you must provide a minimal actual implementation of something.

I do think the extension compiler trying to use the “current module” when loading the bundle is an issue, though perhaps all we can do about that is document the case for notebooks. Please file a GitHub Issue with these details. In the mean time, best practice is really to put the JS implementation in a sidecar .js file, and provide the path to that, for the implementation. Does that improve things?

thank you, i did not understand this at all, and thought inheriting from Div would create an object that retained the behavior of Div. perhaps this should be clarified in the docs?

i guess the next step for me is to figure out how to copy Div 's JS behavior

Happy to consider any docs PR however the docs do already state this IMO:

While the Python side has little to no code, the JavaScript side requires code to implement the model.

Extending Bokeh — Bokeh 2.4.3 Documentation

Just reiterating I do think there is an issue to file, something is trying to assume module.__file__ which will not work in main modules. That either needs a fix or a workaround or at least to be documented.

thank you! i’ll collect my thoughts and file an issue about the __file__ behavior i saw

1 Like