From 7e48dfe3c368e2941890bec8e5d148bccc7323ed Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Tue, 10 Sep 2024 16:10:14 +0200 Subject: [PATCH] feat: use embedded qt browser for jdaviz standalone --- .github/workflows/standalone.yml | 23 +++++++++++++++++++--- jdaviz/cli.py | 12 ++++------- standalone/hooks/hook-matplotlib_inline.py | 5 +++++ standalone/jdaviz-cli-entrypoint.py | 17 +++++++++++++++- standalone/jdaviz.spec | 2 +- 5 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 standalone/hooks/hook-matplotlib_inline.py diff --git a/.github/workflows/standalone.yml b/.github/workflows/standalone.yml index c44c03a111..21f5ec8bae 100644 --- a/.github/workflows/standalone.yml +++ b/.github/workflows/standalone.yml @@ -31,11 +31,28 @@ jobs: with: python-version: "3.11" + - uses: ConorMacBride/install-package@v1 + with: + # mirrored from glue-qt + # https://github.com/glue-viz/glue-qt/blob/main/.github/workflows/ci_workflows.yml + # using + # https://github.com/OpenAstronomy/github-actions-workflows/blob/5edb24fa432c75c0ca723ddea8ea14b72582919d/.github/workflows/tox.yml#L175C15-L175C49 + # Linux PyQt 5.15 and 6.x installations require apt-getting xcb and EGL deps + # and headless X11 display; + apt: '^libxcb.*-dev libxkbcommon-x11-dev libegl1-mesa libopenblas-dev libhdf5-dev' + + - name: Setup headless display + uses: pyvista/setup-headless-display-action@v2 + - name: Install jdaviz - run: pip install .[test] + run: pip install .[test,qt] - name: Install pyinstaller - run: pip install "pyinstaller<6" + # see https://github.com/erocarrera/pefile/issues/420 for performance issues on + # windows for pefile == 2024.8.26 + # also see https://github.com/widgetti/solara/pull/724 + # or https://solara.dev/documentation/advanced/howto/standalone (currently unpublished) + run: pip install "pyinstaller" "pefile<2024.8.26" - name: Create standalone binary env: @@ -43,7 +60,7 @@ jobs: run: (cd standalone; pyinstaller ./jdaviz.spec) - name: Run jdaviz cmd in background - run: ./standalone/dist/jdaviz/jdaviz-cli imviz& + run: ./standalone/dist/jdaviz/jdaviz-cli imviz --port 8765 & - name: Install playwright run: (pip install playwright; playwright install chromium) diff --git a/jdaviz/cli.py b/jdaviz/cli.py index e5d44f3f08..f6cb9d5c29 100644 --- a/jdaviz/cli.py +++ b/jdaviz/cli.py @@ -70,20 +70,16 @@ def main(filepaths=None, layout='default', instrument=None, browser='default', solara.theme = theme solara.jdaviz_verbosity = verbosity solara.jdaviz_history_verbosity = history_verbosity - args = [] - if hotreload: - args += ['--auto-restart'] - else: - args += ['--production'] - run_solara(host=host, port=port, theme=theme, browser=browser) + run_solara(host=host, port=port, theme=theme, browser=browser, production=not hotreload) -def run_solara(host, port, theme, browser): +def run_solara(host, port, theme, browser, production: bool = True): os.environ["SOLARA_APP"] = "jdaviz.solara" import solara.server.starlette import solara.server.settings solara.server.settings.theme.variant = theme solara.server.settings.theme.loader = "plain" + solara.server.settings.main.mode = "production" if production else "development" server = solara.server.starlette.ServerStarlette(host="localhost", port=port) print(f"Starting server on {server.base_url}") @@ -125,7 +121,7 @@ def _main(config=None): parser.add_argument('--instrument', type=str, default='nirspec', help='Manually specifies which instrument parser to use, for Mosviz') parser.add_argument('--browser', type=str, default='default', - help='Browser to use for application (use qt for embedded qt browser).') + help='Browser to use for application (use qt for embedded Qt browser).') parser.add_argument('--theme', choices=['light', 'dark'], default='light', help='Theme to use for application.') parser.add_argument('--verbosity', choices=_verbosity_levels, default='info', diff --git a/standalone/hooks/hook-matplotlib_inline.py b/standalone/hooks/hook-matplotlib_inline.py new file mode 100644 index 0000000000..432d0d302b --- /dev/null +++ b/standalone/hooks/hook-matplotlib_inline.py @@ -0,0 +1,5 @@ +from PyInstaller.utils.hooks import collect_data_files, copy_metadata + +datas = collect_data_files('matplotlib_inline') +# since matplotlib 3.9 entry_points.txt is needed +datas += copy_metadata('matplotlib_inline') diff --git a/standalone/jdaviz-cli-entrypoint.py b/standalone/jdaviz-cli-entrypoint.py index 5fbcbf7f59..05c29281ad 100644 --- a/standalone/jdaviz-cli-entrypoint.py +++ b/standalone/jdaviz-cli-entrypoint.py @@ -7,9 +7,24 @@ import matplotlib_inline import matplotlib_inline.backend_inline +# We still see the above error on CI on jdaviz, and the PyInstaller +# output recommends the following: +import matplotlib +matplotlib.use("module://matplotlib_inline.backend_inline") +# since matplotlib 3.9 (see https://github.com/matplotlib/matplotlib/pull/27948), +# it seems that matplotlib_inline.backend_inline is an alias for inline +# so we make sure to communicate that to PyInstaller +matplotlib.use("inline") + import jdaviz.cli if __name__ == "__main__": # should change this to _main, but now it doesn't need arguments - jdaviz.cli.main(layout="") + args = sys.argv.copy() + # change the browser to qt if not specified + if "--browser" not in args: + args.append("--browser") + args.append("qt") + sys.argv = args + jdaviz.cli._main() diff --git a/standalone/jdaviz.spec b/standalone/jdaviz.spec index 11ddf9a610..83ff977079 100644 --- a/standalone/jdaviz.spec +++ b/standalone/jdaviz.spec @@ -50,7 +50,7 @@ exe = EXE( bootloader_ignore_signals=False, strip=False, upx=True, - console=True, + console=False, disable_windowed_traceback=False, argv_emulation=False, target_arch=None,