Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notebook API Support #12442

Merged
merged 94 commits into from
Aug 31, 2023
Merged

Notebook API Support #12442

merged 94 commits into from
Aug 31, 2023

Conversation

jonah-iden
Copy link
Contributor

@jonah-iden jonah-iden commented Apr 21, 2023

What it does

Closes #8395.
Future Improvements: #12863.

This implements the basics of the notebook api for theia. This includes following features:

  • opening notebooks in a custom editor widget
  • editing and saving of notebooks through the new widget
  • executing cells and notebooks and displaying cell outputs through renderers contributed by extensions
  • general starting and comunicating with notebook extensions like jupyter

Also this PR includes some prepared functionality not in use yet but needed for implementations later on.

To keep the size of the PR on the smaller size (it's already gigantic as it is), some less important notebook features haven't been implemented yet. Don't expect everything to work perfectly as expected
see #12442 (comment) for information on known issues and missing features.

How to test

Basic Notebook support is given through the builtin ipynb extension. So execute yarn download:plugins once in the project root.
For Cell execution the python and juypter extensions are needed.

Make sure that the workspace you're using for testing is trusted or you have disabled the workspace trust feature. Otherwise, some features, such as notebook kernel selection might not work as expected.

Also here is a notebook for testing W39Mon_Lecture8_DemoNotebook.zip

Review checklist

Reminder for reviewers

@msujew msujew added notebook issues related to notebooks vscode issues related to VSCode compatibility labels Apr 21, 2023
@vince-fugnitto
Copy link
Member

@jonah-iden do you mind resolving the conflicts so we can continue with a review?

@vince-fugnitto vince-fugnitto modified the milestone: 1.37.0 Apr 27, 2023
@jonah-iden jonah-iden force-pushed the msujew/notebooks branch 2 times, most recently from ece1f44 to b0089c9 Compare May 2, 2023 07:00
@tsmaeder
Copy link
Contributor

tsmaeder commented May 8, 2023

@jonah-iden since I was on vacation when this was discussed in the dev call: what's the story with this PR? Are you looking to merge this code or just looking for feedback? What's the plan for the missing pieces like renderers?

@jonah-iden
Copy link
Contributor Author

jonah-iden commented May 8, 2023

Hi @tsmaeder , to be honest i'm not sure if it was ever discussed how exactly to proceed with this regarding merging. I disabled most of the stuff through a hardcoded feature flag, so i guess merging would definitely be a good possiblity. The Idea was mostly to start working on this feature to raise interest and maybe secure more financing to actually finish it, or get other parties involved who would like to contribute to this feature. I will continue working on it on my open source time, but that probably won't be a lot.

@tsmaeder
Copy link
Contributor

tsmaeder commented May 8, 2023

@jonah-iden Thanks for the clarification.

Copy link
Contributor

@tsmaeder tsmaeder left a comment

Choose a reason for hiding this comment

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

Hi @jonah-iden. It's awesome to see notebooks finally coming to Theia. I did a first pass over the Code and most of the comments I have are about naming and code structure.

packages/core/src/common/types.ts Show resolved Hide resolved
packages/monaco/src/browser/monaco-editor-provider.ts Outdated Show resolved Hide resolved
export class NotebookCellActionContribution implements MenuContribution, CommandContribution {

protected runDeleteAction(notebookModel: NotebookModel, cell: NotebookCellModel): void {
notebookModel.removeCell(notebookModel.cells.indexOf(cell), 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not inline this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

because the DeleteAction will very likely become more complicated later on. Like having to inform the backend/plugin about the delete

}

protected requestCellEdit(notebookModel: NotebookModel, cell: NotebookCellModel): void {
cell.requestEdit();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not inline this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

same as for the DeleteAction

packages/plugin-ext/src/plugin/notebook/notebooks.ts Outdated Show resolved Hide resolved

// --- serialize/deserialize

private _handlePool = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not a pool: a pool is something you get entities from and return them to after use. Also, why is this a "handle" and not an "id"? My suggestion would be: "nextId".

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, my preference would be to use distinct id spaces for the different entities: I find it makes it easier to identify stuff when debugging or analyzing logs.

packages/plugin-ext/src/plugin/notebook/notebooks.ts Outdated Show resolved Hide resolved
packages/plugin-ext/src/plugin/notebook/notebooks.ts Outdated Show resolved Hide resolved
@@ -96,7 +96,9 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager {
'onFileSystem',
'onCustomEditor',
'onStartupFinished',
'onAuthenticationRequest'
'onAuthenticationRequest',
'onNotebook',
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we need to add something to plugin-activation-events.ts to make this work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah i have to take a look at that. I was kind of confused by the onNotebook and onNotebookSerializer events.

@tsmaeder
Copy link
Contributor

@jonah-iden is there a plan of what still needs to be done to consider the feature complete?

@jonah-iden
Copy link
Contributor Author

jonah-iden commented May 15, 2023

Hi, thanks a lot for your first pass. There currently is no list of things still needed for feature completion, but i can take some time tomorrow to create one

@tsmaeder
Copy link
Contributor

Testing with the ms jupyter extension gave the following exception, which I think is relevant:

2023-05-12T08:54:31.922Z root ERROR Warning: Each child in a list should have a unique "key" prop.

Check the render method of `NotebookCellListView`. See https://reactjs.org/link/warning-keys for more information.
    at NotebookCellListView (http://localhost:3000/packages_notebook_lib_browser_notebook-editor-widget_js-packages_notebook_lib_browser_noteboo-2c2e12.js:792:9)
    at div
2023-05-12T08:54:32.827Z root INFO [hosted-plugin: 101308] PLUGIN_HOST(101308): PluginManagerExtImpl/loadPlugin(/tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js)
2023-05-12T08:54:33.189Z root ERROR [hosted-plugin: 101308] extension activation failed TypeError: this.vscNotebook.onDidChangeNotebookCellExecutionState is not a function
    at new S (/tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:207218)
    at Object.t.resolveInstance (/tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:1297910)
    at /tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:1299848
    at /tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:1298766
    at Array.map (<anonymous>)
    at /tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:1298738
    at Array.map (<anonymous>)
    at Object.t.resolveInstance (/tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:1297684)
    at /tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:1299848
    at Object.t.resolve (/tmp/vscode-unpacked/ms-toolsai.jupyter-2022.10.110.vsix/extension/out/extension.node.js:17:1300111)

@jonah-iden
Copy link
Contributor Author

jonah-iden commented May 16, 2023

Regarding the list of things still needed for full feature completion, as it is in vscode, this is what i could think of right now.
I will update the list if i remember more

  1. Code cell execution
  2. Cell editing is missing alot.
    a. the context dependent toolbar. (has been started)
    b. adding new cells (has been started)
    c. drag and drop of cells
  3. General rendering improvements
    a. css fixes (there are some smaller issues here and there)
    b. use EditorWidget instead of the more heavyweight MonacoEditor created through createInline
    c. NotebookCellListView optimization, so only cells in the current viewport are rendered as real cells.
  4. The cell side toolbar
  5. Finish implementing plugin api methods
  6. Custom Notebook Renderes https://code.visualstudio.com/api/extension-guides/notebook#notebook-renderer

@tsmaeder
Copy link
Contributor

@jonah-iden what about custom cell renderers?

@jonah-iden
Copy link
Contributor Author

right thats also a feature still missing. Added it to the list

@tsmaeder
Copy link
Contributor

@jonah-iden I was playing around with the Python notebooks extensions. For an MVP, that can run python notebooks, I would think we would need cell execution & custom renderers, right? My guesstimate is that this would take around a third of the effort already spent. Would you agree with this? MVP+ would be with decent editing support. Just trying to find out when we could have something we can present to users.

@jonah-iden
Copy link
Contributor Author

Im not totally sure we need the custom renderers for an MVP but yeah code execution and full Editing support would definitley be needed. I think the code execution could be quite complex so i would say that all 3 would easily need 5PD, if not a little bit more. I think mark estimated initially something like 25-30PD for full support of which we put in about 10. Though of course i have by far not nearly as much expreience as all the core theia team yet. So my 10PD is problably far less than someone with more expreience would have been able to do

@msujew
Copy link
Member

msujew commented May 22, 2023

@tsmaeder @jonah-iden Exactly, my initial estimate for the full feature was something along the lines of 25-30 PD, with 10 having been spent on this MVP. I can imagine execution support being implemented (with custom renderers) in roughly 5 days as well.

@jonah-iden
Copy link
Contributor Author

jonah-iden commented Jul 17, 2023

@tsmaeder, @JonasHelming
Hi, this last commit finishes the 2nd spike for Notebook api since we used up all the time.
I updated the How to test section since this now all works with jupyter and the builtin vscode.ipynb extension.
Getting cell execution working was alot more complicated than initially estimated so we sadly didn't get to implementing notebook-renderers. But the basic cell execution framework is there and execution of single cells is working.
This probably needs alot of more cleanup before being able to merge and there are still quite a few issues and bugs in it.
But we at Typefox likely allready secured more founding for countinuing development and i will continue working on this in my open source time.

@jonah-iden
Copy link
Contributor Author

Oh and a small general note for testing. There is currently a problem with the python extension. (see #12708 for more details).
So if anything does not work after some time try checking the {userdir}/.theia/plugin-storage/global-state.json ad delete it if it gets to large

@tsmaeder
Copy link
Contributor

@jonah-iden awesome, thanks. My hope is to get this merged as soon as possible, but it's a big one, and world+dog seems to be on vacation, so it might take a while.
After this one is merged, I would suggest that we open an epic with the remaining gaps so that willing parties can pick up tasks when they have capacity.

@msujew
Copy link
Member

msujew commented Aug 25, 2023

Thanks @vince-fugnitto for looking into it!

If we open the notebook, close and re-open we get a memory leak:

Right, there were in fact multiple memory leaks. Those should hopefully all be fixed now. At least I don't get any event listener warnings anymore when opening and closing the widget multiple times.

The latest commit should fix a lot of other smaller issues in general, such as cell document updates in the plugin host and how the cell execution output is handled in the widget (clearOutput requests from plugins weren't respected, leading to duplicated output).

auto-save does not seem to be respected by the notebook

Looking into this, I have a feeling our saving infrastructure is a bit antiquated. Every model is somehow in charge of managing the files.autoSave by itself, with varying results. See also #12844, #11646 and #9230. I would prefer to fix this in a separate PR. I've created #12863 to track this.

@vince-fugnitto
Copy link
Member

I've noticed a minor issue when testing, there seems to be a bogus toolbar item (000) which does nothing:

image

@msujew
Copy link
Member

msujew commented Aug 28, 2023

@vince-fugnitto Thanks for the heads-up, that seems to be a regression from my previous change. I've fixed it 👍

@tsmaeder
Copy link
Contributor

I'm currently in the middle of reading through the code.

await this.delegate?.save(options);
}

revert?(options?: Saveable.RevertOptions): Promise<void>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does the Saveable mechanism handle dynamically adding the function members? How would actions like "revert" get enabled when the saveable turns out to support them?

packages/core/src/common/array-utils.ts Show resolved Hide resolved
packages/core/src/browser/saveable.ts Show resolved Hide resolved
packages/core/src/browser/saveable.ts Show resolved Hide resolved
this.dirty = delegate.dirty;
this.onDirtyChangedEmitter.fire();
});
this.autoSave = delegate.autoSave;
Copy link
Contributor

Choose a reason for hiding this comment

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

How will users pick up that the autosave setting of the delegate has changed?


registerNotebookCellStatusBarItemProvider(notebookType: string, provider: theia.NotebookCellStatusBarItemProvider): theia.Disposable {

const handle = this.currentSerializerHandle++;
Copy link
Contributor

Choose a reason for hiding this comment

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

Either use different handle counters or rename currentSerializerHandle to somethind generic.


export class NotebooksExtImpl implements NotebooksExt {

private readonly notebookStatusBarItemProviders = new Map<number, theia.NotebookCellStatusBarItemProvider>();
Copy link
Contributor

Choose a reason for hiding this comment

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

notebookCellStatusBarItemProviders

const revivedUri = URI.fromComponents(uri);
const document = this.documents.get(revivedUri.toString());

if (document) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe warn if we're removing a non-existing document?

}
}

getNotebookDocument(uri: TheiaURI, relaxed: true): NotebookDocument | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

I haven't found a call site that uses the "relaxed" parameter. let's remove it.

return result;
}

private createExtHostEditor(document: NotebookDocument, editorId: string, data: NotebookEditorAddData): void {
Copy link
Contributor

Choose a reason for hiding this comment

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

createNotebookEditor.

@tsmaeder
Copy link
Contributor

@jonah-iden @msujew I've finished reading through the code. There are a couple of architectural issues, a bunch of functional ones, but many of the comments are just about naming.
Theia is 2m lines of code that a random person who has not yet started university will look at in five years. Using descriptive and consistent naming allows us to read and understand code we're not familiar with quickly and safely. Ideally, we should look at the name of a thing and correctly assume what it is or does without having to look at its implementation or usage. Bad naming in our code base has literally cost me weeks of time (wondering why nothing made sense), that's why I've become a bit of a stickler for naming.
@vince-fugnitto with the other stuff on my plate, I probably won't be able to do any meaningful testing before tomorrow. If you are reasonably convinced this PR will not break the world, can you give it your approval?
As we discussed in yesterday's community meeting, there will be follow-up work on this topic, but we want this in to allow adopters to exercise the feature.

@tsmaeder tsmaeder self-requested a review August 30, 2023 08:42
@tsmaeder tsmaeder dismissed their stale review August 30, 2023 08:48

We've decided to go ahead and address comments later

@msujew
Copy link
Member

msujew commented Aug 30, 2023

@vince-fugnitto Any chance to get an approval today or tomorrow?

@tsmaeder
Copy link
Contributor

When I install the python & jupyter extensions, the python extension seems to be activated even though I don't work with python files at all: in fact, I'm working on the Theia project itself.

2023-08-31T07:20:43.721Z root ERROR [hosted-plugin: 3092] Promise rejection not handled in one second: Error: Client is not running and can't be stopped. It's current state is: startFailed , reason: Error: Client is not running and can't be stopped. It's current state is: startFailed
2023-08-31T07:20:43.721Z root ERROR [hosted-plugin: 3092] With stack trace: Error: Client is not running and can't be stopped. It's current state is: startFailed
    at E.shutdown (c:\Users\thomas\AppData\Local\Temp\vscode-unpacked\ms-python.python-2023.14.0.vsix\extension\out\client\extension.js:2:2063715)
    at E.stop (c:\Users\thomas\AppData\Local\Temp\vscode-unpacked\ms-python.python-2023.14.0.vsix\extension\out\client\extension.js:2:2063296)
    at E.stop (c:\Users\thomas\AppData\Local\Temp\vscode-unpacked\ms-python.python-2023.14.0.vsix\extension\out\client\extension.js:2:2225576)
    at E.doInitialize (c:\Users\thomas\AppData\Local\Temp\vscode-unpacked\ms-python.python-2023.14.0.vsix\extension\out\client\extension.js:2:2063119)
    at async E.start (c:\Users\thomas\AppData\Local\Temp\vscode-unpacked\ms-python.python-2023.14.0.vsix\extension\out\client\extension.js:2:2059685)

@tsmaeder
Copy link
Contributor

tsmaeder commented Aug 31, 2023

I also get "python" and "python language server" channels in the "Output" widget. And error messages when starting up about not being able to start up the language server, etc.
@jonah-iden could you have a quick look at this?

@jonah-iden
Copy link
Contributor Author

sure i can take a look later today

@jonah-iden
Copy link
Contributor Author

@tsmaeder
The python extension being activated seems to be a general thing since it has an onDebugDynamicConfigurations activation event which in theia is currently allways being fired on startup. It seems to be fired from the DebugConfigurationSelect component when its mounted. If thats a problem we should probably create a sperate issue for that.
Regarding your error messages for the language server. I'm sadly not able to reproduce them. For me the python extension is working fine and i don't see any errors in the output widget

Copy link
Member

@vince-fugnitto vince-fugnitto left a comment

Choose a reason for hiding this comment

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

I'm fine with merging the pull-request even with improvements in #12863 and feedback from Thomas not being implemented for the release since it offers functionality that was previously missing in the framework, and is requested by interested parties 👍

I did not notice any regressions with content outside of notebook editors, and CI successfully passes.

@vince-fugnitto
Copy link
Member

vince-fugnitto commented Aug 31, 2023

@msujew @jonah-iden do you want to organize and preserve some commits, or do you want to squash into a single one?

@jonah-iden
Copy link
Contributor Author

I think squashing is fine. There should not be any important information in the single commits

@msujew msujew merged commit 97fe17e into eclipse-theia:master Aug 31, 2023
14 checks passed
@tsmaeder
Copy link
Contributor

🥳 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
notebook issues related to notebooks vscode issues related to VSCode compatibility
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[vscode] native notebook support
7 participants