如何获取当前的IPython / Jupyter Notebook名称


85

我正在尝试在运行IPython笔记本时获取当前的笔记本名称。我知道我可以在笔记本顶部看到它。我喜欢什么之后

currentNotebook = IPython.foo.bar.notebookname()

我需要在变量中获取名称。


您打算如何处理?按照设计,内核(运行代码的位)不了解前端(打开笔记本的位)。
Thomas K

7
嗨,我想与nbconvert一起使用它来自动执行笔记本到乳胶/ pdf的创建过程。我的笔记本可以远程运行。上课后,学生可以下载结果的pdf版本。
Tooblippe 2012年

1
P.Toccaceli的答案在JupyterLab(1.1.4)(笔记本5.6.0)的最新版本中效果很好,并且不需要javascript。
joelostblom


一些人做了工作并制作了一个pip包:pypi.org/project/ipynbname install bypip install ipynbname
NeoTT

Answers:


24

如前所述,您可能真的不应该能够执行此操作,但是我确实找到了一种方法。尽管这是一个令人发指的骇客,所以请不要完全依赖于此:

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

我更新了答案,以包含至少在一个简单的测试中即可在IPython 2.0中“运行”的解决方案。如果有多个笔记本连接到同一内核等,则可能无法保证给出正确的答案。


connection_file_path = kernel.get_connection_file()不再起作用,文件名为arg。
Purrell 2013年

2
一些更新:而不是from IPython.lib import kernel现在from IPython import kernel。同样,不要使用字典中的键“名称”,而应使用键“路径”
Tristan Reid

1
正如回答者本人所宣传的那样,此回答不适用于最新的IPython。我创建了一个似乎可以在Python 3.5中使用IPython 4.2.0的版本:gist.github.com/mbdevpl/f97205b73610dd30254652e7817f99cb
mbdevpl

1
从4.3.0版开始,您需要提供一个身份验证令牌。可以使用以下方法检索notebook.notebookapp.list_running_servers()
yingted

1
如果有多个服务器在运行,则可以检查内核的父进程正在侦听哪个端口,这应该告诉您要连接到哪个服务器(或者您可以仅连接到每个本地Jupyter服务器并检查正在运行的内核)。
yingted

40

我有以下与IPython 2.0一起使用的东西。我观察到,笔记本电脑的名称被存储为属性的值'data-notebook-name'<body>页面的标签。因此,首先想到的是让Javascript检索属性-借助魔术,可以从代码单元中调用JavaScript %%javascript。然后,可以通过设置Python变量的命令通过调用Python内核来访问Javascript变量。由于从内核知道了最后一个变量,因此也可以在其他单元中对其进行访问。

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

从Python代码单元

print(theNotebook)

出[]:HowToGetTheNameOfTheNoteBook.ipynb

该解决方案的一个缺陷是,当一个人更改笔记本的标题(名称)时,该名称似乎不会立即更新(可能存在某种缓存),因此有必要重新加载笔记本以访问该笔记本。新名字。

[编辑]反射时,一种更有效的解决方案是查找笔记本名称的输入字段,而不是<body>标签。查看源代码,似乎该字段的ID为“ notebook_name”。然后可以通过a捕获此值document.getElementById(),然后采用与上述相同的方法。代码变得仍然使用javascript magic

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

然后,在ipython单元中,

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

与第一种解决方案相反,笔记本名称的修改会立即更新,因此无需刷新笔记本。


也许我错过了一些东西,但是您如何从python调用javascript代码?
Artjom B. 2014年

7
也可以使用应用于javascript对象的显示方法(例如def getname(): display(Javascript('IPython.notebook.kernel.execute("theNotebook = " + "\'"+IPython.notebook.notebook_name+"\'");'))
Jakob

我该如何修改以获得笔记本的路径?
Pedro M Duarte

@PedroMDuarte:您可以在上述脚本中的'thename'中使用javascript中的IPython.notebook.notebook_path来获取该值。
特里斯坦·里德

1
要获得没有JS欺骗的笔记本路径:globals()['_dh'][0]
胚芽

38

除了以前的答案,

要获取笔记本名称,请在单元格中运行以下命令:

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

这将为您获取nb_name中的文件名

然后要获取完整路径,可以在单独的单元格中使用以下内容:

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

1
使用IPython.notebook.notebook_name这个可以做到用%%javascript IPython.notebook.kernel.execute('notebookName = ' + '"' + IPython.notebook.notebook_name + '"')
JFB

9
由于某些原因,这仅在我“手动”运行javascript单元时有效。如果我运行整个笔记本,则第二个单元将失败。知道为什么吗?
Pierre-Antoine

我猜出于某种原因,如果从javascript修改了一个变量,然后在同一调用中从纯python访问了该变量,则python版本看不到更新,并且还会替换javascript版本。因此,我想您可以将javascript单元移到顶部,运行它,然后使用“ Cell> Run All Bellow”。
Mahmoud Elagdar

2
为什么我们实际上需要JavaScript?仅此而已?
matanster '18

1
在Jupyter Lab上失败:Javascript Error: IPython is not defined
magicrebirth

27

在Jupyter 3.0上,以下工作。在这里,我显示了Jupyter服务器上的整个路径,而不仅仅是笔记本名称:

要将其存储NOTEBOOK_FULL_PATH在当前笔记本前端上:

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

然后显示它:

print("NOTEBOOK_FULL_PATH:\n", NOTEBOOK_FULL_PATH)

运行第一个Javascript单元不会产生任何输出。运行第二个Python单元会产生类似以下内容:

NOTEBOOK_FULL_PATH:
 /user/zeph/GetNotebookName.ipynb

4
这很干净。那么您将如何从Python函数中调用Javascript代码?
卢卡斯2015年

嗯...也许在这种情况下,您应该在端口后面加上一个冒号,再加上端口号?
Zephaniah Grunschlag'9

3
这是相对路径而不是完整路径
Ivelin

这也不包括的设置c.NotebookApp.notebook_dir
sappjw

4
我越来越Javascript Error: IPython is not defined。我如何为JavaScript加载IPython
zozo

25

看来我无法发表评论,因此我必须将其发布为答案。

@iguananaut接受的解决方案和@mbdevpl的更新似乎不适用于笔记本的最新版本。我按如下所示修复了它。我在Python v3.6.1 + Notebook v5.0.0以及Python v3.6.5和Notebook v5.5.0上进行了检查。

from notebook import notebookapp
import urllib
import json
import os
import ipykernel

def notebook_path():
    """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 notebookapp.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['notebook_dir'],sess['notebook']['path'])
        except:
            pass  # There may be stale entries in the runtime directory 
    return None

如文档字符串中所述,这仅在没有身份验证或身份验证基于令牌的情况下有效。

请注意,正如其他人所报道的那样,基于Javascript的方法在执行“运行所有单元格”时似乎不起作用(但在“手动”执行单元格时有效),这对我来说是一个大问题。


有图书馆吗?
matanster

Javascript方法的失败对我来说也是一个难题。感谢您发布此替代方法!
gumption

我必须用来自jupyter_core的srv ['notebook_dir']替换。从traitlets.config导入Config; c = Config(); file_path = os.path.join(jupyter_config_dir(),'jupyter_notebook_config.py'); exec(open(文件路径).read()); root_dir = c ['FileContentsManager'] ['root_dir']
Dave Babbitt

14

ipyparams包可以做到这一点很容易地。

import ipyparams
currentNotebook = ipyparams.notebook_name

这似乎比顶部的答案更好。
alejandro

1

假设您拥有Jupyter Notebook服务器的主机,端口和身份验证令牌,则此方法将为您工作。它基于此答案

import os
import json
import posixpath
import subprocess
import urllib.request
import psutil

def get_notebook_path(host, port, token):
    process_id = os.getpid();
    notebooks = get_running_notebooks(host, port, token)
    for notebook in notebooks:
        if process_id in notebook['process_ids']:
            return notebook['path']

def get_running_notebooks(host, port, token):
    sessions_url = posixpath.join('http://%s:%d' % (host, port), 'api', 'sessions')
    sessions_url += f'?token={token}'
    response = urllib.request.urlopen(sessions_url).read()
    res = json.loads(response)
    notebooks = [{'kernel_id': notebook['kernel']['id'],
                  'path': notebook['notebook']['path'],
                  'process_ids': get_process_ids(notebook['kernel']['id'])} for notebook in res]
    return notebooks

def get_process_ids(name):
    child = subprocess.Popen(['pgrep', '-f', name], stdout=subprocess.PIPE, shell=False)
    response = child.communicate()[0]
    return [int(pid) for pid in response.split()]

用法示例:

get_notebook_path('127.0.0.1', 17004, '344eb91bee5742a8501cc8ee84043d0af07d42e7135bed90')

0

由于我的笔记本服务器可以更改,这是又一个骇人听闻的解决方案。基本上,您打印随机字符串,保存它,然后在工作目录中搜索包含该字符串的文件。需要while,因为save_checkpoint是异步的。

from time import sleep
from IPython.display import display, Javascript
import subprocess
import os
import uuid

def get_notebook_path_and_save():
    magic = str(uuid.uuid1()).replace('-', '')
    print(magic)
    # saves it (ctrl+S)
    display(Javascript('IPython.notebook.save_checkpoint();'))
    nb_name = None
    while nb_name is None:
        try:
            sleep(0.1)
            nb_name = subprocess.check_output(f'grep -l {magic} *.ipynb', shell=True).decode().strip()
        except:
            pass
    return os.path.join(os.getcwd(), nb_name)

0

如果一次执行多个单元,则所有基于Json的解决方案都会失败,因为结果要到执行结束后才能准备就绪(这与使用睡眠或等待时间无关,请自己检查一下,但记得重新启动内核)然后运行所有测试)

根据以前的解决方案,这样可以避免在需要将其放入其他代码中间的情况下避免使用%%魔术:

from IPython.display import display, Javascript

# can have comments here :)
js_cmd = 'IPython.notebook.kernel.execute(\'nb_name = "\' + IPython.notebook.notebook_name + \'"\')'
display(Javascript(js_cmd))

对于python 3,以下基于@Iguananaut的答案并针对最新python和可能的多个服务器进行更新的方法将起作用:

import os
import json
try:
    from urllib2 import urlopen
except:
    from urllib.request import urlopen
import ipykernel

connection_file_path = ipykernel.get_connection_file()
connection_file = os.path.basename(connection_file_path)
kernel_id = connection_file.split('-', 1)[1].split('.')[0]    
    
running_servers = !jupyter notebook list
running_servers = [s.split('::')[0].strip() for s in running_servers[1:]]
nb_name = '???'
for serv in running_servers:
    uri_parts = serv.split('?')
    uri_parts[0] += 'api/sessions'
    sessions = json.load(urlopen('?'.join(uri_parts)))
    for sess in sessions:
        if sess['kernel']['id'] == kernel_id:
            nb_name = os.path.basename(sess['notebook']['path'])
            break
    if nb_name != '???':
        break
print (f'[{nb_name}]')
    
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.