enthought / traits

Observable typed attributes for Python classes
Other
438 stars 85 forks source link

Problem locating icons for standalone applications generated by cx_freeze/py2exe #228

Open pbrod opened 9 years ago

pbrod commented 9 years ago

When running traits from a standalone executable, icons are expected to be found inside the executable itself. This is because of the statement "dirname(getattr( sys.modules.get( module ), 'file' ))" which is used to get the path to the icon folder. The assumption is that the icons resides in subfolders of the module folder (i.e. 'traitsui\image' and 'traitsui\wx\images'). When generating a standalone executable, it is convenient to have the icons in a folder OUTSIDE the executable file. Thus, the function get_resource_path in 'traits\traitbase.py' has to be modified. The code below is a proposal on how that could be done (see also enthought/pyface#116):

def get_resource_path ( level = 2 ):
    """Returns a resource path calculated from the caller's stack.
    """
    module = sys._getframe( level ).f_globals.get( '__name__', '__main__' )

    if module != '__main__':
        # Return the path to the module:
        try:
            path = dirname(getattr( sys.modules.get( module ), '__file__' ))
        except:
            # Apparently 'module' is not a registered module...treat it like
            # '__main__':
            pass
        else:
            if hasattr(sys, 'frozen'):
                app_dir, app_name = os.path.split(sys.executable)
                sub_dir = path.replace(sys.executable, '')
                path = ''.join(app_dir, sub_dir)
            return path

    # '__main__' is not a real module, so we need a work around:
    for path in [ dirname( sys.argv[0] ), getcwd() ]:
        if exists( path ):
            break

    return path
ibell commented 9 years ago

+1 I have the same problem

pbrod commented 9 years ago

A solution for pyface was proposed in enthought/pyface#116. Below is the resulting code adapted to our application for traitsui. A workaround for “pyface” images/icons is also included (see also enthought/pyface#116).

Note that all images/icons in the “pyface” and “traitsui” packages are copied and placed in the application folder with folder structure preserved.

import sys
import os
from pyface.resource_manager import resource_manager

def set_pyface_resource_path():
    """Set Pyface image/icon path to local application folder"""
    if hasattr(sys, 'frozen'):  # If we're in an .exe file
        path = os.path.dirname(sys.executable)
        for root_path in ['pyface', 'traitsui']:
            for root, dirs, _files in os.walk(root_path):
                if 'images' in dirs:
                    resource_manager.extra_paths.append(os.path.join(path, root))

def set_traitsui_resource_path():
    """Set Traitsui image/icon path to local application folder"""
    if hasattr(sys, 'frozen'):  # If we're in an .exe file
        path = os.path.dirname(sys.executable)
        os.environ['TRAITS_IMAGES'] = os.path.join(path, r'traitsui\image\library')