Python Bokeh markup text value can't update

Bokeh state only synchronizes with the browser when the callback ends. If you want to do some update, then alot of blocking work, then another update, you will need to split things up so the first callback completes immediately then schedules the rest of the work to happen after the return. The simplest way is with add_next_tick_callback:

from time import sleep
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import Button, Div

d = Div(text="start")

b = Button()

def work():
    sleep(2)
    d.text = "end"

def cb():
    d.text = "middle"
    curdoc().add_next_tick_callback(work)

b.on_click(cb)

curdoc().add_root(column(d, b))