ฉันจะรับชื่อ IPython / Jupyter Notebook ปัจจุบันได้อย่างไร


87

ฉันพยายามรับชื่อ NoteBook ปัจจุบันเมื่อเรียกใช้สมุดบันทึก IPython ฉันรู้ว่าฉันสามารถมองเห็นได้ที่ด้านบนของโน้ตบุ๊ก สิ่งที่ฉันเป็นหลังจากสิ่งที่ชอบ

currentNotebook = IPython.foo.bar.notebookname()

ฉันต้องการรับชื่อในตัวแปร


คุณพยายามทำอะไรกับมัน? จากการออกแบบเคอร์เนล (บิตที่รันโค้ด) ไม่ทราบเกี่ยวกับส่วนหน้า (บิตที่เปิดสมุดบันทึก)
Thomas K

7
สวัสดีฉันต้องการใช้กับ nbconvert เพื่อทำให้สมุดบันทึกเป็นกระบวนการสร้าง latex / pdf โดยอัตโนมัติ สมุดบันทึกของฉันทำงานจากระยะไกล หลังจากจบชั้นเรียนแล้วนักเรียนสามารถดาวน์โหลดผลการเรียนในรูปแบบ pdf ได้
Tooblippe

1
คำตอบของ P. Toccaceliทำงานได้ดีกับ JupyterLab (1.1.4) (โน้ตบุ๊ก 5.6.0) เวอร์ชันล่าสุดและไม่ต้องใช้จาวาสคริปต์
joelostblom

1
ที่เกี่ยวข้อง: github.com/jupyter/notebook/issues/1000#issuecomment-359875246
ถึง

บางคนได้ผลและสร้างแพ็คเกจ 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 () ไม่ทำงานอีกต่อไปต้องระบุชื่อไฟล์
Purrell

2
บางการปรับปรุง: แทนที่จะตอนนี้มันเป็นเพียงfrom IPython.lib import kernel from IPython import kernelนอกจากนี้แทนที่จะใช้คีย์ 'ชื่อ' ในพจนานุกรมให้ใช้คีย์ 'เส้นทาง'
Tristan Reid

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 Kernel ด้วยคำสั่งที่ตั้งค่าตัวแปร 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
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

ตรงกันข้ามกับวิธีแก้ปัญหาแรกการแก้ไขชื่อโน้ตบุ๊กจะได้รับการอัปเดตทันทีและไม่จำเป็นต้องรีเฟรชโน้ตบุ๊ก


บางทีฉันอาจพลาดบางอย่างไป แต่คุณจะเรียกใช้โค้ดจาวาสคริปต์จาก python ได้อย่างไร
Artjom B.

7
นอกจากนี้ยังสามารถเรียกใช้จาวาสคริปต์จากภายใน python โดยใช้วิธีการแสดงผลที่ใช้กับวัตถุจาวาสคริปต์เช่นdef getname(): display(Javascript('IPython.notebook.kernel.execute("theNotebook = " + "\'"+IPython.notebook.notebook_name+"\'");'))
Jakob

ฉันจะแก้ไขสิ่งนี้เพื่อรับเส้นทางของสมุดบันทึกได้อย่างไร
Pedro M Duarte

@PedroMDuarte: คุณสามารถใช้ IPython.notebook.notebook_path ใน javascript สำหรับ 'thename' ในสคริปต์ด้านบนเพื่อรับค่านั้น
Tristan Reid

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

10
ด้วยเหตุผลบางประการสิ่งนี้ใช้ได้เฉพาะเมื่อฉันเรียกใช้เซลล์จาวาสคริปต์ "ด้วยตนเอง" ถ้าฉันเรียกใช้สมุดบันทึกเต็มเซลล์ที่สองล้มเหลว คิดว่าทำไม?
Pierre-Antoine

ฉันเดาด้วยเหตุผลบางประการหากตัวแปรถูกแก้ไขจาก javascript แล้วเข้าถึงจาก python แท้ในการเรียกเดียวกันเวอร์ชัน python จะไม่เห็นการอัปเดตและจะแทนที่เวอร์ชันจาวาสคริปต์ด้วย ดังนั้นฉันเดาว่าคุณอาจย้ายเซลล์จาวาสคริปต์ไปด้านบนเรียกใช้จากนั้นใช้ "Cell> Run All Bellow"
Mahmoud Elagdar

2
ทำไมเราต้องใช้จาวาสคริปต์จริง ๆ ? ไม่มีอะไรพื้นเมืองอีกแล้ว?
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 ได้อย่างไร?
Lukas

อืม ... บางทีในกรณีนั้นคุณควรต่อท้ายพอร์ตด้วยโคลอนตามด้วยหมายเลขพอร์ต?
Zephaniah Grunschlag

3
นี่คือเส้นทางสัมพัทธ์ไม่ใช่เส้นทางเต็ม
Ivelin

นอกจากนี้ยังไม่รวมการตั้งค่าของc.NotebookApp.notebook_dir.
sappjw

4
Javascript Error: IPython is not definedฉันได้รับ ฉันจะโหลด IPython สำหรับ javascript ได้อย่างไร
zozo

26

ดูเหมือนว่าฉันไม่สามารถแสดงความคิดเห็นได้ดังนั้นฉันจึงต้องโพสต์สิ่งนี้เป็นคำตอบ

โซลูชันที่ยอมรับโดย @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

ตามที่ระบุไว้ใน docstring สิ่งนี้ใช้ได้เฉพาะเมื่อไม่มีการพิสูจน์ตัวตนหรือการตรวจสอบความถูกต้องเป็นแบบโทเค็น

โปรดทราบว่าตามที่รายงานโดยคนอื่น ๆ ดูเหมือนว่าวิธีการที่ใช้ Javascript จะไม่ได้ผลเมื่อเรียกใช้ "เรียกใช้เซลล์ทั้งหมด" (แต่ใช้ได้ผลเมื่อเรียกใช้เซลล์ "ด้วยตนเอง") ซึ่งเป็นตัวทำลายข้อตกลงสำหรับฉัน


มีห้องสมุดสำหรับสิ่งนี้หรือไม่?
matanster

ความล้มเหลวของวิธีการ Javascript เป็นตัวทำลายข้อตกลงสำหรับฉันเช่นกัน ขอบคุณที่โพสต์ทางเลือกนี้!
การริเริ่ม

ฉันต้องแทนที่ srv ['notebook_dir'] ด้วยจาก jupyter_core.paths import jupyter_config_dir; จาก traitlets.config นำเข้า Config; c = กำหนดค่า (); file_path = os.path.join (jupyter_config_dir (), 'jupyter_notebook_config.py'); exec (เปิด (file_path) .read ()); root_dir = c ['FileContentsManager'] ['root_dir']
Dave Babbitt

15

ipyparamsแพคเกจสามารถทำเช่นนี้สวยได้อย่างง่ายดาย

import ipyparams
currentNotebook = ipyparams.notebook_name

1
ดูเหมือนจะเป็นคำตอบที่ดีกว่าคำตอบที่ได้รับการยอมรับในอันดับต้น
alejandro

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

ยังเป็นอีกวิธีแก้ปัญหาที่แฮ็กเนื่องจากเซิร์ฟเวอร์โน้ตบุ๊กของฉันสามารถเปลี่ยนแปลงได้ โดยทั่วไปคุณจะพิมพ์สตริงแบบสุ่มบันทึกแล้วค้นหาไฟล์ที่มีสตริงนั้นในไดเร็กทอรีการทำงาน จำเป็นต้องใช้ 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)

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}]')
    
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.