FileInput widget's callback on "value" parameter comes before filename is set

When a callback is assigned to a FileInput widget on a change of the “value” parameter, the callback function runs before the FileInput widget’s “filename” parameter is set. This can cause some unexpected results.

For example, taking bokeh/file_input.py at ed54705d627ae500509e57fe071fc7a60fc8a951 · bokeh/bokeh · GitHub and making a slight change such that the callback gets attached to the ‘value’ parameter:

from bokeh.layouts import column
from bokeh.models import CustomJS, Div, FileInput
from bokeh.plotting import output_file, show

# Set up widgets
file_input = FileInput(accept=".csv,.json")
para = Div(text="<h1>FileInput Values:</h1><p>filename:<p>b64 value:")

# Create CustomJS callback to display file_input attributes on change
callback = CustomJS(args=dict(para=para, file_input=file_input), code="""
    para.text = "<h1>FileInput Values:</h1><p>filename: " + file_input.filename  + "<p>b64 value: " + file_input.value
""")

# Attach callback to FileInput widget
file_input.js_on_change('value', callback) # THIS IS THE CHANGE


output_file("file_input.html")

show(column(file_input, para))

Running this shows the filename not showing up.

This is not an issue for this particular case, since we can use the js_on_change function with ‘change’ instead of ‘value’. However, if I want to attach a typical Python function as the callback, e.g., using file_input.change('value', callback), where ‘callback’ is a Python function of the form def callback(attr, old, new), then using ‘change’ isn’t an option.

I was using ‘value’ for a while (since this is what’s shown in the documentation) and trying to figure out why my filename wasn’t showing up in the callback. It took me a while to figure out that I should be using ‘filename’ instead (since ‘filename’ gets changed later on in bokeh.models.widgets.inputs — Bokeh 2.3.3 Documentation than ‘value’).

Is there some way to attach a callback to a widget that waits for all properties of the widget to be updated prior to running the callback function? Similar to what’s done with file_input.js_on_change('change', callback), but when using a typical Python function instead of a CustomJS.

@efremdan1 The case where there are multiple related properties that might need to be responded to as a group, is not the common case with Bokeh. Most properties are “standalone” in that sense. But there are some cases, e.g. wanting to respond to a consolidated range update instead of separate start and end updates separately. This that you have mentioned here, would be yet another case, where it is reasonable to want to respond to both value and filename together only after they are both guaranteed to be updated.

I expect there will be more cases like this over time, and it has recently been subject to some discussion. Specifically, a RangeUpdate event was added to afford the ability to respond to consolidated range updates. But nothing has been proposed or done for this case as of yet. I’d suggest starting a GitHub development discussion to that the core team might consider how to improve these cases in a consistent way going forward.

As a final aside, regarding this:

file_input.js_on_change('change', callback)

AFAIK this is not documented or supported public API. I would caution not to rely on it. The internal BokehJS change events are not meant for users, and it’s only an accident that js_on_change responds to them. Where did you see this demonstrated? If nothing else, as a practical matter, change fires when any property is updated, not when all properties are updated so I would not imagine it to be a reliably useful in this situation.

This is in the example given in bokeh/file_input.py at ed54705d627ae500509e57fe071fc7a60fc8a951 · bokeh/bokeh · GitHub. This was one of the few search results of the Bokeh github for “FileInput” in the examples directory.

I tried to do this, but unfortunately I’m not being allowed to start a new discussion topic (not sure why…).

I think that is a mistake, I will open a GitHub issue to correct it.

Edit: Update file_input.py by bryevdv · Pull Request #11459 · bokeh/bokeh · GitHub

I tried to do this, but unfortunately I’m not being allowed to start a new discussion topic

AFAIK GitHub discussions are open to anyone, what was the exact error message? In any case you can also open a GitHub Issue is discussions don’t work.

There’s just no button visible for me to create a new discussion (see screenshot below). I’m creating a new issue now though.


@efremdan1 I’m not sure, there should be a green “New Discussion” button on the right. GitHub’s documention is pretty clear that

Anyone with access to a repository can create a discussion.

So maybe there is some local browser configuration interfering with the page render? :man_shrugging:

https://docs.github.com/en/discussions/quickstart#creating-a-new-discussion