How do I get the current IPython / Jupyter Notebook name

63,289

Solution 1

As already mentioned you probably aren't really supposed to be able to do this, but I did find a way. It's a flaming hack though so don't rely on this at all:

import json
import os
import urllib2
import IPython
from IPython.lib import kernel
connection_file_path = kernel.get_connection_file()
connection_file = os.path.basename(connection_file_path)
kernel_id = connection_file.split('-', 1)[1].split('.')[0]

# Updated answer with semi-solutions for both IPython 2.x and IPython < 2.x
if IPython.version_info[0] < 2:
    ## Not sure if it's even possible to get the port for the
    ## notebook app; so just using the default...
    notebooks = json.load(urllib2.urlopen('http://127.0.0.1:8888/notebooks'))
    for nb in notebooks:
        if nb['kernel_id'] == kernel_id:
            print nb['name']
            break
else:
    sessions = json.load(urllib2.urlopen('http://127.0.0.1:8888/api/sessions'))
    for sess in sessions:
        if sess['kernel']['id'] == kernel_id:
            print sess['notebook']['name']
            break

I updated my answer to include a solution that "works" in IPython 2.0 at least with a simple test. It probably isn't guaranteed to give the correct answer if there are multiple notebooks connected to the same kernel, etc.

Solution 2

adding to previous answers,

to get the notebook name run the following in a cell:

%%javascript
IPython.notebook.kernel.execute('nb_name = "' + IPython.notebook.notebook_name + '"')

this gets you the file name in nb_name

then to get the full path you may use the following in a separate cell:

import os
nb_full_path = os.path.join(os.getcwd(), nb_name)

Solution 3

I have the following which works with IPython 2.0. I observed that the name of the notebook is stored as the value of the attribute 'data-notebook-name' in the <body> tag of the page. Thus the idea is first to ask Javascript to retrieve the attribute --javascripts can be invoked from a codecell thanks to the %%javascript magic. Then it is possible to access to the Javascript variable through a call to the Python Kernel, with a command which sets a Python variable. Since this last variable is known from the kernel, it can be accessed in other cells as well.

%%javascript
var kernel = IPython.notebook.kernel;
var body = document.body,  
    attribs = body.attributes;
var command = "theNotebook = " + "'"+attribs['data-notebook-name'].value+"'";
kernel.execute(command);

From a Python code cell

print(theNotebook)

Out[ ]: HowToGetTheNameOfTheNoteBook.ipynb

A defect in this solution is that when one changes the title (name) of a notebook, then this name seems to not be updated immediately (there is probably some kind of cache) and it is necessary to reload the notebook to get access to the new name.

[Edit] On reflection, a more efficient solution is to look for the input field for notebook's name instead of the <body> tag. Looking into the source, it appears that this field has id "notebook_name". It is then possible to catch this value by a document.getElementById() and then follow the same approach as above. The code becomes, still using the javascript magic

%%javascript
var kernel = IPython.notebook.kernel;
var thename = window.document.getElementById("notebook_name").innerHTML;
var command = "theNotebook = " + "'"+thename+"'";
kernel.execute(command);

Then, from a ipython cell,

In [11]: print(theNotebook)
Out [11]: HowToGetTheNameOfTheNoteBookSolBis

Contrary to the first solution, modifications of notebook's name are updated immediately and there is no need to refresh the notebook.

Solution 4

It seems I cannot comment, so I have to post this as an answer.

The accepted solution by @iguananaut and the update by @mbdevpl appear not to be working with recent versions of the Notebook. I fixed it as shown below. I checked it on Python v3.6.1 + Notebook v5.0.0 and on Python v3.6.5 and Notebook v5.5.0.

import jupyterlab
if jupyterlab.__version__.split(".")[0] == "3":
    from jupyter_server import serverapp as app
    key_srv_directory = 'root_dir'
else : 
    from notebook import notebookapp as app
    key_srv_directory = 'notebook_dir'
import urllib
import json
import os
import ipykernel

def notebook_path(key_srv_directory, ):
    """Returns the absolute path of the Notebook or None if it cannot be determined
    NOTE: works only when the security is token-based or there is also no password
    """
    connection_file = os.path.basename(ipykernel.get_connection_file())
    kernel_id = connection_file.split('-', 1)[1].split('.')[0]

    for srv in app.list_running_servers():
        try:
            if srv['token']=='' and not srv['password']:  # No token and no password, ahem...
                req = urllib.request.urlopen(srv['url']+'api/sessions')
            else:
                req = urllib.request.urlopen(srv['url']+'api/sessions?token='+srv['token'])
            sessions = json.load(req)
            for sess in sessions:
                if sess['kernel']['id'] == kernel_id:
                    return os.path.join(srv[key_srv_directory],sess['notebook']['path'])
        except:
            pass  # There may be stale entries in the runtime directory 
    return None

As stated in the docstring, this works only when either there is no authentication or the authentication is token-based.

Note that, as also reported by others, the Javascript-based method does not seem to work when executing a "Run all cells" (but works when executing cells "manually"), which was a deal-breaker for me.

Solution 5

On Jupyter 3.0 the following works. Here I'm showing the entire path on the Jupyter server, not just the notebook name:

To store the NOTEBOOK_FULL_PATH on the current notebook front end:

%%javascript
var nb = IPython.notebook;
var kernel = IPython.notebook.kernel;
var command = "NOTEBOOK_FULL_PATH = '" + nb.base_url + nb.notebook_path + "'";
kernel.execute(command);

To then display it:

print("NOTEBOOK_FULL_PATH:\n", NOTEBOOK_FULL_PATH)

Running the first Javascript cell produces no output. Running the second Python cell produces something like:

NOTEBOOK_FULL_PATH:
 /user/zeph/GetNotebookName.ipynb
Share:
63,289

Related videos on Youtube

Tooblippe
Author by

Tooblippe

Hacker

Updated on November 25, 2021

Comments

  • Tooblippe
    Tooblippe over 2 years

    I am trying to obtain the current NoteBook name when running the IPython notebook. I know I can see it at the top of the notebook. What I am after something like

    currentNotebook = IPython.foo.bar.notebookname()
    

    I need to get the name in a variable.

    • Thomas K
      Thomas K over 11 years
      What are you trying to do with it? By design, the kernel (the bit that runs code) doesn't know about the frontend (the bit that opens notebooks).
    • Tooblippe
      Tooblippe over 11 years
      Hi, I want to use it with nbconvert to automate the notebook to latex/pdf creation process. My notebooks run remotely. after a class students can download a pdf version of their results.
    • joelostblom
      joelostblom over 4 years
      P.Toccaceli's answer works well with recent versions of JupyterLab (1.1.4) (notebook 5.6.0) and does not require javascript.
    • matth
      matth about 4 years
    • NeoTT
      NeoTT over 3 years
      Some did the work and made a pip package: pypi.org/project/ipynbname install by pip install ipynbname
    • lhoupert
      lhoupert about 3 years
      Yes ipynbname is now working with jupyter 3 (more details here)
    • Admin
      Admin over 2 years
      ipynbname did not work on jupyter 4 though.
  • Purrell
    Purrell over 10 years
    connection_file_path = kernel.get_connection_file() doesn't work anymore, filename is required arg.
  • Paul
    Paul over 10 years
    This worked fine for me on IPython.__version__ of '0.13.2' and I didnot have to specify a filename for the kernel.get_connection_file()
  • Artjom B.
    Artjom B. almost 10 years
    Maybe I missed something, but how do you invoke the javascript code from python?
  • Jakob
    Jakob almost 10 years
    It is also possible to call the javascript from within python using the display method applied to a javascript object like def getname(): display(Javascript('IPython.notebook.kernel.execute("theNote‌​book = " + "\'"+IPython.notebook.notebook_name+"\'");'))
  • Pedro M Duarte
    Pedro M Duarte about 9 years
    How do I modify this to get the notebook's path?
  • Tristan Reid
    Tristan Reid about 9 years
    @PedroMDuarte: You can use IPython.notebook.notebook_path in javascript for 'thename' in the above script to get that value.
  • Tristan Reid
    Tristan Reid about 9 years
    @PedroMDuarte: Note that the path is relative to the root of the notebook server.
  • Pierre D
    Pierre D almost 9 years
    @Jakob: it works fine if done in a cell, but not in a function as you have it. I asked a question about this here.
  • Jakob
    Jakob almost 9 years
    @PierreD Well, you cannot immediately return the value but it gets stored as theNotebook. Nevertheless, I also would prefer a solution to directly get such variables.
  • Lukas
    Lukas over 8 years
    This is very clean. How would you call the Javascript code from a Python function then?
  • Tristan Reid
    Tristan Reid over 8 years
    Some updates: Instead of from IPython.lib import kernel now it's just from IPython import kernel. Also instead of using the key 'name' in the dictionaries, use the key 'path'
  • mbdevpl
    mbdevpl almost 8 years
    As advertised by the answerer himself, this answer doesn't work for latest IPython. I've created a version that seems to work with IPython 4.2.0 in Python 3.5: gist.github.com/mbdevpl/f97205b73610dd30254652e7817f99cb
  • Zephaniah Grunschlag
    Zephaniah Grunschlag over 7 years
    Hmmmm... maybe in that case you should append the port with a colon followed by the port number?
  • Ivelin
    Ivelin over 7 years
    This is relative path not full path
  • yingted
    yingted over 6 years
    As of version 4.3.0, you need to provide an auth token. This can be retrieved using notebook.notebookapp.list_running_servers().
  • yingted
    yingted over 6 years
    If you have multiple servers running, you can check what port the kernel's parent process is listening on, which should tell you which server to connect to (or you can just connect to every local Jupyter server and check which is running your kernel).
  • jfb
    jfb over 6 years
    Using IPython.notebook.notebook_name this can be done using %%javascript IPython.notebook.kernel.execute('notebookName = ' + '"' + IPython.notebook.notebook_name + '"')
  • sappjw
    sappjw over 6 years
    This also doesn't include the setting of c.NotebookApp.notebook_dir.
  • Pierre-Antoine
    Pierre-Antoine almost 6 years
    For some reason this only work if I run the javascript cell "manually". If I run the full notebook the second cell fails. Any idea why?
  • Mahmoud Elagdar
    Mahmoud Elagdar almost 6 years
    I guess for some reason, if a variable is modified from javascript then accessed from pure python in the same call, the python version doesn't see the update and also replaces the javascript version. So I guess you may move the javascript cell to the top, run it, then use "Cell>Run All Bellow".
  • matanster
    matanster over 5 years
    Why do we need javascript actually? nothing more native?
  • Mahmoud Elagdar
    Mahmoud Elagdar over 5 years
    Let me guess that your python code is sent to a kernel running in the terminal where you launched Jupyter. That kernel doesn't know much about your notebook and the only solution I found so far is using Javascript. There's however a way to run Javascript using iPython, see the following two lines: from IPython.display import Javascript as d_js; d_js("IPython.notebook.kernel.execute('nb_name = \"' + IPython.notebook.notebook_name + '\"')")
  • Sunday
    Sunday over 5 years
    The second solution, which looks for the notebook-name <input> element has another advantage: If you rename a notebook, this method immediately reflects this, while the body attribute is only updated when you close and re-open the notebook.
  • matanster
    matanster over 5 years
    at least using a recent version of Jupyter, this doesn't capture the full path
  • matanster
    matanster over 5 years
    Is there any library for this?
  • Fernando Wittmann
    Fernando Wittmann about 5 years
    NameError: name 'nb_name' is not defined
  • Fernando Wittmann
    Fernando Wittmann about 5 years
    NameError: name 'NOTEBOOK_FULL_PATH' is not defined when trying on colab
  • Mahmoud Elagdar
    Mahmoud Elagdar almost 5 years
    Did the JavaScript part run without errors before you ran the Python part?
  • germ
    germ almost 5 years
    To get the notebook path without JS trickery: globals()['_dh'][0]
  • alancalvitti
    alancalvitti almost 5 years
    @MahmoudElagdar, "Cell>Run All Bellow" doesn't seem an option when remotely running the notebook from another notebook with %run
  • alancalvitti
    alancalvitti almost 5 years
    @MahmoudElagdar, the d_js method works in a given notebook when called by a wrapper function, say notebook_name() that returns nb_name. However, it throws NameError: name 'nb_name' is not defined when %run is used to evaluate the notebook containing notebook_name(). Any ideas?
  • Mahmoud Elagdar
    Mahmoud Elagdar over 4 years
    @alancalvitti perhaps P.Toccaceli's post can help? the problem is you can't set the variable nb_name and use it in the same run because of the way javascript calls are implemented so you have to split it into two runs
  • Arjun A J
    Arjun A J over 4 years
    @MahmoudElagdar Can we convert the Javascript part to python? I tried from IPython import notebook print(IPython.notebook.notebook_name) But it's throwing error: cannot import name 'notebook'. Please help. Thanks
  • gumption
    gumption over 4 years
    The failure of Javascript methods was a deal-breaker for me too. Thanks for posting this alternative!
  • magicrebirth
    magicrebirth over 4 years
    Fails on Jupyter Lab: Javascript Error: IPython is not defined
  • Dave Babbitt
    Dave Babbitt over 4 years
    I have to replace srv['notebook_dir'] with from jupyter_core.paths import jupyter_config_dir; from traitlets.config import Config; c = Config(); file_path = os.path.join(jupyter_config_dir(), 'jupyter_notebook_config.py'); exec(open(file_path).read()); root_dir = c['FileContentsManager']['root_dir']
  • zozo
    zozo about 4 years
    I am getting Javascript Error: IPython is not defined. How can I load IPython for javascript
  • kawingkelvin
    kawingkelvin about 4 years
    I tried but got "ReferenceError: Can't find variable: IPython" on the browser console log. I also tried to "Import IPython" in a code cell before executing this, same issue. Btw: I am trying this on google colab, perhaps this doesn't work there?
  • ntg
    ntg over 3 years
    if you have multiple servers running, you can list all of them using !jupyter notebook list This will give all running notebooks and then use the one with the correct pwd, or just check them all
  • alejandro
    alejandro over 3 years
    This seems a better answer than the accepted one at the top.
  • alejandro
    alejandro over 3 years
    This may be outdated, another answer in this thread below shows that not only it is fine but fairly easy to get the name of the current notebook from within itself.
  • germ
    germ over 3 years
    @BND, just tried it on IPython 7.12.0 and Python 3.7: It works. What versions are you using?
  • lhoupert
    lhoupert over 3 years
    Hi @bill, I tried this solution on recent jupyter notebook version but I didn't manage to make it work. I create a post [here]
  • lhoupert
    lhoupert about 3 years
    I found the solution with the package ipynbname
  • mirekphd
    mirekphd about 3 years
    It's good only for manual execution of a single cell... Javascript calls are async and not guaranteed to complete before python starts running another cell that contains the consumer of this notebook name... resulting in NameError.
  • Mahmoud Elagdar
    Mahmoud Elagdar about 3 years
    @P.Toccaceli making lots of assumptions for when line count is relevant, maybe it can be reduced to this from jupyter_server import serverapp as app; import ipykernel, requests, os; kernel_id = os.path.basename(ipykernel.get_connection_file()).split('-', 1)[1].split('.')[0]; srv = next(app.list_running_servers()); nb_path = srv["root_dir"]+"/"+next(s for s in requests.get(srv['url']+'api/sessions?token='+srv['token']).‌​json() if s["kernel"]["id"]==kernel_id)['notebook']['path']
  • Mahmoud Elagdar
    Mahmoud Elagdar about 3 years
    @mirekphd The async idea is interesting, IDK I tried adding a sleep and still didn't work. Maybe try P.Toccaceli's solution
  • FarisHijazi
    FarisHijazi almost 3 years
    that's a super weird way but this works great, thank you
  • Warlax56
    Warlax56 over 2 years
    This is great. Other Javascript based solutions haven't been working well in my environment (sagemaker studio). This one does though!
  • Admin
    Admin over 2 years
    I always thought of so many applications of knowing the notebook filename (e.g. based on the filename one could import different sets of modules for a given notebook). Truly this functionality is much needed, ideally it should be perhaps built into the jupyter's core package itself.
  • tel
    tel over 2 years
    @Ramirez Literally no one on Stackoverflow cares about your two cents. However, if you post your view/use cases to the "pass notebook name to kernel" feature discussion thread, the actual Jupyter devs will read them and likely respond
  • alEx
    alEx over 2 years
    The option with ipynbname is the ONLY ONE straight forward. All the other I have to deal with installation of IPyton, Javablahblah, and so on. Thanks
  • Julian - BrainAnnex.org
    Julian - BrainAnnex.org almost 2 years
    Thank you! Worked for me, with jupyterlab==3.3.4 and Python 3.7
  • BSalita
    BSalita almost 2 years
    ipynbname takes 16 seconds to execute in my minimal notebook.