Skip to content

Enable embedded Jupyter kernel for live access to ImSwitch managers/variables #155

@openuc2-gmbh

Description

@openuc2-gmbh

Description:
It would be extremely useful to have a running Jupyter kernel inside ImSwitch so that we can inspect and interact with the current application context (e.g. managers, controllers, global variables) directly from a notebook/console while the app is running outside from ImSwitchClient via REST. Direct hardware access and processing abilites would be great to have!

This would allow:

  • Debugging of live experiments by checking the state of managers
  • Calling functions directly (e.g. stage moves, camera acquisition)
  • Prototyping new analysis code without restarting the full app

Proposed approach:

  • Use ipykernel.embed.embed_kernel or IPKernelApp to start an in-process Jupyter kernel.
  • Inject globals() (and importantly the moduleMainControllers, managers, etc.) into the kernel’s namespace so they are directly accessible.
  • Because embed_kernel() is blocking, this needs to run in its own thread. Otherwise it conflicts with the main Qt loop (GUI mode) or the while True loop (headless mode).

Code sketch (inside applaunch.py):

import threading
try:
    from ipykernel.embed import embed_kernel
except ImportError:
    embed_kernel = None

def start_embedded_kernel(ns):
    if embed_kernel is not None:
        embed_kernel(local_ns=ns)

def launchApp(app, mainView, moduleMainControllers):
    # ... existing code ...
    
    # Start Jupyter kernel in background
    ns = globals().copy()
    ns.update({
        "moduleMainControllers": moduleMainControllers,
        # optionally inject managers here if available
    })
    threading.Thread(target=start_embedded_kernel, args=(ns,), daemon=True).start()
    
    if IS_HEADLESS:
        while True:
            emit_queued()
            # ... existing disk check logic ...
    else:
        if mainView is not None:
            mainView.showMaximized()
            mainView.show()
        exitCode = app.exec_()

Open questions:

  • Where is the best injection point? launchApp seems natural, but maybe after moduleMainControllers is fully initialized.
  • Should we expose only high-level managers (StageManager, LaserManager, etc.) or all globals?
  • Security: embedding a kernel means anyone with access can execute arbitrary Python. Should we guard this behind a config flag?
  • In headless mode, do we want the kernel loop to replace the infinite while True, or run alongside it?

Next steps:

  • Add a config option (--with-kernel?) to enable/disable this feature.
  • Verify it works both in GUI and headless modes.
  • Document how to connect (jupyter console --existing or select kernel in JupyterLab).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions