Skip to content

Add ctx.packages namespace to code mode#9233

Merged
mscolnick merged 4 commits intomainfrom
push-qrvxrmqploro
Apr 17, 2026
Merged

Add ctx.packages namespace to code mode#9233
mscolnick merged 4 commits intomainfrom
push-qrvxrmqploro

Conversation

@manzt
Copy link
Copy Markdown
Collaborator

@manzt manzt commented Apr 16, 2026

Code mode's single install_packages() method dispatched to InstallPackagesCommand, which scans the kernel for all other missing modules and re-runs affected cells on success. That's the right default for auto-install on import error, but surprising when an agent is explicitly asking to add one package.

These changes introduces a ctx.packages namespace with add, remove, and list, installed into marimo/_code_mode/_packages.py.

add goes through a custom install loop that keeps the streaming frontend notifications (queued → installing → installed/failed with logs) but drops the missing-module scan and cell re-runs (installing exactly what was asked, nothing more). remove and list are thin wrappers over PackageManager.uninstall / list_packages and update the script metadata for sandboxed notebooks the same way the HTTP endpoints do.

Mutations are queued and flushed on context exit before cell ops, so newly installed packages are importable from cells added in the same batch. list returns the current environment state and raises if add or remove have been queued. The alternative (stale data or silently overlaying pending ops) is worse than a hard error.

async with cm.get_context() as ctx:
    ctx.packages.list()
    ctx.packages.add("pandas", "numpy>=1.26")
    ctx.packages.remove("old-pkg")

Code mode's single `install_packages()` method dispatched to
`InstallPackagesCommand`, which scans the kernel for all other missing
modules and re-runs affected cells on success. That's the right default
for auto-install on import error, but surprising when an agent is
explicitly asking to add one package.

These changes introduces a `ctx.packages` namespace with `add`,
`remove`, and `list`, installed into `marimo/_code_mode/_packages.py`.


`add` goes through a custom install loop that keeps the streaming
frontend notifications (queued → installing → installed/failed with
logs) but drops the missing-module scan and cell re-runs (installing
exactly what was asked, nothing more). `remove` and `list` are thin
wrappers over `PackageManager.uninstall` / `list_packages` and update
the script metadata for sandboxed notebooks the same way the HTTP
endpoints do.

Mutations are queued and flushed on context exit before cell ops, so
newly installed packages are importable from cells added in the same
batch. `list` returns the current environment state and raises if `add`
or `remove` have been queued. The alternative (stale data or silently
overlaying pending ops) is worse than a hard error.

    async with cm.get_context() as ctx:
        ctx.packages.list()
        ctx.packages.add("pandas", "numpy>=1.26")
        ctx.packages.remove("old-pkg")
Copilot AI review requested due to automatic review settings April 16, 2026 18:55
@manzt manzt added the enhancement New feature or request label Apr 16, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Apr 16, 2026 8:20pm

Request Review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces an explicit ctx.packages namespace in code mode to manage Python packages in a queued/atomic way, avoiding the surprising “scan for other missing modules + rerun cells” behavior when a caller asks to install a specific package.

Changes:

  • Added marimo/_code_mode/_packages.py implementing queued add, remove, and list operations with streaming install notifications and optional script-metadata updates.
  • Integrated package-op flushing into AsyncCodeModeContext.__aexit__ (flushed before cell operations) and added AsyncCodeModeContext.packages property.
  • Updated code-mode context tests to cover ctx.packages behavior (queueing, flushing, list semantics, summary output, etc.).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
tests/_code_mode/test_context.py Replaces install_packages() tests with comprehensive coverage for ctx.packages.{add,remove,list}.
marimo/_code_mode/_packages.py New implementation of the queued package-ops API with notifications + script-metadata updates.
marimo/_code_mode/_context.py Wires Packages into code-mode context lifecycle and summary output; removes install_packages().

ctx.packages.remove("old-pkg")
"""
return self._packages

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

install_packages() was removed from AsyncCodeModeContext, but the repo still references it (e.g. scratchpad import-error hint + its test expect ctx.install_packages). This will break those call sites and likely fail the existing test suite. Consider keeping install_packages() as a backwards-compatible alias that delegates to ctx.packages.add(...) (possibly deprecated), or update all remaining references in the same PR.

Suggested change
def install_packages(self, *packages: str) -> None:
"""Backwards-compatible alias for ``ctx.packages.add(...)``.
This preserves older internal call sites that still use
``ctx.install_packages(...)`` after package management moved to
the ``packages`` accessor.
"""
self.packages.add(*packages)

Copilot uses AI. Check for mistakes.
Comment on lines +653 to +654

async def test_remove_single(self, k: Kernel) -> None:
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_add_queued_before_cell_ops only asserts that install was called, not that it happened before the queued cell operations were applied. To actually verify the ordering guarantee, consider tracking both the package install and the kernel cell-execution (e.g., patch the kernel run/execute path) and assert the relative call sequence.

Copilot uses AI. Check for mistakes.
Comment on lines +152 to +155

ops = self._ops
self._ops = []

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _flush() docstring says it "Returns the ops that ran", but the method can return ops that were never executed (e.g., when there’s no package manager or it isn’t installed). Either adjust the docstring to reflect "ops that were queued/attempted" or change the return value to only include successfully executed ops.

Copilot uses AI. Check for mistakes.
Comment on lines +162 to +166
return ops

source: Literal["kernel", "server"] = "kernel"
statuses: PackageStatusType = {}
for op in ops:
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When package_manager is None or the manager binary is missing, _flush() returns ops even though nothing was executed. Since AsyncCodeModeContext uses this return value for the printed summary, this can result in misleading "installed/uninstalled ..." output. Consider returning an empty list here (or returning a separate "attempted" list) so summaries reflect what actually happened.

Copilot uses AI. Check for mistakes.
manzt added a commit to marimo-team/marimo-pair that referenced this pull request Apr 16, 2026
Pending on marimo-team/marimo#9233

The code mode API for package installation changed from a single
`ctx.install_packages()` method to a `ctx.packages` namespace, with
`add()` as the install entry point. This brings the docs in line with
the current API so examples actually run, and leaves room for related
package operations (remove, list) to live under the same namespace.

`ctx.install_packages()` still will work (but with deprecation notice).
manzt added a commit to marimo-team/marimo-pair that referenced this pull request Apr 16, 2026
Pending on marimo-team/marimo#9233

The code mode API for package installation changed from a single
`ctx.install_packages()` method to a `ctx.packages` namespace, with
`add()` as the install entry point. This brings the docs in line with
the current API so examples actually run, and leaves room for related
package operations (remove, list) to live under the same namespace.

`ctx.install_packages()` still will work (but with deprecation notice).
The previous commit replaced `ctx.install_packages()` with
`ctx.packages.add()`, but existing skills and example snippets still
reach for the old name. Rather than churn those, this adds a
`__getattr__` shim on `AsyncCodeModeContext` that transparently forwards
`install_packages` to `packages.add`.

`__getattr__` only fires when normal attribute lookup fails, so the name
doesn't show up in `dir()` or IDE completion — the new `ctx.packages`
namespace remains the discoverable API surface while the legacy call
path keeps working silently. Easy to delete once all callers migrate.
# API. Kept as a hidden shim for in-flight skills / examples;
# does not appear in dir() or IDE completion. Prefer
# `ctx.packages.add(...)` in new code.
if name == "install_packages":
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctx.install_packages is referenced in the skill, so we should probably keep around for a bit: marimo-team/marimo-pair#36

Could use as a hook/nudge to prompt the user to upgrade the skill.

return result


class Packages:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably worth adding the help class here

@mscolnick mscolnick merged commit 9798c58 into main Apr 17, 2026
33 of 61 checks passed
@mscolnick mscolnick deleted the push-qrvxrmqploro branch April 17, 2026 13:32
@github-actions
Copy link
Copy Markdown

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.2-dev47

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants