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 .exe
file (i.e. not in the zipfile), which will work with this solution.