Jak uzyskać aktualną nazwę notatnika IPython / Jupyter


85

Próbuję uzyskać aktualną nazwę NoteBook podczas uruchamiania notebooka IPython. Wiem, że widzę to na górze notesu. Po co mi coś takiego

currentNotebook = IPython.foo.bar.notebookname()

Muszę uzyskać nazwę w zmiennej.


Co próbujesz z tym zrobić? Z założenia jądro (bit, który uruchamia kod) nie wie o frontend (bit, który otwiera notatniki).
Thomas K

7
Cześć, chcę go używać z nbconvert, aby zautomatyzować proces tworzenia notebooka do latex / pdf. Moje notebooki działają zdalnie. po zajęciach uczniowie mogą pobrać wersję PDF swoich wyników.
Tooblippe

1
Odpowiedź P.Toccaceli działa dobrze z najnowszymi wersjami JupyterLab (1.1.4) (notebook 5.6.0) i nie wymaga javascript.
joelostblom


Niektórzy wykonali pracę i stworzyli pakiet pip: pypi.org/project/ipynbname install dopip install ipynbname
NeoTT

Odpowiedzi:


24

Jak już wspomniano, prawdopodobnie nie powinieneś być w stanie tego zrobić, ale znalazłem sposób. To jednak płonący hack, więc nie polegaj wcale na tym:

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

Zaktualizowałem swoją odpowiedź, aby zawierała rozwiązanie, które „działa” w IPython 2.0, przynajmniej za pomocą prostego testu. Prawdopodobnie nie ma gwarancji udzielenia poprawnej odpowiedzi, jeśli do tego samego jądra jest podłączonych wiele notebooków itp.


connection_file_path = kernel.get_connection_file () już nie działa, nazwa pliku jest wymagana arg.
Purrell

2
Trochę aktualizacji: zamiast from IPython.lib import kernelteraz to po prostu from IPython import kernel. Zamiast używać klucza „nazwa” w słownikach, użyj klucza „ścieżka”
Tristan Reid

1
Jak reklamował sam odpowiadający, ta odpowiedź nie działa w przypadku najnowszego IPythona. Stworzyłem wersję, która wydaje się działać z IPythonem 4.2.0 w Pythonie 3.5: gist.github.com/mbdevpl/f97205b73610dd30254652e7817f99cb
mbdevpl

1
Od wersji 4.3.0 musisz podać token autoryzacji. Można to pobrać za pomocą notebook.notebookapp.list_running_servers().
wysłano

1
Jeśli masz uruchomionych wiele serwerów, możesz sprawdzić, na jakim porcie nasłuchuje proces nadrzędny jądra, co powinno ci powiedzieć, z którym serwerem się połączyć (lub możesz po prostu połączyć się z każdym lokalnym serwerem Jupyter i sprawdzić, na którym działa jądro).
wysłano

40

Mam następujące, które działają z IPython 2.0. Zauważyłem, że nazwa notatnika jest przechowywana jako wartość atrybutu 'data-notebook-name'w <body>tagu strony. Dlatego pomysł polega na tym, aby najpierw poprosić Javascript o pobranie atrybutu - dzięki %%javascriptmagii można wywoływać javascripts z komórki kodowej . Następnie możliwy jest dostęp do zmiennej Javascript poprzez wywołanie jądra Pythona za pomocą polecenia ustawiającego zmienną Pythona. Ponieważ ta ostatnia zmienna jest znana z jądra, można uzyskać do niej dostęp również w innych komórkach.

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

Z komórki kodu Python

print(theNotebook)

Out []: HowToGetTheNameOfTheNoteBook.ipynb

Wadą tego rozwiązania jest to, że po zmianie tytułu (nazwy) notatnika nazwa ta wydaje się nie być aktualizowana od razu (prawdopodobnie jest jakaś pamięć podręczna) i konieczne jest ponowne załadowanie notatnika, aby uzyskać dostęp do nowe imie.

[Edytuj] Po namyśle, bardziej efektywnym rozwiązaniem jest wyszukanie pola wprowadzania nazwy notatnika zamiast <body>tagu. Patrząc na źródło, okazuje się, że to pole ma identyfikator „nazwa_ notebooka”. Następnie można złapać tę wartość przez a, document.getElementById()a następnie zastosować to samo podejście, co powyżej. Kod nadal używa magii javascript

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

Następnie z komórki Ipython

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

W przeciwieństwie do pierwszego rozwiązania, modyfikacje nazwy notebooka są aktualizowane natychmiast i nie ma potrzeby odświeżania notebooka.


Może coś przeoczyłem, ale jak wywołać kod javascript z Pythona?
Artjom B.

7
Możliwe jest również wywołanie javascript z poziomu Pythona za pomocą metody wyświetlania zastosowanej do obiektu javascript, takiego jakdef getname(): display(Javascript('IPython.notebook.kernel.execute("theNotebook = " + "\'"+IPython.notebook.notebook_name+"\'");'))
Jakob

Jak to zmienić, aby uzyskać ścieżkę do notatnika?
Pedro M Duarte

@PedroMDuarte: Aby uzyskać tę wartość, możesz użyć IPython.notebook.notebook_path w javascript jako „nazwa_nazwy” w powyższym skrypcie.
Tristan Reid

1
Aby uzyskać ścieżkę notatnika bez oszustwa JS:globals()['_dh'][0]
kiełek

38

dodawanie do poprzednich odpowiedzi,

aby uzyskać nazwę notatnika, uruchom w komórce następujące polecenie:

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

w ten sposób otrzymasz nazwę pliku w nb_name

następnie, aby uzyskać pełną ścieżkę, możesz użyć następującego w osobnej komórce:

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

1
Korzystanie IPython.notebook.notebook_namemożna to zrobić za pomocą%%javascript IPython.notebook.kernel.execute('notebookName = ' + '"' + IPython.notebook.notebook_name + '"')
JFB

9
Z jakiegoś powodu to działa tylko wtedy, gdy uruchomię komórkę javascript „ręcznie”. Jeśli uruchomię pełny notebook, druga komórka ulegnie awarii. Każdy pomysł, dlaczego?
Pierre-Antoine,

Myślę, że z jakiegoś powodu, jeśli zmienna jest modyfikowana z javascript, a następnie dostępna z czystego Pythona w tym samym wywołaniu, wersja pythona nie widzi aktualizacji i zastępuje również wersję javascript. Więc myślę, że możesz przenieść komórkę javascript na górę, uruchomić ją, a następnie użyć "Komórka> Uruchom wszystko poniżej".
Mahmoud Elagdar

2
Dlaczego właściwie potrzebujemy javascript? nic bardziej natywnego?
matanster

1
Niepowodzenie w Jupyter Lab:Javascript Error: IPython is not defined
magiczne odrodzenie

27

Na Jupyter 3.0 działa następująco. Tutaj pokazuję całą ścieżkę na serwerze Jupyter, a nie tylko nazwę notatnika:

Aby zapisać w NOTEBOOK_FULL_PATHbieżącym interfejsie notebooka:

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

Aby go następnie wyświetlić:

print("NOTEBOOK_FULL_PATH:\n", NOTEBOOK_FULL_PATH)

Uruchomienie pierwszej komórki JavaScript nie daje żadnych wyników. Uruchomienie drugiej komórki Pythona daje coś takiego:

NOTEBOOK_FULL_PATH:
 /user/zeph/GetNotebookName.ipynb

4
To jest bardzo czyste. Jak w takim razie wywołać kod JavaScript z funkcji Pythona?
Lukas,

Hmmmm ... może w takim przypadku należy dodać do portu dwukropek i numer portu?
Zephaniah Grunschlag

3
To jest ścieżka względna, a nie pełna ścieżka
Ivelin

Nie obejmuje to również ustawienia c.NotebookApp.notebook_dir.
sappjw

4
Dostaję Javascript Error: IPython is not defined. Jak mogę załadować IPython dla javascript
zozo

25

Wygląda na to, że nie mogę komentować, więc muszę to opublikować jako odpowiedź.

Rozwiązanie zaakceptowane przez @iguananaut i aktualizacja @mbdevpl wydają się nie działać z najnowszymi wersjami notebooka. Naprawiłem to, jak pokazano poniżej. Sprawdziłem to na Pythonie 3.6.1 + Notebook v5.0.0 oraz na Pythonie v3.6.5 i 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

Jak stwierdzono w dokumentacji, działa to tylko wtedy, gdy nie ma uwierzytelnienia lub uwierzytelnianie jest oparte na tokenach.

Zwróć uwagę, że, jak donoszą również inni, metoda oparta na Javascript nie wydaje się działać podczas wykonywania polecenia „Uruchom wszystkie komórki” (ale działa podczas wykonywania komórek „ręcznie”), co było dla mnie przełomem.


Czy jest do tego jakaś biblioteka?
matanster

Awaria metod Javascript była również dla mnie przełomem. Dziękujemy za opublikowanie tej alternatywy!
przyjęcie

Muszę zamienić srv ['notebook_dir'] na z jupyter_core.paths import jupyter_config_dir; z traitlets.config import Config; c = Config (); file_path = os.path.join (jupyter_config_dir (), 'jupyter_notebook_config.py'); exec (open (ścieżka_pliku) .read ()); root_dir = c ['FileContentsManager'] ['root_dir']
Dave Babbitt,

14

Ipyparams Pakiet może to zrobić bardzo łatwo.

import ipyparams
currentNotebook = ipyparams.notebook_name

Wydaje się, że jest to lepsza odpowiedź niż przyjęta na górze.
alejandro

1

Zakładając, że masz hosta, port i token uwierzytelniający serwera Jupyter Notebook, powinno to działać. Opiera się na tej odpowiedzi .

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()]

Przykładowe użycie:

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

0

Kolejne hakerskie rozwiązanie, ponieważ mój serwer notebooka może się zmienić. Zasadniczo drukujesz losowy ciąg, zapisujesz go, a następnie szukasz pliku zawierającego ten ciąg w katalogu roboczym. Czas jest potrzebny, ponieważ funkcja save_checkpoint jest asynchroniczna.

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

Wszystkie rozwiązania oparte na Json zawodzą, jeśli wykonujemy więcej niż jedną komórkę naraz, ponieważ wynik będzie gotowy dopiero po zakończeniu wykonywania (nie jest to kwestia użycia uśpienia lub czekania w dowolnym momencie, sprawdź to sam, ale pamiętaj o ponownym uruchomieniu jądra) i uruchom wszystkie testy)

Opierając się na poprzednich rozwiązaniach, pozwala to uniknąć używania magii %% na wypadek, gdybyś musiał umieścić ją w środku innego kodu:

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))

W przypadku Pythona 3, następujące, oparte na odpowiedzi @Iguananaut i zaktualizowane pod kątem najnowszego Pythona i prawdopodobnie wielu serwerów, będą działać:

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}]')
    
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.