py2app: how to include modules that will be loaded by __import__?
I have a Python application that loads python modules dynamically at run time (using __import__
). The modules to load are in a package called 'plugins
' (i.e. subfolder called plugins
with __init__.py
etc). All works fine running from the python interpreter, and even when compiled to a windows binary using py2exe.
I tried building a OSX app from it, which succeeded, but when running the .app I get an ImportError: 'no module named plugins.xxxx
'.
I am pretty sure I gave the correct options to py2app ('includes': [...]
, 'packages':['plugins']
, identical to what I do for py2exe), since when I browse the .app content, I see all the plugin modules in a folder Contents/Resources/lib/python2.5/plugins/
.
So, why can't the app find my modules (must be some path issue)?
Edit:
I've found a way to make it work, but it isn't a good solution:
When I printed the paths Python searches for modules (using print sys.path
), I noticed that the folder开发者_JAVA技巧 Contents/Resources/lib/python2.5/plugins/
was NOT listed. However, the folder Contents/Resources/
is, so I moved the plugins
folder to the Contents/Resources
folder. Now the plugins are found. But I am still not happy with this ugly, manual hack.
Koo uses the following code. You'll probably need to do something similar to detect that you're in py2app, and adjust your import accordingly.
http://bazaar.launchpad.net/~openobject-client-kde/openobject-client-kde/5.0/annotate/head%3A/Koo/Common/Plugins.py
def scan( module, directory ):
pluginImports = __import__(module, globals(), locals())
# Check if it's being run using py2exe or py2app environment
frozen = getattr(sys, 'frozen', None)
if frozen == 'macosx_app' or hasattr(pluginImports, '__loader__'):
# If it's run using py2exe or py2app environment, all files will be in a single
# zip file and we can't use listdir() to find all available plugins.
zipFiles = pluginImports.__loader__._files
moduleDir = os.sep.join( module.split('.') )
files = [zipFiles[file][0] for file in zipFiles.keys() if moduleDir in file]
files = [file for file in files if '__init__.py' in file]
for file in files:
d = os.path.dirname(file)
if d.endswith( moduleDir ):
continue
newModule = os.path.basename(os.path.dirname(file))
__import__( '%s.%s' % (module, newModule), globals(), locals(), [newModule] )
else:
for i in os.listdir(directory):
path = os.path.join( directory, i, '__init__.py' )
if os.path.isfile( path ):
__import__( '%s.%s' % (module, i), globals(), locals(), [i] )
精彩评论