Jak mogę sprawdzić, czy kod jest wykonywany w notatniku IPython?

89

Mam przykład kodu w Pythonie, który chciałbym udostępnić, który powinien zrobić coś innego, jeśli zostanie wykonany w terminalu Python / IPython lub w notatniku IPython.

Jak mogę sprawdzić na podstawie mojego kodu Pythona, czy działa on w notatniku IPython?

Christoph
źródło
3
Proponuję przyjąć odpowiedź Gustavo Bezerra . Aktualnie zaakceptowana odpowiedź nie odpowiada na pytanie, a odpowiedź Gustavo to najwyżej oceniona odpowiedź, która nadal działa w najnowszej wersji Jupyter Notebook.
Mark Amery,

Odpowiedzi:

9

Pytanie brzmi, co chcesz wykonać inaczej.

Robimy co w naszej mocy w IPythonie, aby jądro nie wiedziało, do jakiego typu frontendu jest podłączone, a właściwie możesz nawet mieć jądro podłączone do wielu różnych frontendów w tym samym czasie. Nawet jeśli możesz stderr/outrzucić okiem na typ, aby wiedzieć, czy jesteś w jądrze ZMQ, czy nie, nie gwarantuje to tego, co masz po drugiej stronie. Możesz nawet nie mieć żadnych frontendów.

Prawdopodobnie powinieneś napisać swój kod w sposób niezależny od frontendu, ale jeśli chcesz wyświetlać różne rzeczy, możesz użyć bogatego systemu wyświetlania (link przypięty do wersji 4.x IPythona), aby wyświetlić różne rzeczy w zależności od frontendu, ale frontend wybierze, a nie biblioteka.

Matt
źródło
2
Powyższe łącze do Rich Display System IPython jest uszkodzone. Oto link do aktualnej dokumentacji: ipython.org/ipython-doc/dev/config/integrating.html , a tutaj link do kilku świetnych przykładów: nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch
2
Mam taki problem w moim module rysunkowym . Muszę zaimportować wywołanie matplotlib.use ("Agg") tam dla travis-ci, aby umożliwić zapisywanie rysunków (patrz stackoverflow.com/questions/4706451/ ... ) Ale to generuje ostrzeżenie w notatniku UserWarning: To wywołanie matplotlib.use () nie działa, ponieważ backend został już wybrany; Jak to rozwiązać?
Dr. Goulu
30
Mam jeden przykład: paski postępu. Emulator terminala notebooka Jupyter nie obsługuje rozszerzonych znaków kontrolnych terminala, takich jak \x1b[A(przesuń w górę), więc nie można drukować zagnieżdżonych słupków . Nie ma problemu z ipywidgets , możemy użyć natywnych widżetów Jupyter do wyświetlania pasków postępu. Ale mamy dwa różne sposoby wyświetlania paska postępu, a aplikacja może chcieć wiedzieć, jakie jest środowisko wyświetlania, aby dostosować i wydrukować zgodny pasek.
hałaśliwy
2
na przykład chcę ustawić konfigurację IPython tak, aby zawsze działała, %matplotlib inlinegdy działa jako notebook, ale nie w terminalu, ponieważ nie jest to potrzebne.
Ciprian Tomoiagă
3
Chociaż jest to całkowicie uzasadniona opinia, ta odpowiedź nie odnosi się do rzeczywistego pytania. Bez względu na to, jak bardzo byś tego chciał, zawsze będą istnieć różnice w zachowaniu, które mogą mieć znaczenie.
Christopher Barber
69

Na moje potrzeby działały:

get_ipython().__class__.__name__

Powraca 'TerminalInteractiveShell'na terminalowym IPythonie, 'ZMQInteractiveShell'na Jupyter (notebook AND qtconsole) i kończy się niepowodzeniem ( NameError) na zwykłym interpreterze Pythona. get_python()Wydaje się, że metoda jest domyślnie dostępna w globalnej przestrzeni nazw podczas uruchamiania IPythona.

Opakowanie w prostą funkcję:

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

Powyższe zostało przetestowane z Python 3.5.2, IPython 5.1.0 i Jupyter 4.2.1 na macOS 10.12 i Ubuntu 14.04.4 LTS

Gustavo Bezerra
źródło
5
On jupyter consoleniestety get_ipython()zwraca instancję ZMQInteractiveShelltakże
Josh Bode
7
Jeśli ktoś jest zainteresowany wykryciem, czy notebook działa w Google Colab, możesz to sprawdzić:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz
3
Działa to tylko dla kodu w notatniku. Nie działa, jeśli funkcja znajduje się w zaimportowanym pakiecie.
Christopher Barber,
4
@ChristopherBarber To nie to, co widzę. Jeśli wkleię tę funkcję do pliku, test.pya następnie uruchomię from test import isnotebook; print(isnotebook())w notatniku Jupyter, zostanie wydrukowana True. (Testowane na serwerach Notebook w wersjach 5.2.1 i 6.0.1.)
Mark Amery,
Myślałem, że był jakiś przypadek, który mi nie wyszedł, ale niestety nie pamiętam szczegółów. Być może to już nie problem, a może po prostu byłem zdezorientowany.
Christopher Barber
41

Aby sprawdzić, czy jesteś w notatniku, co może być ważne np. Przy określaniu jakiego rodzaju paska postępu użyć, to zadziałało:

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
źródło
6
W moim IPython-Notebook (IPython w wersji 3.1) cfg['IPKernelApp']['parent_appname']jest a IPython.config.loader.LazyConfigValue, którego nie można porównać Truez"iypthon-notebook"
Dux
5
@juanjux get_ipython zwraca IPython.kernel.zmq.zmqshell.ZMQInteractiveShellinstancję w ipynb (Jupyter) i IPython.terminal.interactiveshell.TerminalInteractiveShellREPL w terminalu, na wypadek, gdybyś potrzebował rozróżnić między notebookami i terminalem / konsolami (co wpływa na drukowanie).
płyty grzewcze
4
^ dlatego możesz zamienić wnętrze trybloku na:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747
Podobnie jak @Dux, to nie działa dla mnie; zawsze zwraca fałsz, nawet w Notatniku. Podejrzewam, że ta odpowiedź stała się przestarzała wraz z wprowadzeniem pewnego rodzaju leniwego systemu ładowania konfiguracji.
Mark Amery,
Zauważ również, że twoja konfiguracja może powrócić jako pusty dykt, w takim przypadku musisz dodać KeyError do bloku except. Prawdopodobnie lepiej jednak użyć kodu opartego na odpowiedzi Gustavo Bezerry. Mimo że otrzymuję pustą konfigurację, otrzymuję shell='PyDevTerminalInteractiveShell'podczas sprawdzania nazwy klasy.
hlongmore
28

Możesz sprawdzić, czy Python jest w trybie interaktywnym za pomocą następującego fragmentu kodu [1] :

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

Uważam, że ta metoda jest bardzo przydatna, ponieważ wykonuję wiele prototypów w zeszycie. Do celów testowych używam parametrów domyślnych. W przeciwnym razie odczytałem parametry z sys.argv.

from sys import argv

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

Po wdrożeniu autonotebookmożesz stwierdzić, czy jesteś w notatniku, używając następującego kodu.

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
Till Hoffmann
źródło
python -c "def is_interactive ():> import main as main> return not hasattr (main, ' file ')> print is_interactive ()" True
marscher Kwietnia
3
is_interactive()nie rozróżnia notebooka i konsoli.
krock
1
Kolejne zastrzeżenie, wydawanie a %runz ipython jest nieinteraktywne. Można argumentować, że tak powinno być, ale wciąż jest to problem.
dirkjot
W przypadku innych prototypów w notatniku wariant podejścia Tilla przedstawiony tutaj może być przydatny.
Wayne,
Druga połowa tej odpowiedzi jest przydatna, ale pierwsza połowa (około is_interactive) wydaje mi się zasadniczo nieistotna dla pytania. Jest to również wątpliwa poprawność; jak wskazuje @marscher, liczy wszystko, co zostało uruchomione, python -cjako działające w trybie „interaktywnym”, nawet jeśli nie jest to prawdą. Nie chcę tego robić samodzielnie, ponieważ to nie moja odpowiedź, ale myślę, że można by to poprawić, usuwając po prostu całą pierwszą połowę odpowiedzi.
Mark Amery
17

Niedawno napotkałem błąd w notatniku Jupyter, który wymaga obejścia i chciałem to zrobić bez utraty funkcjonalności w innych powłokach. Zdałem sobie sprawę, że rozwiązanie keflavicha w tym przypadku nie działa, ponieważ get_ipython()jest dostępne tylko bezpośrednio z notebooka, a nie z importowanych modułów. Więc znalazłem sposób, aby wykryć z mojego modułu, czy jest importowany i używany z notebooka Jupyter, czy nie:

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

Komentarze są mile widziane, jeśli jest to wystarczająco solidne.

W podobny sposób można uzyskać informacje o kliencie, a także o wersji IPythona:

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
źródło
Hm, używam Fedory 23 Jupyter i tam 'Ipython' in sys.modulesocenia False. Może masz na myśli 'IPython' in sys.modules? To jest Truew moim środowisku Jupyter. sys.modulesSłowniku również nie zawiera 'ipykernel'klucz - gdy działa wewnątrz notebooka.
maxschlepzig
2
To najlepsza jak dotąd odpowiedź, IMO. Krótkie i słodkie.
danielpcox
3

Przetestowano pod kątem Pythona 3.7.3

Implementacje CPythona mają tę nazwę __builtins__dostępną jako część ich globali, które przy okazji. można pobrać za pomocą funkcji globals ().
Jeśli skrypt działa w środowisku Ipython, __IPYTHON__powinien mieć atrybut __builtins__.
Dlatego poniższy kod zwraca, Truejeśli jest uruchamiany pod Ipythonem lub podanyFalse

hasattr(__builtins__,'__IPYTHON__')
Robert Nowak
źródło
2

Poniższy opis przedstawia przypadki https://stackoverflow.com/a/50234148/1491619 bez konieczności analizowania danych wyjściowychps

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
źródło
Dla mnie to po prostu pokazuje jupyter, czy jest to jupyter console, jupyter qtconsoleczy jupyter notebook.
Luke Davis
2

Zalecałbym unikanie wykrywania określonego interfejsu, ponieważ jest ich zbyt wiele . Zamiast tego możesz po prostu sprawdzić, czy pracujesz w środowisku iPython:

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

Powyższe zwróci, Falsejeśli wywołujesz running_from_ipythonze zwykłego wiersza poleceń Pythona. Po wywołaniu go z Jupyter Notebook, JupyterHub, iPython shell, Google Colab itp., Wtedy powróci True.

Shital Shah
źródło
Nie działa dla mnie - kiedy próbuję tego w Jupyter Notebook na Ubuntu z Python3, get_ipython()zwraca <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
bohater
Problem z tym podejściem polega na tym, że nie rozwiązuje ono pytania OP: „Jak mogę sprawdzić na podstawie mojego kodu Pythona, czy działa on w notatniku IPython ?” (podkreślenie moje). Powłoka IPython nie jest notatnikiem, ale kiedy uruchamiam ją w mojej konsoli Python w PyCharm, get_ipython() is not Nonezwraca True.
hlongmore
hm, jak mogę wykryć, czy korzystam z jupyter vs. voila?
ntg
2

Wszystko, co musisz zrobić, to umieścić te dwie komórki na początku swojego notatnika:

Komórka 1: (oznaczona jako „kod”):

is_notebook = True

Komórka 2: (oznaczona jako „Raw NBConvert”):

is_notebook = False

Pierwsza komórka będzie zawsze wykonywana, ale druga komórka zostanie wykonana tylko wtedy, gdy wyeksportujesz notatnik jako skrypt Pythona.

Później możesz sprawdzić:

if is_notebook:
    notebook_code()
else:
    script_code()

Mam nadzieję że to pomoże.

Julio Alves
źródło
2

Co powiesz na coś takiego:

import sys

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

print(inJupyter);
user431378
źródło
1

O ile wiem, tutaj są 3 rodzaje ipythonu, które zostały użyte ipykernel

  1. ipython qtconsole (w skrócie „qtipython”)
  2. IPython w spyder (w skrócie „spyder”)
  3. IPython w notatniku Jupyter (w skrócie „jn”)

posługiwać się 'spyder' in sys.modules pozwala odróżnić Spydera

ale dla qtipython i jn są trudne do rozróżnienia

mają taką samą sys.modulesi taką samą konfigurację IPythona:get_ipython().config

Znajduję różnicę między qtipython i jn:

pierwsze uruchomienie os.getpid()w powłoce IPython pobierz numer pid

następnie uruchomić ps -ef|grep [pid number]

mój numer pid qtipython to 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

mój pid jn to 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

różnica z qtipython i jn to nazwa json ipythona, nazwa jn jn jest dłuższa niż nazwa qtipython

więc możemy automatycznie wykryć całe środowisko Pythona, wykonując następujący kod:

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)

kod źródłowy jest tutaj: Detection Python Environment, szczególnie wyróżnia Spyder, Jupyter notebook, Qtconsole.py

Yang
źródło
0

Używam Django Shell Plus do uruchomienia IPython i chciałem, aby „praca w notebooku” była dostępna jako wartość ustawień Django. get_ipython()nie jest dostępny podczas ładowania ustawień, więc używam tego (co nie jest kuloodporne, ale wystarczająco dobre dla lokalnych środowisk programistycznych, w których jest używany):

import sys

if '--notebook' in sys.argv:
    ENVIRONMENT = "notebook"
else:
    ENVIRONMENT = "dev"
user31415629
źródło
0

Zakładając, że masz kontrolę nad notebookiem Jupyter, możesz:

  1. ustaw wartość środowiska w komórce, która używa tego jako flagi w kodzie . Umieść unikalny komentarz w tej komórce (lub we wszystkich komórkach, które chcesz wykluczyć)

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Wyeksportuj notatnik jako skrypt w języku Python do użycia w innym kontekście. Eksport wykluczy skomentowane komórki, a następnie kod, który ustawia wartość środowiska. Uwaga: zastąp your_notebook.ipynb nazwą rzeczywistego pliku notatnika.

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

Spowoduje to wygenerowanie pliku, który nie będzie miał ustawionej flagi środowiska jupyter, umożliwiającej kod, który używa jej do deterministycznego wykonywania.

Ron Sims II
źródło