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.
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.
pip install ipynbname
Odpowiedzi:
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.
from IPython.lib import kernel
teraz to po prostu from IPython import kernel
. Zamiast używać klucza „nazwa” w słownikach, użyj klucza „ścieżka”
notebook.notebookapp.list_running_servers()
.
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 %%javascript
magii 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.
def getname(): display(Javascript('IPython.notebook.kernel.execute("theNotebook = " + "\'"+IPython.notebook.notebook_name+"\'");'))
globals()['_dh'][0]
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)
IPython.notebook.notebook_name
można to zrobić za pomocą%%javascript IPython.notebook.kernel.execute('notebookName = ' + '"' + IPython.notebook.notebook_name + '"')
Javascript Error: IPython is not defined
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_PATH
bieżą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
c.NotebookApp.notebook_dir
.
Javascript Error: IPython is not defined
. Jak mogę załadować IPython dla javascript
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.
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')
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)
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}]')