Async programmatic control of a running marimo notebook. Use as an async context manager — mutations are queued during the block and applied atomically on exit:: async with cm.get_context() as ctx: ctx.create_cell("x = 1") ctx.edit_cell("my_cell", code="x =
| 675 | |
| 676 | @helpable |
| 677 | class AsyncCodeModeContext: |
| 678 | """Async programmatic control of a running marimo notebook. |
| 679 | |
| 680 | Use as an async context manager — mutations are queued during the |
| 681 | block and applied atomically on exit:: |
| 682 | |
| 683 | async with cm.get_context() as ctx: |
| 684 | ctx.create_cell("x = 1") |
| 685 | ctx.edit_cell("my_cell", code="x = 42") |
| 686 | ctx.delete_cell("old_cell") |
| 687 | |
| 688 | Read cells via `ctx.cells[key]` where *key* is an integer index, |
| 689 | cell ID string, or cell name. |
| 690 | """ |
| 691 | |
| 692 | def __init__( |
| 693 | self, |
| 694 | kernel: Kernel, |
| 695 | cell_manager: CellManager | None = None, |
| 696 | *, |
| 697 | skip_validation: bool = False, |
| 698 | skip_staleness_check: bool = False, |
| 699 | ) -> None: |
| 700 | from marimo._messaging.notebook.document import get_current_document |
| 701 | |
| 702 | document = get_current_document() |
| 703 | if document is None: |
| 704 | raise RuntimeError( |
| 705 | "NotebookDocument not available — code_mode must be invoked " |
| 706 | "via the /api/execute endpoint which sets the document " |
| 707 | "context variable" |
| 708 | ) |
| 709 | self._kernel = kernel |
| 710 | self._document = document |
| 711 | # Output snapshot is optional — callers that don't pass one |
| 712 | # (e.g. the MCP code server) get ``cell.output is None`` and |
| 713 | # ``cell.console_outputs == []`` for every cell, same as cells |
| 714 | # that genuinely produced no output. |
| 715 | self._outputs: CellOutputs | None = get_current_outputs() |
| 716 | self._cell_manager = cell_manager |
| 717 | self._skip_validation = skip_validation |
| 718 | self._skip_staleness_check = skip_staleness_check |
| 719 | self._ops: list[_Op] = [] |
| 720 | # Track cell IDs added during this batch so subsequent ops |
| 721 | # can reference them before they exist in the graph. |
| 722 | self._pending_adds: dict[CellId_t, _AddOp] = {} |
| 723 | # ID generator for new cells — seed=None uses OS entropy so we |
| 724 | # never replay a prior session's ID sequence. seen_ids from the |
| 725 | # document prevents collisions with cells already on disk. |
| 726 | self._id_generator = CellIdGenerator(seed=None) |
| 727 | self._id_generator.seen_ids = set(document.cell_ids) |
| 728 | self._packages = Packages(self) |
| 729 | self._ui_updates: list[tuple[UIElementId, Any]] = [] |
| 730 | self._cells_to_run: set[CellId_t] = set() |
| 731 | self._entered = False |
| 732 | self._screenshot_session: _ScreenshotSession | None = None |
| 733 | |
| 734 | def _require_entered(self) -> None: |
no outgoing calls
searching dependent graphs…