Search code examples
pythoncx-freeze

cx_freeze module dependency


So my python script depends on another module I created. This module reads in a text file. The script, the module, and the file it reads are normally in the same directory when I run from source and everything works great.

I compiled with cx_freeze, and when I run it, the imported module fails. The module tries to read the file and says it can't find it, and everything stops right there.

The text file is included in the library.zip, and the build folder (probably unnecessarily, but I figured it couldn't hurt). I decided to print the working directory in the module before reading the file to see what was happening, and it looks like the working directory isn't the build folder, but my user home directory.

Of course the text file isn't in my user's home directory. How can I fix this?

Just to be concrete, here's an example. All files are in the same directory.

script.py:

import hello

hello.py

import os
print(os.getcwd())
f = open('hello.txt','r')
print(f.read())
f.close()

hello.txt

hello!

setup.py

import sys
import os
from cx_Freeze import setup, Executable

# Dependencies are automatically detected, but it might need fine tuning.

includes = ['hello.txt']
zip_inc = ['hello.txt']

build_exe_options = {"packages": ["os"], "include_files": includes, "zip_includes": zip_inc}

setup(  name = "test",
        version = "0.1",
        description = "test",
        options = {"build_exe": build_exe_options},
        executables = [Executable("script.py")])

I built with the command:

python setup.py build

Then I ran the file called script in the build directory. I'm in Mac OS X if it matters. The output is as follows:

/Users/pianowow
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages/cx_Freeze/initscripts/Console3.py", line 27, in <module>
    exec(code, m.__dict__)
  File "script.py", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/importlib/_bootstrap.py", line 1558, in _find_and_load
    return _find_and_load_unlocked(name, import_)
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/importlib/_bootstrap.py", line 1525, in _find_and_load_unlocked
    loader.load_module(name)
  File "/Users/pianowow/Desktop/test/hello.py", line 3, in <module>
    f = open('hello.txt','r')
FileNotFoundError: [Errno 2] No such file or directory: 'hello.txt'

Solution

  • I've got a pull request to update the docs - here's the updated section on using data files:

    Applications often need data files besides the code, such as icons. Using a setup script, you can list data files or directories in the include_files option to build_exe. They'll be copied to the build directory alongside the executable. Then to find them, use code like this:

    def find_data_file(filename):
        if getattr(sys, 'frozen', False):
            # The application is frozen
            datadir = os.path.dirname(sys.executable)
        else:
            # The application is not frozen
            # Change this bit to match where you store your data files:
            datadir = os.path.dirname(__file__)
    
        return os.path.join(datadir, filename)
    

    An alternative is to embed data in code, for example by using Qt's resource system.

    [From this file]