Examples of Python-based JupyterLab notebooks using the Lumino widgets

Lumino has a very interesting typescript-based example of an IDE-like UI:

https://lumino.readthedocs.io/en/latest/examples/dockpanel/index.html

Currently, the Lumino example shows only the frontend Typescript code, e.g.:

function main(): void {
  commands.addCommand('example:cut', {
    label: 'Cut',
    mnemonic: 1,
    iconClass: 'fa fa-cut',
    execute: () => {
      console.log('Cut');
    }
  });

How would we define a Python notebook to handle the command callbacks from the UI?

Two packages I know that expose deeper parts of the lumino/jupyterlab stack to kernels:

  • ipylab (example)
    • offers commands, sidebars
  • wxyz-lab, part of the sprawling wxyz (example, disclaimer: author)
    • offers dockpanel, main area widget, codemirror, marked, etc.

Both use the ipywidgets bus to handle bidirectional communication, and the frontend assets could theoretically be re-implemented for other kernels and re-use the frontends.

1 Like

Thanks for the prompt feedback @bollwyvl !

Before jumping in one of the approaches listed in the wxyz-lab doc, I would like to find a way to do an apples-to-apples comparison; for example:

  1. How do the widgets fit in the JupyterLab UI and what are the dependencies, if any, on JupyterLab extensions?

    I like that the ipylab examples have an explicit JupyterFrontEnd class, though it is unclear to me how this approach handles JupyterLab extensions.

    For wxyz-lab, it is unclear to me whether there is a corresponding mechanism as ipylab’s JupyterFrontEnd and, if not, whether it is needed at all for some reason.

  2. For a given frontend widget (e.g. Lumino or Lumino-based extension), how do we find what needs to be done on the Python side to use that widget and what options are available for customizing its behavior?

  3. Related to that question is clarifying the relationship between the JupyterLab Ui widgets (i.e Lumino) and other widgets (e.g. ipywidgets)

    In the wxyz-lab examples, I see several references to the ipywidgets whereas in the source I see references to Lumino widgets. I confess that I am a bit confused about this: are they two different libraries of UI widgets or is there some kind of dependency between them?

  4. If we need to do some debugging (e.g. like opening the developer view in a browser), is there a way to trace the UI-side JS calls to the kernel-side Python callbacks?

  5. What do we need to do to handle frontend/backend synchronization? e.g., there could be two different UI buttons, one for incrementing a counter, one for decrementing it. How do we avoid race conditions in the callbacks to the Python code and in the rendering of the counter state in the UI?

  6. For simplifying onboarding with new developers unfamiliar with this ecosystem, are there examples showing how individual widgets work (frontend/backend) where it is clear what belongs to the frontend vs. backend?

apples-to-apples

they complement each other, more than anything, and have similar approaches:

  • wxyz.lab.DockPanel and wxyz.lab.DockPop are “abuses” of the customized lumino widgets lab uses.
  • ipylab wraps the CommandRegistry hanging off a FrontEnd

They put these things on the evented widgets bus, backed by kernel comms: lumino has no prescribed common data model that one would sync (though wxyz.datagrid.StyleGrid is a wrapper around lumino/datagrid which does have a model).

a given frontend widget

Yeah… you go read the source of the core, extensions, and API docs.

ipywidgets whereas in the source I see references to Lumino widgets

Yes. Jupyter Widgets antedate lumino by a half decade, and use a backbone model and view system, and historically used a lot of jquery.

As of some point, all the core @jupyter-widgets/controls are implemented in JupyterLab as lumino widgets, which makes… exactly nothing clearer.

do some debugging

  • jupyterlab-kernelspy will help
  • using a new-enough ipykernel will let you throw breakpoints inside declared callbacks
    • using even newer lab and ipykernel will let you navigate files more generally

handle frontend/backend synchronization

This is pretty much the point of the widgets model system: direct manipulation (of, say, an HTML5 number widget or slider) would immediately change the frotnend, then propagate the value to the backend. backend observer code could then react to it.

there actually aren’t incrementer primitives in the core jupyter widget implementation… directly modeling transfer functions is actually one of the purposes of wxyz (though I never sat down and built the math stuff).

onboarding with new developers

1 Like

Thanks again; you’ve been very helpful!

Ah, this seems to me like an indication that there is still a fair amount of bleeding-edge churn to be expected before we can expect good documentation and examples.

Until then, we have to rely on the source as you pointed out, and a good IDE to help understand it.

It will take me a while to digest all of the above.