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?
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.
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
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.
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:]
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']
Pour autant que je sache, voici 3 types d’ipython utilisant ipykernel
ipython qtconsole
("qtipython" pour faire court)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
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
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.
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"