Internal Design#

Pigweed AI summary: The Pigweed Console runs user repl code in a dedicated thread with stdout and stderr patched to capture output, allowing the user interface to stay responsive and new log messages to continue to be displayed. This is different from ptpython and IPython, where all user repl code is run in the foreground, which can hide or freeze the prompt_toolkit user interface while running repl code. The diagram shows how Pigweed Console threads and asyncio tasks are organized.

Threads and Event Loops#

Pigweed AI summary: The article discusses how user repl code is run in the foreground in ptpython and IPython, allowing for interrupts and functions to work as expected. However, Pigweed's Console runs user repl code in a dedicated thread with stdout and stderr patched to capture output, in order to keep the user interface responsive. The article includes a diagram showing how pw_console threads and asyncio tasks are organized.

In ptpython and IPython all user repl code is run in the foreground. This allows interrupts like Ctrl-C and functions like print() and time.sleep() to work as expected. Pigweed’s Console doesn’t use this approach as it would hide or freeze the prompt_toolkit user interface while running repl code.

To get around this issue all user repl code is run in a dedicated thread with stdout and stderr patched to capture output. This lets the user interface stay responsive and new log messages to continue to be displayed.

Here’s a diagram showing how pw_console threads and asyncio tasks are organized.

flowchart LR classDef eventLoop fill:#e3f2fd,stroke:#90caf9,stroke-width:1px; classDef thread fill:#fffde7,stroke:#ffeb3b,stroke-width:1px; classDef plugin fill:#fce4ec,stroke:#f06292,stroke-width:1px; classDef builtinFeature fill:#e0f2f1,stroke:#4db6ac,stroke-width:1px; %% Subgraphs are drawn in reverse order. subgraph pluginThread [Plugin Thread 1] subgraph pluginLoop [Plugin Event Loop 1] toolbarFunc-->|"Refresh<br/>UI Tokens"| toolbarFunc toolbarFunc[Toolbar Update Function] end class pluginLoop eventLoop; end class pluginThread thread; subgraph pluginThread2 [Plugin Thread 2] subgraph pluginLoop2 [Plugin Event Loop 2] paneFunc-->|"Refresh<br/>UI Tokens"| paneFunc paneFunc[Pane Update Function] end class pluginLoop2 eventLoop; end class pluginThread2 thread; subgraph replThread [Repl Thread] subgraph replLoop [Repl Event Loop] Task1 -->|Finished| Task2 -->|Cancel with Ctrl-C| Task3 end class replLoop eventLoop; end class replThread thread; subgraph main [Main Thread] subgraph mainLoop [User Interface Event Loop] log[[Log Pane]] repl[[Python Repl]] pluginToolbar([User Toolbar Plugin]) pluginPane([User Pane Plugin]) class log,repl builtinFeature; class pluginToolbar,pluginPane plugin; end class mainLoop eventLoop; end class main thread; repl-.->|Run Code| replThread pluginToolbar-.->|Register Plugin| pluginThread pluginPane-.->|Register Plugin| pluginThread2