py2app:如何包含通过__import__加载的模块?
我有一个用Python写的应用程序,它可以在运行时动态加载Python模块(使用 __import__
)。要加载的模块都在一个叫做'plugins
'的包里(也就是一个名为plugins
的子文件夹,里面有__init__.py
等文件)。在Python解释器中运行时一切正常,甚至在用py2exe编译成Windows可执行文件时也没问题。
我尝试从这个应用程序构建一个OSX应用,虽然成功了,但在运行这个.app文件时却出现了导入错误:'no module named plugins.xxxx
'。
我很确定我给py2app设置了正确的选项('includes': [...]
, 'packages':['plugins']
,和我为py2exe做的一样),因为当我查看这个.app的内容时,看到所有的插件模块都在一个文件夹Contents/Resources/lib/python2.5/plugins/
里。
那么,为什么应用程序找不到我的模块呢(肯定是路径的问题)?
编辑:
我找到了一种方法让它工作,但这并不是个好解决方案:当我打印出Python搜索模块的路径(使用 print sys.path
)时,我注意到文件夹Contents/Resources/lib/python2.5/plugins/
并没有被列出。不过,文件夹Contents/Resources/
是被列出的,所以我把plugins
文件夹移动到了Contents/Resources
文件夹里。现在插件可以被找到。但我还是对这个丑陋的手动解决方案不满意。
1 个回答
0
Koo使用了以下代码。你可能也需要做类似的事情来检测你是否在py2app环境中,并相应地调整你的导入。
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] )