Hi Antonio,

> Yes, in my experience packging an ETS app with pyinstaller is but an
> easy task. I'm pretty sure it can't be done with a "stock Makespec and
> Build commands".

I think the changes in ETS related to namespace package imports
referenced in the thread you linked to have helped in this. At least
pyinstaller seemed to happily import ETS packages when I enabled debug
messages in pyinstaller's iu.py. Or then I interpreted the debug
messages incorrectly...

The work by my colleague I referred to was mainly about this stuff,
how to collect needed ETS packages for pyinstaller. So it would seem
that it's not needed anymore. However, it went roughly like this:

import enthought
base = os.path.abspath(os.path.join(os.path.dirname(enthought.__file__),
'..', '..'))
...
for item in os.listdir(base):
    if item.lower().startswith('traits-'):
        traits = os.path.join(base, item)
        print 'added traits from', item
... etc for the other needed ETS packages used with PKG below
basefiles = [os.path.join(HOMEPATH,'support/_mountzlib.py'),
              os.path.join(HOMEPATH,'support/useUnicode.py'),
              os.path.join(base, 'pkg_resources.py'),
              'unpackMetadata.py',
              '../yasso.py',
              '../modelcall.py',
              ]
a = Analysis(basefiles,
             pathex=[''],
             hookspath=[''],
             excludes=['enthought', 'wx'])
pyz = PYZ(a.pure)
wx = PKG(Tree(wx), name='wx.pkg')
traits = PKG(Tree(traits), name='traits.pkg')
traitsgui = PKG(Tree(traitsgui), name='traitsgui.pkg')
traitswx = PKG(Tree(traitswx), name='traitswx.pkg')
enable = PKG(Tree(enable), name='enable.pkg')
enthought = PKG(Tree(enthought), name='enthought.pkg')
chaco = PKG(Tree(chaco), name='chaco.pkg')
exe = EXE(wx,
          traitswx,
          traitsgui,
          traits,
          enable,
          enthought,
          chaco,
          pyz,
          a.scripts, #+[("v", "", "OPTION")],
          a.binaries+libfiles,
          a.zipfiles,
          name=os.path.join('dist', exename),
          debug= False,
          strip=False,
          upx=False,
          icon='yasso.ico',
          console=False )

There was also a hook-enthought.py:
hiddenimports = ['uuid', 'colorsys', 'wx', 'wx.html']
--------------------------
Then at runtime the unpackMetadata.py was the key:
import carchive
import sys
import os

this = carchive.CArchive(sys.executable)
archives = os.environ['_MEIPASS2']
pkgs = ['wx', 'traits', 'traitswx', 'chaco', 'enthought', 'enable', 'traitsgui']
for pkg in pkgs:
    mp = this.openEmbedded('%s.pkg' % pkg)
    targetdir = os.path.join(archives,pkg)
    os.mkdir(targetdir)
    print "Extracting %s ..." % pkg,
    for fnm in mp.contents():
        try:
            stuff = mp.extract(fnm)[1]
            outnm = os.path.join(targetdir, fnm)
            dirnm = os.path.dirname(outnm)
            if not os.path.exists(dirnm):
                os.makedirs(dirnm)
            open(outnm, 'wb').write(stuff)
        except Exception, mex:
            print mex
    mp = None
    sys.path.insert(0, targetdir)
    if pkg == 'traitsgui':
        imagepath = os.path.join(targetdir, 'enthought', 'traits',
'ui', 'image', 'library')
        os.environ['TRAITS_IMAGES'] = imagepath
        os.putenv('TRAITS_IMAGES', imagepath)
    print "ok"

from resource_path_override import ResourcePathOverride
resource_override = ResourcePathOverride(archives)

-------------------------------------
And then the custom ResourcePathOverride:
import sys
import os
"""This class will extend the original resource_path function so that it
will always point to the archive_path instead of whatever was frozen into it.
WARNING: Do not create an instance of this class before the archives
have been extracted!
"""
class ResourcePathOverride(object):
    resource_path_orig = None
    archive_path = None

    def __init__(self, archive_path):
        import enthought.resource.resource_path #here, so that you can
import the module freely (at least in theory)
        self.resource_path_orig = enthought.resource.resource_path.resource_path
        self.archive_path = archive_path
        enthought.resource.resource_path.resource_path = self.resource_path

    def resource_path(self, level = 2):
        path = self.resource_path_orig(level+1)
        path = path.rsplit(''.join((os.path.sep, 'enthought', os.path.sep)), 1)
        root = path[0].rsplit(os.path.sep, 1)
        path = os.path.join(self.archive_path,
self.get_pkg_name(root[1]), 'enthought', path[1])
        return path

    def get_pkg_name(self, path):
        """This function must mirror the list in yasso.spec
        """
        if path.lower().startswith('traits-'):
            return 'traits'
        if path.lower().startswith('traitsgui'):
            return 'traitsgui'
        if path.lower().startswith('traitsbackendwx'):
            return 'traitswx'
        if path.lower().startswith('enable'):
            return 'enable'
        if path.lower().startswith('enthought'):
            return 'enthought'
        if path.lower().startswith('chaco'):
            return 'chaco'


> The graphical toolkit is imported only when actually needed and this
> import is quite hard to detect for pyinstaller.

Any ideas how to force this? The GUI is invoked using configure_traits:
...
yasso = Yasso()

if __name__ == '__main__':
    yasso.configure_traits()

Jussi

-- 
You received this message because you are subscribed to the Google Groups 
"PyInstaller" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/pyinstaller?hl=en.

Reply via email to