-
Notifications
You must be signed in to change notification settings - Fork 74
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
POC: Attempt to package jdaviz in Pyinstaller (take 2) #1960
Changes from 34 commits
f760572
b520aef
58730c3
47f966b
2f9041a
5569a4c
ba8ee5a
ef4b254
02e7025
b0c526d
afebeee
309860a
9577b2a
c80aad5
3687266
6c5da95
a7c7e34
76657d1
8c0e2af
42cfcf2
e7cfa49
f70642e
c083476
7c42fce
dbd8142
4aa88bf
42d3eb1
00b1886
3adfbb4
18f750d
ab8f881
fc5fb85
df0ace8
6a79df3
54ae4c8
8350d83
4872695
83ccc6c
4c4ef73
30c5ec8
3638a50
2b1eff9
4d6658d
f43ee63
a402b02
e6b9eb4
723fe1a
4d6e2a4
ef6a38b
0817e83
8672106
1688ec1
06f2ed0
0fdb3bd
a160c5f
d5fbd70
40116b9
bc6cdee
55a19f4
a9f13e9
4018883
b6feaa6
2c03ef1
eb62365
91d6978
40fd901
a569123
24ff314
b365d80
d3d2513
cefb486
e652be8
f3bb66d
dff234b
ceb79b0
b980750
bfa8a41
73c4b6f
0df09d9
507a528
47b50a5
0cd7a80
294c8d6
4c859b7
42075d8
d421571
9e2c857
c28cb2e
946780b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 |
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__)) |
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 | ||||||||||
|
@@ -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() | ||||||||||
|
||||||||||
|
||||||||||
|
@@ -144,3 +147,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') | ||||||||||
Comment on lines
+159
to
+176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @duytnguyendtn do these need to be changed to use And @maartenbreddels, are these necessary for the stand-alone to work? I changed the standalone entry point to call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope! In the launcher PR, the Lines 146 to 149 in 9427518
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Excellent, got it. I'll just leave this alone then! |
||||||||||
|
||||||||||
|
||||||||||
if __name__ == "__main__": | ||||||||||
_main() |
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 | ||
} |
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 | ||
} |
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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cami found the executable on macos was not flagged as an executable, requiring a
chmod +x
. This article suggests the manifest flag should fix this: https://stackoverflow.com/questions/9969464/why-does-my-pyinstaller-created-executable-require-admin-privilegesThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@duytnguyendtn it looks like you linked the wrong thing here, your comment points to a Jira ticket rather than an article. Any chance you have the original link?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI this does not work as suggested, the
-m
argument requires a file as input.