我正在尝试在运行IPython笔记本时获取当前的NoteBook名称。我知道我可以在笔记本的顶部看到它。我喜欢
之类的东西currentNotebook = IPython.foo.bar.notebookname()
我需要在变量中获取名称。
答案 0 :(得分:30)
我有以下适用于IPython 2.0的内容。我发现笔记本的名称存储为页面'data-notebook-name'
标记中属性<body>
的值。因此,这个想法首先要求Javascript检索属性 - 由于%%javascript
魔法,可以从代码单元调用javascripts。然后可以通过调用Python Kernel来访问Javascript变量,并使用一个设置Python变量的命令。由于最后一个变量是从内核中获知的,因此也可以在其他单元格中访问它。
%%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)
Out []:HowToGetTheNameOfTheNoteBook.ipynb
此解决方案中的一个缺陷是,当更改笔记本的标题(名称)时,此名称似乎不会立即更新(可能存在某种缓存)并且需要重新加载笔记本才能获得访问新名称。
[编辑] 在反思中,更有效的解决方案是查找笔记本名称的输入字段,而不是<body>
标记。查看源代码,该字段似乎具有id“notebook_name”。然后可以通过document.getElementById()
捕获此值,然后按照与上面相同的方法。代码变成,仍然使用javascript魔法
%%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
与第一种解决方案相反,笔记本名称的修改会立即更新,无需刷新笔记本。
答案 1 :(得分:24)
添加到之前的答案,
获取笔记本名称在单元格中运行以下内容:
%%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)
答案 2 :(得分:23)
正如已经提到的,你可能不是真的应该这样做,但我确实找到了办法。这是一个火热的黑客,所以不要依赖这个:
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中“工作”的解决方案,至少通过一个简单的测试。如果有多个笔记本连接到同一个内核等,可能无法保证给出正确的答案。
答案 3 :(得分:23)
在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 :(得分:14)
ipyparams软件包可以很容易地做到这一点。
import ipyparams
currentNotebook = ipyparams.notebook_name
答案 5 :(得分:10)
似乎我无法发表评论,因此我必须将其发布为答案。
@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的方法在执行“运行所有单元格”时似乎不起作用(但在“手动”执行单元格时有效),这对我来说是一个大问题。
答案 6 :(得分:1)
假设您拥有Jupyter Notebook服务器的主机,端口和身份验证令牌,则此方法将为您工作。它基于this answer。
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')
答案 7 :(得分:1)
要了解为什么使用这些基于 JS 的解决方案无法获取笔记本名称,请运行此代码并注意在 python 完成单元/整个笔记本执行后消息框出现所需的延迟:
%%javascript
function sayHello() {
alert('Hello world!');
}
setTimeout(sayHello, 1000);
Javascript 调用是异步的,因此不能保证在 python 开始运行另一个单元格之前完成,该单元格包含期望已创建此笔记本名称变量的代码...导致尝试访问不存在的变量时 NameError
应包含笔记本名称。
我怀疑在选民发现所有基于 %%javascript
的解决方案最终都不起作用之前,此页面上的一些赞成票已被锁定...当生产者和消费者笔记本单元一起执行(或快速连续执行时) ).
答案 8 :(得分: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)
答案 9 :(得分: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}]')