Question

I'm trying to use cxfreeze to build my Python scripts into an .exe file. However my scripts use some external data files which aren't being packaged into the libary.zip file created.

For example, my scripts are located in src/, and the external data is located in src/data/. I've specified the include_files property in the build_exe_options, but this only copies the directory and files into the built directory; it doesn't add them to library.zip, which is where the scripts end up looking for the files.

Even if I go in to the created library.zip and manually add the data directory, I receive the same error. Any idea how to get cxfreeze to package these external resources appropriately?

setup.py

from cx_Freeze import setup, Executable

build_exe_options = {"includes" : ["re"], "include_files" : ["data/table_1.txt", "data/table_2.txt"]}

setup(name = "My Script",
      version = "0.8",
      description = "My Script",
      options = { "build_exe" : build_exe_options },
      executables = [Executable("my_script.py")])

fileutil.py (where it tries to read the resource files)

def read_file(filename):
    path, fl = os.path.split(os.path.realpath(__file__))
    filename = os.path.join(path, filename)
    with open(filename, "r") as file:
        lines = [line.strip() for line in file]
        return [line for line in lines if len(line) == 0 or line[0] != "#"]

... called with ...

read_file("data/table_1.txt")

Error Traceback

Traceback (most recent call last):
  File "C:\Python33\lib\site-packages\cx_Freeze\initscripts\Console3.py", line 2
7, in <module> exec(code, m.__dict__)
  File "my_script.py", line 94, in <module>
  File "my_script.py", line 68, in run
  File "C:\workspaces\py\test_script\src\tables.py", line 12, in load_data
    raw_gems = read_file("data/table_1.txt")
  File "C:\workspaces\py\test_script\src\fileutil.py", line 8, in read_file
    with open(filename, "r") as file:
FileNotFoundError: [Errno 2] No such file or directory:
'C:\\workspaces\\py\\test_script\\src\\build\\exe.win32-3.3\\library.zip\\data/table_1.txt'
Was it helpful?

Solution

The following structure worked for me:

|-main.py
|-src
 |-utils.py (containing get_base_dir())
|-data

then refer to your data always relative to the location of main.py that you receive through the following function within the src directory:

import os, sys, inspect
def get_base_dir():
   if getattr(sys,"frozen",False):
       # If this is running in the context of a frozen (executable) file, 
       # we return the path of the main application executable
       return os.path.dirname(os.path.abspath(sys.executable))
   else:
       # If we are running in script or debug mode, we need 
       # to inspect the currently executing frame. This enable us to always
       # derive the directory of main.py no matter from where this function
       # is being called
       thisdir = os.path.dirname(inspect.getfile(inspect.currentframe()))
       return os.path.abspath(os.path.join(thisdir, os.pardir))

If you include the data according to the cx_Freeze documentation, it will be in the same directory as the .exefile (i.e. not in the zipfile), which will work with this solution.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top