Reputation: 31
Here is my system info:
123 INFO: PyInstaller: 4.0
123 INFO: Python: 3.5.4
124 INFO: Platform: Windows-10-10.0.18362-SP0
I've been trying to generate a Python (PyQt) executable using Pyinstaller to be used in an app. However, when I package the executable and run it, it will throw this:
pkg_resources.DistributionNotFound: The 'flask-compress' distribution was not found and is required
by the application
[14684] Failed to execute script main
This dependency already exists in my virtual environment and I have tried specifying the path to the site packages directory and the flask_compress import like this:
pyinstaller --paths C:\Users\alan9\PycharmProjects\PracticumProject\venv\Lib\site-packages --hidden-import=flask_compress main.py
Note: I have tried to create the executable for this application using different python versions, with different pyinstaller flags (onefile, windowed, onedir), on different computers with Windows 7/10, on a clean copy of a Windows 10 VM, and with fbs but I always receive the same error message:(
Upvotes: 3
Views: 3778
Reputation: 11
Since I cannot put comments yet (not enough contributions on stackoverflow?) I am adding this update to say that I tried the hook-based solution (which, in theory is the best way to deal with this sort of problem), but like Sören reported, this did not seem to get flask-compress into the distribution.
The monkey-patching solution is clearly preferable, both because it leaves the flask code intact (and apparently the original functionality), but also because it (presumably) identifies the true underlying problem -- flask-compress is being brought along for the ride but simply isn't detected by pkg_resources... I wonder what (if anything) can be done to generalize this -- it may be possible to modify pkg_resources to work in a "bundled" Pyinstaller context.
I got hit with the exact same problem. Now, the "correct" thing to do is to figure out the apparently subtle way to add a proper Pyinstaller hook to take care of this issue. Maybe I will get around to doing that at some point -- certainly, what you tried to do makes sense and should've worked. I did the even more basic move of explicitly importing flask_compress in the main python script, without success.
However, since we are both trying to Pyinstallerize a flask-dependent (desktop) application, chances are very good that neither of us actually needs to gzip the responses that are being generated, so it is possible to eliminate the whole problem by "simplifying the software a bit". In my case, the references to flask_compress came from dash, so I ripped out the gzip functionality (found in Lib/site-packages/dash/dash.py
). The key relevant references are on lines 21, 53, 292, 321 and 432.
"Rewire" references like those (in whatever library you use which references flask-compress) and all your problems magically disappear -- worked for me :-)
My bet is that line 53 engages machinery that is too clever/dynamic for Pyinstaller. Don't get me wrong -- Pyinstaller is nothing short of a miracle but as a community we will be forever running around trying to plug these clever-hacks because Python simply was not made to generate nice standalone executables.
Upvotes: 1
Reputation: 21
I was experiencing a similar problem and this solution was not working for me in an environment with pyinstaller==4.0
, dash==1.17.0
and flask_compress==1.8.0
.
However, I found that the solution proposed by Legorooj here works quite well in my case, basically instead of tensorflow
one uses flask
and flask_compress
in the hook file.
For completeness here is how I wrote the hook-flask.py
file.
from PyInstaller.utils.hooks import collect_all
def hook(hook_api):
packages = [
'flask',
'flask_compress',
'flask_caching'
]
for package in packages:
datas, binaries, hiddenimports = collect_all(package)
hook_api.add_datas(datas)
hook_api.add_binaries(binaries)
hook_api.add_imports(*hiddenimports)
Of this way no monkey patching is needed.
Upvotes: 2
Reputation: 96
I solved this problem with monkey patching. Just paste this code in a module that you import before dash and you should be good to go. In my case I had flask-compress==1.5.0 so I just hardcoded the version but you could probably do something more clever.
"""
Simple module that monkey patches pkg_resources.get_distribution used by dash
to determine the version of Flask-Compress which is not available with a
flask_compress.__version__ attribute. Known to work with dash==1.16.3 and
PyInstaller==3.6.
"""
import sys
from collections import namedtuple
import pkg_resources
IS_FROZEN = hasattr(sys, '_MEIPASS')
# backup true function
_true_get_distribution = pkg_resources.get_distribution
# create small placeholder for the dash call
# _flask_compress_version = parse_version(get_distribution("flask-compress").version)
_Dist = namedtuple('_Dist', ['version'])
def _get_distribution(dist):
if IS_FROZEN and dist == 'flask-compress':
return _Dist('1.5.0')
else:
return _true_get_distribution(dist)
# monkey patch the function so it can work once frozen and pkg_resources is of
# no help
pkg_resources.get_distribution = _get_distribution
Upvotes: 6