Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace voila with solara for CLI/standalone app #2909

Merged
merged 22 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ body:
import ipygoldenlayout; print("ipygoldenlayout", ipygoldenlayout.__version__)
import ipypopout; print("ipypopout", ipypopout.__version__)
import jinja2; print("Jinja2", jinja2.__version__)
import voila; print("voila", voila.__version__)
import solara; print("solara", solara.__version__)
import vispy; print("vispy", vispy.__version__)
import sidecar; print("sidecar", sidecar.__version__)
import jdaviz; print("Jdaviz", jdaviz.__version__)
8 changes: 4 additions & 4 deletions .github/workflows/standalone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ jobs:
- name: Install pytest
run: pip install pytest-playwright

- name: Wait for Voila to get online
- name: Wait for Solara to get online
uses: ifaxity/wait-on-action@a7d13170ec542bdca4ef8ac4b15e9c6aa00a6866 # v1.2.1
with:
resource: tcp:8866
resource: tcp:8765
timeout: 60000

- name: Test standalone
Expand Down Expand Up @@ -174,10 +174,10 @@ jobs:
- name: Install pytest
run: pip install pytest-playwright

- name: Wait for Voila to get online
- name: Wait for Solara to get online
uses: ifaxity/wait-on-action@a7d13170ec542bdca4ef8ac4b15e9c6aa00a6866 # v1.2.1
with:
resource: tcp:8866
resource: tcp:8765
timeout: 60000

- name: Test standalone
Expand Down
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ New Features

- Plugins can now expose in-UI API hints. [#3137]

- The standalone version of jdaviz now uses solara instead of voila, resulting in faster load times. [#2909]

Cubeviz
^^^^^^^

Expand Down
30 changes: 30 additions & 0 deletions assets/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def pytest_configure(config):
PYTEST_HEADER_MODULES['ipysplitpanes'] = 'ipysplitpanes'
PYTEST_HEADER_MODULES['ipygoldenlayout'] = 'ipygoldenlayout'
PYTEST_HEADER_MODULES['ipypopout'] = 'ipypopout'
PYTEST_HEADER_MODULES['voila'] = 'voila'
PYTEST_HEADER_MODULES['solara'] = 'solara'
PYTEST_HEADER_MODULES['vispy'] = 'vispy'
PYTEST_HEADER_MODULES['gwcs'] = 'gwcs'
PYTEST_HEADER_MODULES['asdf'] = 'asdf'
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/infrastructure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ The target interfaces are:
* **Desktop**: This interface is meant to behave like a more traditional "desktop app",
i.e., a window with a fixed set of functionality and a particular layout for a
specific set of scientific use cases. This interface is accessed via a
`Voilà <https://voila.readthedocs.io>`_ wrapper that loads the same machinery as the
`Solara <https://solara.dev>`_ wrapper that loads the same machinery as the
other interfaces but presents the outputs of notebook "cells" as the only view.
This trades the flexibility of the notebook interface for a consistent and
reproducible layout and simpler interface without the distraction of the notebook
Expand Down
10 changes: 5 additions & 5 deletions docs/dev/win_dev.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ under the source checkout's root directory, you will need to rebuild
the package even in editable install mode. Otherwise, this should not
affect your development experience.

WSL2 and voila
kecnry marked this conversation as resolved.
Show resolved Hide resolved
--------------
WSL2 and Solara
---------------

``voila`` is unable to display when WSL2 cannot start up the
``solara`` is unable to display when WSL2 cannot start up the
Windows-side browser executable. Unfortunately, unlike Jupyter
notebook, ``voila`` does not have a ``--no-browser`` option
notebook, ``solara`` does not have a ``--no-browser`` option
with a tokenized URL you can copy-and-paste manually on the
Windows side (see https://github.com/voila-dashboards/voila/issues/773).
Windows side.
Therefore, you might need to install Jdaviz natively on Windows
to test its standalone application functionality.
1 change: 0 additions & 1 deletion docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ instead of ``pip``:
conda install bottleneck
conda install -c conda-forge notebook
conda install -c conda-forge jupyterlab
conda install -c conda-forge voila
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you need to add a line for solara install here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can either add it (making sure its available on conda-forge first) or wait for any sign that there are problems installing from pip that are resolved by installing through conda? 🤷‍♂️

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to add it here yet (if it's even installable via conda).


You might also want to enable the ``ipywidgets`` notebook extension, as follows:

Expand Down
106 changes: 22 additions & 84 deletions jdaviz/cli.py
kecnry marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
import inspect
import os
import pathlib
import sys
import tempfile

from voila.app import Voila
from voila.configuration import VoilaConfiguration

from jdaviz import __version__
from jdaviz.app import _verbosity_levels, ALL_JDAVIZ_CONFIGS
Expand Down Expand Up @@ -38,21 +33,14 @@
browser : str, optional
Path to browser executable.
theme : {'light', 'dark'}
Theme to use for Voila app or Jupyter Lab.
Theme to use for application.
verbosity : {'debug', 'info', 'warning', 'error'}
Verbosity of the popup messages in the application.
history_verbosity : {'debug', 'info', 'warning', 'error'}
Verbosity of the history logger in the application.
hotreload : bool
Whether to enable hot-reloading of the UI (for development)
"""
import logging # Local import to avoid possibly messing with JWST pipeline logger.

# Tornado Webserver py3.8 compatibility hotfix for windows
if sys.platform == 'win32':
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

if filepaths:
# Convert paths to posix string; windows paths are not JSON compliant
file_list = [pathlib.Path(f).absolute().as_posix() for f in filepaths]
Expand All @@ -63,74 +51,28 @@
else:
file_list = []

if layout == '':
if len(file_list) <= 1:
notebook = "jdaviz_cli_launcher.ipynb"
else:
raise ValueError("'layout' argument is required when specifying multiple files")
else:
notebook = "jdaviz_cli.ipynb"

with open(JDAVIZ_DIR / notebook) as f:
notebook_template = f.read()

start_dir = os.path.abspath('.')
if layout == '' and len(file_list) > 1:
raise ValueError("'layout' argument is required when specifying multiple files")

Check warning on line 55 in jdaviz/cli.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/cli.py#L54-L55

Added lines #L54 - L55 were not covered by tests

# Keep track of start directory in environment variable so that it can be
# easily accessed e.g. in the file load dialog.
os.environ['JDAVIZ_START_DIR'] = start_dir

nbdir = tempfile.mkdtemp()

os.environ['JDAVIZ_START_DIR'] = os.path.abspath('.')

Check warning on line 59 in jdaviz/cli.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/cli.py#L59

Added line #L59 was not covered by tests

from solara.__main__ import cli
from jdaviz import solara
solara.config = layout.capitalize()
solara.data_list = file_list
if layout == 'mosviz':
solara.load_data_kwargs = {'instrument': instrument}
solara.theme = theme
solara.jdaviz_verbosity = verbosity
solara.jdaviz_history_verbosity = history_verbosity
args = []

Check warning on line 70 in jdaviz/cli.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/cli.py#L61-L70

Added lines #L61 - L70 were not covered by tests
if hotreload:
notebook_template = notebook_template.replace("# PREFIX", "from jdaviz import enable_hot_reloading; enable_hot_reloading()") # noqa: E501

with open(os.path.join(nbdir, 'notebook.ipynb'), 'w') as nbf:
nbf.write(
notebook_template
.replace('CONFIG', layout.capitalize())
.replace('DATA_LIST', str(file_list))
.replace('JDAVIZ_VERBOSITY', verbosity)
.replace('JDAVIZ_HISTORY_VERBOSITY', history_verbosity)
# Mosviz specific changes
.replace('load_data(data', 'load_data(directory=data' if layout == 'mosviz' else 'load_data(data') # noqa: E501
.replace(') #ADDITIONAL_LOAD_DATA_ARGS', f', instrument=\'{instrument}\')' if layout == 'mosviz' else ')') # noqa: E501
.strip()
)

os.chdir(nbdir)

try:
logging.getLogger('tornado.access').disabled = True
Voila.notebook_path = 'notebook.ipynb'
VoilaConfiguration.template = 'jdaviz-default'
VoilaConfiguration.enable_nbextensions = True
VoilaConfiguration.file_whitelist = ['.*']
VoilaConfiguration.theme = theme
if browser != 'default':
Voila.browser = browser

voila = Voila.instance()
# monkey patch listen, so we can get a handle on the kernel_manager
# after it is created
previous_listen = voila.listen

def listen(*args, **kwargs):
# monkey patch remove_kernel, so we can stop the event loop
# when a kernel is removed (which means the browser page was closed)
previous_remove_kernel = voila.kernel_manager.remove_kernel

def remove_kernel(kernel_id):
previous_remove_kernel(kernel_id)
voila.ioloop.stop()

voila.kernel_manager.remove_kernel = remove_kernel
return previous_listen(*args, **kwargs)

voila.listen = listen
sys.exit(voila.launch_instance(argv=[]))
finally:
os.chdir(start_dir)
args += ['--auto-restart']

Check warning on line 72 in jdaviz/cli.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/cli.py#L72

Added line #L72 was not covered by tests
else:
args += ['--production']
cli(['run', 'jdaviz.solara'] + args)

Check warning on line 75 in jdaviz/cli.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/cli.py#L74-L75

Added lines #L74 - L75 were not covered by tests


def _main(config=None):
Expand All @@ -157,13 +99,9 @@
help='Verbosity of the application for popup snackbars.')
parser.add_argument('--history-verbosity', choices=_verbosity_levels, default='info',
help='Verbosity of the logger history.')
if sys.version_info >= (3, 9):
# Also enables --no-hotreload
parser.add_argument('--hotreload', action=argparse.BooleanOptionalAction, default=False,
help='Whether to enable hot-reloading of the UI (for development).')
else:
parser.add_argument('--hotreload', action='store_true', default=False,
help='Enable hot-reloading of the UI (for development).')
# Also enables --no-hotreload
parser.add_argument('--hotreload', action=argparse.BooleanOptionalAction, default=False,

Check warning on line 103 in jdaviz/cli.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/cli.py#L103

Added line #L103 was not covered by tests
help='Whether to enable hot-reloading of the UI (for development).')
parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
args = parser.parse_args()

Expand Down
2 changes: 1 addition & 1 deletion jdaviz/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def pytest_configure(config):
PYTEST_HEADER_MODULES['ipysplitpanes'] = 'ipysplitpanes'
PYTEST_HEADER_MODULES['ipygoldenlayout'] = 'ipygoldenlayout'
PYTEST_HEADER_MODULES['ipypopout'] = 'ipypopout'
PYTEST_HEADER_MODULES['voila'] = 'voila'
PYTEST_HEADER_MODULES['solara'] = 'solara'
PYTEST_HEADER_MODULES['vispy'] = 'vispy'
PYTEST_HEADER_MODULES['gwcs'] = 'gwcs'
PYTEST_HEADER_MODULES['asdf'] = 'asdf'
Expand Down
26 changes: 16 additions & 10 deletions jdaviz/core/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,16 @@
mosviz_icon = Unicode(read_icon(os.path.join(ICON_DIR, 'mosviz_icon.svg'), 'svg+xml')).tag(sync=True) # noqa
imviz_icon = Unicode(read_icon(os.path.join(ICON_DIR, 'imviz_icon.svg'), 'svg+xml')).tag(sync=True) # noqa

def __init__(self, main, configs=ALL_JDAVIZ_CONFIGS, filepath='', height=None, *args, **kwargs):
def __init__(self, main=None, configs=ALL_JDAVIZ_CONFIGS, filepath='',
height=None, *args, **kwargs):
self.vdocs = 'latest' if 'dev' in __version__ else 'v'+__version__

if main is None:
main = v.Sheet(class_="mx-25",
attributes={"id": "popout-widget-container"},
color="#00212C",
height=height)

self.main = main
self.configs = configs
self.height = f"{height}px" if isinstance(height, int) else height
Expand Down Expand Up @@ -193,14 +200,19 @@
config = event.get('config')
helper = _launch_config_with_data(config, self.loaded_data,
filepath=self.filepath, show=False)
if self.height != '100%':
if self.height not in ['100%', '100vh']:

Check warning on line 203 in jdaviz/core/launcher.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/core/launcher.py#L203

Added line #L203 was not covered by tests
# We're in jupyter mode. Set to default height
default_height = helper.app.state.settings['context']['notebook']['max_height']
helper.app.layout.height = default_height
self.main.height = default_height
self.main.color = 'transparent'
self.main.children = [helper.app]

@property
def main_with_launcher(self):
self.main.children = [self]
return self.main

Check warning on line 214 in jdaviz/core/launcher.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/core/launcher.py#L213-L214

Added lines #L213 - L214 were not covered by tests


def show_launcher(configs=ALL_JDAVIZ_CONFIGS, filepath='', height='450px'):
'''Display an interactive Jdaviz launcher to select your data and compatible configuration
Expand All @@ -217,11 +229,5 @@
'''
# Color defined manually due to the custom theme not being defined yet (in main_styles.vue)
height = f"{height}px" if isinstance(height, int) else height
main = v.Sheet(class_="mx-25",
attributes={"id": "popout-widget-container"},
color="#00212C",
height=height,
_metadata={'mount_id': 'content'})
main.children = [Launcher(main, configs, filepath, height)]

show_widget(main, loc='inline', title=None)
launcher = Launcher(None, configs, filepath, height)
show_widget(launcher.main_with_launcher, loc='inline', title=None)

Check warning on line 233 in jdaviz/core/launcher.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/core/launcher.py#L232-L233

Added lines #L232 - L233 were not covered by tests
40 changes: 0 additions & 40 deletions jdaviz/jdaviz_cli.ipynb

This file was deleted.

Loading
Loading