Wie kann ich überprüfen, ob Code im IPython-Notizbuch ausgeführt wird?

89

Ich möchte ein Python-Codebeispiel teilen, das etwas anderes tun sollte, wenn es im Terminal Python / IPython oder im IPython-Notizbuch ausgeführt wird.

Wie kann ich anhand meines Python-Codes überprüfen, ob er im IPython-Notizbuch ausgeführt wird?

Christoph
quelle
3
Ich schlage vor, die Antwort von Gustavo Bezerra zu akzeptieren . Die derzeit akzeptierte Antwort beantwortet die Frage nicht und Gustavos Antwort ist die Antwort mit der höchsten Punktzahl, die in der neuesten Version von Jupyter Notebook noch funktioniert.
Mark Amery

Antworten:

9

Die Frage ist, was Sie anders ausführen möchten.

Wir tun unser Bestes in IPython, um zu verhindern, dass der Kernel weiß, mit welcher Art von Frontend verbunden ist, und tatsächlich können Sie sogar einen Kernel gleichzeitig mit vielen verschiedenen Frontends verbinden. Selbst wenn Sie einen Blick auf die Art stderr/outwerfen können, um zu wissen, ob Sie sich in einem ZMQ-Kernel befinden oder nicht, garantiert dies Ihnen nicht, was Sie auf der anderen Seite haben. Sie könnten sogar überhaupt keine Frontends haben.

Sie sollten Ihren Code wahrscheinlich unabhängig vom Frontend schreiben. Wenn Sie jedoch verschiedene Dinge anzeigen möchten, können Sie das Rich-Display-System (Link an Version 4.x von IPython angeheftet) verwenden , um je nach Frontend verschiedene Dinge anzuzeigen Das Frontend wählt, nicht die Bibliothek.

Matt
quelle
2
Der obige Link zum IPython Rich Display System ist unterbrochen. Hier ist der Link zur aktuellen Dokumentation: ipython.org/ipython-doc/dev/config/integrating.html , und hier ist ein Link zu einigen großartigen Beispielen: nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch
2
Ich habe ein solches Problem in meinem Zeichenmodul . Ich muss den Aufruf matplotlib.use ("Agg") für travis-ci dort importieren, um das Speichern von Zeichnungen zu ermöglichen (siehe stackoverflow.com/questions/4706451/… ). Dies generiert jedoch eine Warnung im Notizbuch. UserWarning: Dieser Aufruf von matplotlib.use () hat keine Auswirkung, da das Backend bereits ausgewählt wurde; Wie kann man das lösen?
Dr. Goulu
30
Ich habe ein Beispiel: Fortschrittsbalken. Der Jupyter-Notebook-Terminalemulator unterstützt keine erweiterten Terminalsteuerzeichen wie \x1b[A(nach oben), sodass verschachtelte Balken nicht gedruckt werden können . Kein Problem mit ipywidgets , wir können native Jupyter-Widgets verwenden, um Fortschrittsbalken anzuzeigen. Dann haben wir zwei verschiedene Möglichkeiten, einen Fortschrittsbalken anzuzeigen, und eine Anwendung möchte möglicherweise wissen, wie die Anzeigeumgebung aussieht, um den kompatiblen Balken anzupassen und zu drucken.
gaborous
2
Ich möchte beispielsweise festlegen, dass die IPython-Konfiguration immer ausgeführt wird, %matplotlib inlinewenn sie als Notebook fungiert, jedoch nicht in einem Terminal, da dies nicht erforderlich ist.
Ciprian Tomoiagă
3
Obwohl dies eine vollkommen gültige Meinung ist, geht diese Antwort nicht auf die eigentliche Frage ein. Egal wie sehr Sie es sich wünschen würden, es wird immer Unterschiede im Verhalten geben, die wichtig sein könnten.
Christopher Barber
68

Folgendes hat für meine Bedürfnisse funktioniert:

get_ipython().__class__.__name__

Es kehrt 'TerminalInteractiveShell'auf einem Terminal-IPython 'ZMQInteractiveShell'auf Jupyter (Notebook UND qtconsole) zurück und schlägt NameErrorauf einem normalen Python-Interpreter fehl ( ). Die Methode get_python()scheint standardmäßig im globalen Namespace verfügbar zu sein, wenn IPython gestartet wird.

Wickeln Sie es in eine einfache Funktion:

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

Das Obige wurde mit Python 3.5.2, IPython 5.1.0 und Jupyter 4.2.1 unter macOS 10.12 und Ubuntu 14.04.4 LTS getestet

Gustavo Bezerra
quelle
5
Auf jupyter console, leider get_ipython()gibt eine Instanz von ZMQInteractiveShellauch
Josh Bode
7
Wenn jemand daran interessiert ist festzustellen, ob das Notebook auf Google Colab ausgeführt wird, können Sie get_ipython().__class__.__module__ == "google.colab._shell"
Folgendes
3
Dies funktioniert nur für Code im Notizbuch. Es funktioniert nicht, wenn sich die Funktion in einem importierten Paket befindet.
Christopher Barber
4
@ChristopherBarber Das sehe ich nicht. Wenn ich diese Funktion in eine Datei einfüge und test.pydann from test import isnotebook; print(isnotebook())in einem Jupyter-Notizbuch ausführe , wird sie gedruckt True. (Getestet auf Notebook-Server-Versionen 5.2.1 und 6.0.1.)
Mark Amery
Ich dachte, es gibt einen Fall, der bei mir nicht funktioniert hat, aber leider erinnere ich mich nicht an die Details. Vielleicht ist es kein Problem mehr oder ich war nur verwirrt.
Christopher Barber
41

Um zu überprüfen, ob Sie sich in einem Notizbuch befinden, was wichtig sein kann, z. B. wenn Sie bestimmen, welche Art von Fortschrittsbalken verwendet werden soll, hat dies für mich funktioniert:

def in_ipynb():
    try:
        cfg = get_ipython().config 
        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
            return True
        else:
            return False
    except NameError:
        return False
Keflavich
quelle
6
In meinem IPython-Notebook (IPython Version 3.1) cfg['IPKernelApp']['parent_appname']befindet sich ein IPython.config.loader.LazyConfigValue, der nicht Truemit"iypthon-notebook"
Dux
5
@juanjux get_ipython gibt eine IPython.kernel.zmq.zmqshell.ZMQInteractiveShellInstanz in ipynb (Jupyter) und eine IPython.terminal.interactiveshell.TerminalInteractiveShellin einem Terminal REPL zurück, falls Sie zwischen Notebooks und Terminal / Konsolen unterscheiden müssen (was sich auf das Plotten auswirkt).
Kochfelder
4
^ Daher können Sie das Innere des tryBlocks ersetzen durch:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747
Wie bei @Dux funktioniert das bei mir nicht. Selbst in einem Notizbuch wird immer false zurückgegeben. Der Verdacht, dass diese Antwort mit der Einführung eines faulen Konfigurationsladesystems überholt war.
Mark Amery
Beachten Sie auch, dass Ihre Konfiguration möglicherweise als leeres Diktat zurückgegeben wird. In diesem Fall müssten Sie KeyError zum Ausnahmeblock hinzufügen. Es ist jedoch wahrscheinlich besser, Code zu verwenden, der auf der Antwort von Gustavo Bezerra basiert. Obwohl ich eine leere Konfiguration erhalte, wird diese shell='PyDevTerminalInteractiveShell'beim Überprüfen des Klassennamens angezeigt.
Hlongmore
28

Mit dem folgenden Snippet [1] können Sie überprüfen, ob sich Python im interaktiven Modus befindet :

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

Ich habe diese Methode als sehr nützlich empfunden, da ich viel Prototyping im Notebook mache. Zu Testzwecken verwende ich Standardparameter. Ansonsten lese ich die Parameter aus sys.argv.

from sys import argv

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

Nach der Implementierung von autonotebookkönnen Sie anhand des folgenden Codes feststellen, ob Sie sich in einem Notizbuch befinden.

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
Bis Hoffmann
quelle
python -c "def is_interactive ():> main als main importieren > nicht hasattr (main, ' file ') zurückgeben> is_interactive () drucken" True
marscher
3
is_interactive()unterscheidet nicht zwischen Notebook und Konsole.
Rock
1
Eine weitere Einschränkung, die eine %runvon ipython ausgibt, ist nicht interaktiv. Man könnte argumentieren, dass es so sein sollte, aber es ist immer noch ein Gotcha.
Dirkjot
Für andere Prototypen im Notebook könnte die hier vorgestellte Variante von Tills Ansatz nützlich sein.
Wayne
Die zweite Hälfte dieser Antwort ist nützlich, aber die erste Hälfte (ungefähr is_interactive) scheint mir für die Frage grundsätzlich irrelevant zu sein. Es ist auch von zweifelhafter Korrektheit; Wie @marscher betont, zählt alles, was ausgeführt wird, python -cals "interaktiv", obwohl dies nicht der Fall ist. Ich möchte es nicht selbst tun, da es nicht meine Antwort ist, aber ich denke, dies würde durch einfaches Löschen der gesamten ersten Hälfte der Antwort verbessert.
Mark Amery
17

Kürzlich bin ich auf einen Fehler im Jupyter-Notizbuch gestoßen, der eine Problemumgehung erfordert, und ich wollte dies tun, ohne die Funktionalität in anderen Shells zu verlieren. Ich habe festgestellt, dass die Lösung von keflavich in diesem Fall nicht funktioniert, da get_ipython()sie nur direkt vom Notebook und nicht von importierten Modulen verfügbar ist. So habe ich einen Weg gefunden, anhand meines Moduls zu erkennen, ob es von einem Jupyter-Notebook importiert und verwendet wird oder nicht:

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

Kommentare sind willkommen, wenn dies robust genug ist.

Auf ähnliche Weise können Sie auch Informationen zum Client und zur IPython-Version abrufen:

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']
deeenes
quelle
Hm, ich benutze den Fedora 23 Jupyter und dort wird 'Ipython' in sys.modulesausgewertet False. Vielleicht meinst du 'IPython' in sys.modules? Dies ist Truein meiner Jupyter-Umgebung. Das sys.modulesWörterbuch enthält auch nicht den 'ipykernel'Schlüssel - wenn es in einem Notizbuch ausgeführt wird.
Maxschlepzig
2
Dies ist die bisher beste Antwort, IMO. Kurz und bündig.
Danielpcox
3

Getestet auf Python 3.7.3

CPython-Implementierungen haben den Namen __builtins__übrigens als Teil ihrer Globals verfügbar. kann von der Funktion globals () abgerufen werden.
Wenn ein Skript in einer Ipython-Umgebung ausgeführt wird, __IPYTHON__sollte dies ein Attribut von sein __builtins__.
Der folgende Code wird daher zurückgegeben, Truewenn er unter Ipython ausgeführt wird oder wenn er angezeigt wirdFalse

hasattr(__builtins__,'__IPYTHON__')
Robert Nowak
quelle
2

Im Folgenden werden die Fälle von https://stackoverflow.com/a/50234148/1491619 erfasst, ohne dass die Ausgabe von analysiert werden mussps

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
Bob Weigel
quelle
Für mich ist dies nur zeigt , jupyterob es ein jupyter console, jupyter qtconsoleoder jupyter notebook.
Luke Davis
2

Ich würde empfehlen, das Erkennen eines bestimmten Frontends zu vermeiden, da es zu viele davon gibt . Stattdessen können Sie einfach testen, ob Sie in einer iPython-Umgebung ausgeführt werden:

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

Oben wird zurückgegeben, Falsewenn Sie über die running_from_ipythonübliche Python-Befehlszeile aufrufen . Wenn Sie es über Jupyter Notebook, JupyterHub, iPython Shell, Google Colab usw. aufrufen, wird es zurückgegeben True.

Shital Shah
quelle
Funktioniert bei mir nicht - Wenn ich dies in Jupyter Notebook unter Ubuntu mit Python3 versuche, get_ipython()kehrt es zurück <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
Protagonist
Das Problem bei diesem Ansatz ist, dass die Frage des OP "Wie kann ich anhand meines Python-Codes überprüfen, ob er im IPython- Notizbuch ausgeführt wird ?" Nicht gelöst wird. (Hervorhebung von mir). Die IPython-Shell ist kein Notizbuch, aber wenn ich sie in meiner Python-Konsole in PyCharm ausführe, kehre ich get_ipython() is not Nonezurück True.
Hlongmore
hm, wie kann ich erkennen, ob ich auf jupyter vs. voila laufe?
ntg
2

Sie müssen lediglich diese beiden Zellen am Anfang Ihres Notizbuchs platzieren:

Zelle 1: (markiert als "Code"):

is_notebook = True

Zelle 2: (markiert als "Raw NBConvert"):

is_notebook = False

Die erste Zelle wird immer ausgeführt, die zweite Zelle wird jedoch nur ausgeführt, wenn Sie das Notizbuch als Python-Skript exportieren.

Später können Sie überprüfen:

if is_notebook:
    notebook_code()
else:
    script_code()

Hoffe das hilft.

Julio Alves
quelle
2

Wie wäre es mit so etwas:

import sys

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

print(inJupyter);
user431378
quelle
1

Soweit ich weiß, hat Here 3 Arten von Ipython verwendet ipykernel

  1. ipython qtconsole (kurz "qtipython")
  2. IPython in Spyder (kurz "Spyder")
  3. IPython im Jupyter-Notizbuch (kurz "jn")

Verwendung 'spyder' in sys.moduleskann Spyder unterscheiden

aber für qtipython und jn ist die Ursache schwer zu unterscheiden

Sie haben die sys.modulesgleiche IPython-Konfiguration:get_ipython().config

Ich finde einen Unterschied zwischen qtipython und jn:

Beim ersten Ausführen os.getpid()in der IPython-Shell wird die PID-Nummer abgerufen

dann renne ps -ef|grep [pid number]

meine qtipython pid ist 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

meine jn pid ist 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

Der Unterschied zwischen qtipython und jn ist der json-Name des ipython. Der json-Name von jn ist länger als der von qtipython

Daher können wir alle Python-Umgebungen automatisch anhand des folgenden Codes erkennen:

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)

Der Quellcode ist hier: Erkennung Python-Umgebung, besonders unterscheiden Spyder, Jupyter Notebook, Qtconsole.py

Yang
quelle
0

Ich verwende Django Shell Plus, um IPython zu starten, und wollte "In Notebook ausführen" als Django-Einstellungswert verfügbar machen. get_ipython()ist beim Laden von Einstellungen nicht verfügbar, daher verwende ich diese (die nicht kugelsicher ist, aber für die lokalen Entwicklungsumgebungen, in denen sie verwendet wird, gut genug ist):

import sys

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

Angenommen, Sie haben die Kontrolle über das Jupyter-Notizbuch, könnten Sie:

  1. Legen Sie einen Umgebungswert in einer Zelle fest, der diesen Wert als Flag in Ihrem Code verwendet . Fügen Sie einen eindeutigen Kommentar in diese Zelle ein (oder in alle Zellen, die Sie ausschließen möchten).

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Exportieren Sie das Notizbuch als Python-Skript, um es in einem anderen Kontext zu verwenden. Der Export würde die kommentierten Zellen und anschließend den Code ausschließen, der den Umgebungswert festlegt. Hinweis: Ersetzen Sie your_notebook.ipynb durch den Namen Ihrer tatsächlichen Notebook-Datei.

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

Dadurch wird eine Datei generiert, für die das Jupyter-Umgebungsflag nicht gesetzt ist. Dies ermöglicht Code, der es zur deterministischen Ausführung verwendet.

Ron Sims II
quelle