cx_freeze - including my own modules?

dan_g picture dan_g · Dec 16, 2014 · Viewed 9.2k times · Source

I have a small application built with PyQt4 that I'm trying to freeze with cx_freeze, but I'm running into an issue with cx_freeze including some of my own modules that are required for the application to work.

I have two modules that are imported in my application that are located in a folder above where the application is located. I.e.:

Application path:

Python\DataViewer-PyQt4\DataViewer.py

Other modules:

Python\My Analysis Packages\Ephystools

Python\My Analysis Packages\PrairieAnalysis

In my application I import these by using (if they're not in my python path already)

sys.path.append(os.path.abspath('../My Analysis Packages'))

I have tried including PrairieAnalysis and EphysTools in both 'includes' and 'packages' in my setup.py file. I have tried including 'My Analysis Packages' as well. I have tried providing the paths to these as well.

They all contain init.py files, as the actual application is capable of importing them just fine.

If I put PrairieAnalysis and/or EphysTools in the 'includes' list then setup.py build returns an ImportError:

 File "C:\Anaconda3\lib\site-packages\cx_Freeze\finder.py", line 386, in _ImportModule
    raise ImportError("No module named %r" % name)
ImportError: No module named 'PrairieAnalysis'

If I leave them out of 'includes' setup.py build completes, but then when I go to open the application I get that same error.

I've looked through the various cx_freeze module import questions but none seem to have dealt with this particular scenario.

My actual setup.py:

# -*- coding: utf-8 -*-

import sys
from cx_Freeze import setup, Executable

base = None
if sys.platform == 'win32':
    base = 'Win32GUI'

options = {
    'build_exe': {
        'includes': ['atexit', 'PrairieAnalysis', 'EphysTools'],
    }
}

executables = [
    Executable('DataViewer.py', base=base)
]

setup(name='DataViewer',
      version='0.1',
      description='Application for viewing Prairie-generated csv data files',
      options=options,
      executables=executables
      )

Edit 1: Output from os.getcwd() in setup.py file:

D:\OneDrive\Documents\Python\DataViewer-PyQt4

Output from sys.path in setup.py file:

    ['D:\\OneDrive\\Documents\\Python\\DataViewer-PyQt4', 'D:\\OneDrive\\Documents\\Python\\My Analysis Packages', 'C:\\Anac
    onda3\\python34.zip', 'C:\\Anaconda3\\DLLs', 'C:\\Anaconda3\\lib', 'C:\\Anaconda3', 'C:\\Anaconda3\\lib\\site-packages',
     'C:\\Anaconda3\\lib\\site-packages\\Sphinx-1.2.3-py3.4.egg', 'C:\\Anaconda3\\lib\\site-packages\\win32', 'C:\\Anaconda3
    \\lib\\site-packages\\win32\\lib', 'C:\\Anaconda3\\lib\\site-packages\\Pythonwin', 'C:\\Anaconda3\\lib\\site-packages\\r
    unipy-0.1.1-py3.4.egg', 'C:\\Anaconda3\\lib\\site-packages\\setuptools-7.0-py3.4.egg']

Edit 2:

So I've also tried using py2exe and I run into the same issue. If I include the packages in "includes" I get the following traceback:

Traceback (most recent call last):
  File "setup.py", line 7, in <module>
    setup(windows=['DataViewer.py'], options={"py2exe": {"includes" :["sip", "PyQt4.QtCore", "PyQt4.QtGui", "PrairieAnal
ysis", "EphysTools"]}})
  File "C:\Anaconda3\lib\distutils\core.py", line 148, in setup
    dist.run_commands()
  File "C:\Anaconda3\lib\distutils\dist.py", line 955, in run_commands
    self.run_command(cmd)
  File "C:\Anaconda3\lib\distutils\dist.py", line 974, in run_command
    cmd_obj.run()
  File "C:\Anaconda3\lib\site-packages\py2exe\distutils_buildexe.py", line 188, in run
    self._run()
  File "C:\Anaconda3\lib\site-packages\py2exe\distutils_buildexe.py", line 267, in _run
    builder.analyze()
  File "C:\Anaconda3\lib\site-packages\py2exe\runtime.py", line 164, in analyze
    mf.import_hook(modname)
  File "C:\Anaconda3\lib\site-packages\py2exe\mf3.py", line 120, in import_hook
    module = self._gcd_import(name)
  File "C:\Anaconda3\lib\site-packages\py2exe\mf3.py", line 274, in _gcd_import
    return self._find_and_load(name)
  File "C:\Anaconda3\lib\site-packages\py2exe\mf3.py", line 318, in _find_and_load
    loader = importlib.find_loader(name, path)
  File "C:\Anaconda3\lib\importlib\__init__.py", line 87, in find_loader
    name=name)
ImportError: namespace packages do not have loaders

In this case I put my two packages (PrairieAnalysis and EphysTools) into my site-packages folder. Why are my packages being treated differently than the other packages?

Edit 3: So I have gotten py2exe to work by using the following setup script:

from distutils.core import setup
import py2exe
import PrairieAnalysis.pv_import
import EphysTools.utilities

includes = ["sip", "PyQt4.QtCore", "PyQt4.QtGui", "PrairieAnalysis", "EphysTools", "lxml._elementpath"]
packages = ["PrairieAnalysis", "EphysTools"]

setup(windows=['DataViewer.py'], options={"py2exe": {"includes" : includes,
                                                     "packages": packages}})

just importing PrairieAnalysis and EphysTools alone didn't work though, nor did doing

from PrairieAnalysis import *
from EphysTools import *

Adding those import statements to my cx_freeze setup.py script, however, does not fix the issue.

Edit 4:

>>> import PrairieAnalysis
>>> print(PrairieAnalysis.__file__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute '__file__'
>>> print(PrairieAnalysis.__init__)
<method-wrapper '__init__' of module object at 0x0000000002B9C9F8>

Edit 5:

>>> os.listdir('D:\\OneDrive\\Documents\\Python\\My Analysis Packages')
['.idea', 'EphysTools', 'PrairieAnalysis', '__init___.py']
>>> os.listdir('D:\\OneDrive\\Documents\\Python\\My Analysis Packages\\PrairieAnalysis')
['misc_code.py', 'pv_import.py', 'pxml_parse.py', '__init___.py', '__pycache__']
>>> os.listdir('D:\\OneDrive\\Documents\\Python\\My Analysis Packages\\EphysTools')
['synaptics.py', 'utilities.py', '__init___.py', '__pycache__']

Answer

Thomas K picture Thomas K · Dec 16, 2014

You need to modify sys.path in your setup.py script in the same way that you do in your application. cx_Freeze looks at sys.path to find the modules and packages to include in your build, so if the directory containing those packages is not on sys.path, it can't find them.

Edit: It turned out that the problem was a misnamed __init__.py file. The package was still importable as a PEP 420 namespace package, but cx_Freeze doesn't handle those yet.