PyInstaller与pipenv一起使用时无法导入分发

时间:2019-12-22 14:08:00

标签: python virtualenv pyinstaller pipenv

在raspbian中使用virtualenv(16.7.7)在pipenv(2018.11.26)中运行以下代码片段时,它会完美执行,并且所有操作均按预期完成。

import logging
import distutils
from PIL import Image, ImageDraw, ImageFont, ImageFile, ImageOps
from pathlib import Path

logger = logging.getLogger(__name__)
logger.root.setLevel('DEBUG')

image = Path('/home/pi/tmp/4886.jpg').expanduser()

size = (100, 200)
try:
    logging.info(f'opening image: {image}')
    im = Image.open(image)
    im.thumbnail(size)

except (PermissionError, FileNotFoundError, OSError) as e:
    logging.warning(f'could not open image file: {image}')
    logging.warning(f'image error: {e}')
    logging.warning(f'using empty image')

print(f'image size is: {im.size}')

输出 这样会产生预期的结果

INFO:root:opening image: /home/pi/tmp/4886.jpg
image size is: (100, 90)

pipenv run python -m PyInstaller im_open.py打包后,编译后的版本会显示DEBUG:PIL.Image:Image: failed to import JpegImagePlugin: No module named 'distutils'

输出

INFO:root:opening image: /home/pi/tmp/4886.jpg
...
DEBUG:PIL.Image:Importing IptcImagePlugin
DEBUG:PIL.Image:Importing JpegImagePlugin
DEBUG:PIL.Image:Image: failed to import JpegImagePlugin: No module named 'distutils'
DEBUG:PIL.Image:Importing Jpeg2KImagePlugin
DEBUG:PIL.Image:Importing McIdasImagePlugin
DEBUG:PIL.Image:Importing MicImagePlugin
DEBUG:PIL.Image:Image: failed to import MicImagePlugin: No module named 'olefile'
DEBUG:PIL.Image:Importing MpegImagePlugin
DEBUG:PIL.Image:Importing MpoImagePlugin
DEBUG:PIL.Image:Image: failed to import MpoImagePlugin: No module named 'distutils'
DEBUG:PIL.Image:Importing MspImagePlugin
DEBUG:PIL.Image:Importing PalmImagePlugin
DEBUG:PIL.Image:Importing PcdImagePlugin
...
WARNING:root:could not open image file: /home/pi/tmp/4886.jpg
WARNING:root:image error: cannot identify image file '/home/pi/tmp/4886.jpg'
WARNING:root:using empty image
Traceback (most recent call last):
  File "im_open.py", line 69, in <module>
    print(f'image size is: {im.size}')
NameError: name 'im' is not defined

我尝试了以下操作:

  • 明确包含distutils(如上面的代码片段所示)
  • 将distutils添加到.spec文件的hiddeimports=['distutils']
  • 的隐藏导入列表中

相关研究

1 个答案:

答案 0 :(得分:0)

另一个错误报告中有一个workaround用于解决此问题。以下方法似乎可以通过至少16.7.7来解决virtualenv 16.4.0的此问题

  1. 在pipenv中安装PyInstaller(我不确定为什么可以解决此问题,但目前看来是最可靠的):pipenv install PyInstaller
  2. 打开pipenv创建的PyInstaller目录:pipenv open PyInstaller并编辑hooks/pre_find_module_path/hook-distutils.py以匹配下面显示的补丁。

修补了pre_find_module_path / hook-distutils.py

import distutils
import os

from PyInstaller.utils.hooks import logger


def pre_find_module_path(api):
    # Absolute path of the system-wide "distutils" package when run from within
    # a venv or None otherwise.
    distutils_dir = getattr(distutils, 'distutils_path', None)
    if distutils_dir is not None:
        # workaround for https://github.com/pyinstaller/pyinstaller/issues/4064
        if distutils_dir.endswith('__init__.py'):
            distutils_dir = os.path.dirname(distutils_dir)
        # end workaround patch

        # Find this package in its parent directory.
        api.search_dirs = [os.path.dirname(distutils_dir)]
        logger.info('distutils: retargeting to non-venv dir %r' % distutils_dir)