That is expected The new value will be assigned in the next rerun, but the callback is called before that so it is gets the old value. You can use session_state.user_input, though.
I like your working version, but I would put the conditional out of the with block. As the saying goes, flat is better than nested.
Thanks for confirming that this is WAI. I’m still puzzled why session_state can capture user_input correctly but not the argument passed to the callback. While using session_state for this might work as a workaround, it feels a bit hacky, and I’d prefer to avoid it if possible.
Because session_state.user_input is updated as soon as you press the submit button, but the assignment to user_input doesn’t happen until the next rerun.
Using session state in that way doesn’t feel hacky to me, but relying on global state can certainly become a problem in complex applications. There are ways to deal with that, but they are out of scope here IMO.
Anyway I would favour your second implementation, that delays the handling until the next rerun, when user_input has already been assigned the new value.
I find this behavior quite counterintuitive. It’s natural to expect that the callback function would process the form input directly. If that’s not the case, the callback function loses much of its usefulness. At the very least, this should be clearly documented in my opinion.