jupyterlab / extension-examples

JupyterLab Extensions by Examples

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Extension that executes shell or python code

luis-chaves-visa opened this issue · comments

Problem

I'd like to create an extension that runs some shell or python code. From what I've been able to find (mainly this: https://github.com/enlznep/jupyterlab-shell-file/blob/master/src/index.ts) and a failed attempt at using child_process or zx from the src/index.ts file I have not managed to execute any shell code from an extension. I am trying to replicate the toolbar button example but executing some shell code (could be python too - but ideally shell) when the button is clicked

Proposed Solution

I have also tried adding the following (to no success):

const { exec } = require("child_process");

exec("ls -la", (error, stdout, stderr) => {
    if (error) {
        console.log(`error: ${error.message}`);
        return;
    }
    if (stderr) {
        console.log(`stderr: ${stderr}`);
        return;
    }
    console.log(`stdout: ${stdout}`);
});

Any help is appreciated, also I'd love to see an example of this feature if it's possible at all

Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! 🤗

If you haven't done so already, check out Jupyter's Code of Conduct. Also, please try to follow the issue template as it helps other other community members to contribute more effectively.
welcome
You can meet the other Jovyans by joining our Discourse forum. There is also an intro thread there where you can stop by and say Hi! 👋

Welcome to the Jupyter community! 🎉

require("child_process");

Keep in mind that you're extension code is running in the browser, so child_process is not available.

I'd suggest two approaches:

  1. If you want to run code on the server, create a server extension that exposes a Rest API, and a JupyterLab extension that communicates with that server extension over the Rest API to do the execution you want. See https://github.com/jupyterlab/extension-examples/tree/master/server-extension for an example.
  2. If you want to run code in the kernel, you'll need access to the kernel associated with some document. Here is an example of executing code in a kernel: https://github.com/jupyterlab/extension-examples/tree/master/kernel-messaging, and here is another example: https://github.com/jupyterlab/extension-examples/tree/master/kernel-output
    If you are tying this to an existing document, you can get the document's session context and then get the kernel from that.

I would also need to execute a shell command from a Jupyterlab extension. Unfortunately, I'm not sure to understand at which level it should be executed. The command I want to execute looks like that (see https://discourse.jupyter.org/t/jupyterlab-extension-to-add-a-button-to-save-the-notebook-and-launch-a-command/14844/2 for some context)

jupyter-nbconvert pres.ipynb \
    --to slides --no-input --SlidesExporter.reveal_scroll=True \
    --SlidesExporter.reveal_number=c/t \
  && sed -i 's$<meta charset="utf-8" />$<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />$g' pres.slides.html

So it uses the notebook file (here pres.ipnb) and should produce/update a .html file next to it.

I'm quite confuse with the overall organization of Jupyterlab and I'm not quite sure on which side the .ipynb file is saved. (Usually, for me, the server and client applications run on the same computer.)

I tend to think that the ipynb file is physically on the server side and so that I should run the command in the server extension (in python, approach 1 of your answer @jasongrout). This message is just to ask for a confirmation that I'm going in the right direction?

Sorry for this very naive question.

Where possible, you'll want to use existing jupyterlab_server or jupyter_server REST API endpoints. These cover a lot of cases... indeed everything you see in JupyterLab!

To get really custom behavior, you'd extend the REST API with a python serverextension, and you can distribute both the static assets of the labextension and the handler in the same pip-installable package.

Of note: when the things you are calling are possible to be called directly from python, it can be useful to call them there, as you don't have to worry as much about cross-platform concerns. nbconvert is such an example... but doesn't have an asynchronous API. However, any time your code "blocks", e.g. with subrocess.check_output it will block the whole system, and no other server methods will fire. For a while now, we've had anyio at our disposal, which has good support for cross-platform, async processes .

Hey @bollwyvl and @jasongrout, thanks for your replies!

After some digging I've gone down the server extension way. I still have some issues though, regarding how to get the current notebook path as @paugier is asking in #203. I'll write another issue for clarity