Como posso verificar se o código é executado no notebook IPython?

89

Eu tenho algum exemplo de código Python que gostaria de compartilhar que deve fazer algo diferente se executado no terminal Python / IPython ou no notebook IPython.

Como posso verificar no meu código Python se ele está sendo executado no notebook IPython?

Christoph
fonte
3
Sugiro aceitar a resposta de Gustavo Bezerra . A resposta atualmente aceita não responde à pergunta, e a resposta de Gustavo é a resposta com pontuação mais alta que ainda funciona na versão mais recente do Jupyter Notebook.
Mark Amery de

Respostas:

8

A questão é o que você deseja executar de forma diferente.

Fazemos nosso melhor em IPython para evitar que o kernel saiba a que tipo de frontend está conectado e, na verdade, você pode até ter um kernel conectado a muitos front-ends diferentes ao mesmo tempo. Mesmo que você possa dar uma olhada no tipo de stderr/outpara saber se você está em um kernel ZMQ ou não, isso não garante o que você tem do outro lado. Você poderia até mesmo não ter front-ends.

Você provavelmente deve escrever seu código de uma maneira independente de front-end, mas se quiser exibir coisas diferentes, você pode usar o sistema de exibição rico (link fixado na versão 4.x do IPython) para exibir coisas diferentes dependendo do frontend, mas o frontend irá escolher, não a biblioteca.

Matt
fonte
2
O link acima para o sistema IPython Rich Display está quebrado. Aqui está o link para a documentação atual: ipython.org/ipython-doc/dev/config/integrating.html , e aqui está um link para alguns ótimos exemplos: nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch
2
Tenho um problema como este no meu módulo de desenho . Eu preciso importar a chamada matplotlib.use ("Agg") lá para travis-ci para permitir salvar desenhos (consulte stackoverflow.com/questions/4706451/… ) Mas isso gera um aviso no bloco de notas UserWarning: Esta chamada para matplotlib.use () não tem efeito porque o backend já foi escolhido; Como resolver isso?
Dr. Goulu
33
Eu tenho um exemplo: barras de progresso. O emulador de terminal de notebook Jupyter não oferece suporte a caracteres de controle de terminal estendido, como \x1b[A(mover para cima), portanto, não é possível imprimir barras aninhadas . Nenhum problema com ipywidgets , podemos usar widgets nativos do Jupyter para exibir barras de progresso. Mas então temos dois meios diferentes de exibir uma barra de progresso, e um aplicativo pode querer saber qual é o ambiente de exibição para adaptar e imprimir a barra compatível.
gaborous
2
por exemplo, quero definir a configuração do IPython para sempre ser executada %matplotlib inlinequando funcionar como um notebook, mas não em um terminal, já que isso não é necessário.
Ciprian Tomoiagă
3
Embora esta seja uma opinião perfeitamente válida, esta resposta não aborda a questão real. Não importa o quanto você deseje que seja, sempre haverá diferenças de comportamento que podem importar.
Christopher Barber
72

O seguinte funcionou para minhas necessidades:

get_ipython().__class__.__name__

Ele retorna 'TerminalInteractiveShell'em um terminal IPython, 'ZMQInteractiveShell'em Jupyter (notebook AND qtconsole) e fail ( NameError) em um interpretador Python regular. O método get_python()parece estar disponível no namespace global por padrão quando o IPython é iniciado.

Envolvendo-o em uma função simples:

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

O acima foi testado com Python 3.5.2, IPython 5.1.0 e Jupyter 4.2.1 no macOS 10.12 e Ubuntu 14.04.4 LTS

Gustavo Bezerra
fonte
5
On jupyter console, infelizmente get_ipython()retorna uma instância de ZMQInteractiveShelltambém
Josh Bode
7
Se alguém estiver interessado em detectar se o notebook está rodando no Google Colab, você pode verificar isto:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz
3
Isso só funciona para código no notebook. Não funciona se a função estiver em um pacote importado.
Christopher Barber
4
@ChristopherBarber Não é isso que eu vejo. Se eu colar essa função em um arquivo e test.pydepois executar from test import isnotebook; print(isnotebook())em um Jupyter Notebook, ela será impressa True. (Testado nas versões 5.2.1 e 6.0.1 do servidor Notebook.)
Mark Amery
Pensei que havia algum caso que não funcionou para mim, mas infelizmente não me lembro dos detalhes. Talvez não seja mais um problema ou talvez eu esteja apenas confuso.
Christopher Barber
41

Para verificar se você está em um notebook, o que pode ser importante, por exemplo, ao determinar que tipo de barra de progresso usar, isso funcionou para mim:

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
fonte
6
Na minha IPython-Notebook (IPython versão 3.1), cfg['IPKernelApp']['parent_appname']é um IPython.config.loader.LazyConfigValue, que não se compara ao Truecom"iypthon-notebook"
Dux
5
@juanjux get_ipython retorna uma IPython.kernel.zmq.zmqshell.ZMQInteractiveShellinstância em ipynb (Jupyter) e um IPython.terminal.interactiveshell.TerminalInteractiveShellREPL em um terminal, caso você precise diferenciar entre notebooks e terminal / consoles (o que afeta a plotagem).
horas de
4
^ portanto, você pode substituir o interior do trybloco por:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
usuário2561747
Como @Dux, isso não funciona para mim; sempre retorna falso, mesmo em um Notebook. Suspeite que esta resposta se tornou obsoleta com a introdução de algum tipo de sistema de carregamento de configuração lento.
Mark Amery
Observe também que sua configuração pode retornar como um dicionário vazio, caso em que você precisa adicionar KeyError ao bloco except. No entanto, provavelmente é melhor usar código baseado na resposta de Gustavo Bezerra. Embora eu receba uma configuração vazia, recebo shell='PyDevTerminalInteractiveShell'ao inspecionar o nome da classe.
hlongmore
29

Você pode verificar se o python está no modo interativo com o seguinte snippet [1] :

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

Achei esse método muito útil porque faço muitos protótipos no notebook. Para fins de teste, uso parâmetros padrão. Caso contrário, eu li os parâmetros de sys.argv.

from sys import argv

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

Após a implementação de autonotebook, você pode dizer se está em um notebook usando o código a seguir.

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
fonte
python -c "def is_interactive ():> import main as main> return not hasattr (main, ' file ')> print is_interactive ()" True
marscher
3
is_interactive()não faz distinção entre notebook e console.
krock
1
Outra ressalva, a emissão de um %rundo ipython não é interativa. Você poderia argumentar que deveria ser, mas ainda é uma pegadinha.
dirkjot
Para outros protótipos no notebook, a variante da abordagem de Till apresentada aqui pode ser útil.
Wayne de
A segunda metade dessa resposta é útil, mas a primeira metade (cerca de is_interactive) me parece basicamente irrelevante para a pergunta. É também de exatidão duvidosa; como @marscher aponta, ele conta qualquer coisa executada usando python -ccomo estando no modo "interativo", mesmo que isso não seja verdade. Não quero fazer isso sozinho, pois não é minha resposta, mas acho que seria melhorado simplesmente excluindo toda a primeira metade da resposta.
Mark Amery de
17

Recentemente, encontrei um bug no notebook Jupyter que precisa de uma solução alternativa e eu queria fazer isso sem perder a funcionalidade em outros shells. Percebi que a solução do keflavich não funciona neste caso, pois get_ipython()está disponível apenas diretamente do notebook, e não de módulos importados. Então, descobri uma maneira de detectar no meu módulo se ele é importado e usado de um notebook Jupyter ou não:

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

Os comentários são apreciados se for robusto o suficiente.

De forma semelhante, é possível obter algumas informações sobre o cliente e também a versão do 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']
Deeenes
fonte
Hm, estou usando o Fedora 23 Jupyter, e 'Ipython' in sys.modulesavalia False. Talvez você queira dizer 'IPython' in sys.modules? Isso está Trueno meu ambiente Jupyter. O sys.modulesdicionário também não inclui a 'ipykernel'chave - quando executado dentro de um notebook.
maxschlepzig
2
Esta é a melhor resposta até agora, IMO. Curto e grosso.
danielpcox
3

Testado para python 3.7.3

As implementações de CPython têm o nome __builtins__disponível como parte de seus globais que btw. pode ser recuperado pela função globals ().
Se um script estiver sendo executado em um ambiente Ipython, __IPYTHON__deve ser um atributo de __builtins__.
O código abaixo, portanto, retorna Truese executado em Ipython ou então ele forneceFalse

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

O seguinte captura os casos de https://stackoverflow.com/a/50234148/1491619 sem a necessidade de analisar a saída 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
Bob Weigel
fonte
Para mim, isto só mostra jupyterse é um jupyter console, jupyter qtconsoleou jupyter notebook.
Luke Davis de
2

Eu recomendaria evitar detectar front-end específico porque há muitos deles . Em vez disso, você pode apenas testar se está executando de dentro do ambiente iPython:

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

Acima irá retornar Falsese você estiver invocando a running_from_ipythonpartir da linha de comando usual do python. Quando você o invoca do Jupyter Notebook, JupyterHub, shell do iPython, Google Colab, etc., ele retorna True.

Shital Shah
fonte
Não funciona para mim - Quando tento fazer isso no Jupyter Notebook no Ubuntu com Python3, get_ipython()retorna <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
protagonista de
O problema com essa abordagem é que ela não resolve a questão do OP, "Como posso verificar no meu código Python se ele está sendo executado no notebook IPython ?" (ênfase minha). O shell IPython não é um notebook, mas quando o executo em meu console Python no PyCharm, consigo get_ipython() is not Noneretornar True.
hlongmore
hm, como posso detectar se estou executando no jupyter vs. voila?
ntg
2

Tudo que você precisa fazer é colocar essas duas células no início do seu caderno:

Célula 1: (marcada como "código"):

is_notebook = True

Célula 2: (marcada como "Raw NBConvert"):

is_notebook = False

A primeira célula sempre será executada, mas a segunda célula só será executada quando você exportar o bloco de notas como um script Python.

Mais tarde, você pode verificar:

if is_notebook:
    notebook_code()
else:
    script_code()

Espero que isto ajude.

Julio Alves
fonte
2

Que tal algo como isso:

import sys

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

print(inJupyter);
user431378
fonte
1

Até onde eu sei, aqui tem 3 tipos de ipython que usavam ipykernel

  1. ipython qtconsole ("qtipython" para breve)
  2. IPython em spyder ("spyder" para abreviar)
  3. IPython no notebook jupyter ("jn" para breve)

usar 'spyder' in sys.modules pode distinguir spyder

mas para qtipython e jn são difíceis de distinguir causa

eles têm a mesma sys.modulesconfiguração IPython:get_ipython().config

Acho uma diferença entre qtipython e jn:

Primeira corrida os.getpid() no shell IPython, obtenha o número pid

então corra ps -ef|grep [pid number]

meu qtipython pid é 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

meu jn pid é 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

o diferente de qtipython e jn é o nome json do ipython, os nomes json de jn são mais longos que os de qtipython

portanto, podemos detectar automaticamente todo o ambiente Python seguindo o código:

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)

o código-fonte está aqui: Detecção de ambiente Python, especialmente distinguir Spyder, Jupyter notebook, Qtconsole.py

Yang
fonte
0

Estou usando o Django Shell Plus para iniciar o IPython e queria disponibilizar 'running in notebook' como um valor de configurações do Django. get_ipython()não está disponível ao carregar as configurações, então eu uso isso (que não é à prova de balas, mas bom o suficiente para os ambientes de desenvolvimento local em que é usado):

import sys

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

Supondo que você tenha o controle do Jupyter Notebook, você pode:

  1. defina um valor de ambiente em uma célula que usa isso como um sinalizador em seu código . Coloque um comentário exclusivo nessa célula (ou em todas as células que deseja excluir)

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Exporte o bloco de notas como um script Python para ser usado em um contexto diferente. A exportação excluiria a (s) célula (s) comentada (s) e, subsequentemente, o código que define o valor do ambiente. Nota: substitua your_notebook.ipynb pelo nome do seu arquivo de notebook real.

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

Isso irá gerar um arquivo que não terá o sinalizador de ambiente jupyter definido, permitindo que o código que o usa seja executado de forma determinística.

Ron Sims II
fonte