Как мне получить текущее имя IPython / Jupyter Notebook


87

Я пытаюсь получить текущее имя NoteBook при запуске ноутбука IPython. Я знаю, что вижу это вверху блокнота. Что мне нужно после чего-то вроде

currentNotebook = IPython.foo.bar.notebookname()

Мне нужно получить имя в переменной.


Что вы пытаетесь с этим делать? По замыслу, ядро ​​(бит, выполняющий код) не знает о внешнем интерфейсе (бит, который открывает записные книжки).
Thomas K

7
Привет, я хочу использовать его с nbconvert, чтобы автоматизировать процесс создания записной книжки в latex / pdf. Мои ноутбуки работают удаленно. после урока ученики могут скачать свои результаты в формате pdf.
Tooblippe

1
Ответ П.Токкачели хорошо работает с последними версиями JupyterLab (1.1.4) (ноутбук 5.6.0) и не требует javascript.
joelostblom


Некоторые выполнили эту работу и сделали пакет pip: pypi.org/project/ipynbname, установленныйpip install ipynbname
NeoTT

Ответы:


26

Как уже упоминалось, вы, вероятно, действительно не должны уметь этого делать, но я нашел способ. Это пламенный хакер, так что не стоит на него полагаться:

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

2
Некоторые обновления: Вместо from IPython.lib import kernelэтого просто from IPython import kernel. Также вместо использования ключа «имя» в словарях используйте ключ «путь»
Тристан Рид

1
Как сообщает сам ответчик, этот ответ не работает для последней версии IPython. Я создал версию, которая, похоже, работает с IPython 4.2.0 в Python 3.5: gist.github.com/mbdevpl/f97205b73610dd30254652e7817f99cb
mbdevpl

1
Начиная с версии 4.3.0, вам необходимо предоставить токен авторизации. Это можно получить с помощью notebook.notebookapp.list_running_servers().
yingted

1
Если у вас работает несколько серверов, вы можете проверить, какой порт прослушивает родительский процесс ядра, что должно сообщить вам, к какому серверу подключаться (или вы можете просто подключиться к каждому локальному серверу Jupyter и проверить, на каком из них запущено ваше ядро).
yingted

41

У меня есть следующее, которое работает с IPython 2.0. Я заметил, что имя записной книжки хранится как значение атрибута 'data-notebook-name'в <body>теге страницы. Таким образом, идея состоит в том, чтобы сначала попросить Javascript получить атрибут - javascripts может быть вызван из кодовой ячейки благодаря %%javascriptмагии. Затем можно получить доступ к переменной Javascript через вызов ядра Python с помощью команды, которая устанавливает переменную 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>тега. Заглянув в источник, выясняется, что это поле имеет идентификатор «notebook_name». Затем можно поймать это значение с помощью a, 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

В отличие от первого решения, модификации имени записной книжки обновляются сразу, и нет необходимости обновлять записную книжку.


Может, я что-то упустил, но как вызвать код javascript из python?
Artjom B.

7
Также можно вызвать javascript из Python, используя метод отображения, примененный к объекту javascript, напримерdef getname(): display(Javascript('IPython.notebook.kernel.execute("theNotebook = " + "\'"+IPython.notebook.notebook_name+"\'");'))
Якоб

Как мне изменить это, чтобы получить путь к записной книжке?
Pedro M Duarte,

@PedroMDuarte: вы можете использовать IPython.notebook.notebook_path в javascript для 'thename' в приведенном выше скрипте, чтобы получить это значение.
Тристан Рид

1
Чтобы получить путь к записной книжке без JS-уловок:globals()['_dh'][0]
germ

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

10
По какой-то причине это работает, только если я запускаю ячейку javascript «вручную». Если я запустил полный блокнот, вторая ячейка выйдет из строя. Есть идеи, почему?
Pierre-Antoine

Я думаю, по какой-то причине, если переменная изменена из javascript, а затем доступна из чистого python в том же вызове, версия python не видит обновления, а также заменяет версию javascript. Итак, я думаю, вы можете переместить ячейку javascript наверх, запустить ее, а затем использовать «Ячейка> Выполнить все ниже».
Махмуд Элагдар

2
Зачем вообще нужен javascript? ничего роднее?
matanster

2
Неудачи на 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
Это очень чисто. Как бы вы тогда вызывали код Javascript из функции Python?
Лукас

Хмммм ... может в таком случае стоит добавить порт двоеточием, а затем номер порта?
Zephaniah Grunschlag 01

3
Это относительный путь, а не полный путь
Ивелин

Это также не включает настройку c.NotebookApp.notebook_dir.
sappjw

4
Я получаю Javascript Error: IPython is not defined. Как загрузить IPython для javascript
zozo

26

Кажется, я не могу комментировать, поэтому я должен опубликовать это в качестве ответа.

Принятое решение от @iguananaut и обновление от @mbdevpl, похоже, не работают с последними версиями Notebook. Я исправил это, как показано ниже. Я проверял это на 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 02

Для меня отказ методов Javascript тоже был препятствием. Спасибо, что разместили эту альтернативу!
сообразительность

Мне нужно заменить srv ['notebook_dir'] на from jupyter_core.paths import jupyter_config_dir; из traitlets.config import Config; c = Config (); file_path = os.path.join (jupyter_config_dir (), 'jupyter_notebook_config.py'); exec (open (путь к файлу) .read ()); root_dir = c ['FileContentsManager'] ['root_dir']
Дэйв Бэббитт

15

Пакет ipyparams может сделать это довольно легко.

import ipyparams
currentNotebook = ipyparams.notebook_name

1
Это кажется лучшим ответом, чем принятый вверху.
Алехандро

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

Еще одно хакерское решение, поскольку мой ноутбук-сервер может измениться. Обычно вы печатаете случайную строку, сохраняете ее, а затем ищите файл, содержащий эту строку, в рабочем каталоге. Время необходимо, потому что 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}]')
    
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.