Skip to content

Conversation

@MaWeffm
Copy link

@MaWeffm MaWeffm commented Oct 29, 2025

📝 Summary

This PR adds read-only and reactive exposure of parent variables to embedded children notebooks via app.embed(). The goal was to improve modularity and enable bi-directional communication of variables between parent notebooks and embedded children. This topic has been discussed in #5092 and #6918. I am not a professional software developer and this PR has been implemented with the help of ChatGPT5. I could not find any community rules against this but understand potential reservations. If this PR is not acceptable, I hope that I at least triggers a discussion about parent->child exposure of variables.

This implementation could likely be improved to add some syntactic sugar to simplify usage of this feature. I'd also appreciate constructive feedback on the implementation and this PR, thanks!

🔍 Description of Changes

This PR entails larger changes and extends App.embed() to accept three additional variables expose, namespace, and readonly. In notebook mode, the exposures are registered with the child runner before the first run. In script mode, a one-shot namespace is injected into globals without reactivity. InternalApp is extended to be able to schedule child updates and minimal reruns.

/_runtime/app/kernel_runner.py was extended to keep a registry of exposures for each runner by installing a read-only namespace object in the child kernel's globals.

/_runtime/runner/hooks_post_execution.py was extended by adding a post-execution hook that pushes updated parent defs into children and schedules minimal re-runs of those child cells that reference the namespace.

Examples were added to /examples/reactive_embedding/. See screenshots of code of a parent app and the two child apps it embeds below, and a video of the parent notebook in action further down:

child_1.py:
Screenshot from 2025-10-29 21-54-30

child_2.py
Screenshot from 2025-10-29 21-53-42

parent.py
Screenshot from 2025-10-29 21-55-07

See the parent notebook in action below, the children notebooks run stand-alone, too:

Screencast.from.2025-10-29.21-41-31.webm

📋 Checklist

  • [x ] I have read the contributor guidelines.
  • [ x] For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • [ x] I have added tests for the changes made.
  • [ x] I have run the code and verified that it works as expected.

I have read the CLA Document and I hereby sign the CLA.

@vercel
Copy link

vercel bot commented Oct 29, 2025

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

Project Deployment Preview Comments Updated (UTC)
marimo-docs Ready Ready Preview Comment Nov 14, 2025 7:57am

@github-actions
Copy link

github-actions bot commented Oct 29, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@MaWeffm
Copy link
Author

MaWeffm commented Oct 29, 2025

I have read the CLA Document and I hereby sign the CLA

@MaWeffm
Copy link
Author

MaWeffm commented Oct 29, 2025

recheck

@mscolnick
Copy link
Contributor

Hey @MaWeffm - this is something we are interested in exploring for sure, but we haven't landed on the API / feature-set for this.

Our team can slot in some time this week to discuss how we want to prioritize this and what the solution should look like.

@MaWeffm
Copy link
Author

MaWeffm commented Nov 3, 2025

Sounds fantastic, @mscolnick! Thank you for considering this!

Copy link
Collaborator

@dmadisetti dmadisetti left a comment

Choose a reason for hiding this comment

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

Super interesting. I think we might need something a bit more scaled down, but maybe we can build a widget class?

Also just my opinion ! Interest to see what the rest of the team things

return self._kernel.globals

# Simple read-only proxy that can be mutated behind the scenes.
class _ReadOnlyNamespace:
Copy link
Collaborator

Choose a reason for hiding this comment

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

dataclass(frozen=True)

Comment on lines +791 to +795
- If `namespace=None`, exposed names are injected flat into child globals. This
is advanced, may be shadowed by child definitions, and should be avoided
unless that behavior is desired.
- In script mode, exposure is a one-time snapshot without reactivity. The namespace
is still read-only to prevent accidental mutation.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think namespace scoping and read-only add potentially unneeded complexity. This logic could be downstreamed to mowidgets, and once a stable api we can upstream it

Comment on lines +787 to +790
- If running in a notebook, `expose` installs a **read-only** namespace that
is called `parent` by default inside the child kernel. The child must make a
**static reference** to that name (e.g., `parent` or `from parent import ...`)
for the analyzer to mark dependencies and enable targeted re-runs.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thoughts on matching api with run? run has defs, I wonder if exposure works just by using state.

Exposure on a widget level does make sense though

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants