为什么 PyInstaller 生成的 exe 无法导入?

问题描述

我在使用 PyInstaller 时遇到问题。我正在尝试构建主文件 (Logical.py -> Logical.exe)。当我将文件作为 python 脚本运行时,它运行良好(终端:python Logical.py examples/led.lgc)。当我运行 PyInstaller 构建的 exe 时(终端:./Logical examples/led.lgc),我收到此错误消息:

Traceback (most recent call last):
  File "Logical.py",line 2,in <module>
    from pynput import keyboard
  File "PyInstaller\loader\pyimod03_importers.py",line 540,in exec_module
  File "pynput\__init__.py",line 40,in <module>
  File "PyInstaller\loader\pyimod03_importers.py",in exec_module
  File "pynput\keyboard\__init__.py",line 31,in <module>
  File "pynput\_util\__init__.py",line 76,in backend
ImportError
[10688] Failed to execute script Logical

它似乎对 pynput 导入感到不安,但我不知道为什么。我的来源的进口如下。 loadingui 都在项目目录中,本文底部列出了 simpleANSI 的源代码

import sys,time,os,ctypes
from pynput import keyboard
from loading.loading import loadElement
from ui import vec2,widget,ansiManager
import simpleANSI as ANSI
import pdb

我运行这两个存储库,因此我可以保证在我解决此问题之前它们不会更改。

我在 Windows 10 x64 上使用 Python 3.9.5,PyInstaller 版本 4.3,pynput 版本 1.7.3。

编辑:我翻阅了 Python lib 文件并找到了回溯的目的地。这是 ...\python\3.9.5\Lib\site-packages\pynput\_util\__init__.py 中的违规函数

def backend(package):
    """Returns the backend module for a package.

    :param str package: The package for which to load a backend.
    """
    backend_name = os.environ.get(
        'PYNPUT_BACKEND_{}'.format(package.rsplit('.')[-1].upper()),os.environ.get('PYNPUT_BACKEND',None))
    if backend_name:
        modules = [backend_name]
    elif sys.platform == 'darwin':
        modules = ['darwin']
    elif sys.platform == 'win32':
        modules = ['win32']
    else:
        modules = ['xorg']

    errors = []
    resolutions = []
    for module in modules:
        try:
            return importlib.import_module('._' + module,package)
        except ImportError as e:
            errors.append(e)
            if module in RESOLUTIONS:
                resolutions.append(RESOLUTIONS[module])

    raise ImportError('this platform is not supported: {}'.format(    # AwesomeCronk: This is the offending line
        '; '.join(str(e) for e in errors)) + ('\n\n'
            'Try one of the following resolutions:\n\n'
            + '\n\n'.join(
                ' * {}'.format(s)
                for s in resolutions))
            if resolutions else '')

解决方法

我尝试将 --hidden-import "pynput.keyboard._win32" --hidden-import "pynput.mouse._win32" 添加到 PyInstaller 参数中,但无济于事。我最终将 pynput 回滚到 1.6.8 版。