Skip to content

Commit

Permalink
POC: Attempt to package jdaviz in Pyinstaller (take 2) (#1960)
Browse files Browse the repository at this point in the history
* feat: pyinstaller

* codesign osx

* debug: try without codesign

* does not need arguments

* use hooks

* also download the app

* use branch of pyinstaller

* better hooks

* pin to 5.11

Otherwise we need to do at least:
+        rm -rf standalone/dist/jdaviz.app/Contents/MacOS/jedi/third_party/typeshed/stdlib/
+        rm -rf standalone/dist/jdaviz.app/Contents/MacOS/**/*.dist-info

* fix: maintain symlinks by zipping, upload-artifact does not support it

* GHA logic?

* code sign on gha

* run notary tool on gha

* fix: redo codesign after modifications

* fix: reorder zipping and notary step

* remove invalid symlink

* make sure the program executes

* fix path of entitlements file

* add comment for hint with the osx fix

* gpt assisted way of running the log tool on failure

* fix syntax error

* fix path

* comments for the future

* fix uuid parsing and re-zip the app after notary step

* fix: use ditto instead of zip

from https://developer.apple.com/forums/thread/116831

zip might cause issues with utf8 or metadata.

* comments for the future

* fix uuid for notary step

* upload different artifact for osx

* cleanup spec file and hooks, no more __pycache__ files should be included

* ci: do not cancel on failure

* fix: mistune 3.0 needs this

* make dmg instead of zip for osx

* BUG: Fix mouseover behavior in Cubeviz
spectrum viewer when spatial subset is present.

Co-authored-by: Duy Nguyen <[email protected]>

* Remove change log from #2258

because the bug only affects unreleased code

[ci skip] [rtd skip]

* Deprecate get_subsets_from_viewer

* Missing region index

* Fix subset args

* Remove get_data_from_viewer from imviz viewer tests

* Remove get_data_from_viewer from mosviz data loading test and sub hardcoded viewer ref names

* Mosviz test update image truth class

* Fix incorrect viewer ref

* Set Mos2Dviewer data statistic to None by default

* Non-existent data check

* Properly deprecate getters

* Properly check for valueError on non-existent label

* Update Specviz get_data_from_viewer test

* Rename "subset_to_apply" to "spectral_subset

* Codestyle

* Fix docs wording

Co-authored-by: Jesse Averbukh <[email protected]>

* Catch missed code, fix bug

* Retain Mosviz get_data behavior
and fix change log

* Undo bad diff

* MNT: Add .mailmap
so git shortlog -es gives sane listing.

* DOC: Add warning about surface brightness in Simple Aperture Photometry plugin (#2261)

* DOC: Add warning about surface brightness
in Simple Aperture Photometry plugin.

I am beginning to think the Simple in plugin name no longer applies.

* DOC: Improve verbiage.

Co-authored-by: Camilla Pacifici <[email protected]>

---------

Co-authored-by: Camilla Pacifici <[email protected]>

* FEAT: Annulus draw tool for Imviz (#2240)

* FEAT: Annulus draw tool for Imviz.

TODO: Need to fix icon.

TST: Add tests.

[ci skip] [rtd skip]

* Pull in #2204 into this PR
and bump upstream pins

* Changed function name
upstream in glue-astronomy during review process

* Proper annulus icon from J. Kotler

Co-authored-by: Jennifer Kotler <[email protected]>

* Avoid error traceback with bad annulus radii

* Disable recentering for annulus

* Fix test failure
because not sure why spectral region is using Imviz centering method
but okay.

---------

Co-authored-by: Jennifer Kotler <[email protected]>
Co-authored-by: Ricky O'Steen <[email protected]>

* MNT: Temporarily pin voila<0.5 (#2269)

* MNT: Temp pin voila<0.5
because voila-template is incompatible, see #2268

* TST: Disable voila dev in test matrix

* TST: Ignore DeprecationWarning from asteval (#2274)

* TST: Ignore DeprecationWarning from asteval.
For example https://github.com/newville/asteval/issues/120

* Also ignore FutureWarning from asteval

* Add doc for windows latency issue

* Deprecate load_spectrum

* Update tests and docs from load_spectrum

* Docstring suggestions

Co-authored-by: P. L. Lim <[email protected]>

* Changelog

* Changelog

* Button to export Cubeviz movie (#2264)

* WIP: Backend API to write movie file
but got stuck with bqplot not cooperating after first frame.

[ci skip] [rtd skip]

* fix: bqplot stuck after the first frame of the movie

We have to run the loop outside the main thread; otherwise, the
processing of messages from the frontend is blocked, causing the
message with the first image to never be received. The "save_image"
method can only save the next image after the previous image is
received.

* Fix typo, this works now from the API.

[ci skip] [rtd skip]

* Add frontend and tests

* Add user doc

* DOC: Add note about standalone app
saving file into weird places.

* Address some review comments

* Expose FPS and fix test

* DOC: Baby Shark roundtrip
as promised.

* DOC: Ellie said more shark!

* Vue.js style improvements

[ci skip] [rtd skip]

Co-authored-by: Kyle Conroy <[email protected]>

* Display pls install msg in plugin

* Address review comments

* Fix test

* Fix path resolution in standalone app

* Improve frontend validation and access.

Co-authored-by: Kyle Conroy <[email protected]>

* Disable video for spectrum-viewer in GUI
and add comment to Slice.

* Add tooltip to kill switch
but it only shows when activated

* Rename kill with something less scary

* Hide stop button
since disabling is not obvious enough, also moar tooltip

* Disable the whole movie menu for spectrum

viewer in Cubeviz [ci skip] [rtd skip]

Co-authored-by: Ricky O'Steen <[email protected]>

* Fix RTD warnings about invalid prop
and remove unnecessary frontend check now that Ricky's suggestion is accepted.

---------

Co-authored-by: Mario Buikhuizen <[email protected]>
Co-authored-by: Kyle Conroy <[email protected]>
Co-authored-by: Ricky O'Steen <[email protected]>

* Add functional but ugly launcher

* Use launcher notebook if neither config nor filepath is specified

* Codestyle

* Add margins on left and right to avoid cutoff in notebook

* Support launcher from cli

* Codestyle

* Remove URI from path text until implemented

* Fix standalone bug

* Specify --layout= as new required cli syntax

* Remove unused import

Co-authored-by: P. L. Lim <[email protected]>

* Update readme to show required layout flag

* Changelog

* Changelog

Co-authored-by: P. L. Lim <[email protected]>

* Changelog

* Update .github/workflows/standalone.yml

Co-authored-by: P. L. Lim <[email protected]>

* Update .github/workflows/standalone.yml

* Update to use config launcher

* Moved changelog entry to new section

---------

Co-authored-by: Duy Nguyen <[email protected]>
Co-authored-by: Pey Lian Lim <[email protected]>
Co-authored-by: Duy Tuong Nguyen <[email protected]>
Co-authored-by: Jesse Averbukh <[email protected]>
Co-authored-by: Camilla Pacifici <[email protected]>
Co-authored-by: Jennifer Kotler <[email protected]>
Co-authored-by: Ricky O'Steen <[email protected]>
Co-authored-by: Mario Buikhuizen <[email protected]>
Co-authored-by: Kyle Conroy <[email protected]>
Co-authored-by: Ricky O'Steen <[email protected]>
  • Loading branch information
11 people authored Jul 5, 2023
1 parent 4c859b7 commit 46be84f
Show file tree
Hide file tree
Showing 26 changed files with 754 additions and 1 deletion.
141 changes: 141 additions & 0 deletions .github/workflows/standalone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Build standalone

on:
push:
branches:
- main
- 'v*'
tags:
- 'v*'

defaults:
run:
shell: bash {0}


jobs:
build_binary:
runs-on: ${{ matrix.os }}-latest
strategy:
matrix:
os: [ubuntu, windows, macos]
steps:
# osx signing based on https://melatonin.dev/blog/how-to-code-sign-and-notarize-macos-audio-plugins-in-ci/
- name: Import Certificates (macOS)
uses: apple-actions/import-codesign-certs@v1
if: ${{ matrix.os == 'macos' }}
with:
p12-file-base64: ${{ secrets.DEV_ID_APP_CERT }}
p12-password: ${{ secrets.DEV_ID_APP_PASSWORD }}
- uses: actions/checkout@v3
with:
fetch-depth: 0

- uses: actions/setup-python@v4
with:
python-version: "3.10"

- name: Install jdaviz
run: pip install .

- name: Install pyinstaller
run: pip install pyinstaller==5.11

- name: Create standalone binary
env:
DEVELOPER_ID_APPLICATION: ${{ secrets.DEVELOPER_ID_APPLICATION }}
run: (cd standalone; pyinstaller ./jdaviz.spec)

- name: Remove invalid files for OSX
# hopefully we can improve this in the future
# by using good hooks
# i think the issue is that we have a . in the name, there are many
# google hits on pyqt having the same issue
# and we might be able to remove it after https://github.com/pyinstaller/pyinstaller/pull/7619
# is released (pyinstaller 5.13 probably)
if: ${{ matrix.os == 'macos' }}
run: |
rm -rf standalone/dist/jdaviz.app/Contents/MacOS/skimage/.dylibs
rm -rf standalone/dist/jdaviz.app/Contents/Resources/skimage/.dylibs
- name: Codesign (OSX)
if: ${{ matrix.os == 'macos' }}
run: |
cd standalone/dist
codesign --deep --force --options=runtime --entitlements ../entitlements.plist --sign ${{ secrets.DEVELOPER_ID_APPLICATION }} --timestamp jdaviz.app
- name: Create dmg (OSX)
# if we do not call always() GHA will && with success()
if: ${{ always() && (matrix.os == 'macos') }}
# it seems ditto (not zip) should be used in combination with notarization
# see https://developer.apple.com/forums/thread/116831
# but dmg also works
# see https://github.com/glue-viz/glue-standalone-apps/blob/main/.github/workflows/build_stable.yml
run: |
rm -rf standalone/dist/jdaviz
hdiutil create -volname "Jdaviz" -srcfolder standalone/dist -ov -format UDZO standalone/dist/jdaviz.dmg
- name: Notary step + stapling (OSX)
if: ${{ matrix.os == 'macos' }}
run: |
output=$(xcrun notarytool submit standalone/dist/jdaviz.dmg --apple-id ${{ secrets.NOTARIZATION_USERNAME }} --team-id ${{ secrets.TEAM_ID }} --wait --password ${{ secrets.NOTARIZATION_PASSWORD }}) || true
echo "$output"
uuid=$(echo "$output" | awk -F '[ :]+' '/id:/ {print $3; exit}')
echo "UUID: $uuid"
if [[ $output == *"status: Accepted"* ]]; then
echo "Great, notarization succeeded, staple it!"
xcrun stapler staple standalone/dist/jdaviz.dmg
else
echo "Log output for failed notarization: $uuid"
xcrun notarytool log --apple-id ${{ secrets.NOTARIZATION_USERNAME }} --team-id ${{ secrets.TEAM_ID }} --password ${{ secrets.NOTARIZATION_PASSWORD }} $uuid || true
fi
- name: Validate app (OSX)
if: ${{ matrix.os == 'macos' }}
run: |
spctl -a -vvv -t execute standalone/dist/jdaviz.app
- name: Run jdaviz cmd in background
if: ${{ matrix.os == 'macos' }}
run: ./standalone/dist/jdaviz.app/Contents/MacOS/jdaviz-cli imviz&

- name: Run jdaviz cmd in background
if: ${{ matrix.os != 'macos' }}
run: ./standalone/dist/jdaviz/jdaviz-cli imviz&

- name: Install playwright
run: (pip install playwright; playwright install chromium)

- name: Install pytest
run: pip install pytest-playwright

- name: Wait for Voila to get online
uses: ifaxity/wait-on-action@v1
with:
resource: tcp:8866
timeout: 60000

- name: Test standalone
run: (cd standalone; touch pytest.ini; JUPYTER_PLATFORM_DIRS=1 pytest test.py --video=on)

- name: Upload Test artifacts
if: always()
uses: actions/upload-artifact@v3
with:
name: test-results-${{ matrix.os }}
path: standalone/test-results

- name: Upload jdaviz standalone (non-OSX)
if: ${{ always() && (matrix.os != 'macos') }}
uses: actions/upload-artifact@v3
with:
name: jdaviz-standlone-${{ matrix.os }}
path: |
standalone/dist/jdaviz
- name: Upload jdaviz standalone (OSX)
if: ${{ always() && (matrix.os == 'macos') }}
uses: actions/upload-artifact@v3
with:
name: jdaviz-standlone-${{ matrix.os }}
path: standalone/dist/jdaviz.dmg
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ Other Changes and Additions
- Gaussian smooth plugin excludes results from the gaussian smooth plugin from the input
dataset dropdown. [#2239]

- CLI launchers no longer require data to be specified [#1960]

- Added direct launchers for each config (e.g. ``specviz``) [#1960]

3.5.1 (unreleased)
==================

Expand Down
23 changes: 23 additions & 0 deletions jdaviz/_astropy_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
import os
import sys

if not hasattr(sys.modules["__main__"], "__file__"):
# this happens under pyinstaller when running jdaviz cli
# which triggers an error in astropy, so we set it to the
# executable path of the cli executable
sys.modules["__main__"].__file__ = sys.executable


from astropy.tests.runner import TestRunner

__all__ = ['__version__', 'test']

try:
from .version import version as __version__
except ImportError:
__version__ = ''

# Create the test function for self test
test = TestRunner.make_test_runner_in(os.path.dirname(__file__))
test = TestRunner.make_test_runner_in(os.path.dirname(__file__))
27 changes: 27 additions & 0 deletions jdaviz/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Command-line interface for jdaviz

import inspect
import os
import pathlib
import sys
Expand All @@ -10,9 +11,11 @@

from jdaviz import __version__
from jdaviz.app import _verbosity_levels
from jdaviz import configs

__all__ = ['main']

CONFIGS_DIR = str(pathlib.Path(inspect.getfile(configs)).parent)
JDAVIZ_DIR = pathlib.Path(__file__).parent.resolve()
DEFAULT_VERBOSITY = 'warning'
DEFAULT_HISTORY_VERBOSITY = 'info'
Expand Down Expand Up @@ -151,3 +154,27 @@ def _main(config=None):
main(filepaths=args.filepaths, layout=layout, instrument=args.instrument, browser=args.browser,
theme=args.theme, verbosity=args.verbosity, history_verbosity=args.history_verbosity,
hotreload=args.hotreload)


def _specviz():
_main(config='specviz')


def _specviz2d():
_main(config='specviz2d')


def _imviz():
_main(config='imviz')


def _cubeviz():
_main(config='cubeviz')


def _mosviz():
_main(config='mosviz')


if __name__ == "__main__":
_main()
41 changes: 41 additions & 0 deletions jdaviz/configs/cubeviz/cubeviz.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# PREFIX\n",
"from jdaviz import Cubeviz\n",
"\n",
"cubeviz = Cubeviz(verbosity='JDAVIZ_VERBOSITY', history_verbosity='JDAVIZ_HISTORY_VERBOSITY')\n",
"data_path = 'DATA_FILENAME'\n",
"if data_path:\n",
" cubeviz.load_data('DATA_FILENAME')\n",
"cubeviz.app"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6-final"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
50 changes: 50 additions & 0 deletions jdaviz/configs/default/default.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"from jdaviz.app import Application\n",
"app = Application(configuration='default')\n",
"app.verbosity = 'JDAVIZ_VERBOSITY'\n",
"app.history_verbosity = 'JDAVIZ_HISTORY_VERBOSITY'\n",
"data_path = 'DATA_FILENAME'\n",
"if data_path:\n",
" app.load_data('DATA_FILENAME')\n",
"app"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
41 changes: 41 additions & 0 deletions jdaviz/configs/imviz/imviz.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# PREFIX\n",
"from jdaviz import Imviz\n",
"\n",
"imviz = Imviz(verbosity='JDAVIZ_VERBOSITY', history_verbosity='JDAVIZ_HISTORY_VERBOSITY')\n",
"data_path = 'DATA_FILENAME'\n",
"if data_path:\n",
" imviz.load_data('DATA_FILENAME')\n",
"imviz.app"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading

0 comments on commit 46be84f

Please sign in to comment.