Як я можу перевірити, чи виконується код у блокноті IPython?


89

У мене є приклад коду Python, яким я хотів би поділитися, який повинен робити щось інше, якщо він виконується в терміналі Python / IPython або в блокноті IPython.

Як я можу перевірити з мого коду Python, чи працює він у блокноті IPython?


3
Пропоную прийняти відповідь Густаво Безерри . Наразі прийнята відповідь не відповідає на запитання, а відповідь Густаво - це найвища оцінка, яка досі працює в останній версії Jupyter Notebook.
Mark Amery

Відповіді:


9

Питання в тому, що ви хочете виконати інакше.

Ми робимо все, що в наших силах, у IPython, щоб ядро ​​не знало, до якого типу інтерфейсу підключено, і насправді ви навіть можете одночасно підключити ядро ​​до багатьох різних інтерфейсів. Навіть якщо ви можете підглянути тип, stderr/outщоб дізнатися, чи перебуваєте ви в ядрі ZMQ, чи ні, це не гарантує вам того, що ви маєте з іншого боку. Ви навіть можете взагалі не мати фронтендів.

Ймовірно, вам слід писати свій код незалежно від інтерфейсу, але якщо ви хочете відображати різні речі, ви можете використовувати розширену систему відображення (посилання, прикріплене до версії 4.x IPython), щоб відображати різні речі залежно від інтерфейсу, але вибере фронтенд, а не бібліотека.


2
Посилання вище на систему розширеного відображення IPython порушено. Ось посилання на поточну документацію: ipython.org/ipython-doc/dev/config/integrating.html , і ось посилання на кілька чудових прикладів: nbviewer.ipython.org/github/ipython/ipython/blob/master/ ...
Who8MyLunch

2
У мене така проблема в моєму модулі малювання . Мені потрібно імпортувати виклик matplotlib.use ("Agg") туди, щоб travis-ci дозволив зберігати креслення (див. Stackoverflow.com/questions/4706451/… ) Але це генерує попередження в блокноті UserWarning: Цей виклик matplotlib.use () не має ефекту, оскільки серверну інформацію вже вибрано; Як це вирішити?
Доктор Гоулу,

30
У мене є один приклад: індикатори прогресу. Емулятор терміналу ноутбука Jupyter не підтримує розширені символи управління терміналом, такі як \x1b[A(переміщення вгору), тому друкувати вкладені смуги неможливо . Немає проблем з ipywidgets , ми можемо використовувати власні віджети Jupyter для відображення індикаторів прогресу. Але тоді ми маємо два різні способи відображення індикатора прогресу, і програма може захотіти знати, що таке середовище відображення, щоб адаптувати та надрукувати сумісну панель.
важкий

2
наприклад, я хочу встановити IPython config, щоб він завжди працював, %matplotlib inlineколи він діє як блокнот, але не в терміналі, оскільки це не потрібно.
Ciprian Tomoiagă

3
Хоча це цілком слушна думка, ця відповідь не стосується фактичного питання. Як би ти не хотів, щоб інакше завжди існували відмінності в поведінці, які можуть мати значення.
Крістофер Барбер

69

Для моїх потреб працювали:

get_ipython().__class__.__name__

Він повертається 'TerminalInteractiveShell'на терміналі IPython, 'ZMQInteractiveShell'на Jupyter (ноутбук І qtconsole) і не працює ( NameError) на звичайному інтерпретаторі Python. get_python()Здається, метод доступний у глобальному просторі імен за замовчуванням при запуску IPython.

Обертаючи його простою функцією:

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

Вищезазначене було протестовано на Python 3.5.2, IPython 5.1.0 та Jupyter 4.2.1 на macOS 10.12 та Ubuntu 14.04.4 LTS


5
Увімкнено jupyter console, на жаль, get_ipython()повертає екземпляр ZMQInteractiveShellтакож
Джош Боде

7
Якщо хтось зацікавлений виявити, чи працює ноутбук на Google Colab, ви можете перевірити це:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz

3
Це працює лише для коду в блокноті. Це не працює, якщо функція знаходиться в імпортованому пакеті.
Крістофер Барбер

4
@ChristopherBarber Це не те, що я бачу. Якщо я вставляю цю функцію у файл, test.pyа потім запускаю from test import isnotebook; print(isnotebook())у блокноті Jupyter, вона друкується True. (Перевірено на сервері Notebook, версії 5.2.1 та 6.0.1.)
Марк Амері

Я думав, що була якась справа, яка у мене не спрацювала, але, на жаль, я не пам’ятаю подробиці. Можливо, це вже не проблема, або, можливо, я просто розгубився.
Крістофер Барбер,

41

Щоб перевірити, чи перебуваєте ви в зошиті, що може бути важливим, наприклад, під час визначення того, який тип індикатора використовувати, це мені вдалося:

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
У моєму IPython-Notebook (версія IPython 3.1) cfg['IPKernelApp']['parent_appname']є a IPython.config.loader.LazyConfigValue, що не порівняно Trueз"iypthon-notebook"
Dux

5
@juanjux get_ipython повертає IPython.kernel.zmq.zmqshell.ZMQInteractiveShellекземпляр у ipynb (Jupyter) та an IPython.terminal.interactiveshell.TerminalInteractiveShellу терміналі REPL, на випадок, якщо вам потрібно розрізнити блокноти та термінали / консолі (що впливає на побудову графіків).
конфорки

4
^ тому ви можете замінити внутрішню частину tryблоку на:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747

Як і @Dux, це не працює для мене; воно завжди повертає false, навіть у блокноті. Підозрюємо, що ця відповідь застаріла із введенням якоїсь лінивої системи завантаження конфігурації.
Mark Amery

Зауважте також, що ваша конфігурація може повернутися як порожній дикт, і в цьому випадку вам потрібно буде додати KeyError до блоку за винятком. Напевно, краще використовувати код, заснований на відповіді Густаво Безерри. Незважаючи на те, що я отримую порожню конфігурацію, я отримую її shell='PyDevTerminalInteractiveShell'під час перевірки назви класу.
hlongmore

28

Ви можете перевірити, чи python перебуває в інтерактивному режимі, за допомогою такого фрагмента [1] :

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

Я знайшов цей метод дуже корисним, оскільки я роблю багато прототипів у зошиті. Для тестування я використовую параметри за замовчуванням. В іншому випадку я читаю параметри з sys.argv.

from sys import argv

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

Після реалізації програми autonotebookви можете визначити, чи перебуваєте ви в зошиті, використовуючи наступний код.

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 ():> імпортувати main як main> return not hasattr (main, ' file ')> print is_interactive ()" True
marscher

3
is_interactive()не розрізняє блокнот і консоль.
krock

1
Ще одне застереження - випуск a %runз ipython є неінтерактивним. Можна стверджувати, що так повинно бути, але це все одно проблема.
dirkjot

Для інших, що роблять прототипи в зошиті, варіант підходу Тілла, який міститься тут, може бути корисним.
Wayne

Друга половина цієї відповіді корисна, але перша половина (приблизно is_interactive) мені здається в основному неактуальною для питання. Це також сумнівна коректність; як зазначає @marscher, він вважає, що все, що використовується python -c, перебуває в "інтерактивному" режимі, хоча це не відповідає дійсності. Я не хочу робити це сам, оскільки це не моя відповідь, але я думаю, що це було б покращено простим видаленням усієї першої половини відповіді.
Mark Amery

17

Нещодавно я зіткнувся з помилкою в ноутбуці Jupyter, яка потребує обхідного шляху , і я хотів зробити це, не втрачаючи функціональності інших оболонок. Я зрозумів, що рішення кефлавича в цьому випадку не працює, оскільки get_ipython()воно доступне лише безпосередньо з ноутбука, а не з імпортованих модулів. Тож я знайшов спосіб визначити з мого модуля, імпортований він чи використовується із блокнота Юпітера чи ні:

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

Коментарі вдячні, якщо це досить надійно.

Подібним чином можна отримати деяку інформацію про клієнта, а також версію 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']

Хм, я використовую Fedora 23 Jupyter, і там 'Ipython' in sys.modulesоцінює False. Можливо, ти маєш на увазі 'IPython' in sys.modules? Це Trueв моєму середовищі Юпітера. sys.modulesСловник також не включає в себе 'ipykernel'ключ - при роботі всередині ноутбука.
maxschlepzig

2
Наразі це найкраща відповідь, ІМО. Короткий і солодкий.
danielpcox

3

Перевірено на python 3.7.3

Реалізації CPython мають назву, __builtins__доступну як частина їх глобальних даних, які, до речі. можна отримати за допомогою функції globals ().
Якщо скрипт працює в середовищі Ipython, тоді він __IPYTHON__повинен бути атрибутом __builtins__.
Тому наведений нижче код повертається, Trueякщо він працює під Ipython або, якщо він надаєтьсяFalse

hasattr(__builtins__,'__IPYTHON__')

2

Далі описано випадки https://stackoverflow.com/a/50234148/1491619 без необхідності аналізувати результати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

Для мене, це тільки показує , jupyterчи є це jupyter console, jupyter qtconsoleабо jupyter notebook.
Люк Девіс,

2

Я б рекомендував уникати виявлення конкретного інтерфейсу, оскільки їх занадто багато . Натомість ви можете просто перевірити, чи запускаєте ви всередині середовища iPython:

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

Вище повернеться, Falseякщо ви звертаєтесь running_from_ipythonіз звичайного командного рядка python. Коли ви викликаєте його з Jupyter Notebook, JupyterHub, оболонки iPython, Google Colab тощо, він повернеться True.


Мені не вдається - Коли я спробую це в Jupyter Notebook на Ubuntu з Python3, get_ipython()повертається <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
головний герой

Проблема цього підходу полягає в тому, що він не вирішує питання OP: "Як я можу перевірити за своїм кодом Python, чи працює він у блокноті IPython ?" (наголос мій). Оболонка IPython не є блокнотом, але коли я запускаю її у своїй консолі Python у PyCharm, я get_ipython() is not Noneповертаюся True.
hlongmore

хм, як я можу визначити, якщо я працюю на jupyter проти voila?
ntg

2

Все, що вам потрібно зробити, це розмістити ці дві комірки на початку вашого блокнота:

Осередок 1: (позначений як "код"):

is_notebook = True

Клітинка 2: (позначена як "Raw NBConvert"):

is_notebook = False

Перша комірка завжди буде виконана, але друга комірка буде виконана лише тоді, коли ви експортуєте блокнот як сценарій Python.

Пізніше ви можете перевірити:

if is_notebook:
    notebook_code()
else:
    script_code()

Сподіваюся, це допомагає.



1

Наскільки я знаю, тут є 3 види ipython, які використовувались ipykernel

  1. ipython qtconsole (коротше "qtipython")
  2. IPython в spyder (коротше "шпигун")
  3. IPython у блокноті jupyter (скорочено "jn")

використання 'spyder' in sys.modulesможе розрізнити шпигуна

але для qtipython та jn важко розрізнити причину

вони мають однакову sys.modulesта однакову конфігурацію IPython:get_ipython().config

Я знаходжу різницю між qtipython та jn:

перший запуск os.getpid()в оболонці IPython отримає номер pid

то біжи ps -ef|grep [pid number]

мій 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

мій 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

відмінне від qtipython та jn - це ім'я json ipython, ім'я json jn довше, ніж qtipython

отже, ми можемо автоматично виявити все середовище Python за таким кодом:

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)

вихідний код тут: Виявлення середовища Python, Особливо виділяють Spyder, блокнот Jupyter, Qtconsole.py


0

Я використовую Django Shell Plus для запуску IPython, і я хотів зробити «запуск у блокноті» доступним як значення параметрів Django. get_ipython()недоступний під час завантаження налаштувань, тому я використовую це (яке не є стійким до кулі, але досить добре для місцевих середовищ розробки, в яких він використовується):

import sys

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

0

Припускаючи, що ви маєте під контролем блокнот Юпітера, ви можете:

  1. встановіть значення середовища в комірці, яка використовує це як прапор у вашому коді . Розмістіть унікальний коментар у цій комірці (або всіх комірках, які ви хочете виключити)

    # exclude_from_export
    % set_env is_jupyter = 1

  2. Експортуйте блокнот як сценарій python, який буде використовуватися в іншому контексті. Експорт виключає коментовані комірки та згодом код, що встановлює значення середовища. Примітка: замініть your_notebook.ipynb на ім'я вашого фактичного файлу блокнота.

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

Це створить файл, у якому не буде встановлено прапор середовища jupyter, що дозволяє коду, який використовує його для детермінованого виконання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.