notebook icon indicating copy to clipboard operation
notebook copied to clipboard

JN 7 execute, get notebook name, save from within a notebook

Open liquidcarbon opened this issue 1 year ago • 5 comments
trafficstars

Problem

Hello, I used to run the following in notebook 6.5:

class NotebookRunner:
    """Helper class for rendering the notebook to HTML using Quarto.
    
    This only works in the context of a Jupyter notebook.
    
    Usage
    -----
    # place in a cell, launch with Shift+Enter
    # all cells below will be executed automatically
    # if no errors, the notebooks will be saved and publish will happen
    nr = NotebookPublisher()  # retrieves notebook name from browser and passes the value python variable
   
    """
    
    JS = """
    Jupyter.notebook.kernel.execute(
        "NB_NAME = " + "\'" + window.document.getElementById("notebook_name").innerHTML + "\'"
    );
    function runCellsBelow() {
        var cells = Jupyter.notebook.get_cells();
        for (var i = Jupyter.notebook.get_selected_index(); i < cells.length; i++) {
            if (cells[i].cell_type === 'code') {
                Jupyter.notebook.execute_cell_range(i, i + 1);
            }
        }
    }
    runCellsBelow();
    """
    
    def __init__(self, run=True, **kwargs):
        """Checks that Quarto is available and saves the current notebook."""

        log.info(" ⬇ your notebook is running ⬇ ")
        if run: self.run(**kwargs)
        return
    
    def run(self, **kwargs):
        """Runs the current notebook."""
        
        from IPython.display import display, Javascript
        display(Javascript(self.JS))
        return

The running part worked well, the saving part never properly worked. But now I understand the Jupyter javascript global is gone, so I'm getting Javascript Error: Jupyter is not defined

How do I run and save from within a notebook? Ideally, my last cell is "publish" (via nbconvert or quarto) and the notebook is saved right before then. What's the proper way to do this now?

Additional context

https://github.com/jupyter/notebook/issues/7225 https://github.com/jupyter/notebook/issues/6949 https://github.com/jupyter/notebook/issues/6394

liquidcarbon avatar Mar 11 '24 14:03 liquidcarbon

Thank you for opening this issue @liquidcarbon, as mentioned in the issues you have linked to. Have you tried the suggestions in https://github.com/jupyter/notebook/issues/6949#issuecomment-1605864571?

RRosio avatar Mar 12 '24 16:03 RRosio

Hi, thanks for your response! It's not completely clear how to proceed based on this comment. Hope I don't have to develop a whole extension for this!

Or is it as simple as replacing Jupyter.notebook with window.jupyterapp?

liquidcarbon avatar Mar 12 '24 17:03 liquidcarbon

No problem @liquidcarbon! You will likely need to add more than just the window.jupyterapp for most of the functionality. For something like saving a notebook it is window.jupyterapp.commands.execute('docmanager:save') that does the trick. All commands can be found in this page of the documentation! For some of the functions referenced in the code snippet I couldn't find direct replacements but I could have missed something.

RRosio avatar Mar 12 '24 22:03 RRosio

Thanks @RRosio !

This works when you start jupyter-lab with --expose-app-in-browser flag

Javascript("""
let app = window.jupyterapp;
// app.commands.execute('notebook:run-all-cells')
// app.commands.execute('notebook:run-cell-and-select-next')
app.commands.execute('docmanager:save')
""")

But I'm still unclear how to get the name of the running notebook. This logs the page title to the console.

%%javascript
let notebook_name = window.document.querySelector('title').textContent;
console.log(notebook_name);

But you can't seem to be able to move variables easily between python and JS like you could in old JN.

Here's one option via ipylab: https://github.com/jupyterlab/jupyterlab/issues/13020#issuecomment-1232909058

Appreciate any pointers!

liquidcarbon avatar Mar 13 '24 00:03 liquidcarbon

Answered in https://github.com/jtpio/ipylab/discussions/139

import os
os.environ.get('JPY_SESSION_NAME')

liquidcarbon avatar May 20 '24 14:05 liquidcarbon