问题
There is a chance this is still a problem and the Pyinstaller and/or Folium people have no interest in fixing it, but I'll post it again here in case someone out there has discovered a workaround.
I have a program that creates maps, geocodes etc and recently added the folium package to create some interactive maps in html format. I always compile my code using pyinstaller so that others at my company can just use the executable rather than running the python code. If I run my code in an IDE, it loads, runs and performs exactly as expected. However, when I attempt to compile while I have import folium
somewhere in my script, I get an error when trying to run the executable that pyinstaller creates.
The error text reads something like this:
Traceback (most recent call last):
File "analysisSuite.py", line 58, in <module>
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\folium\__init__.py", line 8, in <module>
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\branca\__init__.py", line 5, in <module>
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\branca\colormap.py", line 29, in <module>
File "site-packages\pkg_resources\__init__.py", line 1143, in resource_stream
File "site-packages\pkg_resources\__init__.py", line 1390, in get_resource_stream
File "site-packages\pkg_resources\__init__.py", line 1393, in get_resource_string
File "site-packages\pkg_resources\__init__.py", line 1469, in _get
File "c:\users\natha\appdata\local\programs\python\python36-32\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 479, in get_data
with open(path, 'rb') as fp:
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\natha\\AppData\\Local\\Temp\\_MEI309082\\branca\\_cnames.json'
[30956] Failed to execute script analysisSuite
I am still relatively new to Python, so trying to decipher what the issue is by this text is pretty overwhelming. I have no idea if there is a workaround, where I just need to edit a file, add a file or add some parameter to pyinstaller, but perhaps someone else out there can read this and has an idea of what could be causing this problem. Thanks in advance to anyone that has suggestions.
EDIT: The problem seems to be with branca, which is a dependency of folium. It looks for that _cnames.json file which is in the site-packages\branca folder but either doesn't get copied as it should or perhaps I need to somehow identify in my script where it should look for those files and then just manually copy them into a folder that I choose.
ADDITIONAL UPDATE: I've been testing and testing and have determined the heart of the problem. When you run your exe, it gets unpacked in a temp folder. One of the modules within branca
is colormap.py
In the colormap
file, there are essentially three lines that keep branca
from loading correctly.
resource_package = __name__
resource_path_schemes = '/_schemes.json'
resource_path_cnames = '/_cnames.json'
So, when the executable gets unpacked in this temp folder and branca tries to load up, because of these above lines, it expects these two files to also be in this temp folder, but of course, they won't be because they're being told to always and only be in the folder where the colormap module lives. The key here is figuring out a way so that the path reference can be relative, so that it doesn't look in the temp folder but also that the reference is dynamic, so that wherever you have your executable, as long as you have those json files present in some folder that it "knows" about, then you'll be good. Now I just need to figure out how to do that.
回答1:
I had the same problem. Pyinstaller could not work with the Python Folium package. I could not get your cx_Freeze solution to work due to issues with Python 3.7 and cx_Freeze but with a day of stress I found a Pyinstaller solution which I am sharing with the community.
Firstly you have to edit these 3 files:
\folium\folium.py
\folium\raster_layers.py
- \branca\element.py
Makes the following changes, commenting out the existing ENV line and replacing with the code below:
#ENV = Environment(loader=PackageLoader('folium', 'templates'))
import os, sys
from jinja2 import FileSystemLoader
if getattr(sys, 'frozen', False):
# we are running in a bundle
templatedir = sys._MEIPASS
else:
# we are running in a normal Python environment
templatedir = os.path.dirname(os.path.abspath(__file__))
ENV = Environment(loader=FileSystemLoader(templatedir + '\\templates'))
Create this spec file in your root folder, obviously your pathex and project name will be different:
# -*- mode: python -*-
block_cipher = None
a = Analysis(['time_punch_map.py'],
pathex=['C:\\Users\\XXXX\\PycharmProjects\\TimePunchMap'],
binaries=[],
datas=[
(".\\venv\\Lib\\site-packages\\branca\\*.json","branca"),
(".\\venv\\Lib\\site-packages\\branca\\templates","templates"),
(".\\venv\\Lib\\site-packages\\folium\\templates","templates"),
],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='time_punch_map',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=True )
Finally generate the single exe with this command from the terminal:
pyinstaller time_punch_map.spec
回答2:
I could not get this to work using pyinstaller. I had to instead use cx_Freeze.
pip install cx_Freeze
cx_Freeze requires that a setup.py file is created, typically in the same folder as the main script that is being converted to an exe. My setup.py file looks like this:
import sys
from cx_Freeze import setup, Executable
import os.path
PYTHON_INSTALL_DIR = os.path.dirname(os.path.dirname(os.__file__))
os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6')
os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6')
# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {"packages": ["pkg_resources","asyncio","os","pandas","numpy","idna","folium","branca","jinja2","matplotlib"]}
# GUI applications require a different base on Windows (the default is for a
# console application).
base = None
if sys.platform == "win32":
base = "Win32GUI"
options = {
'build_exe': {
'include_files':[
os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tk86t.dll'),
os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tcl86t.dll'),
# 'C:\\Users\\natha\\AppData\\Local\\Programs\\Python\\Python36-32\\Lib\\site-packages\\branca\\_cnames.json',
# 'C:\\Users\\natha\\AppData\\Local\\Programs\\Python\\Python36-32\\Lib\\site-packages\\branca\\_schemes.json'
],
},
}
setup( name = "MyProgram",
version = "0.1",
description = "MyProgram that I created",
options = {"build_exe": build_exe_options},
executables = [Executable("myProgram.py", base=base)])
Notice I had to add various folium dependencies to the "packages" dictionary, such as branca, asyncio and pkg_resources. Also, I did independent updates for asyncio, pkg_resources and even setuptools using pip - for example:
pip install --upgrade setuptools
Once those were in place, I would open a command prompt from the directory where my setup.py file is saved and just type python setup.py build
Once this runs, I have a new folder in my directory called build
and inside of that is another folder, inside of which is my exe, which ran perfectly. Hope this helps someone else that may encounter this problem.
来源:https://stackoverflow.com/questions/54836440/branca-python-module-is-unable-to-find-2-essential-json-files-when-running-an-ex