Chapter 4: Streamlit’s execution model
This chapter introduces Streamlit’s execution model, state management, and troubleshooting through a daily to-do list app with intentionally created bugs.
After this chapter you will be able to
- Execution model and app state. Explain that understanding Streamlit’s execution model and managing an app’s state are necessary for building more complex Streamlit applications.
- Execution model learning focus. Explain that the chapter’s primary purpose is to familiarize readers with Streamlit’s execution model, using the to-do list app as the example.
- Daily to-do app concept. State that the app is a Streamlit app for adding tasks to a daily to-do list and tracking each task's status.
- Daily to-do user requirements. Describe the actions and information the daily to-do app must support: viewing a task list, adding and removing tasks, marking tasks done or not done, and seeing total and completed-task status.
- Single-session scope boundaries. Explain that the app is intentionally a basic daily tool whose tasks exist only during one open browser session; refreshing or reopening the page clears its data, and it does not export lists or retain task history.
- Two-area to-do layout. Describe the mock UI's two sections: a sidebar for entering new tasks and a main area for viewing tasks and updating their status.
- Task actions and progress feedback. Trace what happens after a user enters a task and clicks the add button: the task appears as a checkbox in the main area, can be marked done with a strike-through, or deleted with its adjacent button. Describe how the tracker reports completed tasks out of the total.
- Task and task-list model. Describe a task as an object with a name and a status of either done or not done, and describe the task list as an ordered list of those tasks.
- Task-list action effects. Explain how adding, marking done, marking not done, and deleting are all modifications to the task list: adding appends an item, status actions update an item's status, and deleting removes an item.
- Action and display architecture. Describe the app as three parts: the task list, actions connected to buttons and checkboxes that modify it, and display logic that renders the list's latest state. Explain that after an action, the display logic loops through the tasks again and applies rules such as checked and strikethrough if done.
- Troubleshooting-driven development. Explain that the to-do list app is built through realistic problems and errors, using those problems to develop a deeper understanding of Streamlit and how to fix app issues.
- Task list data model. Describe how the app represents each task as a Task dataclass with a string name and a boolean is_done field, and how todo_list.py holds Task objects in a Python list. State that is_done defaults to False when it is omitted while creating a task.
- Dynamic task controls. Explain how looping over task_list renders one checkbox and one Delete button per task, with the checkbox label taken from task.name and its checked value taken from task.is_done. Describe using two weighted columns so the checkbox and task text occupy 80% of the row while the Delete button occupies 20%.
- Unique widget key assignment. Explain that Streamlit uses widget keys to identify widgets and requires them to be unique. Describe why repeated Delete buttons get identical automatic keys from their shared label, and how enumerate supplies each task index for explicit keys such as delete_0; also explain that explicitly keyed checkboxes allow duplicate task names.
- Task list action functions. Describe how the app changes its task_list: add_task creates a Task from a task name and appends it, completion functions update a Task instance’s is_done field, and deletion removes an item by its list index.
- Task loss troubleshooting evidence. Trace the observed bug in which a newly added task disappears after another interaction, and explain how displaying task_list with st.info shows that the list itself is being emptied or recreated rather than the display loop merely hiding tasks.
- Execution model importance. Explain why a deeper understanding of Streamlit’s execution model becomes necessary when building more complex Streamlit apps, beyond knowing syntax and a surface-level view of app behavior.
- Streamlit app architecture. Describe the two parts of a Streamlit app: the backend Streamlit server and the browser-based frontend. Explain that the server runs on a computer while the frontend is the part users see and interact with in a web browser.
- Request-to-display flow. Trace the flow after a browser requests a Streamlit app: the Streamlit server executes the Python script from top to bottom, then sends a message telling the browser frontend what to display. State that the frontend consists of HTML, CSS, and JavaScript that the browser understands.
- Whole-script reruns. Explain that the Streamlit server runs the entire Python script again whenever the page changes or Streamlit needs to update the display. State that this happens for all widget interactions, not only button clicks.
- Frontend-server update cycle. Trace the sequence after a widget interaction: the frontend reports the interaction to the server, the server reruns the code and evaluates the widget value, then sends display updates for the frontend to apply.
- Task list reset on reruns. Explain why the to-do app loses previously added tasks when a user interacts with it: every rerun begins at the top of the script and assigns task_list to a new empty list.
- Button truth value timing. Describe when st.button evaluates to True and apply that timing to explain why a task is added on the run immediately after its Add Task click but not restored during a later checkbox-triggered rerun.
- Rerun memory loss. Explain why the to-do app forgets its tasks between interactions: Streamlit reruns the entire script, so an ordinary variable such as task_list is reset on each new run.
- Session state persistence. Explain that st.session_state stores variables across app reruns within an app session, and define a session as the time from opening an app until refreshing or closing it. State that separate browser tabs have separate sessions.
- One-time state initialization. Explain why a session-state key must be checked before initialization, and trace the number example: initialize number to zero only when it does not exist, then let the button increment the retained value and display it. Contrast this with resetting number to zero on every rerun, which would overwrite prior increments.
- Session state for app memory. Explain why st.session_state is crucial for anything beyond the simplest Streamlit apps: it gives an app memory that persists across reruns and makes the to-do list app workable.
- Persistent task list. Explain why the app’s task_list must be stored in st.session_state. Describe that an ordinary task_list variable resets on every Streamlit rerun, whereas the session-state task list retains previously added tasks.
- Session-state list alias. Describe the two-part update: initialize task_list in st.session_state when needed, then point the local task_list variable at the session-state version. Explain that this allows the remaining functions to keep using task_list without rewriting every reference.
- Delete button handler. Describe how the Delete buttons are wired by replacing the pass placeholder in the task display loop with a call to the existing delete_task function.
- Delayed deletion display. Explain the observed behavior after wiring the Delete buttons: the first click can change task data but the correct displayed list does not appear until another interaction causes an update, producing temporary misleading results.
- Delete-button rerun timing. Trace the execution after a user clicks a task’s Delete button, including the rerun, the button evaluating to True at that task’s loop iteration, and the call to delete_task with that task’s index.
- Stale display after deletion. Explain why the UI still shows the deleted task immediately after the first Delete click: the display loop rendered the old task_list before delete_task changed it, and no further rerun occurs until another user action.
- Programmatic app reruns. Explain how calling st.rerun() stops the current app run and starts the script again from the top. Describe placing it after a task deletion so the refreshed task list immediately reflects the changed task_list.
- Checkbox completion wiring. Describe how each task checkbox updates a task’s completion status by calling mark_done when checked and mark_not_done when unchecked.
- Checkbox rerun lag. Trace why a checkbox click initially changes task state without immediately updating its displayed label: the click triggers a rerun, but mark_done or mark_not_done runs after that task and label have already been displayed, so a later user action causes the updated display.
- Infinite rerun loop cause. Trace the execution path that creates the infinite rerun loop in the to-do app, from displaying an unchecked task checkbox through the else clause and repeated calls to st.rerun(). Explain why the loop never ends and causes Streamlit to stop responding.
- Conditional task-state transitions. Explain how to prevent the checkbox loop by calling mark_done and st.rerun only when a checked task is not already done, and calling mark_not_done and st.rerun only when an unchecked task is currently done.
- Completion progress metric. Describe how the app displays task-completion progress with st.metric, using the total task count and completed-task count from task_list.
What it builds on
- Building your first app (chapter 2) · Experience building a basic interactive Streamlit password-checker app.
- Writing code (chapter 3) · Experience implementing and connecting a Streamlit app frontend and backend.
- Concept to code: A six-step process (chapter 3) · The earlier concept-to-code process used to plan and build a practical application.
- Iterating on the app (chapter 3) · Experience iterating on an app after its initial implementation.
- Stating our concept: A unit converter (chapter 3) · Stating an app concept.
- Defining the requirements (chapter 3) · Defining requirements and what is out of scope.
- Visualizing the user experience (chapter 3) · Creating a mock to visualize user experience.
- Defining what the app won’t do (chapter 3) · The practice of explicitly defining what an app will not do.
Section by section
Introduction
This chapter introduces Streamlit’s execution model, state management, and troubleshooting through a daily to-do list app with intentionally created bugs.
- Execution model and app state: Explain that understanding Streamlit’s execution model and managing an app’s state are necessary for building more complex Streamlit applications.
Why it matters: This foundation helps you understand why an interactive app behaves the way it does as users interact with it. - Troubleshooting through intentional bugs: Describe the chapter’s troubleshooting approach: build a practical daily to-do list app, intentionally introduce bugs, and fix them to understand Streamlit’s inner workings and debug real apps.
Why it matters: Practicing with deliberate failures prepares you to diagnose unexpected behavior in your own Streamlit apps.
Key terms: Streamlit’s execution model, app state, st.session_state, st.rerun, daily to-do list app, troubleshooting, bugs, debugging
4.1 A more complex app: Daily to-dos
This section introduces a daily to-do list app as the chapter vehicle for learning Streamlit’s execution model, with only a brief design phase before implementation.
- Daily to-do list app: Describe the chapter’s example app as a daily to-do list that lets users track tasks they need to complete.
Why it matters: The to-do list is the concrete app used to demonstrate how Streamlit behaves as users interact with it. - Execution model learning focus: Explain that the chapter’s primary purpose is to familiarize readers with Streamlit’s execution model, using the to-do list app as the example.
Why it matters: Understanding the execution model explains why a Streamlit app responds the way it does when users interact with widgets. - Abbreviated design process: Describe how this chapter handles planning differently from the prior app project: it briefly covers the concept, requirements, and mock design, then moves directly to implementation instead of detailing the full six-step process.
Why it matters: This explains why the chapter moves quickly from the app idea into code while concentrating on execution behavior.
Key terms: to-do list app, tasks, Streamlit’s execution model, six-step development process, concept, requirements, mock design, implementation
4.1.1 Stating the concept
States the concise concept for the daily to-do app before defining its requirements.
- Daily to-do app concept: State that the app is a Streamlit app for adding tasks to a daily to-do list and tracking each task's status.
Why it matters: A concise app concept establishes the purpose that the later requirements and implementation must serve.
Key terms: concept, Streamlit app, daily to-do list, tasks, status
4.1.2 Defining the requirements and what is out of scope
This section defines the daily to-do app’s user requirements and deliberately limits it to a temporary, single-browser-session tool.
- Daily to-do user requirements: Describe the actions and information the daily to-do app must support: viewing a task list, adding and removing tasks, marking tasks done or not done, and seeing total and completed-task status.
Why it matters: Clear requirements establish exactly what the app must let a user do before implementation begins. - Single-session scope boundaries: Explain that the app is intentionally a basic daily tool whose tasks exist only during one open browser session; refreshing or reopening the page clears its data, and it does not export lists or retain task history.
Why it matters: Defining what is out of scope avoids introducing external-storage complexity before the book is ready to address it. - Requirements versus app concept: Distinguish the app concept, which gives a general idea of the product, from requirements, which make that idea concrete by stating what users need it to do.
Why it matters: This distinction helps turn an app idea into an implementable, testable set of capabilities.
Key terms: requirements, daily to-do list, tasks, task-completion status, out of scope, browser session, persisting, external storage, task history, concept
4.1.3 Visualizing the user experience
This section turns the daily to-do app requirements into a mock user interface showing where task creation, task management, and progress tracking appear.
- Two-area to-do layout: Describe the mock UI's two sections: a sidebar for entering new tasks and a main area for viewing tasks and updating their status.
Why it matters: The layout makes task entry separate from managing the current task list. - Task actions and progress feedback: Trace what happens after a user enters a task and clicks the add button: the task appears as a checkbox in the main area, can be marked done with a strike-through, or deleted with its adjacent button. Describe how the tracker reports completed tasks out of the total.
Why it matters: These visible interactions define how users add, complete, remove, and monitor their daily work.
Key terms: mock UI design, sidebar, main area, checkbox, done, strikes through, Delete buttons, tracker
4.1.4 Brainstorming the implementation
This section models the to-do app as an in-memory task list whose user actions modify task data and whose display logic re-renders the current list.
- Task and task-list model: Describe a task as an object with a name and a status of either done or not done, and describe the task list as an ordered list of those tasks.
Why it matters: A clear data model makes it possible to define what every user action changes. - Task-list action effects: Explain how adding, marking done, marking not done, and deleting are all modifications to the task list: adding appends an item, status actions update an item's status, and deleting removes an item.
Why it matters: Viewing all four controls as state changes gives the app a consistent implementation plan. - Action and display architecture: Describe the app as three parts: the task list, actions connected to buttons and checkboxes that modify it, and display logic that renders the list's latest state. Explain that after an action, the display logic loops through the tasks again and applies rules such as checked and strikethrough if done.
Why it matters: Separating stored tasks, state-changing controls, and rendering explains why every interaction can show an updated interface.
Key terms: task, task list, name, status, done, not done, Add a task, Mark the task as done, Mark the task as not done, Delete the task
4.2 Implementing and troubleshooting the app
This section introduces the deliberately problem-driven build of a to-do list app and prepares the reader to create its source file.
- Troubleshooting-driven development: Explain that the to-do list app is built through realistic problems and errors, using those problems to develop a deeper understanding of Streamlit and how to fix app issues.
Why it matters: Working through failures is how this chapter develops a practical understanding of Streamlit behavior. - Concise implementation tradeoff: Describe why the chapter temporarily avoids some chapter 3 best practices, specifically strict frontend-backend separation and a clear API, in favor of concise code for hands-on troubleshooting.
Why it matters: This explains why the example's structure may be simpler and less separated than the earlier unit converter. - To-do app source file: State that the reader should create a new file in their code editor named todo_list.py to begin the app.
Why it matters: This file is the starting point for implementing the chapter's to-do list application.
Key terms: troubleshooting, errors, Streamlit, backend, frontend, API, best practices, todo_list.py
4.2.1 Displaying the task list
This section incrementally renders a to-do list by modeling tasks, generating checkbox-and-delete controls in a loop, arranging them in columns, and assigning unique widget keys.
- Task list data model: Describe how the app represents each task as a Task dataclass with a string name and a boolean is_done field, and how todo_list.py holds Task objects in a Python list. State that is_done defaults to False when it is omitted while creating a task.
Why it matters: A clear task representation supplies the data from which the interface is rendered. - Dynamic task controls: Explain how looping over task_list renders one checkbox and one Delete button per task, with the checkbox label taken from task.name and its checked value taken from task.is_done. Describe using two weighted columns so the checkbox and task text occupy 80% of the row while the Delete button occupies 20%.
Why it matters: Generating controls from data lets the UI show every current task rather than a fixed set of widgets. - Unique widget key assignment: Explain that Streamlit uses widget keys to identify widgets and requires them to be unique. Describe why repeated Delete buttons get identical automatic keys from their shared label, and how enumerate supplies each task index for explicit keys such as delete_0; also explain that explicitly keyed checkboxes allow duplicate task names.
Why it matters: Unique keys prevent duplicate-widget errors and let repeated task controls be distinguished reliably. - Task list header: State that st.header renders the task-list heading at a size smaller than st.title, and that its divider argument can display a line beneath the header, including a specified divider color or cycling colors with True across multiple headers.
Why it matters: A header makes the task list visually identifiable while demonstrating a basic Streamlit text element.
Key terms: Task, dataclass, name, is_done, task_list, st.checkbox, st.button, for loop, st.columns, relative widths
4.2.2 Enabling actions
This section adds task actions to the to-do app, then uses the app’s surprising loss of tasks to motivate examining Streamlit’s execution behavior.
- Task list action functions: Describe how the app changes its task_list: add_task creates a Task from a task name and appends it, completion functions update a Task instance’s is_done field, and deletion removes an item by its list index.
Why it matters: These functions separate the operations that change to-do data from the UI controls that trigger them. - Sidebar task entry controls: Explain how the app lets a user enter a task name with st.text_input and invoke add_task with an st.sidebar button, and why the Add Task button is styled as the primary action.
Why it matters: Connecting an input and button to app logic is how the user can create tasks rather than relying on dummy data. - Task loss troubleshooting evidence: Trace the observed bug in which a newly added task disappears after another interaction, and explain how displaying task_list with st.info shows that the list itself is being emptied or recreated rather than the display loop merely hiding tasks.
Why it matters: Inspecting the running state narrows the problem to the data variable and prepares you to understand Streamlit reruns.
Key terms: task_list, Task, add_task, is_done, st.text_input, st.button, st.sidebar, type="primary", primary action, st.info
4.3 How Streamlit executes an app
This section introduces Streamlit’s execution model as the foundation needed to build more complex apps.
- Execution model importance: Explain why a deeper understanding of Streamlit’s execution model becomes necessary when building more complex Streamlit apps, beyond knowing syntax and a surface-level view of app behavior.
Why it matters: Understanding the execution model prepares you to reason about how complex Streamlit apps behave.
Key terms: execution model, Streamlit apps
4.3.1 Frontend and server
This section explains how a Streamlit server and browser frontend communicate to run a script and display an app.
- Streamlit app architecture: Describe the two parts of a Streamlit app: the backend Streamlit server and the browser-based frontend. Explain that the server runs on a computer while the frontend is the part users see and interact with in a web browser.
Why it matters: This model makes it easier to understand what happens when a user opens or interacts with a Streamlit app. - Ports and browser requests: Explain that a server listens on a port, which is a virtual communication channel identifying a particular program on a computer. Describe how visiting an address such as http://localhost:8502 causes the browser to send a request to the Streamlit server listening on that port.
Why it matters: Knowing the role of a port explains why a local Streamlit app is reached through a particular localhost address. - Request-to-display flow: Trace the flow after a browser requests a Streamlit app: the Streamlit server executes the Python script from top to bottom, then sends a message telling the browser frontend what to display. State that the frontend consists of HTML, CSS, and JavaScript that the browser understands.
Why it matters: This request-and-response flow is the foundation for understanding why Streamlit app code executes again as users interact with it.
Key terms: backend Streamlit server, frontend, server, listens, port, localhost, request, executes, top to bottom, HTML
4.3.2 App reruns
This section explains that Streamlit reruns the entire Python script whenever an interaction or display change occurs, and traces the frontend-server update cycle.
- Whole-script reruns: Explain that the Streamlit server runs the entire Python script again whenever the page changes or Streamlit needs to update the display. State that this happens for all widget interactions, not only button clicks.
Why it matters: Understanding whole-script reruns is essential for predicting why an app recalculates and redraws after user input. - Frontend-server update cycle: Trace the sequence after a widget interaction: the frontend reports the interaction to the server, the server reruns the code and evaluates the widget value, then sends display updates for the frontend to apply.
Why it matters: This cycle explains how a browser interaction becomes new Python execution and a visible app update.
Key terms: app reruns, Streamlit server, Python script, widgets, frontend, server, button click, display updates
4.3.3 Applying reruns to the app
This section traces how full Streamlit reruns make the current to-do app lose its in-memory task list after user interactions.
- Task list reset on reruns: Explain why the to-do app loses previously added tasks when a user interacts with it: every rerun begins at the top of the script and assigns task_list to a new empty list.
Why it matters: This explains why ordinary Python variables cannot retain app data across Streamlit interactions. - Button truth value timing: Describe when st.button evaluates to True and apply that timing to explain why a task is added on the run immediately after its Add Task click but not restored during a later checkbox-triggered rerun.
Why it matters: Understanding a button's one-rerun True value lets you predict which conditional code will execute after each interaction. - Interaction scenario outcomes: Trace the first run, an Add Task click, and a later interaction in the to-do app, including the textbox value, whether add_task runs, and the resulting displayed tasks.
Why it matters: Tracing individual runs makes seemingly inconsistent Streamlit UI behavior predictable.
Key terms: rerun, task_list, st.button, True, False, add_task, st.text_input, Task
4.4 Persisting variables across reruns
This section frames the to-do app’s memory problem: full Streamlit reruns reset ordinary variables such as the task list.
- Rerun memory loss: Explain why the to-do app forgets its tasks between interactions: Streamlit reruns the entire script, so an ordinary variable such as task_list is reset on each new run.
Why it matters: Recognizing that reruns discard ordinary variable values explains why an interactive app can appear to lose user actions.
Key terms: reruns, task_list, execution model
4.4.1 st.session_state
This section explains how st.session_state preserves per-session values across Streamlit reruns and how to initialize and manipulate that state safely.
- Session state persistence: Explain that st.session_state stores variables across app reruns within an app session, and define a session as the time from opening an app until refreshing or closing it. State that separate browser tabs have separate sessions.
Why it matters: Session state lets an interactive app remember values instead of starting over after every user action. - Session state dictionary operations: Describe how to add, retrieve, test for, iterate over, and delete key-value pairs in st.session_state using mostly dictionary-style syntax. State that dot notation, such as st.session_state.x, is also available even though st.session_state is not technically a Python dictionary.
Why it matters: Knowing the state interface lets you store and manage values while writing a Streamlit app. - One-time state initialization: Explain why a session-state key must be checked before initialization, and trace the number example: initialize number to zero only when it does not exist, then let the button increment the retained value and display it. Contrast this with resetting number to zero on every rerun, which would overwrite prior increments.
Why it matters: Conditional initialization prevents reruns from erasing the values an app is meant to remember.
Key terms: st.session_state, app session, reruns, key-value pairs, st.session_state["x"], st.session_state.x, items(), del, "number" key, initial check
4.5 Completing the app
This section introduces the return to the to-do list app now that session state can preserve information across Streamlit reruns.
- Session state for app memory: Explain why st.session_state is crucial for anything beyond the simplest Streamlit apps: it gives an app memory that persists across reruns and makes the to-do list app workable.
Why it matters: Without persistent state, interactive apps lose the information they need whenever Streamlit reruns the script. - To-do app implementation return: Describe the purpose of the upcoming work: revisit the previously attempted daily to-do list app and use st.session_state to get it working.
Why it matters: The to-do list provides the concrete example through which persistent state is applied.
Key terms: st.session_state, reruns, memory, to-do list app
4.5.1 Adding session state
This subsection fixes the to-do app’s disappearing tasks by storing the task list in session state and binding the existing variable to that persistent list.
- Persistent task list: Explain why the app’s task_list must be stored in st.session_state. Describe that an ordinary task_list variable resets on every Streamlit rerun, whereas the session-state task list retains previously added tasks.
Why it matters: Keeping the list in session state lets the to-do app preserve a user’s tasks while Streamlit reruns the script. - Session-state list alias: Describe the two-part update: initialize task_list in st.session_state when needed, then point the local task_list variable at the session-state version. Explain that this allows the remaining functions to keep using task_list without rewriting every reference.
Why it matters: Using a local alias keeps the existing task functions working while making their list persistent.
Key terms: task_list, st.session_state, rerun, st.session_state.task_list
4.5.2 Wiring up the Delete buttons
This section connects each Delete button to the existing delete_task function and exposes the delayed, incorrect UI updates that result.
- Delete button handler: Describe how the Delete buttons are wired by replacing the pass placeholder in the task display loop with a call to the existing delete_task function.
Why it matters: Connecting a widget action to its task-deletion logic is necessary before the app can remove tasks. - Delayed deletion display: Explain the observed behavior after wiring the Delete buttons: the first click can change task data but the correct displayed list does not appear until another interaction causes an update, producing temporary misleading results.
Why it matters: Recognizing this apparent lag helps you diagnose why an action may seem to fail or remove the wrong item before the screen catches up.
Key terms: Delete buttons, display loop, pass, delete_task function, Delete, lag, checkboxes, task entry textbox
4.5.3 What’s happening behind the scenes
This section traces why deleting a task updates the list after the display code has already run, producing stale or incorrect to-do UI until a later rerun.
- Delete-button rerun timing: Trace the execution after a user clicks a task’s Delete button, including the rerun, the button evaluating to True at that task’s loop iteration, and the call to delete_task with that task’s index.
Why it matters: Following the order of execution explains why an apparently correct state update may not immediately appear in the app UI. - Stale display after deletion: Explain why the UI still shows the deleted task immediately after the first Delete click: the display loop rendered the old task_list before delete_task changed it, and no further rerun occurs until another user action.
Why it matters: This is the key reason an in-memory update alone does not refresh a Streamlit interface at the right moment. - Middle-deletion index shift: Describe why deleting a task in the middle can make the following task disappear: deleting shifts later list indices down while the current display loop continues forward, causing it to skip the task that moved into the deleted position.
Why it matters: Recognizing index shifts helps explain a second symptom of mutating a list while iterating through it.
Key terms: rerun, st.button, delete_task(idx), task_list, idx, widget keys, display logic, delete_task, list indices, display loop
4.5.4 Triggering reruns automatically
This section fixes the to-do deletion display problem by explicitly triggering a Streamlit rerun after a task is deleted.
- Programmatic app reruns: Explain how calling st.rerun() stops the current app run and starts the script again from the top. Describe placing it after a task deletion so the refreshed task list immediately reflects the changed task_list.
Why it matters: Programmatically rerunning the app lets the interface immediately display changes made during the current run.
Key terms: st.rerun, rerun, task_list
4.5.5 Wiring up the checkboxes
This section wires task checkboxes to completion state and Markdown labels, then exposes the rerun lag and the hang caused by adding manual reruns.
- Checkbox completion wiring: Describe how each task checkbox updates a task’s completion status by calling mark_done when checked and mark_not_done when unchecked.
Why it matters: A checkbox must update the underlying task, not merely look checked on screen. - Completion label formatting: Explain how the checkbox label reflects completion state: an unfinished task uses its name, while a finished task uses the name surrounded by two pairs of tildes to produce a Markdown strikethrough.
Why it matters: The strikethrough gives users visible feedback about which tasks are complete. - Checkbox rerun lag: Trace why a checkbox click initially changes task state without immediately updating its displayed label: the click triggers a rerun, but mark_done or mark_not_done runs after that task and label have already been displayed, so a later user action causes the updated display.
Why it matters: Understanding this one-action delay is necessary to diagnose seemingly stale Streamlit interfaces. - Manual rerun failure: Describe the result of adding a manual rerun inside the mark_* functions: after adding the first task, the app hangs with a grayed-out screen and a RUNNING indicator instead of becoming responsive.
Why it matters: Recognizing the hang identifies that forcing reruns has introduced a new execution problem to solve.
Key terms: mark_done, mark_not_done, checkbox, is_done, Markdown, strikethrough, label parameter, tildes, rerun, manual rerun
4.5.6 An infinite rerun loop
This section traces how an unchecked task checkbox repeatedly calls st.rerun(), creating an infinite Streamlit rerun loop that makes the app stop responding.
- Infinite rerun loop cause: Trace the execution path that creates the infinite rerun loop in the to-do app, from displaying an unchecked task checkbox through the else clause and repeated calls to st.rerun(). Explain why the loop never ends and causes Streamlit to stop responding.
Why it matters: Recognizing this execution chain lets you diagnose why a Streamlit app becomes unresponsive after a widget interaction.
Key terms: infinite rerun loop, task_list, Task, is_done, display loop, else clause
4.5.7 Preventing the infinite rerun
This section fixes an infinite rerun loop by updating a task and calling st.rerun only when its checkbox value represents an actual change in completion status.
- Conditional task-state transitions: Explain how to prevent the checkbox loop by calling mark_done and st.rerun only when a checked task is not already done, and calling mark_not_done and st.rerun only when an unchecked task is currently done.
Why it matters: Guarding state changes this way lets checkboxes update tasks once instead of continually rerunning the app. - Infinite rerun loop cause: Describe why the original display loop could not stop rerunning: every checkbox result selected a branch that called a marking function followed by st.rerun, even when the task already had that status.
Why it matters: Recognizing unnecessary state updates helps you diagnose rerun loops in interactive Streamlit apps.
Key terms: mark_done, mark_not_done, st.rerun, is_done, checkbox, display for loop
4.5.8 Adding the completion progress indicator
This section finishes the to-do app by adding a large completion-progress metric derived from the task list and presenting the final app.
- Completion progress metric: Describe how the app displays task-completion progress with st.metric, using the total task count and completed-task count from task_list.
Why it matters: A visible progress measure gives users feedback and an extra sense of accomplishment as they complete tasks. - Completed-task list comprehension: Explain that the completed-task count is obtained with a list comprehension over task_list, using the concise form allowed when the expression is wrapped in a function.
Why it matters: This concise count supplies the completed-task value needed by the progress metric. - Final interface cleanup: State that the troubleshooting st.info box is removed from the final app because the app is no longer in troubleshooting mode.
Why it matters: Removing temporary diagnostic UI leaves the finished app focused on its intended user experience.
Key terms: st.metric, task_list, completed tasks, total number of tasks, completed_tasks, list comprehension, st.info, troubleshooting mode
4.6 Summary
This summary recaps how Streamlit identifies widgets, reruns scripts, preserves state, and supports troubleshooting interactive apps.
Where this is used later
- Setting widget defaults through st.session_state (chapter 7) · Widget defaults are set through st.session_state.
- Setting up persistent storage (chapter 8) · Persistent storage is introduced later as the solution for data that must survive beyond a session.
- What is deployment? (chapter 5) · The distinction between the browser frontend and the Streamlit server backend.
- Connecting PostgreSQL to the app (chapter 8) · The distinction between a Streamlit frontend and its server-side Python execution.
- Caching data (chapter 6) · Session state persists values for an individual user session.
- Enabling deeplinks (chapter 7) · The use of st.session_state to persist variables across Streamlit reruns.
- (chapter intro) (chapter 8) · The idea that Streamlit session state can persist variables across app reruns.
- Moving through game states (chapter 9) · Using st.session_state to retain variables across reruns.
Concepts explained in this chapter
- buttonA button is a Streamlit user-interface control that can initiate an application action when activated.
- check boxst.checkbox is a Streamlit input API element that renders a Boolean checkbox with a label.
- rerunAlways Rerun is a Streamlit development setting that automatically reruns an app whenever its source code changes.
- widget keyA widget key is an identifier that distinguishes a Streamlit widget from other widgets, especially widgets with identical characteristics.
- st.infost.info is a Streamlit output element that displays an informational message with informational semantic styling.
- st.headerst.header is a Streamlit display API element that renders text as a section heading smaller than a title.
- columnsst.columns is a Streamlit layout API function that creates side-by-side columns with equal or relative widths.
- sessionst.session_state is Streamlit's session-scoped state store for retaining values across reruns of an app session.
- st.rerunst.rerun is a Streamlit API function that stops the current script execution and starts a new execution from the beginning.
- requirementsSoftware requirements are stated needs, capabilities, goals, and constraints that a software system is expected to satisfy.
- scopeScope is the boundary of functionality and behavior included in a software project or application.
- StreamlitStreamlit is an open-source Python framework for building interactive web applications, especially data and machine-learning applications.
- frontend developmentFrontend development is the software engineering discipline concerned with implementing the user-facing parts of web applications.
- streamlit runThe streamlit run command is a command-line interface command that launches a Streamlit application from a Python source file.
- stateA graph state is the structured mutable data associated with a graph execution, including the messages for a conversation thread.
- st.metricst.metric is a Streamlit display function that presents a labeled metric value and optionally its change from a reference value.
- conditional logicBranching logic is control flow that selects among alternative execution paths based on conditions or decisions.
- memoryApplication memory is the transient information retained by a running application while it executes.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
