检测ipython notebook是否输出到终端

3
我希望能够检测Jupyter Notebook是否在终端中执行,例如通过ipython --TerminalIPythonApp.file_to_run命令,与启用HTML的Notebook相反。请注意,这与检测Python代码是否在python中运行或在Notebook中运行是不同的。
基于此,我可以格式化适合HTML或终端显示的Pandas DataFrames。
如何检测笔记本电脑是否输出到终端?

如果这个答案对您有用,您能否接受以下内容作为答案?谢谢。 - William
嗨,William!抱歉,我还没有找到时间尝试答案,但你肯定会得到勾选标记的。在接受之前,我希望能够测试并留下一些反馈。赏金仍然运行了3天。 - Mikko Ohtamaa
谢谢Mikko。感激不尽。 - William
3个回答

2
这可能会有所帮助。
from IPython import get_ipython
def type_of_execution():
    try:
        type_of_exec = str(type(get_ipython()))
        if 'terminal' in type_of_exec:
            return 'terminal'
        elif 'zmqshell' in type_of_exec:
            return 'jupyter'
        else:
            return 'python'
    except:
        return 'terminal likely'
print("Checking..")
print(type_of_execution())

1

根据William的回答,我搞清楚了。

终端输出示例:

输入图像描述

HTML输出示例:

输入图像描述

以下是一些样例代码,已从William的答案中进行了清理,并提供了更多上下文说明如何利用它。

查看使用此功能的量化金融笔记本示例查看完整源代码

"""Helpers to deal with Jupyter Notebook issues."""
import enum
from typing import Callable

import pandas as pd
from IPython import get_ipython
from IPython.display import display
from IPython.terminal.interactiveshell import TerminalInteractiveShell
from ipykernel.zmqshell import ZMQInteractiveShell


class JupyterOutputMode(enum.Enum):
    """What kind of output Jupyter Notebook supports."""

    #: We could not figure out - please debug
    unknown = "unknown"

    #: The notebook is run by terminal
    terminal = "terminal"

    #: Your normal HTML notebook
    html = "html"


def get_notebook_execution_mode() -> JupyterOutputMode:
    """Determine if the Jupyter Notebook supports HTML output."""

    # See https://dev59.com/128NtIcB2Jgan1zneQfK
    # for discussion
    ipython = get_ipython()

    if isinstance(ipython, TerminalInteractiveShell):
        # Hello ANSI graphics my old friend
        return JupyterOutputMode.terminal
    elif isinstance(ipython, ZMQInteractiveShell):
        # MAke an assumption ZMQ instance is a HTML notebook
        return JupyterOutputMode.html

    return JupyterOutputMode.unknown


def display_with_styles(df: pd.DataFrame, apply_styles_func: Callable):
    """Display a Pandas dataframe as a table.

    DataFrame styler objects only support HTML output.
    If the Jupyter Notebook output does not have HTML support,
    (it is a command line), then display DataFrame as is
    without styles.

    For `apply_style_func` example see :py:method:`tradingstrategy.analysis.portfolioanalyzer.expand_timeline`.

    :param df: Pandas Dataframe we want to display as a table.

    :param apply_styles_func: A function to call on DataFrame to add its styles on it.
        We need to pass this as callable due to Pandas architectural limitations.
        The function will create styles using `pandas.DataFrame.style` object.
        However if styles are applied the resulting object can no longer be displayed in a terminal.
        Thus, we need to separate the procses of creating dataframe and creating styles and applying them.

    """
    mode = get_notebook_execution_mode()
    if mode == JupyterOutputMode.html:
        display(apply_styles_func(df))
    else:
        display(df)


1
很不幸,到目前为止的答案与这个问题上的答案相似,即试图通过诸如get_ipython()是否被定义或返回某个特定类的实例等细节来推测运行时特性。这些测试总是会很脆弱,而且很可能也是错误的,因为存在许多笔记本运行时的变体,例如Jupyter、JupyterLab和Google Colab,而这些测试只能间接证明HTML支持。
阅读Matt的回答(与前面的链接相同)让我意识到有一种更直接和可靠的方法:尝试显示一些内容,然后查看运行时选择了什么格式。
为了将这个想法转化为代码,这里有一个小的辅助类。它可以显示为HTML或纯文本,并记录运行时的选择。
class DisplayInspector:
    """Objects that display as HTML or text."""
    def __init__(self) -> None:
        self.status = None

    def _repr_html_(self) -> str:
        self.status = 'HTML'
        return '<p>Checking HTML support: ✅</p>'

    def __repr__(self) -> str:
        self.status = 'Plain'
        return 'Checking HTML support: ❌'

我们还需要一个实际进行实验的函数:
import sys

def supports_html() -> bool:
    """Test whether current runtime supports HTML."""
    if (
        'IPython' not in sys.modules
        or 'IPython.display' not in sys.modules
    ):
        return False

    from IPython.display import display
    inspector = DisplayInspector()
    display(inspector)
    return inspector.status == 'HTML'

就是这样。按设计,这个测试会留下可见的痕迹。这是件好事:它使得测试更加健壮,因为它实际上测试了我们想要知道的内容。但同时也是件坏事:它留下了可见的痕迹。如果这让你感到困扰,我建议从两个方法中返回空字符串。至少对我来说,这样做有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接