Cannot Update Select Options From Python Callback (works with CustomJS)

If I have a simple widget with a select drop-down menu, a text box and a button:

image

I would like to enter text into the text box and it appear in the select drop down when I press the button. If I do this via Python, as follows, I cannot get the DOM to update even though the print statement shows the correct value for options:

from bokeh.plotting import curdoc
from bokeh.layouts import column
from bokeh.models import Button, CustomJS, Select, TextInput
from bokeh.events import ButtonClick

def add_entry(event):
    options.append(text_input.value)
    select.options = options
    select.value = text_input.value
    text_input.value = ''
    
    print(f'\n{select.options}\n')
    
options = ['first']

# Site selector
select = Select(title = 'Choose Option:', options = options)
text_input = TextInput(value = '', title = 'Enter Name:')
button = Button(label = 'Add New Entry')

# Listen for events
button.on_event(ButtonClick, add_entry)

# put the button and plot in a layout and add to the document
curdoc().add_root(column(select, text_input, button))

However, if I do the same thing via a Javascript callback I get the intended behaviour:

# %% Imports
# Bokeh imports
from bokeh.plotting import curdoc
from bokeh.layouts import column
from bokeh.models import Button, CustomJS, Select, TextInput
from bokeh.events import ButtonClick
    
options = ['first']

# Site selector
select = Select(title = 'Choose Option:', options = options)
text_input = TextInput(value = '', title = 'Enter Name:')
button = Button(label = 'Add New Entry')

# Listen for events
button.js_on_event(ButtonClick, CustomJS(args = {'options': options, 'select': select, 'text_input': text_input}, code = """
      options.push(text_input.value);
      select.options = options;
      select.value = text_input.value;
      text_input.value = '';
"""))

# put the button and plot in a layout and add to the document
curdoc().add_root(column(select, text_input, button))

Is this expected or am I doing something wrong?

You’re modifying the options list in-place, so Bokeh cannot detect whether the value was changed or not. Even though you assign the changed options to select, the object itself is the same.
Instead, try:

select.options = select.options + [text_input.value]

Thanks @p-himik! That worked.

So is it the case that Bokeh looks for a change in the id() of the object to ascertain whether a change has occurred? So since lists are mutable adding or removing items still means the list has the same id().

@Cuahchic it’s a little more complicated than that, Bokeh’s property system is based on the Python descriptor protocol, which allows for customizing what happens when an assignment like select.options = new_options happens. Internally the code actually performs an equality check to determine whether a value is “new” or not, but most importantly: the change has to be the result of an actual assignment.

Ah, OK, thanks for the extra information @Bryan.