Làm cách nào để lấy tên Máy tính xách tay IPython / Jupyter hiện tại


85

Tôi đang cố lấy tên NoteBook hiện tại khi chạy sổ ghi chép IPython. Tôi biết tôi có thể nhìn thấy nó ở đầu cuốn sổ. Tôi là gì sau một cái gì đó như thế nào

currentNotebook = IPython.foo.bar.notebookname()

Tôi cần lấy tên trong một biến.


Bạn đang cố gắng làm gì với nó? Theo thiết kế, hạt nhân (bit chạy mã) không biết về giao diện người dùng (bit mở sổ ghi chép).
Thomas K

7
Xin chào, tôi muốn sử dụng nó với nbconvert để tự động hóa quá trình tạo sổ tay sang latex / pdf. Máy tính xách tay của tôi chạy từ xa. sau một lớp học, sinh viên có thể tải xuống phiên bản pdf của kết quả của họ.
Tooblippe

1
Câu trả lời của P.Toccaceli hoạt động tốt với các phiên bản mới đây của JupyterLab (1.1.4) (notebook 5.6.0) và không yêu cầu javascript.
joelostblom


Một số đã làm việc và tạo một gói pip: pypi.org/project/ipynbname cài đặt bởipip install ipynbname
NeoTT

Câu trả lời:


24

Như đã đề cập, có lẽ bạn không thực sự được cho là có thể làm được điều này, nhưng tôi đã tìm ra cách. Tuy nhiên, đó là một vụ hack rực lửa vì vậy đừng dựa vào điều này chút nào:

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

Tôi đã cập nhật câu trả lời của mình để đưa vào giải pháp ít nhất là "hoạt động" trong IPython 2.0 với một bài kiểm tra đơn giản. Có thể không đảm bảo đưa ra câu trả lời chính xác nếu có nhiều sổ ghi chép được kết nối với cùng một hạt nhân, v.v.


connection_file_path = kernel.get_connection_file () không hoạt động nữa, tên tệp là bắt buộc.
Purrell

2
Một số cập nhật: Thay vì from IPython.lib import kernelbây giờ chỉ là from IPython import kernel. Ngoài ra thay vì sử dụng chìa khóa 'tên' trong từ điển, sử dụng phím 'path'
Tristan Reid

1
Như được quảng cáo bởi chính người trả lời, câu trả lời này không hoạt động cho IPython mới nhất. Tôi đã tạo một phiên bản mà dường như làm việc với IPython 4.2.0 bằng Python 3.5: gist.github.com/mbdevpl/f97205b73610dd30254652e7817f99cb
mbdevpl

1
Kể từ phiên bản 4.3.0, bạn cần cung cấp mã thông báo xác thực. Điều này có thể được truy xuất bằng cách sử dụng notebook.notebookapp.list_running_servers().
yingted

1
Nếu bạn có nhiều máy chủ đang chạy, bạn có thể kiểm tra xem tiến trình cha của hạt nhân đang nghe trên cổng nào, nó sẽ cho bạn biết máy chủ nào cần kết nối (hoặc bạn có thể chỉ cần kết nối với mọi máy chủ Jupyter cục bộ và kiểm tra xem máy chủ nào đang chạy hạt nhân của bạn).
yingted

40

Tôi có phần sau hoạt động với IPython 2.0. Tôi quan sát thấy rằng tên của sổ ghi chép được lưu trữ dưới dạng giá trị của thuộc tính 'data-notebook-name'trong <body>thẻ của trang. Vì vậy, ý tưởng đầu tiên là yêu cầu Javascript truy xuất thuộc tính --javascripts có thể được gọi từ codecell nhờ %%javascriptphép thuật. Sau đó, có thể truy cập vào biến Javascript thông qua lệnh gọi đến Hạt nhân Python, bằng lệnh đặt biến Python. Vì biến cuối cùng này được biết đến từ kernel, nên nó cũng có thể được truy cập trong các ô khác.

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

Từ một ô mã Python

print(theNotebook)

Ra []: HowToGetTheNameOfTheNoteBook.ipynb

Một khiếm khuyết trong giải pháp này là khi người ta thay đổi tiêu đề (tên) của sổ ghi chép, thì tên này dường như không được cập nhật ngay lập tức (có thể có một số loại bộ nhớ cache) và cần phải tải lại sổ ghi chép để có quyền truy cập vào tên mới.

[Chỉnh sửa] Khi phản ánh, một giải pháp hiệu quả hơn là tìm kiếm trường nhập cho tên sổ ghi chép thay vì <body>thẻ. Nhìn vào nguồn, có vẻ như trường này có id "notebook_name". Sau đó có thể bắt giá trị này bằng a document.getElementById()và sau đó thực hiện theo cách tiếp cận tương tự như trên. Mã trở thành, vẫn sử dụng phép thuật javascript

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

Sau đó, từ một ô ipython,

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

Trái với giải pháp đầu tiên, các sửa đổi về tên sổ ghi chép được cập nhật ngay lập tức và không cần phải làm mới sổ ghi chép.


Có thể tôi đã bỏ lỡ điều gì đó, nhưng làm thế nào để bạn gọi mã javascript từ python?
Artjom B.

7
Cũng có thể gọi javascript từ bên trong python bằng cách sử dụng phương thức hiển thị được áp dụng cho đối tượng javascript nhưdef getname(): display(Javascript('IPython.notebook.kernel.execute("theNotebook = " + "\'"+IPython.notebook.notebook_name+"\'");'))
Jakob

Làm cách nào để sửa đổi điều này để lấy đường dẫn của sổ ghi chép?
Pedro M Duarte

@PedroMDuarte: Bạn có thể sử dụng IPython.notebook.notebook_path trong javascript cho 'thename' trong tập lệnh trên để nhận giá trị đó.
Tristan Reid

1
Để có được con đường xách tay mà không JS thủ đoạn gian trá:globals()['_dh'][0]
mầm

38

thêm vào các câu trả lời trước,

để có được tên sổ ghi chép, hãy chạy như sau trong một ô:

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

điều này giúp bạn có tên tệp trong nb_name

sau đó để có được đường dẫn đầy đủ, bạn có thể sử dụng như sau trong một ô riêng biệt:

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

1
Sử dụng IPython.notebook.notebook_nameđiều này có thể được thực hiện bằng cách sử dụng%%javascript IPython.notebook.kernel.execute('notebookName = ' + '"' + IPython.notebook.notebook_name + '"')
jfb

9
Vì một số lý do, điều này chỉ hoạt động nếu tôi chạy ô javascript "theo cách thủ công". Nếu tôi chạy toàn bộ sổ ghi chép, ô thứ hai không thành công. Bất kỳ ý tưởng tại sao?
Pierre-Antoine

Tôi đoán vì lý do nào đó, nếu một biến được sửa đổi từ javascript sau đó được truy cập từ python thuần túy trong cùng một lệnh gọi, phiên bản python không thấy bản cập nhật và cũng thay thế phiên bản javascript. Vì vậy, tôi đoán bạn có thể di chuyển ô javascript lên trên cùng, chạy nó, sau đó sử dụng "Cell> Run All Bellow".
Mahmoud Elagdar

2
Tại sao chúng ta cần javascript? không có gì bản địa hơn?
matanster

1
Không thành công trên Jupyter Lab:Javascript Error: IPython is not defined
magicrebirth

27

Trên Jupyter 3.0, các hoạt động sau đây. Ở đây tôi đang hiển thị toàn bộ đường dẫn trên máy chủ Jupyter, không chỉ tên sổ ghi chép:

Để lưu trữ NOTEBOOK_FULL_PATHtrên giao diện người dùng của sổ ghi chép hiện tại:

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

Để sau đó hiển thị nó:

print("NOTEBOOK_FULL_PATH:\n", NOTEBOOK_FULL_PATH)

Chạy ô Javascript đầu tiên không tạo ra kết quả nào. Chạy ô Python thứ hai tạo ra một cái gì đó như:

NOTEBOOK_FULL_PATH:
 /user/zeph/GetNotebookName.ipynb

4
Đây là rất sạch sẽ. Sau đó, bạn sẽ gọi mã Javascript từ một hàm Python như thế nào?
Lukas

Hmmmm ... có lẽ trong trường hợp đó bạn nên nối cổng bằng dấu hai chấm theo sau là số cổng?
Zephaniah Grunschlag

3
Đây là đường dẫn tương đối không phải đường dẫn đầy đủ
Ivelin

Điều này cũng không bao gồm cài đặt của c.NotebookApp.notebook_dir.
sappjw

4
Tôi đang nhận được Javascript Error: IPython is not defined. Làm cách nào để tải IPython cho javascript
zozo

25

Có vẻ như tôi không thể bình luận, vì vậy tôi phải đăng điều này như một câu trả lời.

Giải pháp được chấp nhận bởi @iguananaut và bản cập nhật của @mbdevpl dường như không hoạt động với các phiên bản gần đây của Notebook. Tôi đã sửa nó như hình dưới đây. Tôi đã kiểm tra nó trên Python v3.6.1 + Notebook v5.0.0 và trên Python v3.6.5 và 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

Như đã nêu trong docstring, điều này chỉ hoạt động khi không có xác thực hoặc xác thực dựa trên mã thông báo.

Lưu ý rằng, như những người khác đã báo cáo, phương pháp dựa trên Javascript dường như không hoạt động khi thực thi "Chạy tất cả các ô" (nhưng hoạt động khi thực thi các ô "theo cách thủ công"), đó là một công cụ phá vỡ thỏa thuận đối với tôi.


Có thư viện nào cho cái này không?
matanster

Sự thất bại của các phương thức Javascript cũng là một lỗi đối với tôi. Cảm ơn đã đăng thay thế này!
gumption

Tôi phải thay thế srv ['notebook_dir'] bằng từ jupyter_core.paths import jupyter_config_dir; từ cấu hình nhập traitlets.config; c = Cấu hình (); file_path = os.path.join (jupyter_config_dir (), 'jupyter_notebook_config.py'); execute (open (file_path) .read ()); root_dir = c ['FileContentsManager'] ['root_dir']
Dave Babbitt

14

Các ipyparams gói có thể làm được điều này khá dễ dàng.

import ipyparams
currentNotebook = ipyparams.notebook_name

Đây có vẻ là một câu trả lời tốt hơn câu trả lời được chấp nhận ở trên cùng.
alejandro

1

Giả sử bạn có máy chủ, cổng và mã xác thực của máy chủ Jupyter Notebook, điều này sẽ phù hợp với bạn. Nó dựa trên câu trả lời này .

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

Ví dụ sử dụng:

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

0

Tuy nhiên, một giải pháp hacky khác vì máy chủ notebook của tôi có thể thay đổi. Về cơ bản, bạn in một chuỗi ngẫu nhiên, lưu nó và sau đó tìm kiếm tệp chứa chuỗi đó trong thư mục làm việc. Trong khi đó là cần thiết vì save_checkpoint là không đồng bộ.

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

Tất cả các giải pháp dựa trên Json đều thất bại nếu chúng ta thực thi nhiều ô tại một thời điểm vì kết quả sẽ không sẵn sàng cho đến khi kết thúc quá trình thực thi (vấn đề không phải là sử dụng sleep hay chờ bất cứ lúc nào, hãy tự kiểm tra nhưng nhớ khởi động lại kernel và chạy tất cả mọi thử nghiệm)

Dựa trên các giải pháp trước đây, điều này tránh sử dụng phép thuật %% trong trường hợp bạn cần đặt nó ở giữa một số mã khác:

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

Đối với python 3, phần sau dựa trên câu trả lời của @Iguananaut và được cập nhật cho python mới nhất và có thể nhiều máy chủ sẽ hoạt động:

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}]')
    
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.