I am utilizing the FileIinput widget to allow users to upload csv/xlsx. I am using a Bokeh Server and set a callback like so:
fileinput_obj.on_change(‘filename’,my_cb)
My callback works fine and processes the csv/xlsx. However, my app will perform integrity checks on the input data and respond if the data is not in the correct format.
Now, as a user of my app, if I see the error message, correct the file on my machine and then try to re-upload the file, the callback is not triggered.
I can save the file with a new name, and the update works.
So Can I reset the filename property on the FileInput object so that the callback will work when attempting to re-upload the same file? Or do I need to do something as drastic as inserting a new FileInput widget into the document whenever the callback is called? (a workaround that I may try).
Example, run with
bokeh serve [file_name]
then upload the same file twice
from bokeh.plotting import figure, curdoc
from bokeh.layouts import layout
from bokeh.models import FileInput
def hello(attr,old,new):
print('hello', attr, old, new)
pass
f=FileInput(accept='.csv',multiple=False)
f.on_change('filename',hello)
l=layout(f)
curdoc().add_root(l)
Or do I need to do something as drastic as inserting a new FileInput widget into the document whenever the callback is called?
@jgriffi6 a simpler WAR to try would be to reset the filename property value to the empty string some random junk string you would never expect for a real filename when the invalidation occurs.
In general, Bokeh property change events only trigger when a property value actually changes, and that is a foundational, bedrock assumption that can’t really be altered. So making the FileInput behave differently to support immediate re-uploads of the same filename is not impossible, but it would necessarily mean moving away from using properties at all for this (e.g. events or something else).
Neither worked. When modifying the private data member, was able to change the python value of filename, but on the js side, nothing changed and thus callback is still not being called.
Ah, I forgot the property was readonly. That actually makes sense, but it means my idea will not work. For now I am afraid your idea of replacing the widget entirely may be the best option available. (Feel free to open a GitHub Issue about supporting this use-case more directly).
Thanks again for the quick response. I will try to raise a github issue on this. My WAR is not too bad, if others come across this issue, here it is:
def insert_file_input(n,cb,accept='.csv,.xlsx',multiple=False):
file_input=FileInput(accept=accept,name=n,multiple=multiple)
file_input.on_change('filename',cb)
col_name='column_'+n
if curdoc().get_model_by_name(n):
#the FileInput is already in the doc, swap it out
curdoc().get_model_by_name(col_name).children[0]=file_input
else:
#Introduce this to the document
return column(file_input,name=col_name)
return file_input
def my_callback(attr,old,new):
"""do the work here"""
my_specific_file_input()
def my_specific_file_input():
return insert_file_input('my_file_input',cb=my_callback)
my_layout=layout(..., my_specific_file_input())
curdoc.add_root(my_layout)
I just wanted to share that I ran into a similar problem and found that it’s a browser-dependant issue.
Rather than listening to changes in the “filename” property, I have an event handler for the “value” property of FileInput. I upload a file, then change something in the file, and then upload it again. In this situation, I get the same problem that the callback doesn’t get triggered on the second upload on 2 out of 3 browsers. Note also that, if I upload a second file in between the two uploads of the same file, then the callback does get called, and I can see that the “value” property does actually change. So it’s clearly a bug in the FileInput widget.
I use macOS (Big Sur 11.4), and the problem happens on Chrome (version 93.0.4577.82) and Safari (version 14.1.1) while on Firefox (version 91.0.2) it works as expected.