Як отримати поточне ім’я ноутбука IPython / Jupyter


85

Я намагаюся отримати поточне ім'я NoteBook під час запуску блокнота IPython. Я знаю, що бачу це у верхній частині зошита. Який я після чогось подібного

currentNotebook = IPython.foo.bar.notebookname()

Мені потрібно отримати ім’я у змінній.


Що ти намагаєшся з цим робити? За задумом ядро ​​(біт, який запускає код) не знає про інтерфейс (біт, який відкриває блокноти).
Thomas K

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

1
Відповідь P.Toccaceli добре працює з останніми версіями JupyterLab (1.1.4) (зошит 5.6.0) і не вимагає JavaScript.
joelostblom


Деякі виконали роботу і створили пакет pip: pypi.org/project/ipynbname встановитиpip install ipynbname
NeoTT

Відповіді:


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.
Перрелл

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

40

У мене є таке, що працює з 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)

Вихід []: 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?
Артжом Б.

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]
зародок

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 "вручну". Якщо я запускаю повний блокнот, друга комірка виходить з ладу. Будь-яка ідея чому?
П’єр-Антуан

Я думаю, з якихось причин, якщо змінна змінена з javascript, а потім отримано доступ із чистого python у тому самому виклику, версія python не бачить оновлення, а також замінює версію javascript. Отже, я думаю, ви можете перемістити комірку javascript у верхню частину, запустити її, а потім скористатися «Клітинка> Запустити все нижче».
Махмуд Елагдар

2
Навіщо нам насправді javascript? нічого більше рідного?
matanster

1
Невдачі в лабораторії Юпітера: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

3
Це відносний шлях, а не повний шлях
Івелін

Сюди також не входить налаштування c.NotebookApp.notebook_dir.
sappjw

4
Я отримую Javascript Error: IPython is not defined. Як я можу завантажити IPython для javascript
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, здається, не працює при виконанні "Запустити всі комірки" (але працює, коли виконує комірки "вручну"), що для мене було порушенням.


Чи є для цього бібліотека?
матастер

Невдача методів Javascript теж зруйнувала мене. Дякуємо за розміщення цієї альтернативи!
кмітливість

Мені потрібно замінити srv ['notebook_dir'] на з 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 (відкрити (шлях_файлу) .read ()); root_dir = c ['FileContentsManager'] ['root_dir']
Дейв

14

Пакет ipyparams може зробити це досить легко.

import ipyparams
currentNotebook = ipyparams.notebook_name

Це здається кращою відповіддю, ніж прийнята вгорі.
Алехандро

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.