¿Cómo puedo verificar si el código se ejecuta en el cuaderno de IPython?


89

Tengo un ejemplo de código de Python que me gustaría compartir y que debería hacer algo diferente si se ejecuta en el terminal Python / IPython o en el cuaderno de IPython.

¿Cómo puedo verificar en mi código Python si se está ejecutando en el cuaderno IPython?


3
Sugiero aceptar la respuesta de Gustavo Bezerra . La respuesta actualmente aceptada no responde a la pregunta, y la respuesta de Gustavo es la respuesta con la puntuación más alta que todavía funciona en la última versión de Jupyter Notebook.
Mark Amery

Respuestas:


9

La pregunta es qué desea ejecutar de manera diferente.

Hacemos nuestro mejor esfuerzo en IPython para evitar que el kernel sepa a qué tipo de frontend está conectado, y de hecho, incluso puede tener un kernel conectado a muchas frontends diferentes al mismo tiempo. Incluso si puede echar un vistazo al tipo de stderr/outpara saber si está en un kernel ZMQ o no, no le garantiza lo que tiene en el otro lado. Incluso podría no tener ninguna interfaz.

Probablemente debería escribir su código de una manera independiente de la interfaz, pero si desea mostrar diferentes cosas, puede usar el sistema de visualización enriquecido (enlace anclado a la versión 4.x de IPython) para mostrar diferentes cosas dependiendo de la interfaz, pero el la interfaz elegirá, no la biblioteca.


2
El enlace anterior al sistema de visualización enriquecida de IPython está roto. Aquí está el enlace a la documentación actual: ipython.org/ipython-doc/dev/config/integrating.html , y aquí hay un enlace a algunos buenos ejemplos: nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch

2
Tengo un problema como este en mi módulo de dibujo . Necesito importar la llamada matplotlib.use ("Agg") allí para que travis-ci permita guardar dibujos (ver stackoverflow.com/questions/4706451/… ) Pero esto genera una advertencia en el cuaderno UserWarning: Esta llamada a matplotlib.use () no tiene ningún efecto porque el backend ya ha sido elegido; ¿Cómo solucionar esto?
Dr. Goulu

30
Tengo un ejemplo: barras de progreso. El emulador de terminal de portátil de Jupyter no admite caracteres de control de terminal extendido como \x1b[A(subir), por lo que no es posible imprimir barras anidadas . No hay problema con ipywidgets , podemos usar widgets nativos de Jupyter para mostrar barras de progreso. Pero luego tenemos dos formas diferentes de mostrar una barra de progreso, y una aplicación puede querer saber cuál es el entorno de visualización para adaptar e imprimir la barra compatible.
gaborous

2
por ejemplo, quiero configurar la configuración de IPython para que siempre se ejecute %matplotlib inlinecuando actúa como un cuaderno, pero no en una terminal, ya que no es necesario.
Ciprian Tomoiagă

3
Si bien esta es una opinión perfectamente válida, esta respuesta no aborda la pregunta real. No importa cuánto desee que sea, de lo contrario, siempre habrá diferencias en el comportamiento que pueden ser importantes.
Christopher Barber

69

Lo siguiente funcionó para mis necesidades:

get_ipython().__class__.__name__

Vuelve 'TerminalInteractiveShell'en un terminal IPython, 'ZMQInteractiveShell'en Jupyter (notebook Y qtconsole) y falla ( NameError) en un intérprete de Python normal. El método get_python()parece estar disponible en el espacio de nombres global de forma predeterminada cuando se inicia IPython.

Envolviéndolo en una función simple:

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

Lo anterior se probó con Python 3.5.2, IPython 5.1.0 y Jupyter 4.2.1 en macOS 10.12 y Ubuntu 14.04.4 LTS


5
Encendido jupyter console, lamentablemente get_ipython()devuelve una instancia de ZMQInteractiveShelltambién
Josh Bode

7
Si alguien está interesado en detectar si el portátil se está ejecutando en Google Colab, puede verificar esto:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz

3
Esto solo funciona para el código en el cuaderno. No funciona si la función está en un paquete importado.
Christopher Barber

4
@ChristopherBarber Eso no es lo que veo. Si pego esta función en un archivo y test.pyluego ejecuto from test import isnotebook; print(isnotebook())en un Jupyter Notebook, se imprime True. (Probado en las versiones 5.2.1 y 6.0.1 del servidor Notebook.)
Mark Amery

Pensé que había algún caso que no me funcionó, pero desafortunadamente no recuerdo los detalles. Quizás ya no sea un problema o quizás simplemente estaba confundido.
Christopher Barber

41

Para verificar si está en un cuaderno, lo que puede ser importante, por ejemplo, al determinar qué tipo de barra de progreso usar, esto funcionó para mí:

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
En mi IPython-Notebook (IPython versión 3.1), cfg['IPKernelApp']['parent_appname']es un IPython.config.loader.LazyConfigValue, que no se compara Truecon"iypthon-notebook"
Dux

5
@juanjux get_ipython devuelve una IPython.kernel.zmq.zmqshell.ZMQInteractiveShellinstancia en ipynb (Jupyter) y un IPython.terminal.interactiveshell.TerminalInteractiveShellREPL en una terminal, en caso de que necesite diferenciar entre computadoras portátiles y terminales / consolas (lo que afecta el trazado).
placas

4
^ por lo tanto, puede reemplazar el interior del trybloque con:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747

Como @Dux, esto no me funciona; siempre devuelve falso, incluso en un cuaderno. Sospeche que esta respuesta se volvió obsoleta con la introducción de algún tipo de sistema de carga de configuración perezoso.
Mark Amery

Tenga en cuenta también que su configuración puede volver como un dictado vacío, en cuyo caso necesitaría agregar KeyError al bloque except. Sin embargo, probablemente sea mejor usar código basado en la respuesta de Gustavo Bezerra. Aunque obtengo una configuración vacía, obtengo shell='PyDevTerminalInteractiveShell'al inspeccionar el nombre de la clase.
hlongmore

28

Puede verificar si Python está en modo interactivo con el siguiente fragmento [1] :

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

Este método me ha resultado muy útil porque hago muchos prototipos en el portátil. Para propósitos de prueba, utilizo parámetros predeterminados. De lo contrario, leo los parámetros de sys.argv.

from sys import argv

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

Después de la implementación de autonotebook, puede saber si está en un cuaderno usando el siguiente código.

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 ():> importar main como main> return not hasattr (main, ' file ')> print is_interactive ()" True
marscher

3
is_interactive()no distingue entre portátil y consola.
krock

1
Otra advertencia, la emisión de un %runipython no es interactivo. Se podría argumentar que debería serlo, pero sigue siendo un problema.
dirkjot

Para otros prototipos en el portátil, la variante del enfoque de Till que se presenta aquí podría ser útil.
Wayne

La segunda mitad de esta respuesta es útil, pero la primera mitad (aproximadamente is_interactive) me parece básicamente irrelevante para la pregunta. También es de dudosa exactitud; como señala @marscher, cuenta todo lo que se ejecuta usando python -ccomo si estuviera en modo "interactivo" aunque esto no sea cierto. No quiero hacerlo yo mismo ya que no es mi respuesta, pero creo que esto se mejoraría simplemente eliminando toda la primera mitad de la respuesta.
Mark Amery

17

Recientemente encontré un error en el cuaderno Jupyter que necesita una solución, y quería hacerlo sin perder funcionalidad en otros shells. Me di cuenta de que la solución de keflavich no funciona en este caso, porque get_ipython()solo está disponible directamente desde el portátil y no desde módulos importados. Entonces encontré una manera de detectar desde mi módulo si es importado y usado desde un cuaderno Jupyter o no:

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

Se agradecen los comentarios si esto es lo suficientemente sólido.

De manera similar, es posible obtener información sobre el cliente y también sobre la versión de 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, estoy usando Fedora 23 Jupyter, y se 'Ipython' in sys.modulesevalúa como False. ¿Quizás te refieres 'IPython' in sys.modules? Esto es Trueen mi entorno de Jupyter. El sys.modulesdiccionario tampoco incluye la 'ipykernel'clave, cuando se ejecuta dentro de una computadora portátil.
maxschlepzig

2
Esta es la mejor respuesta hasta ahora, en mi opinión. Corto y dulce.
danielpcox

3

Probado para Python 3.7.3

Las implementaciones de CPython tienen el nombre __builtins__disponible como parte de sus globales que por cierto. se puede recuperar mediante la función globals ().
Si un script se está ejecutando en un entorno Ipython, entonces __IPYTHON__debería ser un atributo de __builtins__.
Por lo tanto, el código a continuación devuelve Truesi se ejecuta bajo Ipython o de lo contrario daFalse

hasattr(__builtins__,'__IPYTHON__')

2

A continuación, se capturan los casos de https://stackoverflow.com/a/50234148/1491619 sin necesidad de analizar la salida deps

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

Para mí, esto sólo demuestra jupytersi se trata de una jupyter console, jupyter qtconsoleo jupyter notebook.
Luke Davis

2

Recomendaría evitar detectar frontend específicos porque hay demasiados . En su lugar, puede probar si está ejecutando desde el entorno de iPython:

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

Volverá arriba Falsesi está invocando running_from_ipythondesde la línea de comando habitual de Python. Cuando lo invoca desde Jupyter Notebook, JupyterHub, iPython shell, Google Colab, etc., volverá True.


No me funciona: cuando pruebo esto en Jupyter Notebook en Ubuntu con Python3, get_ipython()regresa <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
protagonista

El problema con este enfoque es que no resuelve la pregunta del OP: "¿Cómo puedo verificar desde mi código Python si se está ejecutando en el cuaderno IPython ?" (énfasis mío). La cáscara IPython no es un portátil, pero cuando lo ejecuto en mi consola Python en PyCharm, consigo get_ipython() is not Noneregresar True.
hlongmore

hm, ¿cómo puedo detectar si estoy ejecutando en jupyter vs. voila?
NTG

2

Todo lo que tiene que hacer es colocar estas dos celdas al principio de su cuaderno:

Celda 1: (marcada como "código"):

is_notebook = True

Celda 2: (marcada como "Raw NBConvert"):

is_notebook = False

La primera celda siempre se ejecutará, pero la segunda celda solo se ejecutará cuando exporte el cuaderno como una secuencia de comandos de Python.

Más tarde, puede comprobar:

if is_notebook:
    notebook_code()
else:
    script_code()

Espero que esto ayude.


2

Qué tal algo como esto:

import sys

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

print(inJupyter);

1

Hasta donde yo sé, aquí tiene 3 tipos de ipython que usaban ipykernel

  1. ipython qtconsole ("qtipython" para abreviar)
  2. IPython en spyder ("spyder" para abreviar)
  3. IPython en el cuaderno jupyter ("jn" para abreviar)

utilizar 'spyder' in sys.modules puede distinguir spyder

pero para qtipython y jn son difíciles de distinguir porque

tienen la misma sys.modulesconfiguración de IPython:get_ipython().config

Encuentro una diferencia entre qtipython y jn:

primer intento os.getpid() en el shell de IPython obtiene el número pid

entonces corre ps -ef|grep [pid number]

mi pid qtipython es 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

mi jn pid es 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

lo diferente de qtipython y jn es el nombre json de ipython, el nombre json de jn es más largo que el de qtipython

entonces, podemos detectar automáticamente todo el entorno Python siguiendo el código:

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)

el código fuente está aquí: Detección del entorno de Python, distinguir especialmente Spyder, cuaderno Jupyter, Qtconsole.py


0

Estoy usando Django Shell Plus para iniciar IPython, y quería que 'ejecutar en el cuaderno' estuviera disponible como un valor de configuración de Django. get_ipython()no está disponible al cargar la configuración, por lo que uso esto (que no es a prueba de balas, pero lo suficientemente bueno para los entornos de desarrollo local en los que se usa):

import sys

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

0

Suponiendo que tenga el control de Jupyter Notebook, podría:

  1. establezca un valor de entorno en una celda que use esto como una bandera en su código . Coloque un comentario único en esa celda (o en todas las celdas que desee excluir)

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Exporte el cuaderno como un script de Python para usarlo en un contexto diferente. La exportación excluiría las celdas comentadas y, posteriormente, el código que establece el valor del entorno. Nota: reemplace your_notebook.ipynb con el nombre de su archivo de cuaderno real.

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

Esto generará un archivo que no tendrá el indicador de entorno jupyter configurado, lo que permitirá que el código que lo usa se ejecute de manera determinista.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.