Bagaimana saya bisa memeriksa apakah kode dieksekusi di notebook IPython?

89

Saya memiliki beberapa contoh kode Python yang ingin saya bagikan yang seharusnya melakukan sesuatu yang berbeda jika dijalankan di terminal Python / IPython atau di notebook IPython.

Bagaimana cara memeriksa dari kode Python saya jika berjalan di notebook IPython?

Christoph
sumber
3
Saya sarankan untuk menerima jawaban Gustavo Bezerra . Jawaban yang diterima saat ini tidak menjawab pertanyaan, dan jawaban Gustavo adalah jawaban dengan skor tertinggi yang masih berfungsi di Jupyter Notebook versi terbaru.
Mark Amery

Jawaban:

8

Pertanyaannya adalah apa yang ingin Anda lakukan secara berbeda.

Kami melakukan yang terbaik di IPython mencegah kernel mengetahui jenis frontend mana yang terhubung, dan sebenarnya Anda bahkan dapat memiliki kernel yang terhubung ke banyak frontend yang berbeda pada saat yang bersamaan. Bahkan jika Anda dapat mengintip jenis stderr/outuntuk mengetahui apakah Anda menggunakan kernel ZMQ atau tidak, itu tidak menjamin Anda tentang apa yang Anda miliki di sisi lain. Anda bahkan bisa tidak memiliki frontend sama sekali.

Anda mungkin harus menulis kode Anda secara independen frontend, tetapi jika Anda ingin menampilkan hal yang berbeda, Anda dapat menggunakan sistem tampilan yang kaya (tautan disematkan ke versi 4.x dari IPython) untuk menampilkan hal-hal yang berbeda tergantung pada frontend, tetapi frontend akan memilih, bukan perpustakaan.

Matt
sumber
2
Tautan di atas ke Sistem Tampilan Kaya IPython rusak. Berikut ini tautan ke dokumentasi saat ini: ipython.org/ipython-doc/dev/config/integrating.html , dan berikut ini tautan ke beberapa contoh yang bagus: nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch
2
Saya punya masalah seperti ini di modul gambar saya . Saya perlu mengimpor panggilan matplotlib.use ("Agg") di sana untuk travis-ci untuk memungkinkan penyimpanan gambar (lihat stackoverflow.com/questions/4706451/… ) Tapi ini menghasilkan peringatan di notebook UserWarning: Panggilan ini ke matplotlib.use () tidak berpengaruh karena backend telah dipilih; Bagaimana mengatasi ini?
Dr. Goulu
33
Saya punya satu contoh: bilah kemajuan. Emulator terminal notebook Jupyter tidak mendukung karakter kontrol terminal yang diperluas seperti \x1b[A(bergerak ke atas), jadi tidak mungkin untuk mencetak bilah bersarang . Tidak masalah dengan ipywidgets , kami dapat menggunakan widget Jupyter asli untuk menampilkan bilah kemajuan. Tetapi kemudian kami memiliki dua cara berbeda untuk menampilkan bilah kemajuan, dan sebuah aplikasi mungkin ingin tahu apa itu lingkungan tampilan untuk menyesuaikan dan mencetak bilah yang kompatibel.
gaborous
2
misalnya, saya ingin menyetel konfigurasi IPython agar selalu berjalan %matplotlib inlinesaat berfungsi sebagai notebook, tetapi tidak di terminal, karena itu tidak diperlukan.
Ciprian Tomoiagă
3
Meskipun ini adalah pendapat yang sepenuhnya valid, jawaban ini tidak menjawab pertanyaan yang sebenarnya. Tidak peduli seberapa besar Anda menginginkannya jika tidak, akan selalu ada perbedaan dalam perilaku yang mungkin penting.
Christopher Barber
72

Berikut ini bekerja untuk kebutuhan saya:

get_ipython().__class__.__name__

Ia kembali 'TerminalInteractiveShell'pada terminal IPython, 'ZMQInteractiveShell'pada Jupyter (notebook AND qtconsole) dan gagal ( NameError) pada interpreter Python biasa. Metode ini get_python()tampaknya tersedia di namespace global secara default saat IPython dimulai.

Membungkusnya dalam fungsi sederhana:

def isnotebook():
    try:
        shell = get_ipython().__class__.__name__
        if shell == 'ZMQInteractiveShell':
            return True   # Jupyter notebook or qtconsole
        elif shell == 'TerminalInteractiveShell':
            return False  # Terminal running IPython
        else:
            return False  # Other type (?)
    except NameError:
        return False      # Probably standard Python interpreter

Di atas diuji dengan Python 3.5.2, IPython 5.1.0 dan Jupyter 4.2.1 di macOS 10.12 dan Ubuntu 14.04.4 LTS

Gustavo Bezerra
sumber
5
Nyala jupyter console, sayangnya get_ipython()mengembalikan contoh ZMQInteractiveShelljuga
Josh Bode
7
Jika seseorang tertarik untuk mendeteksi apakah notebook tersebut berjalan di Google Colab, Anda dapat memeriksanya:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz
3
Ini hanya berfungsi untuk kode di notebook. Itu tidak berfungsi jika fungsinya ada dalam paket yang diimpor.
Christopher Barber
4
@ChristopherBarber Bukan itu yang saya lihat. Jika saya menempelkan fungsi ini ke dalam file test.pylalu menjalankannya from test import isnotebook; print(isnotebook())di Notebook Jupyter, fungsi ini akan dicetak True. (Diuji pada server Notebook versi 5.2.1 dan 6.0.1.)
Mark Amery
Saya pikir ada beberapa kasus yang tidak berhasil untuk saya, tetapi sayangnya saya tidak ingat detailnya. Mungkin sudah bukan masalah lagi atau mungkin saya hanya bingung.
Christopher Barber
41

Untuk memeriksa apakah Anda menggunakan buku catatan, yang mungkin penting misalnya saat menentukan bilah kemajuan seperti apa yang akan digunakan, ini berhasil untuk saya:

def in_ipynb():
    try:
        cfg = get_ipython().config 
        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
            return True
        else:
            return False
    except NameError:
        return False
keflavich.dll
sumber
6
Dalam Notebook IPython saya (IPython versi 3.1), cfg['IPKernelApp']['parent_appname']adalah IPython.config.loader.LazyConfigValue, yang tidak dapat dibandingkan Truedengan"iypthon-notebook"
Dux
5
@juanjux get_ipython mengembalikan sebuah IPython.kernel.zmq.zmqshell.ZMQInteractiveShellinstance di ipynb (Jupyter) dan IPython.terminal.interactiveshell.TerminalInteractiveShelldi REPL terminal, jika Anda perlu membedakan antara notebook dan terminal / konsol (yang memengaruhi plotting).
kompor
4
^ oleh karena itu Anda dapat mengganti bagian dalam tryblok dengan:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747
Seperti @Dux, ini tidak berhasil untuk saya; selalu mengembalikan false, bahkan di Notebook. Curigai bahwa jawaban ini menjadi usang dengan diperkenalkannya semacam sistem pemuatan konfigurasi yang lambat.
Mark Amery
Perhatikan juga bahwa konfigurasi Anda mungkin kembali sebagai dict kosong, dalam hal ini Anda perlu menambahkan KeyError ke blok kecuali. Namun mungkin lebih baik menggunakan kode berdasarkan jawaban Gustavo Bezerra. Meskipun saya mendapatkan konfigurasi kosong, saya dapatkan shell='PyDevTerminalInteractiveShell'saat memeriksa nama kelas.
hlongmore
29

Anda dapat memeriksa apakah python dalam mode interaktif dengan cuplikan berikut [1] :

def is_interactive():
    import __main__ as main
    return not hasattr(main, '__file__')

Saya menemukan metode ini sangat berguna karena saya melakukan banyak prototipe di notebook. Untuk tujuan pengujian, saya menggunakan parameter default. Jika tidak, saya membaca parameter dari sys.argv.

from sys import argv

if is_interactive():
    params = [<list of default parameters>]
else:
    params = argv[1:]

Setelah penerapan autonotebook, Anda dapat mengetahui apakah Anda berada di buku catatan menggunakan kode berikut.

def in_notebook():
    try:
        from IPython import get_ipython
        if 'IPKernelApp' not in get_ipython().config:  # pragma: no cover
            return False
    except ImportError:
        return False
    return True
Sampai Hoffmann
sumber
python -c "def is_interactive ():> import main as main> return not hasattr (main, ' file ')> print is_interactive ()" True
marscher
3
is_interactive()tidak membedakan antara notebook dan konsol.
krock
1
Peringatan lain, mengeluarkan %rundari ipython adalah non-interaktif. Anda bisa membantahnya, tapi itu masih gotcha.
dirkjot
Untuk prototipe lain di notebook, varian pendekatan Till yang ditampilkan di sini mungkin berguna.
Wayne
Paruh kedua dari jawaban ini berguna, tetapi paruh pertama (tentang is_interactive) menurut saya pada dasarnya tidak relevan dengan pertanyaan itu. Ini juga kebenaran yang meragukan; seperti yang ditunjukkan @marscher, ini menghitung apa pun yang dijalankan menggunakan python -cmode "interaktif" meskipun ini tidak benar. Saya tidak ingin melakukannya sendiri karena ini bukan jawaban saya, tetapi saya pikir ini akan diperbaiki hanya dengan menghapus seluruh paruh pertama jawaban.
Mark Amery
17

Baru-baru ini saya menemukan bug di notebook Jupyter yang memerlukan solusi, dan saya ingin melakukan ini tanpa kehilangan fungsionalitas di shell lain. Saya menyadari bahwa solusi keflavich tidak berfungsi dalam kasus ini, karena get_ipython()hanya tersedia langsung dari notebook, dan bukan dari modul yang diimpor. Jadi saya menemukan cara untuk mendeteksi dari modul saya apakah itu diimpor dan digunakan dari notebook Jupyter atau tidak:

import sys

def in_notebook():
    """
    Returns ``True`` if the module is running in IPython kernel,
    ``False`` if in IPython shell or other Python shell.
    """
    return 'ipykernel' in sys.modules

# later I found out this:

def ipython_info():
    ip = False
    if 'ipykernel' in sys.modules:
        ip = 'notebook'
    elif 'IPython' in sys.modules:
        ip = 'terminal'
    return ip

Komentar akan dihargai jika ini cukup kuat.

Dengan cara serupa dimungkinkan untuk mendapatkan beberapa info tentang klien, dan versi IPython juga:

import sys

if 'ipykernel' in sys.modules:
    ip = sys.modules['ipykernel']
    ip_version = ip.version_info
    ip_client = ip.write_connection_file.__module__.split('.')[0]

# and this might be useful too:

ip_version = IPython.utils.sysinfo.get_sys_info()['ipython_version']
deeenes
sumber
Hm, saya menggunakan Fedora 23 Jupyter, dan ada 'Ipython' in sys.modulesevaluasi ke False. Mungkin maksud Anda 'IPython' in sys.modules? Ini ada Truedi lingkungan Jupyter saya. The sys.moduleskamus juga tidak termasuk 'ipykernel'kunci - saat berjalan di dalam notebook.
maxschlepzig
2
Ini adalah jawaban terbaik sejauh ini, IMO. Pendek dan manis.
danielpcox
3

Diuji untuk python 3.7.3

Implementasi CPython memiliki nama yang __builtins__tersedia sebagai bagian dari global mereka yang btw. bisa diambil oleh function globals ().
Jika skrip berjalan di lingkungan Ipython maka __IPYTHON__harus berupa atribut __builtins__.
Karena itu kode di bawah ini kembali Truejika dijalankan di bawah Ipython atau yang diberikannyaFalse

hasattr(__builtins__,'__IPYTHON__')
Robert Nowak
sumber
2

Berikut ini adalah contoh kasus https://stackoverflow.com/a/50234148/1491619 tanpa perlu mengurai keluaran darips

def pythonshell():
    """Determine python shell

    pythonshell() returns

    'shell' (started python on command line using "python")
    'ipython' (started ipython on command line using "ipython")
    'ipython-notebook' (e.g., running in Spyder or started with "ipython qtconsole")
    'jupyter-notebook' (running in a Jupyter notebook)

    See also https://stackoverflow.com/a/37661854
    """

    import os
    env = os.environ
    shell = 'shell'
    program = os.path.basename(env['_'])

    if 'jupyter-notebook' in program:
        shell = 'jupyter-notebook'
    elif 'JPY_PARENT_PID' in env or 'ipython' in program:
        shell = 'ipython'
        if 'JPY_PARENT_PID' in env:
            shell = 'ipython-notebook'

    return shell
Bob Weigel
sumber
Bagi saya, ini hanya menunjukkan jupyterapakah itu adalah jupyter console, jupyter qtconsole, atau jupyter notebook.
Luke Davis
2

Saya akan merekomendasikan untuk menghindari mendeteksi frontend tertentu karena jumlahnya terlalu banyak . Sebagai gantinya Anda bisa menguji apakah Anda menjalankan dari dalam lingkungan iPython:

def is_running_from_ipython():
    from IPython import get_ipython
    return get_ipython() is not None

Di atas akan ditampilkan Falsejika Anda memanggil running_from_ipythondari baris perintah python biasa. Ketika Anda memanggilnya dari Jupyter Notebook, JupyterHub, iPython shell, Google Colab dll maka itu akan kembali True.

Shital Shah
sumber
Tidak berfungsi untuk saya - Ketika saya mencoba ini di Notebook Jupyter di Ubuntu dengan Python3, get_ipython()kembali <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
protagonis
Masalah dengan pendekatan ini adalah bahwa itu tidak menyelesaikan pertanyaan OP, "Bagaimana saya bisa memeriksa dari kode Python saya jika itu berjalan di notebook IPython ?" (penekanan saya). Shell IPython bukan notebook, tetapi ketika saya menjalankannya di Konsol Python saya di PyCharm, saya get_ipython() is not Nonekembali True.
hlongmore
hm, bagaimana cara mendeteksi jika saya menjalankan jupyter vs. voila?
ntg
2

Yang harus Anda lakukan adalah menempatkan kedua sel ini di awal buku catatan Anda:

Sel 1: (ditandai sebagai "kode"):

is_notebook = True

Sel 2: (ditandai sebagai "Raw NBConvert"):

is_notebook = False

Sel pertama akan selalu dijalankan, tetapi sel kedua hanya akan dijalankan saat Anda mengekspor notebook sebagai skrip Python.

Nanti, Anda bisa mengecek:

if is_notebook:
    notebook_code()
else:
    script_code()

Semoga ini membantu.

Julio Alves
sumber
2

Bagaimana dengan sesuatu yang seperti ini:

import sys

inJupyter = sys.argv[-1].endswith('json')

print(inJupyter);
pengguna431378
sumber
1

Setahu saya disini ada 3 macam ipython yang digunakan ipykernel

  1. ipython qtconsole ("qtipython" singkatnya)
  2. IPython di spyder ("spyder" singkatnya)
  3. IPython di notebook jupyter ("jn" singkatnya)

penggunaan 'spyder' in sys.modulesdapat membedakan spyder

tapi untuk qtipython dan jn susah dibedakan penyebabnya

mereka memiliki sys.moduleskonfigurasi IPython yang sama dan sama:get_ipython().config

Saya menemukan perbedaan antara qtipython dan jn:

jalankan pertama os.getpid()di shell IPython dapatkan nomor pid

lalu lari ps -ef|grep [pid number]

pid qtipython saya adalah 8699 yanglei 8699 8693 4 20:31 ? 00:00:01 /home/yanglei/miniconda2/envs/py3/bin/python -m ipykernel_launcher -f /run/user/1000/jupyter/kernel-8693.json

jn pid saya adalah 8832 yanglei 8832 9788 13 20:32 ? 00:00:01 /home/yanglei/miniconda2/bin/python -m ipykernel_launcher -f /run/user/1000/jupyter/kernel-ccb962ec-3cd3-4008-a4b7-805a79576b1b.json

perbedaan qtipython dan jn adalah nama json ipython, nama json jn lebih panjang dari qtipython

jadi, kita bisa otomatis mendeteksi semua Python Environment dengan kode berikut:

import sys,os
def jupyterNotebookOrQtConsole():
    env = 'Unknow'
    cmd = 'ps -ef'
    try:
        with os.popen(cmd) as stream:
            if not py2:
                stream = stream._stream
            s = stream.read()
        pid = os.getpid()
        ls = list(filter(lambda l:'jupyter' in l and str(pid) in l.split(' '), s.split('\n')))
        if len(ls) == 1:
            l = ls[0]
            import re
            pa = re.compile(r'kernel-([-a-z0-9]*)\.json')
            rs = pa.findall(l)
            if len(rs):
                r = rs[0]
                if len(r)<12:
                    env = 'qtipython'
                else :
                    env = 'jn'
        return env
    except:
        return env

pyv = sys.version_info.major
py3 = (pyv == 3)
py2 = (pyv == 2)
class pyi():
    '''
    python info

    plt : Bool
        mean plt avaliable
    env :
        belong [cmd, cmdipython, qtipython, spyder, jn]
    '''
    pid = os.getpid()
    gui = 'ipykernel' in sys.modules
    cmdipython = 'IPython' in sys.modules and not gui
    ipython = cmdipython or gui
    spyder = 'spyder' in sys.modules
    if gui:
        env = 'spyder' if spyder else jupyterNotebookOrQtConsole()
    else:
        env = 'cmdipython' if ipython else 'cmd'

    cmd = not ipython
    qtipython = env == 'qtipython'
    jn = env == 'jn'

    plt = gui or 'DISPLAY' in os.environ 

print('Python Envronment is %s'%pyi.env)

kode sumbernya ada di sini: Deteksi Lingkungan Python, Terutama membedakan Spyder, notebook Jupyter, Qtconsole.py

Yang
sumber
0

Saya menggunakan Django Shell Plus untuk meluncurkan IPython, dan saya ingin membuat 'berjalan di buku catatan' tersedia sebagai nilai pengaturan Django. get_ipython()tidak tersedia saat memuat pengaturan, jadi saya menggunakan ini (yang tidak anti peluru, tapi cukup baik untuk lingkungan pengembangan lokal yang digunakannya):

import sys

if '--notebook' in sys.argv:
    ENVIRONMENT = "notebook"
else:
    ENVIRONMENT = "dev"
pengguna31415629
sumber
0

Dengan asumsi Anda memiliki kendali atas Notebook Jupyter, Anda dapat:

  1. setel nilai lingkungan dalam sel yang menggunakan ini sebagai bendera dalam kode Anda . Tempatkan komentar unik di sel itu (atau semua sel yang ingin Anda kecualikan)

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Ekspor notebook sebagai skrip python untuk digunakan dalam konteks berbeda. Ekspor akan mengecualikan sel yang diberi komentar dan selanjutnya kode yang menetapkan nilai lingkungan. Catatan: ganti buku_Anda.ipynb dengan nama file buku catatan Anda yang sebenarnya.

    jupyter nbconvert --to script --RegexRemovePreprocessor.patterns = "['^ # exclude_from_export']" your_notebook.ipynb

Ini akan menghasilkan file yang tidak akan memiliki set flag lingkungan jupyter yang memungkinkan kode yang menggunakannya untuk mengeksekusi secara deterministik.

Ron Sims II
sumber