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


89

J'ai un exemple de code Python que j'aimerais partager qui devrait faire quelque chose de différent s'il est exécuté dans le terminal Python / IPython ou dans le notebook IPython.

Comment puis-je vérifier à partir de mon code Python s'il s'exécute dans le bloc-notes IPython?


3
Je suggère d'accepter la réponse de Gustavo Bezerra . La réponse actuellement acceptée ne répond pas à la question, et la réponse de Gustavo est la réponse la mieux notée qui fonctionne toujours dans la dernière version de Jupyter Notebook.
Mark Amery

Réponses:


9

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

Nous faisons de notre mieux dans IPython pour empêcher le noyau de savoir à quel type de frontend est connecté, et en fait, vous pouvez même avoir un noyau connecté à plusieurs frontends différents en même temps. Même si vous pouvez jeter un oeil au type de stderr/outpour savoir si vous êtes dans un noyau ZMQ ou non, cela ne vous garantit pas ce que vous avez de l'autre côté. Vous pourriez même ne pas avoir d'interface du tout.

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


2
Le lien ci-dessus vers le système d'affichage riche IPython est rompu. Voici le lien vers la documentation actuelle: ipython.org/ipython-doc/dev/config/integrating.html , et voici un lien vers de bons exemples: nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch

2
J'ai un problème comme celui-ci dans mon module de dessin . Je dois y importer l'appel matplotlib.use ("Agg") pour que travis-ci autorise l'enregistrement des dessins (voir stackoverflow.com/questions/4706451/… ) Mais cela génère un avertissement dans le notebook UserWarning: Cet appel à matplotlib.use () n'a aucun effet car le backend a déjà été choisi; Comment résoudre ça?
Dr Goulu

30
J'ai un exemple: les barres de progression. L'émulateur de terminal pour notebook Jupyter ne prend pas en charge les caractères de contrôle de terminal étendus tels que \x1b[A(monter), il n'est donc pas possible d'imprimer des barres imbriquées . Pas de problème avec ipywidgets , nous pouvons utiliser des widgets Jupyter natifs pour afficher les barres de progression. Mais alors nous avons deux moyens différents d'afficher une barre de progression, et une application peut vouloir savoir quel est l'environnement d'affichage afin d'adapter et d'imprimer la barre compatible.
gaborous le

2
par exemple, je veux que la configuration IPython s'exécute toujours %matplotlib inlinequand elle agit comme un ordinateur portable, mais pas dans un terminal, car cela n'est pas nécessaire.
Ciprian Tomoiagă

3
Bien qu'il s'agisse d'une opinion parfaitement valable, cette réponse ne répond pas à la question réelle. Peu importe combien vous souhaiteriez que ce soit, sinon il y aura toujours des différences de comportement qui peuvent avoir de l'importance.
Christopher Barber

69

Ce qui suit a fonctionné pour mes besoins:

get_ipython().__class__.__name__

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

Emballer 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


5
On jupyter console, get_ipython()renvoie malheureusement une instance de ZMQInteractiveShellaussi
Josh Bode

7
Si quelqu'un est intéressé à détecter si le notebook fonctionne sur Google Colab, vous pouvez vérifier ceci:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz

3
Cela ne fonctionne que pour le code du bloc-notes. Cela ne fonctionne pas si la fonction est dans un package importé.
Christopher Barber

4
@ChristopherBarber Ce n'est pas ce que je vois. Si je colle cette fonction dans un fichier test.pypuis que je l' exécute from test import isnotebook; print(isnotebook())dans un bloc-notes Jupyter, elle s'imprime True. (Testé sur les versions 5.2.1 et 6.0.1 du serveur Notebook.)
Mark Amery

Je pensais qu'il y avait un cas qui ne fonctionnait pas pour moi, mais malheureusement je ne me souviens pas des détails. Ce n'est peut-être plus un problème ou peut-être étais-je simplement confus.
Christopher Barber

41

Pour vérifier si vous êtes dans un cahier, ce qui peut être important, par exemple pour déterminer le type 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

6
Dans mon IPython-Notebook (version 3.1 IPython), cfg['IPKernelApp']['parent_appname']est un IPython.config.loader.LazyConfigValue, qui ne se compare pas à Trueavec"iypthon-notebook"
Dux

5
@juanjux get_ipython renvoie une IPython.kernel.zmq.zmqshell.ZMQInteractiveShellinstance dans ipynb (Jupyter) et une IPython.terminal.interactiveshell.TerminalInteractiveShelldans un terminal REPL, au cas où vous auriez besoin de faire la différence entre les notebooks et les terminaux / consoles (ce qui affecte le traçage).
plaques de cuisson

4
^ vous pouvez donc remplacer l'intérieur du trybloc par:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747

Comme @Dux, cela ne fonctionne pas pour moi; il renvoie toujours false, même dans un notebook. Suspectez que cette réponse est devenue obsolète avec l'introduction d'une sorte de système de chargement de configuration paresseux.
Mark Amery

Notez également que votre configuration peut revenir sous la forme d'un dict vide, auquel cas vous devrez ajouter KeyError au bloc except. Il est probablement préférable d'utiliser du code basé sur la réponse de Gustavo Bezerra. Même si j'obtiens une configuration vide, j'obtiens shell='PyDevTerminalInteractiveShell'lors de l'inspection du nom de la classe.
hlongmore

28

Vous pouvez vérifier si python est en mode interactif avec l'extrait de code 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 les 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:]

Après l'implémentation de autonotebook, vous pouvez savoir si vous êtes dans un bloc-notes à l'aide du code suivant.

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()ne fait pas la distinction entre ordinateur portable et console.
krock

1
Une autre mise en garde, émettre un %rundepuis ipython n'est pas interactif. Vous pourriez dire que ça devrait l'être, mais c'est toujours un piège.
dirkjot

Pour les autres prototypes dans le cahier, la variante de l'approche de Till présentée ici pourrait être utile.
Wayne

La seconde moitié de cette réponse est utile, mais la première moitié (environ is_interactive) me semble être fondamentalement sans rapport avec la question. C'est aussi d'une exactitude douteuse; comme le fait remarquer @marscher, il compte tout ce qui est exécuté en utilisant python -ccomme étant en mode "interactif" même si ce n'est pas vrai. Je ne veux pas le faire moi-même car ce n'est pas ma réponse, mais je pense que cela serait amélioré en supprimant simplement la première moitié de la réponse.
Mark Amery

17

Récemment, j'ai rencontré un bogue dans le notebook Jupyter qui nécessite une solution de contournement, et je voulais le faire sans perdre les fonctionnalités des autres shells. Je me suis rendu compte que la solution de keflavich ne fonctionnait pas dans ce cas, car elle get_ipython()n'est disponible que directement depuis le notebook, et non depuis des modules importés. J'ai donc trouvé un moyen de détecter à partir de mon module s'il est importé et utilisé à partir d'un notebook 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, ainsi que sur la version 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, j'utilise le Fedora 23 Jupyter, et il 'Ipython' in sys.modulesévalue à False. Vous voulez dire peut-être 'IPython' in sys.modules? C'est Truedans mon environnement Jupyter. Le sys.modulesdictionnaire n'inclut pas non plus la 'ipykernel'clé - lors de l'exécution à l'intérieur d'un cahier.
maxschlepzig

2
C'est la meilleure réponse à ce jour, OMI. Court et doux.
danielpcox

3

Testé pour python 3.7.3

Les implémentations CPython ont le nom __builtins__disponible dans le cadre de leurs globals qui btw. peut être récupéré par la fonction globals ().
Si un script s'exécute dans un environnement Ipython, il __IPYTHON__doit être un attribut de __builtins__.
Le code ci-dessous retourne donc Trues'il est exécuté sous Ipython ou bien il donneFalse

hasattr(__builtins__,'__IPYTHON__')

2

Ce qui suit capture les cas de https://stackoverflow.com/a/50234148/1491619 sans avoir besoin d'analyser la sortie 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

Pour moi, ce montre juste jupyterque ce soit un jupyter console, jupyter qtconsoleou jupyter notebook.
Luke Davis le

2

Je recommanderais d'éviter de détecter un frontend spécifique car il y en a trop . Au lieu de cela, vous pouvez simplement tester si vous exécutez à partir de l'environnement iPython:

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

Ci-dessus reviendra Falsesi vous appelez à running_from_ipythonpartir de la ligne de commande python habituelle. Lorsque vous l'invoquez à partir de Jupyter Notebook, JupyterHub, iPython shell, Google Colab, etc., il reviendra True.


Cela ne fonctionne pas pour moi - Lorsque j'essaye cela dans Jupyter Notebook sur Ubuntu avec Python3, get_ipython()revient <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
protagoniste

Le problème avec cette approche est qu'elle ne résout pas la question de l'OP, "Comment puis-je vérifier à partir de mon code Python s'il s'exécute dans le bloc - notes IPython ?" (c'est moi qui souligne). La coque IPython est pas un ordinateur portable, mais quand je le lance dans ma console Python dans PyCharm, je me get_ipython() is not Noneretourner True.
hlongmore

hm, comment puis-je détecter si je cours sur jupyter vs voila?
ntg

2

Tout ce que vous avez à faire est de placer ces deux cellules au début de votre carnet:

Cellule 1: (marquée comme "code"):

is_notebook = True

Cellule 2: (marquée comme "Raw NBConvert"):

is_notebook = False

La première cellule sera toujours exécutée, mais la deuxième cellule ne sera exécutée que lorsque vous exporterez le notebook en tant que script Python.

Plus tard, vous pouvez vérifier:

if is_notebook:
    notebook_code()
else:
    script_code()

J'espère que cela t'aides.


2

Que diriez-vous quelque chose comme ça:

import sys

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

print(inJupyter);

1

Autant que je sache, voici 3 types d'ipython qui utilisaient ipykernel

  1. ipython qtconsole ("qtipython" pour faire court)
  2. IPython dans spyder ("spyder" pour faire court)
  3. IPython dans le notebook jupyter ("jn" pour faire court)

utilisation 'spyder' in sys.modules peut distinguer spyder

mais pour qtipython et jn sont difficiles à distinguer cause

ils ont la même sys.moduleset la même configuration IPython:get_ipython().config

Je trouve un différent entre qtipython et jn:

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

puis courir 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 jn pid 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 d'ipython, le nom json de jn est plus long que celui de qtipython

Ainsi, nous pouvons détecter automatiquement tout l'environnement 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)

le code source est ici: Détection de l'environnement Python, surtout distinguer Spyder, notebook Jupyter, Qtconsole.py


0

J'utilise Django Shell Plus pour lancer IPython, et je voulais rendre `` l'exécution dans le notebook '' disponible en tant que valeur de paramètres Django. get_ipython()n'est pas disponible lors du chargement des paramètres, donc j'utilise ceci (qui n'est pas à l'épreuve des balles, mais assez bon pour les environnements de développement local dans lesquels il est utilisé):

import sys

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

0

En supposant que vous contrôliez le bloc-notes Jupyter, vous pouvez:

  1. définissez une valeur d'environnement dans une cellule qui l'utilise comme indicateur dans votre code . Placez un commentaire unique dans cette cellule (ou dans toutes les cellules que vous souhaitez exclure)

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Exportez le notebook sous forme de script python à utiliser dans un contexte différent. L'exportation exclurait la ou les cellules commentées et, par la suite, le code définissant la valeur d'environnement. Remarque: remplacez votre_notebook.ipynb par le nom de votre fichier de bloc-notes actuel.

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

Cela générera un fichier qui n'aura pas l'indicateur d'environnement jupyter défini, ce qui permettra au code qui l'utilise de s'exécuter de manière déterministe.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.