WxPython:PyInstaller失败,没有名为_core的模块_

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

我正在使用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 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
    这样做)
  • 下载pyinstaller开发zip文件()并手动安装。注:根据标准,这应支持2.7和3.x
  • 就我个人而言,我更喜欢选项1,因为您可以避免自己从压缩的源代码树构建的所有潜在问题

    测试 我在Ubuntu14.04、64位、wxpython 3.0.2.0和python 2.7.6上测试了这一点,使用wxpython网页上的简单代码。OP的问题恰好在安装pyinstaller开发版本之前重现。安装开发版本后,应用程序正确构建并作为可执行文件运行


    将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]
    中的对象。所以它在大多数情况下都应该有效。使用as
    pyinstaller--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谢谢!