WxPython:PyInstaller失败,没有名为_core的模块_
我正在使用PyInstaller将我的wxpython(3.0.2.0)应用程序转换为二进制文件。二进制文件在Ubuntu 12.04上构建和执行时工作良好。然而,如果我在Ubuntu 14.04上构建,我会得到以下错误。(即使在Ubuntu 14.04中,当我直接启动python脚本(即python my_application.py)时,应用程序也可以工作)。你知道使用PyInstaller打包应用程序时会遗漏什么吗WxPython:PyInstaller失败,没有名为_core的模块_,python,ubuntu,wxpython,ubuntu-14.04,pyinstaller,Python,Ubuntu,Wxpython,Ubuntu 14.04,Pyinstaller,我正在使用PyInstaller将我的wxpython(3.0.2.0)应用程序转换为二进制文件。二进制文件在Ubuntu 12.04上构建和执行时工作良好。然而,如果我在Ubuntu 14.04上构建,我会得到以下错误。(即使在Ubuntu 14.04中,当我直接启动python脚本(即python my_application.py)时,应用程序也可以工作)。你知道使用PyInstaller打包应用程序时会遗漏什么吗 $ ./my_application Traceback (most r
$ ./my_application
Traceback (most recent call last):
File "<string>", line 22, in <module>
File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyi_importers.py", line 270, in load_module
exec(bytecode, module.__dict__)
File "/local/workspace/my_application/out00-PYZ.pyz/wx", line 45, in <module>
File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyi_importers.py", line 270, in load_module
exec(bytecode, module.__dict__)
File "/local/workspace/my_application/out00-PYZ.pyz/wx._core", line 4, in <module>
**ImportError: No module named _core_**
基本上,问题在于PyInstaller版本-您需要使用
develope
版本。该问题已被发现,并记录在一份报告中
要安装最新版本并更正-在命令提示下键入:
$ pip install git+https://github.com/pyinstaller/pyinstaller
这将直接从github安装pyinstaller的最新版本(直到最近,pyinstaller还有一个单独的python3
分支,但这一直是。如果需要使用python3.x,您将需要-通过在pip install
命令中附加@develop
来实现这一点)
上面的方法依赖于您在系统上安装了git
,以获得pyinstaller代码(我想,对于现在的开发人员来说,这很有可能)。如果没有,你也可以
apt get install git
安装git(您可能需要sudo
这样做)将pip与git结合使用的文档
你的问题不清楚你在Ubuntu 12.04安装和14.04安装中使用的PyInstaller版本。您在12.04上安装的版本似乎与在14.04上安装的标准版本不存在相同的问题。如果出于某种原因不需要PyInstaller开发版本,则需要进行一些修复
PyInstaller.loader.pyi\u导入程序的BuiltinImporter
、frozenporter
和CExtensionImporter
实例附加到sys.meta\u路径
。和find_module
方法,按顺序调用该方法,直到导入模块时其中一个成功为止
CExtensionImporter
只选择要加载的C扩展的众多后缀中的一个,例如wx.\u core\u386 linux gnu.so
。这就是为什么它无法加载C扩展名wx.\u core\uu.so
错误代码
class CExtensionImporter(object):
def __init__(self):
# Find the platform specific suffix. On Windows it is .pyd, on Linux/Unix .so.
for ext, mode, typ in imp.get_suffixes():
if typ == imp.C_EXTENSION:
self._c_ext_tuple = (ext, mode, typ)
self._suffix = ext # Just string like .pyd or .so
break
固定
1。运行时挂钩
使用运行时挂钩可以在不更改代码的情况下修复问题。这是一个快速修复“WxPython”问题的方法。
此运行时钩子更改CExtensionImporter
实例的一些私有属性。要使用此钩子,请将--runtime hook=wx run hook.py
指定给pyinstaller
wx-run-hook.py
import sys
import imp
sys.meta_path[-1]._c_ext_tuple = imp.get_suffixes()[1]
sys.meta_path[-1]._suffix = sys.meta_path[-1]._c_ext_tuple[0]
import sys
import imp
from PyInstaller.loader import pyi_os_path
class CExtensionImporter(object):
"""
PEP-302 hook for sys.meta_path to load Python C extension modules.
C extension modules are present on the sys.prefix as filenames:
full.module.name.pyd
full.module.name.so
"""
def __init__(self):
# TODO cache directory content for faster module lookup without file system access.
# Find the platform specific suffix. On Windows it is .pyd, on Linux/Unix .so.
self._c_ext_tuples = [(ext, mode, typ) for ext, mode, typ in imp.get_suffixes() if typ == imp.C_EXTENSION]
# Create hashmap of directory content for better performance.
files = pyi_os_path.os_listdir(sys.prefix)
self._file_cache = set(files)
def find_module(self, fullname, path=None):
imp.acquire_lock()
module_loader = None # None means - no module found by this importer.
# Look in the file list of sys.prefix path (alias PYTHONHOME).
for ext, mode, typ in self._c_ext_tuples:
if fullname + ext in self._file_cache:
module_loader = self
self._suffix = ext
self._c_ext_tuple = (ext, mode, typ)
break
imp.release_lock()
return module_loader
def load_module(self, fullname, path=None):
imp.acquire_lock()
try:
# PEP302 If there is an existing module object named 'fullname'
# in sys.modules, the loader must use that existing module.
module = sys.modules.get(fullname)
if module is None:
filename = pyi_os_path.os_path_join(sys.prefix, fullname + self._suffix)
fp = open(filename, 'rb')
module = imp.load_module(fullname, fp, filename, self._c_ext_tuple)
# Set __file__ attribute.
if hasattr(module, '__setattr__'):
module.__file__ = filename
else:
# Some modules (eg: Python for .NET) have no __setattr__
# and dict entry have to be set.
module.__dict__['__file__'] = filename
except Exception:
# Remove 'fullname' from sys.modules if it was appended there.
if fullname in sys.modules:
sys.modules.pop(fullname)
# Release the interpreter's import lock.
imp.release_lock()
raise # Raise the same exception again.
# Release the interpreter's import lock.
imp.release_lock()
return module
### Optional Extensions to the PEP302 Importer Protocol
def is_package(self, fullname):
"""
Return always False since C extension modules are never packages.
"""
return False
def get_code(self, fullname):
"""
Return None for a C extension module.
"""
if fullname + self._suffix in self._file_cache:
return None
else:
# ImportError should be raised if module not found.
raise ImportError('No module named ' + fullname)
def get_source(self, fullname):
"""
Return None for a C extension module.
"""
if fullname + self._suffix in self._file_cache:
return None
else:
# ImportError should be raised if module not found.
raise ImportError('No module named ' + fullname)
def get_data(self, path):
"""
This returns the data as a string, or raise IOError if the "file"
wasn't found. The data is always returned as if "binary" mode was used.
The 'path' argument is a path that can be constructed by munging
module.__file__ (or pkg.__path__ items)
"""
# Since __file__ attribute works properly just try to open and read it.
fp = open(path, 'rb')
content = fp.read()
fp.close()
return content
# TODO Do we really need to implement this method?
def get_filename(self, fullname):
"""
This method should return the value that __file__ would be set to
if the named module was loaded. If the module is not found, then
ImportError should be raised.
"""
if fullname + self._suffix in self._file_cache:
return pyi_os_path.os_path_join(sys.prefix, fullname + self._suffix)
else:
# ImportError should be raised if module not found.
raise ImportError('No module named ' + fullname)
#This may overwrite some other object
#sys.meta_path[-1] = CExtensionImporter()
#isinstance(object, CExtensionImporter)
#type(object) == CExtensioImporter
#the above two doesn't work here
#grab the index of instance of CExtensionImporter
for i, obj in enumerate(sys.meta_path):
if obj.__class__.__name__ == CExtensionImporter.__name__:
sys.meta_path[i] = CExtensionImporter()
break
第二个运行时钩子完全替换了sys.meta\u路径[-1]
中的对象。所以它在大多数情况下都应该有效。使用aspyinstaller--runtime hook=pyinstaller-run-hook.py application.py
pyinstaller-run-hook.py
import sys
import imp
sys.meta_path[-1]._c_ext_tuple = imp.get_suffixes()[1]
sys.meta_path[-1]._suffix = sys.meta_path[-1]._c_ext_tuple[0]
import sys
import imp
from PyInstaller.loader import pyi_os_path
class CExtensionImporter(object):
"""
PEP-302 hook for sys.meta_path to load Python C extension modules.
C extension modules are present on the sys.prefix as filenames:
full.module.name.pyd
full.module.name.so
"""
def __init__(self):
# TODO cache directory content for faster module lookup without file system access.
# Find the platform specific suffix. On Windows it is .pyd, on Linux/Unix .so.
self._c_ext_tuples = [(ext, mode, typ) for ext, mode, typ in imp.get_suffixes() if typ == imp.C_EXTENSION]
# Create hashmap of directory content for better performance.
files = pyi_os_path.os_listdir(sys.prefix)
self._file_cache = set(files)
def find_module(self, fullname, path=None):
imp.acquire_lock()
module_loader = None # None means - no module found by this importer.
# Look in the file list of sys.prefix path (alias PYTHONHOME).
for ext, mode, typ in self._c_ext_tuples:
if fullname + ext in self._file_cache:
module_loader = self
self._suffix = ext
self._c_ext_tuple = (ext, mode, typ)
break
imp.release_lock()
return module_loader
def load_module(self, fullname, path=None):
imp.acquire_lock()
try:
# PEP302 If there is an existing module object named 'fullname'
# in sys.modules, the loader must use that existing module.
module = sys.modules.get(fullname)
if module is None:
filename = pyi_os_path.os_path_join(sys.prefix, fullname + self._suffix)
fp = open(filename, 'rb')
module = imp.load_module(fullname, fp, filename, self._c_ext_tuple)
# Set __file__ attribute.
if hasattr(module, '__setattr__'):
module.__file__ = filename
else:
# Some modules (eg: Python for .NET) have no __setattr__
# and dict entry have to be set.
module.__dict__['__file__'] = filename
except Exception:
# Remove 'fullname' from sys.modules if it was appended there.
if fullname in sys.modules:
sys.modules.pop(fullname)
# Release the interpreter's import lock.
imp.release_lock()
raise # Raise the same exception again.
# Release the interpreter's import lock.
imp.release_lock()
return module
### Optional Extensions to the PEP302 Importer Protocol
def is_package(self, fullname):
"""
Return always False since C extension modules are never packages.
"""
return False
def get_code(self, fullname):
"""
Return None for a C extension module.
"""
if fullname + self._suffix in self._file_cache:
return None
else:
# ImportError should be raised if module not found.
raise ImportError('No module named ' + fullname)
def get_source(self, fullname):
"""
Return None for a C extension module.
"""
if fullname + self._suffix in self._file_cache:
return None
else:
# ImportError should be raised if module not found.
raise ImportError('No module named ' + fullname)
def get_data(self, path):
"""
This returns the data as a string, or raise IOError if the "file"
wasn't found. The data is always returned as if "binary" mode was used.
The 'path' argument is a path that can be constructed by munging
module.__file__ (or pkg.__path__ items)
"""
# Since __file__ attribute works properly just try to open and read it.
fp = open(path, 'rb')
content = fp.read()
fp.close()
return content
# TODO Do we really need to implement this method?
def get_filename(self, fullname):
"""
This method should return the value that __file__ would be set to
if the named module was loaded. If the module is not found, then
ImportError should be raised.
"""
if fullname + self._suffix in self._file_cache:
return pyi_os_path.os_path_join(sys.prefix, fullname + self._suffix)
else:
# ImportError should be raised if module not found.
raise ImportError('No module named ' + fullname)
#This may overwrite some other object
#sys.meta_path[-1] = CExtensionImporter()
#isinstance(object, CExtensionImporter)
#type(object) == CExtensioImporter
#the above two doesn't work here
#grab the index of instance of CExtensionImporter
for i, obj in enumerate(sys.meta_path):
if obj.__class__.__name__ == CExtensionImporter.__name__:
sys.meta_path[i] = CExtensionImporter()
break
2。代码更改
class CExtensionImporter(object):
def __init__(self):
# Find the platform specific suffix. On Windows it is .pyd, on Linux/Unix .so.
self._c_ext_tuples = [(ext, mode, typ) for ext, mode, typ in imp.get_suffixes() if typ == imp.C_EXTENSION]
files = pyi_os_path.os_listdir(sys.prefix)
self._file_cache = set(files)
由于imp.get_后缀
为类型imp.C_扩展
返回多个后缀,并且在找到模块之前无法预先知道正确的后缀,因此我将所有后缀存储在一个列表self.\u C_ext_tuples
中。右后缀在self.\u suffix
中设置,如果找到模块,则通过load\u module
方法从find\u module
方法将其与self.\u ext\u tuple
一起使用
def find_module(self, fullname, path=None):
imp.acquire_lock()
module_loader = None # None means - no module found by this importer.
# Look in the file list of sys.prefix path (alias PYTHONHOME).
for ext, mode, typ in self._c_ext_tuples:
if fullname + ext in self._file_cache:
module_loader = self
self._suffix = ext
self._c_ext_tuple = (ext, mode, typ)
break
imp.release_lock()
return module_loader
我现在无法从这里重现这个问题(不同的操作系统),但您是否尝试过使用pyinstaller的替代方案?(例如cx\u freeze)?从wx import\u core执行时会得到什么;在Python交互式shell上打印u core.uu file uu
?@Nemo-我的答案有什么问题需要我澄清/帮助吗?@Nemo只要一个ping就可以让你知道我的答案,因为你已经发布了慷慨的赏金,我认为这对你来说可能非常重要。到Python 3.x分支的链接目前已断开。@shuttle87-这就是链接断开的原因-正如聊天中所建议的那样-现在它已合并到develope
中,刚刚查看了这个,很好的答案详细说明了为什么会发生这种情况@j-richard-snape谢谢!