Come posso verificare se il codice viene eseguito nel notebook IPython?


89

Ho qualche esempio di codice Python che vorrei condividere che dovrebbe fare qualcosa di diverso se eseguito nel terminale Python / IPython o nel notebook IPython.

Come posso controllare dal mio codice Python se è in esecuzione nel notebook IPython?


3
Suggerisco di accettare la risposta di Gustavo Bezerra . La risposta attualmente accettata non risponde alla domanda e la risposta di Gustavo è la risposta con il punteggio più alto che funziona ancora nell'ultima versione di Jupyter Notebook.
Mark Amery,

Risposte:


8

La domanda è cosa vuoi eseguire in modo diverso.

Facciamo del nostro meglio in IPython per impedire al kernel di sapere a quale tipo di frontend è connesso, e in realtà puoi persino avere un kernel connesso a molti frontend diversi contemporaneamente. Anche se puoi dare un'occhiata al tipo di stderr/outper sapere se sei in un kernel ZMQ o no, non ti garantisce quello che hai dall'altra parte. Potresti anche non avere alcun frontend.

Probabilmente dovresti scrivere il tuo codice in modo indipendente dal frontend, ma se vuoi visualizzare cose diverse, puoi usare il ricco sistema di visualizzazione (collegamento bloccato alla versione 4.x di IPython) per visualizzare cose diverse a seconda del frontend, ma il frontend sceglierà, non la libreria.


2
Il collegamento sopra al Rich Display System IPython è interrotto. Ecco il collegamento alla documentazione corrente: ipython.org/ipython-doc/dev/config/integrating.html , e qui c'è un collegamento ad alcuni ottimi esempi: nbviewer.ipython.org/github/ipython/ipython/blob/master/ ...
Who8MyLunch

2
Ho un problema come questo nel mio modulo di disegno . Devo importare la chiamata matplotlib.use ("Agg") lì per travis-ci per consentire il salvataggio dei disegni (vedere stackoverflow.com/questions/4706451/… ) Ma questo genera un avviso nel notebook Avvertenza utente: questa chiamata a matplotlib.use () non ha effetto perché il backend è già stato scelto; Come risolverlo?
Dr. Goulu

33
Ho un esempio: le barre di avanzamento. L'emulatore di terminale per notebook Jupyter non supporta caratteri di controllo terminale estesi come \x1b[A(sposta su), quindi non è possibile stampare barre nidificate . Nessun problema con ipywidgets , possiamo utilizzare widget nativi di Jupyter per visualizzare le barre di avanzamento. Ma poi abbiamo due modi diversi per visualizzare una barra di avanzamento e un'applicazione potrebbe voler sapere qual è l'ambiente di visualizzazione per adattare e stampare la barra compatibile.
gaborous

2
per esempio, voglio impostare la configurazione IPython in modo che venga eseguita sempre %matplotlib inlinequando agisce come un notebook, ma non in un terminale, poiché non è necessario.
Ciprian Tomoiagă

3
Sebbene questa sia un'opinione perfettamente valida, questa risposta non affronta la domanda reale. Non importa quanto vorresti che fosse, altrimenti ci saranno sempre differenze di comportamento che potrebbero avere importanza.
Christopher Barber il

72

Quanto segue ha funzionato per le mie esigenze:

get_ipython().__class__.__name__

Ritorna 'TerminalInteractiveShell'su un terminale IPython, 'ZMQInteractiveShell'su Jupyter (notebook AND qtconsole) e fail ( NameError) su un normale interprete Python. Il metodo get_python()sembra essere disponibile nello spazio dei nomi globale per impostazione predefinita quando viene avviato IPython.

Avvolgendolo in una semplice funzione:

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

Quanto sopra è stato testato con Python 3.5.2, IPython 5.1.0 e Jupyter 4.2.1 su macOS 10.12 e Ubuntu 14.04.4 LTS


5
Su jupyter console, purtroppo get_ipython()restituisce un'istanza ZMQInteractiveShellanche
Josh Bode

7
Se qualcuno è interessato a rilevare se il notebook è in esecuzione su Google Colab puoi controllare questo:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz

3
Funziona solo per il codice nel notebook. Non funziona se la funzione è in un pacchetto importato.
Christopher Barber il

4
@ChristopherBarber Non è quello che vedo. Se incollo questa funzione in un file e test.pypoi from test import isnotebook; print(isnotebook())eseguo in un notebook Jupyter, viene stampata True. (Testato sulle versioni server Notebook 5.2.1 e 6.0.1.)
Mark Amery

Pensavo ci fosse qualche caso che non ha funzionato per me, ma purtroppo non ricordo i dettagli. Forse non è più un problema o forse ero solo confuso.
Christopher Barber

41

Per verificare se sei in un notebook, che può essere importante ad esempio quando si determina quale tipo di barra di avanzamento utilizzare, questo ha funzionato per me:

def in_ipynb():
    try:
        cfg = get_ipython().config 
        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
            return True
        else:
            return False
    except NameError:
        return False

6
Nel mio IPython-Notebook (IPython versione 3.1), cfg['IPKernelApp']['parent_appname']è una IPython.config.loader.LazyConfigValueche non si confronta con Truecon"iypthon-notebook"
Dux

5
@juanjux get_ipython restituisce IPython.kernel.zmq.zmqshell.ZMQInteractiveShellun'istanza in ipynb (Jupyter) e una IPython.terminal.interactiveshell.TerminalInteractiveShellin un terminale REPL, nel caso in cui sia necessario distinguere tra notebook e terminale / console (che influisce sulla stampa).
piani cottura

4
^ quindi puoi sostituire l'interno del tryblocco con:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747

Come @Dux, questo non funziona per me; restituisce sempre false, anche in un Notebook. Sospetto che questa risposta sia diventata obsoleta con l'introduzione di una sorta di sistema di caricamento della configurazione pigro.
Mark Amery,

Nota anche che la tua configurazione potrebbe tornare come un dict vuoto, nel qual caso dovresti aggiungere KeyError al blocco eccetto. Probabilmente è comunque meglio usare codice basato sulla risposta di Gustavo Bezerra. Anche se ottengo una configurazione vuota, ottengo l' shell='PyDevTerminalInteractiveShell'ispezione del nome della classe.
hlongmore

29

Puoi verificare se Python è in modalità interattiva con il seguente frammento [1] :

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

Ho trovato questo metodo molto utile perché faccio molti prototipi nel notebook. A scopo di test, utilizzo i parametri predefiniti. Altrimenti leggo i parametri da sys.argv.

from sys import argv

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

Dopo l'implementazione di autonotebook, è possibile stabilire se si è in un notebook utilizzando il codice seguente.

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

python -c "def is_interactive ():> import main as main> return not hasattr (main, ' file ')> print is_interactive ()" True
marscher

3
is_interactive()non distingue tra notebook e console.
krock

1
Un altro avvertimento, l'emissione di un %runda ipython non è interattivo. Potresti obiettare che dovrebbe essere, ma è ancora un trucco.
dirkjot

Per altri prototipi nel notebook, la variante dell'approccio di Till qui presentata potrebbe essere utile.
Wayne

La seconda metà di questa risposta è utile, ma la prima metà (circa is_interactive) mi sembra sostanzialmente irrilevante per la domanda. È anche di dubbia correttezza; come fa notare @marscher, conta qualsiasi cosa eseguita utilizzando python -ccome in modalità "interattiva" anche se questo non è vero. Non voglio farlo da solo poiché non è la mia risposta, ma penso che sarebbe migliorato semplicemente eliminando l'intera prima metà della risposta.
Mark Amery,

17

Recentemente ho riscontrato un bug nel notebook Jupyter che necessita di una soluzione alternativa e volevo farlo senza perdere funzionalità in altre shell. Mi sono reso conto che la soluzione di keflavich non funziona in questo caso, perché get_ipython()è disponibile solo direttamente dal notebook e non dai moduli importati. Quindi ho trovato un modo per rilevare dal mio modulo se è importato e utilizzato da un notebook Jupyter o meno:

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

I commenti sono apprezzati se questo è abbastanza solido.

In modo simile è possibile ottenere alcune informazioni sul client e anche sulla versione di IPython:

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']

Hm, sto usando Fedora 23 Jupyter, e lì 'Ipython' in sys.modulesvaluta False. Forse vuoi dire 'IPython' in sys.modules? Questo è Truenel mio ambiente Jupyter. Il sys.modulesdizionario inoltre non include la 'ipykernel'chiave, quando si esegue in un notebook.
maxschlepzig

2
Questa è la migliore risposta finora, IMO. Breve e dolce.
danielpcox

3

Testato per python 3.7.3

Le implementazioni di CPython hanno il nome __builtins__disponibile come parte delle loro globali che btw. può essere recuperato dalla funzione globals ().
Se uno script è in esecuzione in un ambiente Ipython, __IPYTHON__dovrebbe essere un attributo di __builtins__.
Il codice seguente quindi restituisce Truese eseguito in Ipython oppure dàFalse

hasattr(__builtins__,'__IPYTHON__')

2

Quanto segue acquisisce i casi di https://stackoverflow.com/a/50234148/1491619 senza la necessità di analizzare l'output dips

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

Per me, questo a soli spettacoli jupyterche si tratti di una jupyter console, jupyter qtconsoleo jupyter notebook.
Luke Davis

2

Consiglierei di evitare di rilevare frontend specifici perché ce ne sono troppi . Invece puoi semplicemente testare se stai eseguendo dall'ambiente iPython:

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

Sopra tornerà Falsese stai invocando running_from_ipythondalla normale riga di comando di Python. Quando lo richiami da Jupyter Notebook, JupyterHub, iPython shell, Google Colab ecc True., Tornerà .


Non funziona per me - Quando provo questo in Jupyter Notebook su Ubuntu con Python3, get_ipython()restituisce <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
protagonista il

Il problema con questo approccio è che non risolve la domanda dell'OP: "Come posso controllare dal mio codice Python se è in esecuzione nel notebook IPython ?" (enfasi mia). La shell IPython non è un notebook, ma quando la eseguo nella mia console Python in PyCharm, torno get_ipython() is not Noneindietro True.
hlongmore

hm, come posso rilevare se sto utilizzando jupyter vs voilà?
ntg

2

Tutto quello che devi fare è posizionare queste due celle all'inizio del tuo quaderno:

Cella 1: (contrassegnata come "codice"):

is_notebook = True

Cella 2: (contrassegnata come "Raw NBConvert"):

is_notebook = False

La prima cella verrà sempre eseguita, ma la seconda verrà eseguita solo quando esporti il ​​notebook come script Python.

Successivamente, puoi controllare:

if is_notebook:
    notebook_code()
else:
    script_code()

Spero che sia di aiuto.


2

Che ne dici di qualcosa del genere:

import sys

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

print(inJupyter);

1

Per quanto ne so, qui ha 3 tipi di ipython utilizzati ipykernel

  1. ipython qtconsole ("qtipython" in breve)
  2. IPython in spyder ("spyder" in breve)
  3. IPython in jupyter notebook ("jn" in breve)

l'uso 'spyder' in sys.modulespuò distinguere Spyder

ma per qtipython e jn è difficile distinguere la causa

hanno la stessa sys.modulese stessa configurazione IPython:get_ipython().config

Trovo una differenza tra qtipython e jn:

prima esecuzione os.getpid()nella shell IPython ottieni il numero pid

quindi corri ps -ef|grep [pid number]

il mio pid qtipython è 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

il mio jn pid è 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

il diverso di qtipython e jn è il nome json di ipython, il nome json di jn è più lungo di quello di qtipython

quindi, possiamo rilevare automaticamente tutto l'ambiente Python seguendo il codice:

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)

il codice sorgente è qui: Detection Python Environment, Soprattutto distinguere Spyder, Jupyter notebook, Qtconsole.py


0

Sto usando Django Shell Plus per avviare IPython e volevo rendere disponibile "running in notebook" come valore delle impostazioni Django. get_ipython()non è disponibile durante il caricamento delle impostazioni, quindi lo uso (che non è a prova di proiettile, ma abbastanza buono per gli ambienti di sviluppo locale in cui è utilizzato):

import sys

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

0

Supponendo che tu abbia il controllo del Jupyter Notebook potresti:

  1. impostare un valore di ambiente in una cella che lo utilizza come flag nel codice . Inserisci un commento univoco in quella cella (o in tutte le celle che desideri escludere)

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Esporta il notebook come script Python da utilizzare in un contesto diverso. L'esportazione escluderebbe le celle commentate e successivamente il codice che imposta il valore dell'ambiente. Nota: sostituisci your_notebook.ipynb con il nome del tuo file notebook effettivo.

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

Questo genererà un file che non avrà il flag di ambiente jupyter impostato, consentendo l'esecuzione deterministica del codice che lo utilizza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.