web-dev-qa-db-fra.com

Comment puis-je vérifier si le code est exécuté dans le cahier IPython?

J'ai quelques exemples de code Python que j'aimerais partager et qui devraient faire la même chose s'ils sont exécutés dans le terminal Python/IPython ou dans le cahier IPython.

Comment puis-je vérifier à partir de mon code Python s'il est exécuté dans le cahier IPython?

49
Christoph

La question est de savoir ce que vous voulez exécuter différemment.

Nous faisons de notre mieux avec IPython pour empêcher le noyau de savoir à quel type d’interface est connecté, et vous pouvez même avoir un noyau connecté à plusieurs interfaces différentes en même temps. Même si vous pouvez jeter un coup d'œil au type de stderr/out pour savoir si vous êtes ou non dans un noyau ZMQ, cela ne vous garantit pas ce que vous avez de l'autre côté. Vous pourriez même n'avoir aucune interface du tout.

Vous devriez probablement écrire votre code de manière indépendante du frontal, mais si vous voulez afficher différentes choses, vous pouvez utiliser le système d’affichage rich (lien épinglé à la version 4.x de IPython) pour afficher différentes choses en fonction de la frontend, mais le frontend choisira, pas la bibliothèque.

10
Matt

Pour vérifier si vous êtes dans un cahier, ce qui peut être important, par exemple. pour déterminer quelle sorte de barre de progression utiliser, cela a fonctionné pour moi:

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

Ce qui suit a fonctionné pour mes besoins:

get_ipython().__class__.__name__

Il renvoie 'TerminalInteractiveShell' sur un terminal IPython, 'ZMQInteractiveShell' sur Jupyter (notebook AND qtconsole) et échoue (NameError) sur un interpréteur Python standard. La méthode get_python() semble être disponible par défaut dans l'espace de noms global au démarrage d'IPython.

Envelopper dans une fonction 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

Ce qui précède a été testé avec Python 3.5.2, IPython 5.1.0 et Jupyter 4.2.1 sur macOS 10.12 et Ubuntu 14.04.4 LTS.

21
Gustavo Bezerra

Vous pouvez vérifier si python est en mode interactive à l'aide de l'extrait suivant [1] :

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

J'ai trouvé cette méthode très utile car je fais beaucoup de prototypage dans le cahier. À des fins de test, j'utilise des paramètres par défaut. Sinon, je lis les paramètres de sys.argv.

from sys import argv

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

Récemment, j'ai rencontré un bug dans le cahier Jupyter qui nécessite une solution de contournement et je voulais le faire sans perdre la fonctionnalité des autres shells. J'ai réalisé que (solution de keflavich } _ ne fonctionne pas dans ce cas, car get_ipython() n'est disponible que directement à partir du bloc-notes, et non à partir de modules importés. J'ai donc trouvé un moyen de détecter à partir de mon module s'il est importé et utilisé depuis un bloc-notes Jupyter ou non:

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

Les commentaires sont appréciés si cela est suffisamment robuste.

De la même manière, il est possible d’obtenir des informations sur le client et la version d’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']
10
deeenes

Pour autant que je sache, voici 3 types d’ipython utilisant ipykernel

  1. ipython qtconsole ("qtipython" pour faire court)
  2. IPython dans spyder ("spyder" en abrégé)
  3. IPython dans le cahier jupyter ("jn" en abrégé)

utiliser 'spyder' in sys.modules peut distinguer spyder

mais pour qtipython et jn sont difficiles à distinguer cause

ils ont les mêmes sys.modules et la même configuration IPython: get_ipython().config

Je trouve un différent entre qtipython et jn:

première exécution os.getpid() dans IPython Shell obtenir le numéro de pid

puis lancez ps -ef|grep [pid number]

mon pid qtipython est 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

mon pid jn est 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

le différent de qtipython et jn est le nom json de l'ipython, le nom json de jn est plus long que celui de qtipython

alors, nous pouvons détecter automatiquement tous les environnements Python en suivant le code:

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)

les codes sources sont ici: Détection Python Environment, particulièrement distingué Spyder, Jupyter notebook, Qtconsole.py

1
Yang

Ce qui suit illustre les cas de https://stackoverflow.com/a/50234148/1491619 sans avoir à analyser le résultat de ps

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
1
Bob Weigel

Je recommanderais d'éviter de détecter une interface spécifique car il y a trop d'entre eux . Au lieu de cela, vous pouvez simplement tester si vous utilisez l'environnement iPython:

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

L'avis ci-dessus renvoie True si vous appelez running_from_ipython à partir de la ligne de commande Python habituelle. Lorsque vous l'appelez depuis Jupyter Notebook, JupyterHub, iPython Shell, Google Colab, etc., il renvoie True.

0
Shital Shah

J'utilise Django Shell Plus pour lancer IPython et je souhaitais que l'option 'exécuter dans un ordinateur portable' soit disponible en tant que valeur des paramètres Django. get_ipython() n'est pas disponible lors du chargement des paramètres, donc je l'utilise (ce qui n'est pas pare-balles, mais suffisant pour les environnements de développement locaux dans lesquels il est utilisé):

import sys

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