fix(runtime): don't shadow builtin print unless mo.Thread is used (#9765)#9766
Merged
Conversation
) marimo unconditionally replaced the builtin `print` in every cell's global namespace with `print_override` (used to route mo.Thread output to the right cell). This broke libraries that special-case the genuine builtin, e.g. numba's `@njit`, which requires `print is builtins.print` and otherwise fails with "Untyped global name 'print': Cannot determine Numba type of <class 'function'>". Only patch `print` when the feature that needs it is actually used: stop installing the override in create_main_module, and instead have mo.Thread install it lazily into the kernel globals on construction. Thread-free notebooks now keep the real builtin print, so numba and similar libraries work again. Removes the now-unused print_override plumbing through KernelArgs and create_main_module/patch_main_module.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a runtime compatibility issue where marimo shadowed the builtin print in every cell, breaking libraries (notably numba) that require print is builtins.print. The override is now applied only when mo.Thread is actually used, preserving the real builtin in thread-free notebooks while keeping thread output routing functional.
Changes:
- Stop installing
print_overrideincreate_main_module/ kernel startup so thread-free notebooks keep the builtinprint. - Lazily patch
printinto kernel globals when amo.Threadis constructed. - Remove the now-unused
print_overrideplumbing fromKernelArgsand associated kernel/session creation call sites; add tests covering both behaviors.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/_runtime/test_threads.py | Adds coverage ensuring print remains builtin without threads, and becomes overridden after constructing mo.Thread. |
| tests/_runtime/_helpers/session.py | Updates test kernel session construction to match the simplified KernelArgs (removes print_override_fn). |
| marimo/_runtime/threads.py | Implements lazy print patching in mo.Thread.__init__ for kernel contexts. |
| marimo/_runtime/runtime.py | Removes unconditional print_override import and kernel arg wiring. |
| marimo/_runtime/patches.py | Removes print_override from create_main_module/patch_main_module and documents the new lazy behavior. |
| marimo/_runtime/kernel_lifecycle.py | Removes print_override_fn from KernelArgs and stops passing it into module patching. |
| marimo/_runtime/context/script_context.py | Updates create_main_module call signature after removing print_override parameter. |
| marimo/_runtime/app/script_runner.py | Updates create_main_module calls to new signature. |
| marimo/_runtime/app/kernel_runner.py | Updates create_main_module call to new signature. |
| marimo/_pyodide/pyodide_session.py | Updates KernelArgs construction after removing print_override_fn. |
Contributor
There was a problem hiding this comment.
No issues found across 10 files
Architecture diagram
sequenceDiagram
participant Cell as User Cell
participant Module as Kernel __main__ Module
participant Thread as mo.Thread
participant PrintOverride as print_override()
participant Kernel as Kernel
Note over Cell,Kernel: Normal cell execution (no mo.Thread)
Cell->>Module: Execute cell code
Cell->>Cell: print("hello") resolves to builtins.print
Note right of Cell: Libraries like numba see print is builtins.print
alt mo.Thread is constructed
Cell->>Thread: mo.Thread(target=lambda: ...)
Thread->>Kernel: constructor called
Note over Thread,Kernel: Lazy patching of print
Thread->>PrintOverride: ctx.globals.setdefault("print", print_override)
PrintOverride-->>Module: Patches print in kernel globals
Kernel-->>Thread: ThreadLifecycle registered
end
Note over Cell,Kernel: Thread output routing (when thread exists)
Cell->>Thread: thread.start()
Thread->>Thread: target() executes
Thread->>PrintOverride: print() calls print_override
PrintOverride-->>Kernel: Routes output to spawning cell's stream
Kernel-->>Cell: Output appears in cell
Note over Cell,Kernel: Thread-free notebooks keep real builtin
alt No mo.Thread created
Cell->>Module: print refers to builtins.print
Cell->>Cell: print is builtins.print → True
Note right of Cell: numba @njit works correctly
end
Note over Cell,Module: Boundary: cell globals vs kernel globals
Module->>Kernel: print lives in kernel __main__ module globals
Kernel->>PrintOverride: Only set if Thread exists
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
marimo unconditionally replaced the builtin
printin every cell'sglobal namespace with
print_override(used to route mo.Thread outputto the right cell). This broke libraries that special-case the genuine
builtin, e.g. numba's
@njit, which requiresprint is builtins.printand otherwise fails with "Untyped global name 'print': Cannot determine
Numba type of <class 'function'>".
Only patch
printwhen the feature that needs it is actually used:stop installing the override in create_main_module, and instead have
mo.Thread install it lazily into the kernel globals on construction.
Thread-free notebooks now keep the real builtin print, so numba and
similar libraries work again.
Removes the now-unused print_override plumbing through KernelArgs and
create_main_module/patch_main_module.
Fixes #9765