-
Notifications
You must be signed in to change notification settings - Fork 34.7k
Description
In the initial prototype of renderers, we said that kernels would expose an interface in their preloads, and if a renderer loads in and sees that the expected interface is missing, it would be responsible for showing appropriate help to the user. However, this is not a polished experience for a variety of reasons.
In an ideal world both kernel-providing extensions and renderers statically define their compatibility "tags", but Jupyter kernels can be discovered and changed dynamically, so this is not possible. My plan is that:
- Kernels can expose well-known "tags" at runtime in VS Code (or aznb)
- Renderers statically define required or optional tags in their package.json.
This means that when we render an output, we can determine what and whether any installed renderers are compatible. With a marketplace integration that would let us search by tags, we also can suggest renderers that could be useful for the output. This is particularly important if the execution produces a mime type for which there is no existing renderer.
Currently kernels have a list of preload
URIs, but these preloads also define the API(s) that the kernel provides. I suggest introducing a new NotebookKernelPreload
interface that would be used instead:
export interface NotebookKernelPreload {
provides: string | string[];
uri: Uri;
}
export interface NotebookKernel {
- preloads?: Uri[];
+ preloads?: NotebookKernelPreload[];
Then in package.jsons, renders could define a list of dependencies
or optionalDependencies
.
"notebookOutputRenderer": [
{
"id": "github-issues",
"displayName": "Github Issues Notebook Renderer",
"entrypoint": "./dist/renderer.js",
"mimeTypes": [
"x-application/github-issues"
],
"dependencies": [
"gh-issue-kernel"
]
}
],
Dependencies is a "one of" list -- the renderer will be considered compatible if at least one of the requested dependencies is provided by the kernel. optionalDependencies
can be used to hint at compatibility or kernels that can allow for better integration, but aren't required. When picking a renderer to use for some new output, VS Code will prefer renderers that have an available kernel in their dependencies over those which do not.
To be discussed: Do we need to 'pattern match' dependencies, e.g. could I optionally depend on any "jupyter dap" kernel with jupyter/*/dap
versus specifically jupyter/python/dap
.
Followup: we decided to not implement this initially. It can be easily added later, and we feel we can make a more informed decision once an ecosystem of renderers and kernels begins to develop.
Updated from discussion: To choose a renderer for an output, VS Code will assume 'richer-is-better' and prefer:
- For each mime type in the output, choose:
- return renderer with a hard dependency on an available kernel, otherwise
- return renderer with an optional dependency on an available kernel, otherwise
- return any other renderer for this mimetype.
- If no suitable renderer is found, show a 'fallback' for the first mime type. VS Code will suggest searching in the marketplace for an output renderer, and provide a button to do so.
When opening a new notebook with existing output, VS Code will choose the best available renderer assuming that whatever kernel dependency it needs will eventually be available. Therefore, renderers must be able to deal with a kernel loading in after the first render.
If a cell is executed and its output renderer is no longer compatible with the current kernel, the selection algorithm runs again.