python-package/lets_plot/frontend_context/_html_contexts.py (97 lines of code) (raw):
# Copyright (c) 2020. JetBrains s.r.o.
# Use of this source code is governed by the MIT license that can be found in the LICENSE file.
import os
from ._frontend_ctx import FrontendContext
from ._isolated_webview_panel_ctx import IsolatedWebviewPanelContext
from ._jupyter_notebook_ctx import JupyterNotebookContext
from ._static_html_page_ctx import StaticHtmlPageContext
from ._webbr_html_page_ctx import WebBrHtmlPageContext
from .._global_settings import has_global_value, get_global_bool, HTML_ISOLATED_FRAME
def _create_html_frontend_context(
isolated_frame: bool = None,
offline: bool = None,
dev_options: dict = None) -> FrontendContext:
"""
Configures Lets-Plot HTML output.
See the docstring in `setup_html()` for details on parameters.
"""
if dev_options is None:
dev_options = {}
else:
dev_options = dev_options.copy()
# Extract and remove isolated_webview_panel from dev_options
isolated_webview_panel = dev_options.pop('isolated_webview_panel', None)
if isolated_webview_panel is None:
isolated_webview_panel = _is_positron_console()
if isolated_webview_panel:
return IsolatedWebviewPanelContext(offline, **dev_options)
if isolated_frame is None:
isolated_frame = _use_isolated_frame()
if isolated_frame:
return StaticHtmlPageContext(offline, **dev_options)
else:
return JupyterNotebookContext(offline, **dev_options)
def _create_wb_html_frontend_context(exec: str, new: bool) -> FrontendContext:
"""
Configures Lets-Plot HTML output for showing in a web browser.
Parameters
----------
exec : str, optional
The name of the web browser to use.
If not specified, the default browser will be used.
new : bool, default=False
If True, the URL is opened in a new window of the web browser.
If False, the URL is opened in the already opened web browser window.
"""
return WebBrHtmlPageContext(exec, new)
def _use_isolated_frame() -> bool:
# check environment
if has_global_value(HTML_ISOLATED_FRAME):
return get_global_bool(HTML_ISOLATED_FRAME)
# return _detect_isolated_frame()
if not _is_IPython_display():
return True # fallback to a complete HTML page in the output
# Some notebooks behave like a single HTML page where the JS library is loaded once per notebook.
if (_is_jupyter_classic() or
_is_kaggle() or
_is_positron_notebook()):
return False # no iframes in the output cell
# Most online notebook platforms are showing cell output in iframe and require
# a complete HTML page in the output which includes both:
# - the script loading JS library and
# - the script that uses this JS lib to create a plot.
if (_is_google_colab() or
_is_azure_notebook() or
_is_deepnote() or
_is_databricks() or
_is_nextjournal()
):
return True # complete HTML page in the output
# if os.getenv("PLOTLY_RENDERER") == "colab":
# # good enough - something colab-like
# return True # Colab -> iframe
# try:
# shell = get_ipython().__class__.__name__
# if shell == 'ZMQInteractiveShell':
# return False # Jupyter notebook or qtconsole -> load JS librarty once per notebook
# elif shell == 'TerminalInteractiveShell':
# return True # Terminal running IPython -> an isolated HTML page to show somehow
# else:
# return True # Other type (?)
# except NameError:
# return True # some other env (even standard Python interpreter) -> an isolated HTML page to show somehow
# Fallback to a complete HTML page in the output
return True
# def _detect_isolated_frame() -> bool:
# if not _is_IPython_display():
# return True # fallback to a complete HTML page in the output
#
# # Some notebooks behave like a single HTML page where the JS library is loaded once per notebook.
# if (_is_jupyter_classic() or
# _is_kaggle() or
# _is_positron_notebook()):
# return False # no iframes in the output cell
#
# # Most online notebook platforms are showing cell output in iframe and require
# # a complete HTML page in the output which includes both:
# # - the script loading JS library and
# # - the script that uses this JS lib to create a plot.
#
# if (_is_google_colab() or
# _is_azure_notebook() or
# _is_deepnote() or
# _is_databricks() or
# _is_nextjournal()
# ):
# return True # complete HTML page in the output
#
# # if os.getenv("PLOTLY_RENDERER") == "colab":
# # # good enough - something colab-like
# # return True # Colab -> iframe
#
# # try:
# # shell = get_ipython().__class__.__name__
# # if shell == 'ZMQInteractiveShell':
# # return False # Jupyter notebook or qtconsole -> load JS librarty once per notebook
# # elif shell == 'TerminalInteractiveShell':
# # return True # Terminal running IPython -> an isolated HTML page to show somehow
# # else:
# # return True # Other type (?)
# # except NameError:
# # return True # some other env (even standard Python interpreter) -> an isolated HTML page to show somehow
#
# # Fallback to a complete HTML page in the output
# return True
def _is_IPython_display() -> bool:
try:
from IPython.display import display_html
return True
except ImportError:
return False
def _is_jupyter_classic() -> bool:
# This also detects JupyterLab, which uses the same ZMQInteractiveShell
# and also qtconsole (allegedly)
try:
from IPython import get_ipython
except ImportError:
return False
shell = get_ipython()
try:
return shell is not None and shell.__class__.__name__ == "ZMQInteractiveShell"
except AttributeError:
return False
def _is_google_colab() -> bool:
try:
import google.colab
return True
except ImportError:
return False
def _is_kaggle() -> bool:
# This gives a false positive in Colab.
# return os.path.exists("/kaggle/input")
return 'KAGGLE_KERNEL_RUN_TYPE' in os.environ
def _is_azure_notebook() -> bool:
return "AZURE_NOTEBOOKS_HOST" in os.environ
def _is_deepnote() -> bool:
return "DEEPNOTE_PROJECT_ID" in os.environ
def _is_databricks() -> bool:
# As proposed: https://github.com/JetBrains/lets-plot/issues/602
return "databricks" in str(os.environ)
def _is_nextjournal() -> bool:
return "NEXTJOURNAL" in str(os.environ)
def _is_positron_console():
try:
from IPython import get_ipython
except ImportError:
return False
shell = get_ipython()
try:
return shell is not None and shell.session_mode == "console"
except AttributeError:
return False
def _is_positron_notebook():
try:
from IPython import get_ipython
except ImportError:
return False
shell = get_ipython()
try:
return shell is not None and shell.session_mode == "notebook"
except AttributeError:
return False