Hello all, first time posting here. I’m working on creating a JupyterLab extension that will eventually let users test the power usage of their code, and the first step is to create a button that downloads the contents of a Notebook as an executable script.
This can already be done through File > Export Notebook As… > Executable Script or through the Command Palette with Export Notebook: Executable Script, so I suspect it should be fairly straightforward. I’m having trouble getting this command to run from my index.ts file however; any help would be very much appreciated. I believe my main problem is not knowing how to pass the right argument to notebook:export-to-format but I may be doing something else wrong as well.
Welcome! Do you have any compilation errors, or is it working but not doing what you would expect?
The is fragment looks odd to me:
I think that you should pass app object with an instance rather than creation the a new JupyterLab instance (and besides it would be missing parentheses). But I guess it might be just a copy-paste error.
Thanks for the reply! Yes, it compiles ok, but when I press the button nothing happens except for the dummy alert. I did initially try new ButtonExtension(app) there but got “error TS2345: Argument of type ‘JupyterFrontEnd<IShell, “desktop” | “mobile”>’ is not assignable to parameter of type ‘JupyterLab’.
Type ‘JupyterFrontEnd<IShell, “desktop” | “mobile”>’ is missing the following properties from type ‘JupyterLab’: registerPluginErrors, status, info, paths, and 4 more.”
Then I tried ButtonExtension(JupyterLab) which gave me “error TS2345: Argument of type ‘typeof JupyterLab’ is not assignable to parameter of type ‘JupyterLab’.
Type ‘typeof JupyterLab’ is missing the following properties from type ‘JupyterLab’: namespace, registerPluginErrors, restored, status, and 38 more.” The same error message suggested to add “new” so that’s what I did and it fixed the compilation error.
Passing app is the correct way - it does not work because you are creating a custom instance of the application which does not connect to the existing instance. Just update your constructor to use the more general type this is JupyterFrontEnd (JupyterLab is a subclass of JupyterFrontEnd)
Ah I see–yes, the code compiles fine with those changes. That may have been part of the problem. The button still doesn’t download the executable script the way I’d like it to though. I suspect it’s something to do with how I’m passing the argument to commands.execute, since I can replace formatLabel and 'script' with any gibberish I want and the code still compiles.
You are right - the command arguments to execute can be basically any reasonable JSON. Looking at the code of the notebook:export-to-format command, I think that you should use format rather than formatLabel to export the currently active notebook:
The getCurrent function called there also looks at activate argument (which I think should be set to true in your case but I may be wrong).
Follow-up question on this–is there a way to have the .py file go to the same folder in JupyterLab as the notebook that’s being converted rather than the user’s Downloads folder?
It is certainly possible by creating a server-side extension that would instruct nbconvert to output the file there. Have a look at cookiecutter linked from extension tutorial - it should have a stub for creating a server extension.
Maybe instead of doing the server extension you could just send a request to the url and use JupyterLab APIs to open a new file and then to save the context from that (nbconvert output) url into it? Pseudocode below:
As for openNewFileAndWriteToItWithJupterLabAPI it could either use the “upload” method of FileBrowser, or just create a new blank file, open it with text editor, write to it and close it quickly. It might be possible to do so without opening the file in the UI.