mobiusklein / glypy

Glycan Analysis and Glycoinformatics Library for Python
Apache License 2.0
27 stars 14 forks source link

Problem with pyinstaller and glypy #21

Closed michaelgoetze closed 3 years ago

michaelgoetze commented 3 years ago

I tried to produce a windows executable using glypy and pyinstaller. The program fails to start after producing an executable as soon as I import glycoct.This is the error that I get:

Traceback (most recent call last):
  File "min_test.py", line 1, in <module>
    from glypy.io import glycoct
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "PyInstaller\loader\pyimod03_importers.py", line 531, in exec_module
  File "glypy\__init__.py", line 3, in <module>
    from glypy.structure.named_structures import monosaccharides, glycans, motifs, monosaccharide_residues
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "PyInstaller\loader\pyimod03_importers.py", line 531, in exec_module
  File "glypy\structure\named_structures.py", line 55, in <module>
    monosaccharides = (MonosaccharideIndex)()
  File "glypy\structure\named_structures.py", line 50, in __init__
    stream = pkg_resources.resource_stream(__name__, "data/monosaccharides.hjson")
  File "pkg_resources\__init__.py", line 1136, in resource_stream
  File "pkg_resources\__init__.py", line 1385, in get_resource_stream
  File "pkg_resources\__init__.py", line 1388, in get_resource_string
  File "pkg_resources\__init__.py", line 1555, in _get
  File "PyInstaller\loader\pyimod03_importers.py", line 356, in get_data
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\fu2051bc\\AppData\\Local\\Temp\\_MEI159402\\glypy\\
structure\\data\\monosaccharides.hjson'
[18628] Failed to execute script min_test

My minimum test file looked like this:

from glypy.io import glycoct
print('working')

I haven't tested whether it also fails with other imports. I am running windows 10 and python 3.8.5. I tested this in a venv, where it is running fine. The following packages were installed in the venv:

altgraph==0.17
cycler==0.10.0
future==0.18.2
glypy==0.12.6
hjson==3.0.2
kiwisolver==1.3.1
matplotlib==3.3.3
numpy==1.19.5
pefile==2019.4.18
Pillow==8.1.0
pyinstaller==4.2
pyinstaller-hooks-contrib==2020.11
pyparsing==2.4.7
python-dateutil==2.8.1
pywin32-ctypes==0.2.0
six==1.15.0

To create a single executable file, I ran pyinstaller with the following command and started the executable in the dist-folder.

pyinstaller min_test.py -F

I see that the issue is the missing file 'monosaccharides.hjson' (which I also can't find on disk). Is there a way to use pyinstaller with glypy? When I omit the glycoct import, the program works. I couldn't deduce where the program gets the path for the temporary folder and whether I could relpace this and provide the hjson-file(s) another way (e.g. in a bin folder next to the executable)

Without the -F flag glypy was not looking for the hjson-file(s) in a temp folder somewhere in Appdata but in the current working directory. So copying the master branch of the repository made the program work.

So my main question is, is there a way to make glypy and pyinstaller work with the -F flag?

mobiusklein commented 3 years ago

Did you install glypy with pip install glypy or by running python setup.py install from the source directory?

A long standing issue with PyInstaller, https://github.com/pyinstaller/pyinstaller/issues/2717, prevents it from automatically collecting data files from packages installed with pip.

When I use glypy with PyInstaller, I install glypy from source using python setup.py install. If that's not an option for you, you can probably write an import hook to add the package data to the datas tracker from PyInstaller.

# filename: hook-glypy.py
from PyInstaller.utils.hooks import collect_data_files, collect_submodules

datas = collect_data_files('glypy')

Place this script in a directory called hooks in the working directory and run pyinstaller min_test.py -F --additional-hooks-dir ./hooks.

Please let me know if this resolves the issue.

michaelgoetze commented 3 years ago

Hi,

installing from source solved the issue. If I run into this again I might also try the hook option.

thanks for the quick reply!