简体   繁体   中英

APScheduler import error when generate executable with py2exe or cx_freeze

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM