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

2025-02-27 09:05:00
admin
原创
61
摘要:问题描述:我在运行 IPython 笔记本时尝试获取当前笔记本名称。我知道我可以在笔记本顶部看到它。我想要的是currentNotebook = IPython.foo.bar.notebookname() 我需要在变量中获取名称。解决方案 1:要获取笔记本名称,请在单元格中运行以下命令:%%javascri...

问题描述:

我在运行 IPython 笔记本时尝试获取当前笔记本名称。我知道我可以在笔记本顶部看到它。我想要的是

currentNotebook = IPython.foo.bar.notebookname()

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


解决方案 1:

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

%%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:

我有以下适用于 IPython 2.0 的代码。我观察到笔记本的名称作为属性的值存储'data-notebook-name'<body>页面的标签中。因此,首先要让 Javascript 检索属性 --javascripts 可以通过%%javascriptmagic 从代码单元调用。然后,可以通过调用 Python 内核来访问 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)

出[ ]: 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

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

解决方案 3:

正如前面提到的,你可能真的不应该这样做,但我确实找到了一种方法。不过这是一个非常棘手的黑客行为,所以不要完全依赖它:

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 中“有效”的解决方案,至少通过简单的测试。如果有多个笔记本连接到同一个内核,则可能无法保证给出正确的答案。

解决方案 4:

@iguananaut 接受的解决方案似乎不适用于 Notebook 的最新版本。

我按如下所示修复了它。我在 Python v3.6.1 + Notebook v5.0.0 以及 Python v3.6.5 和 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

正如文档字符串中所述,这仅在没有身份验证或身份验证基于令牌时才有效。

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

解决方案 5:

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

import ipyparams
currentNotebook = ipyparams.notebook_name

解决方案 6:

在 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:
", NOTEBOOK_FULL_PATH)

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

NOTEBOOK_FULL_PATH:
 /user/zeph/GetNotebookName.ipynb

解决方案 7:

由于我的笔记本服务器可能会发生变化,因此这又是一个 hacky 解决方案。基本上,您打印一个随机字符串,保存它,然后在工作目录中搜索包含该字符串的文件。需要 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)

解决方案 8:

如果你使用 Visual Studio Code:

import IPython ; IPython.extract_module_locals()[1]['__vsc_ipynb_file__']

解决方案 9:

只需使用ipynbname,这很实用

#! pip install ipynbname

import ipynbname
nb_fname = ipynbname.name()
nb_path = ipynbname.path()
print(f"{nb_fname=}")
print(f"{nb_path=}")

我在https://stackoverflow.com/a/65907473/15497427找到了这个

解决方案 10:

可以从全局变量中获取当前笔记本名称__session__。也可以从环境变量中获取JPY_SESSION_NAME

小提示:这仅在使用 Jupyter 启动会话时有效。如果移动笔记本并且未重新启动会话,则名称将保持旧名称。

经过测试

python == 3.11.7
ipykernel == 6.29.0
jupyter_server == 2.12.5
jupyterlab == 4.0.11

参见:

解决方案 11:

Jupyterlab 中还没有真正的方法可以做到这一点。但有一种官方方法,截至 2021 年 8 月,正在积极讨论/开发中:

https://github.com/jupyter/jupyter_client/pull/656

与此同时,访问api/sessionsREST 端点jupyter_server似乎是最好的选择。以下是该方法的精简版本:

from jupyter_server import serverapp
from jupyter_server.utils import url_path_join
from pathlib import Path
import re
import requests

kernelIdRegex = re.compile(r"(?<=kernel-)[wd-]+(?=.json)")

def getNotebookPath():
    kernelId = kernelIdRegex.search(get_ipython().config["IPKernelApp"]["connection_file"])[0]
    
    for jupServ in serverapp.list_running_servers():
        for session in requests.get(url_path_join(jupServ["url"], "api/sessions"), params={"token": jupServ["token"]}).json():
            if kernelId == session["kernel"]["id"]:
                return Path(jupServ["root_dir"]) / session["notebook"]['path']

经过测试

python==3.9
jupyter_server==1.8.0
jupyterlab==4.0.0a7

解决方案 12:

修改@jfb的答案给出了下面的函数,该函数在ipykernel-5.3.4上运行良好。

def getNotebookName():
    display(Javascript('IPython.notebook.kernel.execute("NotebookName = " + "\'"+window.document.getElementById("notebook_name").innerHTML+"\'");'))
    try:
        _ = type(NotebookName)
        return NotebookName
    except:
        return None

请注意,显示 javascript 需要一些时间才能到达浏览器,执行 JS 并返回内核也需要一些时间。我知道这听起来可能很愚蠢,但最好在两个单元格中运行该函数,如下所示:

nb_name = getNotebookName()

并在以下单元格中:

for i in range(10):
    nb_name = getNotebookName()
    if nb_name is not None:
        break

但是,如果不需要定义函数,明智的做法是display(Javascript(..))在一个单元格中运行,在另一个单元格中检查笔记本名称。这样,浏览器就有足够的时间执行代码并返回笔记本名称。

如果您不介意使用库,最强大的方法是:

import ipynbname
nb_name = ipynbname.name()

解决方案 13:

要了解为什么无法使用这些基于 JS 的解决方案获取笔记本名称,请运行此代码并注意在 python 完成单元格/整个笔记本的执行后消息框出现所需的延迟:

%%javascript

function sayHello() {
    alert('Hello world!');
}

setTimeout(sayHello, 1000);
  • 更多信息

Javascript 调用是异步的,因此不能保证在 python 开始运行另一个包含代码的单元格之前完成,该单元格期望这个笔记本名称变量已经创建……导致NameError尝试访问应该包含笔记本名称的不存在的变量。

我怀疑此页面上的某些赞成票在投票者发现所有%%javascript基于的解决方案最终都不起作用之前就被锁定了……当生产者和消费者笔记本单元一起执行(或快速连续执行)时。

解决方案 14:

假设您有 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')

解决方案 15:

如果我们一次执行多个单元,所有基于 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}]')
    

解决方案 16:

如今,这已作为 IPython 中的一项功能实现,有一个内置的“ vsc_ipynb_file ”变量。

这是修复方法 - https://github.com/microsoft/vscode-jupyter/pull/8531

解决方案 17:

这在 JetBrains DataSpell 中对我有用。

print(str(__session__).split('/')[-1])
<<< output: Салют-Хабаровск-2.ipynb

解决方案 18:

一个简单的方法是获取连接文件,然后读取 json 数据,具体来说是检索“jupyter_session”

下面是一个代码示例:

from ipykernel import get_connection_file
import os
import json

connection_file = get_connection_file()
notebook_path = os.path.dirname(connection_file)

f = open(connection_file)
data = json.load(f)
data["jupyter_session"] # Your information lives here!

编辑:

显然,上述方法不适用于 vscode。此外,如果在会话中已重命名文件名,则连接文件不会更新文件名会话变量,因此上述方法可能不是最好的方法。但您可以尝试下面的方法吗?

如此处所述获取 .ipynb 文件名

def get_notebook_name(filename_only=True, full_path=False):

import re
import os
import json    
import requests
from requests.compat import urljoin

from jupyter_server import serverapp
from ipykernel import get_connection_file    

result = ''
# print(filename_only)
# print(full_path)

if filename_only and full_path:
    raise ValueError("filename_only & full_path cannot simultaneously be true (use one or the other)")

connection_file = get_connection_file()
mo = re.search('kernel-(.*).json', connection_file) # matched objects (mo)
kernel_id = mo.group(1)

# Specifically for jupyter lab / analogous function exists for jupyter notebook
servers = serverapp.list_running_servers()

for ss in servers:
    response = requests.get(urljoin(ss['url'], 'api/sessions'), params={'token': ss.get('token', '')})
    for nn in json.loads(response.text):
        if nn['kernel']['id'] == kernel_id:
            relative_path = nn['notebook']['path']

filename = relative_path.split('/')[-1]

if filename_only:
    result = filename
    return result

if full_path:
    cwd = os.getcwd()
    result = os.path.join(cwd, filename)
    return result

上述函数的用法如下:

get_notebook_name(True, False)

或者

get_notebook_name(False, True)

但当然,您可以尝试一下,并使其满足您的要求......

让我知道进展如何!

解决方案 19:

以下代码片段可在 Jupyter Notebook 和 Jupyter Lab 中使用,无需借助 Javascript。None如果使用 执行该函数,则返回结果jupyter nbconvert --execute ...。如果您想在整个代码库中重复使用该函数,则可以将其添加到包中。

def get_notebook_path() -> str | None:
    import IPython
    import json

    # Try to get IPython and return None if not found.
    ipython = IPython.get_ipython()
    if not ipython:
        return

    # Try to get the __session__ variable from the user namespace.
    return ipython.user_ns.get("__session__")
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3592  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2442  
  敏捷每日站会作为敏捷项目管理中的关键环节,对于提升产品生命周期管理(PLM)效率有着不可忽视的作用。PLM涵盖了产品从概念产生到最终报废的全过程管理,涉及众多环节与人员,而每日站会能够通过优化沟通机制,让信息在团队中快速、准确地流动,从而推动整个PLM流程更加顺畅、高效。接下来,我们将深入探讨如何通过四步优化沟通机制,...
plm系统   17  
  在企业的发展进程中,产品生命周期管理(PLM)项目管理至关重要,而数据驱动决策则是提升PLM项目管理效能的关键手段。通过运用合适的分析模型,企业能够从海量数据中挖掘有价值的信息,为决策提供有力支撑,进而优化产品全生命周期的各个环节。以下将详细介绍助力PLM项目管理实现数据驱动决策的5大分析模型。需求分析模型需求分析是P...
plm系统功能介绍   19  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与运营中扮演着至关重要的角色。它涵盖了从产品概念设计到退役的全流程管理,确保产品数据的有效整合与协同。然而,在复杂多变的商业环境中,黑天鹅事件随时可能降临,给企业带来难以预估的冲击。这些意外事件具有不可预测性、极大的影响力和事后的可解释性等特点,会对PLM系统的正常运...
plm系统的主要功能模块   16  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用