When generating an executable on python 2.7 using py2exe (0.6.9) or cx_freeze (5.0.1) with APScheduler (3.3.1) it gives me the following error:
File "apscheduler\__init__.pyc", line 2, in <module>
File "pkg_resources\__init__.pyc", line 552, in get_distribution
File "pkg_resources\__init__.pyc", line 426, in get_provider
File "pkg_resources\__init__.pyc", line 968, in require
File "pkg_resources\__init__.pyc", line 854, in resolve
pkg_resources.DistributionNotFound: The 'APScheduler' distribution was not found and is required by the application
This is my cx_freeze setup.py file:
import sys
from cx_Freeze import setup, Executable
# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {"includes": ["requests", "apscheduler"], "include_files": ["XXX"]}
# GUI applications require a different base on Windows (the default is for a
# console application).
base = None
if sys.platform == "win32":
base = "Win32GUI"
setup( name = "XXX",
version = "XXX",
description = "XXX",
options = {"build_exe": build_exe_options},
executables = [Executable("XXX.py", base=base), Executable("XXX2.py", base=base)])
And this is my py2exe setup.py file:
from distutils.core import setup
import py2exe
data_files = ['XXX']
setup(
data_files=data_files,
windows=[
{'script': 'XXX.py'},
{'script': 'XXX2.py'},
],
options={'py2exe':{
'includes': ['requests', 'apscheduler'],
'bundle_files': 1,
}
},
)
I already tried to use the 'packages' option but with no success.
If I remove the code from APScheduler __init__.py (apscheduler/__init__.py), it works.
Below is the __init__.py from APScheduler package:
# These will be removed in APScheduler 4.0.
release = __import__('pkg_resources').get_distribution('apscheduler').version.split('-')[0]
version_info = tuple(int(x) if x.isdigit() else x for x in release.split('.'))
version = __version__ = '.'.join(str(x) for x in version_info[:3])
Do I need to include somehow the dependencies into py2exe/cx_freeze library pack?
I already did some research on the internet but with no success.
Found the solution. The problem was py2exe doesn't include the dist-info directory to library.zip. Each module has its own dist-info directory in the site-packages python libraries.
Those directories are used by pkg_resources libraries to import modules as we can see on the apscheduler __init__.py:2
All you have to do is to add those dist-info directories to the library.zip file generated by py2exe.
Below is a example from google importing the (non-related, but could be used as an example) zoneinfo directory to library.zip.
https://github.com/google/transitfeed/blob/master/setup.py#L96
To get the dist-info path of a module, use follow:
import os
import pkg_resources
dist_info_dir = pkg_resources.get_distribution('desired_module')._provider.egg_info
# get base name of directory
base_name = os.path.basename(dist_info_dir)
Note: If there is no dist-info directory and an egg-info instead. You should probably search for the wheel package for the library or build yourself with:
python setup.py bdist_wheel
Cheers!