Packaging Napari app through PyInstaller

Hi,

I’ve recently started using Napari for visualizing layers of data (such as drawing a binary mask and shapes over an HED image), and it’s proved to be really useful. I was hoping I could package and export a napari visualization along with its data as a single runnable binary (.EXE file for Windows and/or ELF binary for linux), so that I can easily send it to a non-technical clinician for review.

I tried using PyInstaller, which is a tool to compile python code into native executables like I wanted. I have had success using PyInstaller on other smaller projects that don’t require many external libraries. However, I can’t seem to make PyInstaller work on even the simplest napari demo:

#!/usr/bin/env python3

import napari
import numpy as np

with napari.gui_qt():
    array = np.reshape(np.arange(256), (16, 16))
    viewer = napari.view_image(array)

When I run pyinstaller main.py -F, I get this output:

❯ pyinstaller -F main.py
30 INFO: PyInstaller: 4.0
30 INFO: Python: 3.8.2
39 INFO: Platform: Linux-5.4.0-42-generic-x86_64-with-glibc2.29
39 INFO: wrote /home/arjvik/Programming/data-science/UTSW/napari-visualization/main.spec
41 INFO: UPX is not available.
42 INFO: Extending PYTHONPATH with paths
['/home/arjvik/Programming/data-science/UTSW/napari-visualization',
 '/home/arjvik/Programming/data-science/UTSW/napari-visualization']
50 INFO: checking Analysis
50 INFO: Building Analysis because Analysis-00.toc is non existent
50 INFO: Initializing module dependency graph...
51 INFO: Caching module graph hooks...
55 INFO: Analyzing base_library.zip ...
2030 INFO: Processing pre-find module path hook distutils from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/hooks/pre_find_module_path/hook-distutils.py'.
2031 INFO: distutils: retargeting to non-venv dir '/usr/lib/python3.8'
3841 INFO: Caching module dependency graph...
3918 INFO: running Analysis Analysis-00.toc
3940 INFO: Analyzing /home/arjvik/Programming/data-science/UTSW/napari-visualization/main.py
4626 INFO: Processing pre-safe import module hook setuptools.extern.six.moves from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-setuptools.extern.six.moves.py'.
5005 INFO: Processing pre-find module path hook site from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/hooks/pre_find_module_path/hook-site.py'.
5005 INFO: site: retargeting to fake-dir '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/fake-modules'
10326 INFO: Processing pre-safe import module hook six.moves from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-six.moves.py'.
/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/traitlets/config/loader.py:795: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if len(key) is 1:
/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/traitlets/config/loader.py:804: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if len(key) is 1:
28692 INFO: Processing module hooks...
28692 INFO: Loading module hook 'hook-jedi.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
29033 INFO: Loading module hook 'hook-jinja2.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
29053 INFO: Loading module hook 'hook-zmq.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
29183 INFO: Loading module hook 'hook-skimage.io.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
29893 INFO: Loading module hook 'hook-docutils.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
30992 INFO: Loading module hook 'hook-skimage.transform.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
31064 INFO: Loading module hook 'hook-IPython.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
31374 INFO: Excluding import 'PyQt4'
31378 INFO:   Removing import of PyQt4 from module IPython.external.qt_loaders
31379 INFO: Excluding import 'PyQt5'
31383 INFO:   Removing import of PyQt5 from module IPython.external.qt_loaders
31383 INFO: Excluding import 'matplotlib'
31387 INFO:   Removing import of matplotlib._pylab_helpers from module IPython.core.pylabtools
31387 INFO:   Removing import of matplotlib.backend_bases from module IPython.core.pylabtools
31387 INFO:   Removing import of matplotlib.figure from module IPython.core.pylabtools
31387 INFO:   Removing import of matplotlib from module IPython.core.pylabtools
31387 INFO:   Removing import of matplotlib.pyplot from module IPython.core.pylabtools
31388 INFO:   Removing import of matplotlib.mathtext from module IPython.lib.latextools
31388 INFO:   Removing import of matplotlib from module IPython.lib.latextools
31388 INFO: Excluding import 'gtk'
31393 INFO: Excluding import 'PySide'
31397 INFO:   Removing import of PySide from module IPython.external.qt_loaders
31398 INFO: Loading module hook 'hook-certifi.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
31399 INFO: Loading module hook 'hook-OpenGL.py' from '/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
Traceback (most recent call last):
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/bin/pyinstaller", line 8, in <module>
    sys.exit(run())
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/__main__.py", line 114, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/__main__.py", line 65, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/building/build_main.py", line 720, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/building/build_main.py", line 667, in build
    exec(code, spec_namespace)
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/main.spec", line 6, in <module>
    a = Analysis(['main.py'],
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/building/build_main.py", line 242, in __init__
    self.__postinit__()
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/building/datastruct.py", line 160, in __postinit__
    self.assemble()
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/building/build_main.py", line 419, in assemble
    self.graph.process_post_graph_hooks()
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/depend/analysis.py", line 365, in process_post_graph_hooks
    module_hook.post_graph()
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/depend/imphook.py", line 440, in post_graph
    self._load_hook_module()
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/depend/imphook.py", line 406, in _load_hook_module
    self._hook_module = importlib_load_source(
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/compat.py", line 588, in importlib_load_source
    return mod_loader.load_module()
  File "<frozen importlib._bootstrap_external>", line 462, in _check_name_wrapper
  File "<frozen importlib._bootstrap_external>", line 962, in load_module
  File "<frozen importlib._bootstrap_external>", line 787, in load_module
  File "<frozen importlib._bootstrap>", line 265, in _load_module_shim
  File "<frozen importlib._bootstrap>", line 702, in _load
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL.py", line 24, in <module>
    from PyInstaller.utils.hooks import opengl_arrays_modules
ImportError: cannot import name 'opengl_arrays_modules' from 'PyInstaller.utils.hooks' (/home/arjvik/Programming/data-science/UTSW/napari-visualization/venv/lib/python3.8/site-packages/PyInstaller/utils/hooks/__init__.py)

Has anyone had success packaging a Napari app through PyInstaller or any other packaging frameworks?

yes, we had a working pyinstaller build a while back (see #496 if you want to look through the code), but we have since moved away from pyinstaller towards a non-frozen solution (using briefcase) that will make it easier to extend the bundle with plugins: https://github.com/napari/napari/pull/1289

looks like that will be merged relatively soon and a basic bundle may be available for the next release (though at this point the bundled app should still be considered “experimental”)

while the briefcase app is likely going to be more flexible for general purposes, for your specific purposes (sending a wrapped executable to a clinician who likely won’t be extending napari at all), pyinstaller will create a smaller bundle that may also launch a bit quicker. So if you would like to continue playing with pyinstaller, I suggest looking at issue #496 linked above. It’s definitely finicky and will depend on the exact versions of pyinstaller you’re using, but I believe there were some hooks included in that PR that might help you out.

edit: I just updated that old pyinstaller PR and made sure it’s working (only on mac though) with the current napari and pyinstaller versions in a branch here (if you want to have a look): https://github.com/tlambert03/napari/tree/pyinstaller. The pyinstaller specfile is here

3 Likes

see also this Stack Overflow answer, where a similar problem to yours is described: https://stackoverflow.com/questions/63052345/pyinstaller-and-opengl-error-importerror-cannot-import-name-opengl-arrays-mod

looks like it may be an issue caused by upgrading pyinstaller (I haven’t yet tried to use v4.0)

@talley In all honesty, smaller binary size and faster launch time are not very important to me. So if I can get Briefcase to build a working standalone binary, I won’t need to use PyInstaller at all.

Thanks for all the suggestions, I’ll be sure to play around with them and report back which ones worked!

@talley Actually, I’m struggling to find a guide on packaging an app using Briefcase. Do you know the general commands to compile an executable using Briefcase?

here’s the tutorial I found most helpful when getting started: https://docs.beeware.org/en/latest/

@talley From the tutorial you linked, it appears you need to use Briefcase to manage the entire lifecycle of a project, from creating it to managing dependencies, before being able to package it? I attempted to make a Briefcase project with the simple demo program above, but ran into several errors in the process. I haven’t even gotten it to launch napari when run in development mode, forget packaging it as a standalone app.

Is there a way I can use Briefcase just to package an existing app (like how PyInstaller allows you to)?

From the tutorial you linked, it appears you need to use Briefcase to manage the entire lifecycle of a project, from creating it to managing dependencies

not exactly… it does use the pyproject.toml file, which is becoming a standard file for python projects, but it’s not the case that you must manage all dependencies via briefcase. (You can still use setuptools or similar for that sort of thing). but you do minimally need to fill out the [tool.briefcase] and [tool.briefcase.app.napari] section of your pyproject.toml file for the bundling process to work. Doing that is the equivalent of using a .spec file in pyinstaller. I’ll point out that the trick of using pyinstaller main.py -F as you showed in your first post often works fine for small projects, but with something like napari that has a lot of dependencies and some (non-python) data files, you almost always need to use the pyinstaller spec file

I attempted to make a Briefcase project with the simple demo program above, but ran into several errors in the process.

meaning you tried to make the app from the briefcase tutorial? or you followed the tutorial but substituted in napari instead of the demo app?

If you’re trying to bundle napari using briefcase, you can look through the PR #1289 that I linked in the first post to see the things that I had to do to get briefcase working to bundle napari (pay particular attention to the pyproject.toml file there)

Alternatively, if you want to try again with pyinstaller, as mentioned above, I just pushed an updated branch with an example napari.spec file (and some necessary hooks) that you can try with pyinstaller v4.0… by checking out that branch and running:

pyinstaller --noconfirm --clean bundle/napari.spec

feel free to come back with more questions if you try either of those… or, hang in there for a week or two and we’ll have an “alpha” version of the bundled app available for download soon

1 Like

@talley Yea I figured out the bit about the specfile earlier today, and was just going through the process of

  1. Attempt to build demo napari app using PyInstaller
  2. Run app, note missing module/resource/etc
  3. Chance main.spec to fix that error, potentially involving research
  4. Return to step 1

I managed to get several errors solved that way, but that is a long and arduous process :slight_smile: . I’ll try to adapt your napari.spec file and see if I can get better results. I’m assuming that pyinstaller spec file is meant to build Napari itself rather than a project using Napari, but I hope that the changes required will be minimal.

By the way, thank you for all the help so far! You’ve gone way above and beyond just giving pointers to code!

2 Likes

definitely :slight_smile: it’s a lot of trial and error. For napari, I think the main things you’ll need are these hidden_imports, and the additional hooks in this folder

that’s correct… but to bundle your “main.py” file that uses napari, I think all you’ll need to do is adjust the first argument to the Analysis() constructor (here) to point it to your custom script instead of napari/__main__.py

my pleasure :slight_smile:

1 Like

I just checked out your tlambert03/napari on the pyinstaller branch, and I’m unable to use the provided build.sh to build an unmodified version of Napari.

I ran the following:

git clone https://github.com/tlambert03/napari --branch=pyinstaller
cd napari
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
bash bundle/build.sh

but that last command errored out with this output:

❯ bash bundle/build.sh
removing old files...
installing build tools...
Processing /home/arjvik/.cache/pip/wheels/84/80/18/9f78fb893223431cb92f5a5601c24769325059a0d2e368541e/PyInstaller-3.5-py3-none-any.whl
Requirement already satisfied: setuptools in ./venv/lib/python3.8/site-packages (from pyinstaller==3.5) (44.0.0)
Collecting altgraph
  Using cached altgraph-0.17-py2.py3-none-any.whl (21 kB)
Installing collected packages: altgraph, pyinstaller
Successfully installed altgraph-0.17 pyinstaller-3.5
bundle/build.sh: line 20: conda: command not found
building app...
Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/arjvik/Programming/data-science/UTSW/napari2/napari/resources/_pkg_tools.py", line 53, in <module>
    write_included_packages()
  File "/home/arjvik/Programming/data-science/UTSW/napari2/napari/resources/_pkg_tools.py", line 41, in write_included_packages
    with open(os.path.join(ROOT, 'requirements', 'default.txt')) as f:
FileNotFoundError: [Errno 2] No such file or directory: '/home/arjvik/Programming/data-science/UTSW/napari2/requirements/default.txt'
34 INFO: PyInstaller: 3.5
35 INFO: Python: 3.8.2
46 INFO: Platform: Linux-5.4.0-42-generic-x86_64-with-glibc2.29
47 INFO: UPX is not available.
48 INFO: Removing temporary files and cleaning cache in /home/arjvik/.cache/pyinstaller
939 INFO: Extending PYTHONPATH with paths
['/home/arjvik/Programming/data-science/UTSW/napari2',
 '/home/arjvik/Programming/data-science/UTSW/napari2/bundle']
939 INFO: checking Analysis
939 INFO: Building Analysis because Analysis-00.toc is non existent
939 INFO: Initializing module dependency graph...
941 INFO: Initializing module graph hooks...
942 INFO: Analyzing base_library.zip ...
3789 INFO: Processing pre-find module path hook   distutils
6379 INFO: Analyzing hidden import 'pkg_resources.py2_warn'
6487 ERROR: Hidden import 'pkg_resources.py2_warn' not found
6487 INFO: Analyzing hidden import 'napari.conftest'
8954 INFO: Processing pre-safe import module hook   six.moves
9398 INFO: Processing pre-safe import module hook   setuptools.extern.six.moves
9881 INFO: Processing pre-find module path hook   site
9882 INFO: site: retargeting to fake-dir '/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/fake-modules'
/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/traitlets/config/loader.py:795: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if len(key) is 1:
/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/traitlets/config/loader.py:804: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if len(key) is 1:
22917 INFO: Processing pre-safe import module hook   win32com
43132 INFO: running Analysis Analysis-00.toc
43191 INFO: Caching module hooks...
43196 INFO: Analyzing /home/arjvik/Programming/data-science/UTSW/napari2/napari/__main__.py
43280 INFO: Loading module hooks...
43280 INFO: Loading module hook "hook-jedi.py"...
43328 INFO: Loading module hook "hook-sysconfig.py"...
43338 INFO: Loading module hook "hook-scipy.special._ufuncs.py"...
43339 INFO: Loading module hook "hook-jinja2.py"...
43352 INFO: Loading module hook "hook-zmq.py"...
43540 INFO: Loading module hook "hook-xml.etree.cElementTree.py"...
43541 INFO: Loading module hook "hook-sphinx.py"...
47586 INFO: Loading module hook "hook-setuptools.py"...
48155 INFO: Loading module hook "hook-pandas.py"...
48795 INFO: Loading module hook "hook-xml.dom.domreg.py"...
48796 INFO: Loading module hook "hook-docutils.py"...
49570 INFO: Loading module hook "hook-PyQt5.QtPrintSupport.py"...
49804 INFO: Loading module hook "hook-skimage.transform.py"...
49811 INFO: Loading module hook "hook-IPython.py"...
49825 INFO: Excluding import 'gtk'
49832 INFO: Excluding import 'matplotlib'
49837 INFO:   Removing import of matplotlib from module IPython.core.pylabtools
49838 INFO:   Removing import of matplotlib from module IPython.lib.latextools
49838 INFO: Excluding import 'PyQt5'
49844 INFO:   Removing import of PyQt5.QtGui from module IPython.external.qt_loaders
49844 INFO:   Removing import of PyQt5.QtCore from module IPython.external.qt_loaders
49844 INFO:   Removing import of PyQt5 from module IPython.external.qt_loaders
49844 INFO:   Removing import of PyQt5.QtSvg from module IPython.external.qt_loaders
49845 INFO:   Removing import of PyQt5.QtWidgets from module IPython.external.qt_loaders
49845 INFO: Excluding import 'PySide'
49851 INFO:   Removing import of PySide from module IPython.external.qt_loaders
49851 INFO: Excluding import 'PyQt4'
49857 INFO:   Removing import of PyQt4 from module IPython.external.qt_loaders
49858 INFO: Loading module hook "hook-scipy.py"...
49859 INFO: Loading module hook "hook-pydoc.py"...
49859 INFO: Loading module hook "hook-pytest.py"...
50465 INFO: Loading module hook "hook-certifi.py"...
50465 INFO: Loading module hook "hook-pkg_resources.py"...
50994 INFO: Loading module hook "hook-numpy.py"...
50994 INFO: Loading module hook "hook-regex.py"...
50994 INFO: Loading module hook "hook-PyQt5.QtSvg.py"...
51102 INFO: Loading module hook "hook-OpenGL.py"...
51227 INFO: Loading module hook "hook-numpy.core.py"...
51228 INFO: Loading module hook "hook-scipy.linalg.py"...
51229 INFO: Loading module hook "hook-lib2to3.py"...
51230 INFO: Loading module hook "hook-pygments.py"...
53060 INFO: Loading module hook "hook-pywt.py"...
53061 INFO: Loading module hook "hook-PyQt5.QtGui.py"...
53150 INFO: Loading module hook "hook-imageio.py"...
53152 INFO: Loading module hook "hook-encodings.py"...
53225 INFO: Loading module hook "hook-PyQt5.QtCore.py"...
53265 INFO: Loading module hook "hook-pytz.py"...
53282 INFO: Loading module hook "hook-scipy.sparse.csgraph.py"...
53284 INFO: Loading module hook "hook-appdirs.py"...
53296 INFO: Excluding import 'win32com'
53300 INFO:   Removing import of win32com from module appdirs
53300 INFO: Loading module hook "hook-xml.py"...
53301 INFO: Loading module hook "hook-PIL.py"...
53306 INFO: Excluding import 'tkinter'
53310 INFO: Excluding import 'FixTk'
53314 INFO: Excluding import 'PyQt5'
53318 INFO:   Removing import of PyQt5.QtCore from module PIL.ImageQt
53318 INFO:   Removing import of PyQt5.QtGui from module PIL.ImageQt
53318 INFO: Excluding import 'PySide'
53322 INFO: Excluding import 'PyQt4'
53327 INFO: Loading module hook "hook-babel.py"...
53344 INFO: Loading module hook "hook-sqlite3.py"...
53408 INFO: Loading module hook "hook-PyQt5.py"...
53420 INFO: Loading module hook "hook-PIL.Image.py"...
53814 INFO: Loading module hook "hook-distutils.py"...
53815 INFO: Loading module hook "hook-PyQt5.QtWidgets.py"...
53913 INFO: Loading module hook "hook-scipy.special._ellip_harm_2.py"...
53914 INFO: Loading module hook "hook-vispy.py"...
54056 INFO: Loading module hook "hook-freetype.py"...
54056 INFO: Loading module hook "hook-parso.py"...
54058 INFO: Loading module hook "hook-ipykernel.py"...
54063 INFO: Loading module hook "hook-PIL.SpiderImagePlugin.py"...
54073 INFO: Excluding import 'tkinter'
54077 INFO: Excluding import 'FixTk'
54081 INFO: Loading module hook "hook-PyQt5.QtOpenGL.py"...
54199 INFO: Loading module hook "hook-PyQt5.QtTest.py"...
54461 INFO: Looking for ctypes DLLs
55617 WARNING: library user32 required via ctypes not found
55928 WARNING: library msvcrt required via ctypes not found
55930 WARNING: Ignoring /usr/lib/libc.dylib imported from /home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/monotonic.py - ctypes imports are only supported using bare filenames
56044 WARNING: library gdiplus.dll required via ctypes not found
56681 INFO: Analyzing run-time hooks ...
56736 INFO: Including run-time hook 'pyi_rth_certifi.py'
56740 INFO: Including run-time hook 'pyi_rth_pyqt5.py'
56743 INFO: Including run-time hook 'pyi_rth_traitlets.py'
56746 INFO: Including run-time hook 'pyi_rth_pkgres.py'
56750 INFO: Including run-time hook 'pyi_rth_multiprocessing.py'
56836 INFO: Looking for dynamic libraries
64923 INFO: Looking for eggs
64923 INFO: Python library not in binary dependencies. Doing additional searching...
64971 INFO: Using Python library /lib/x86_64-linux-gnu/libpython3.8.so.1.0
65227 INFO: Warnings written to /home/arjvik/Programming/data-science/UTSW/napari2/build/napari/warn-napari.txt
65554 INFO: Graph cross-reference written to /home/arjvik/Programming/data-science/UTSW/napari2/build/napari/xref-napari.html
65741 INFO: Appending 'datas' from .spec
65752 INFO: checking PYZ
65752 INFO: Building PYZ because PYZ-00.toc is non existent
65752 INFO: Building PYZ (ZlibArchive) /home/arjvik/Programming/data-science/UTSW/napari2/build/napari/PYZ-00.pyz
Traceback (most recent call last):
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/bin/pyinstaller", line 8, in <module>
    sys.exit(run())
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/__main__.py", line 111, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/__main__.py", line 63, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/build_main.py", line 844, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/build_main.py", line 791, in build
    exec(code, spec_namespace)
  File "/home/arjvik/Programming/data-science/UTSW/napari2/bundle/napari.spec", line 127, in <module>
    pyz = PYZ(a.pure, a.zipped_data, cipher=BLOCK_CIPHER)
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/api.py", line 98, in __init__
    self.__postinit__()
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/datastruct.py", line 158, in __postinit__
    self.assemble()
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/api.py", line 128, in assemble
    self.code_dict = {
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/api.py", line 129, in <dictcomp>
    key: strip_paths_in_code(code)
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/utils.py", line 652, in strip_paths_in_code
    consts = tuple(
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/utils.py", line 653, in <genexpr>
    strip_paths_in_code(const_co, new_filename)
  File "/home/arjvik/Programming/data-science/UTSW/napari2/venv/lib/python3.8/site-packages/PyInstaller/building/utils.py", line 660, in strip_paths_in_code
    return code_func(co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, co.co_stacksize,
TypeError: an integer is required (got type bytes)

It’s a very strange error too! Is this just because you’ve only tested it on MacOS and I’m running Linux? Any idea how to fix it?

This is maybe a bit premature, but the latest release candidate has a Windows bundle (“napari-0.3.7rc0-Windows.zip”) that can be downloaded from here: https://github.com/napari/napari/releases/
I think there should also be a Mac app there but I don’t see one, so maybe we’ll be able to fix that up in the next release candidate or so. We’ll see!

Someone else has already said this, but it’s worth repeating: the app bundle is still very new and should be considered experimental at this stage.

2 Likes

@talley Sorry for the ping, but I’m not sure if you saw my earlier message yesterday.

I am not able to use the napari.spec file you committed yesterday, even without any modifications. See my above message for details.

Is this just because you’ve only tested it on MacOS and I’m running Linux? And any idea how to fix it?

I just made a minimal repo (outside of napari) that includes everything needed… test it on mac and linux. if you still get that error (starting from a clean environment), then let me know: https://github.com/tlambert03/napari-pyinstaller

1 Like

@talley Thanks, that worked very well on my computer!!

I did have to copy the latest verison of hook-OpenGL.py from the pyinstaller-hooks-contrib repo into the hooks/ folder (it seems the latest version hasn’t been uploaded to PyPi yet). But other than that your example worked fine, and I’m able to succesfully launch the generated napari-app binary! These were the commands used to build everything:

git clone https://github.com/tlambert03/napari-pyinstaller
cd napari-pyinstaller
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
wget https://raw.githubusercontent.com/pyinstaller/pyinstaller-hooks-contrib/master/src/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL.py -O hooks/hook-OpenGL.py
pyinstaller napari.spec

You said that you were able to run this on both MacOS and Linux? I’ll be trying a Windows build later today, so I can report back with results.

Thanks for all the help! Hopefully I can tie everything together and incorporate my own code into this without any more issues.

1 Like

Great! Haven’t tried windows yet recently. But see how that build.bat file works, and the .iss file should let you create an installer (but there too, I need to remember how it works)

just pushed an update to make it work for windows, so be sure to pull the most recent commits before trying on windows. but it’s working for me…

1 Like