pyfiglet软件包的PyInstaller缺少模块错误

时间:2019-07-11 19:35:10

标签: python pyinstaller

我想构建一个独立的可执行VLI工具,该工具将使用pyfiglet软件包。当我运行pyinstaller --onefile main.py时,它在build/warn-main.txt文件中导致了一些警告。

我更改了生成的main.spec,添加了"pyfiglet.fonts"和其他一些缺少的模块,然后执行了pyinstaller --onefile main.spec。之后,只有pyfiglet.fonts被“解决”。

最初我在Windows 10 Pro中运行代码,但是由于找不到解决方案,我仅使用linux和python安装了干净的VM进行测试...

我正在使用以下软件在干净的ubuntu 19.04上运行: -从默认存储库安装python3(3.7.3) -没有虚拟环境 - 添加 -已安装的pyinstaller(3.5)简单为pip install pyinstaller

使用此非常基本的代码,问题就会发生

import pyfiglet
print("Basic Work...")
ascii_banner = pyfiglet.figlet_format("Works...")
print(ascii_banner)

缺少的模块是:

missing module named pyimod03_importers - imported by /home/masterlocal/.local/lib/python3.7/site-packages/PyInstaller/loader/rthooks/pyi_rth_pkgres.py (top-level)
missing module named _winreg - imported by platform (delayed, optional), /home/masterlocal/code/cliexe/main.py (top-level), pkg_resources._vendor.appdirs (delayed, conditional)
missing module named java - imported by platform (delayed), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named 'java.lang' - imported by platform (delayed, optional), /home/masterlocal/code/cliexe/main.py (top-level), xml.sax._exceptions (conditional)
missing module named vms_lib - imported by platform (delayed, conditional, optional), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named _scproxy - imported by urllib.request (conditional)
missing module named org - imported by pickle (optional), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named msvcrt - imported by subprocess (conditional), click._compat (conditional, optional), click._winconsole (top-level), getpass (optional), click._termui_impl (conditional), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named _winapi - imported by encodings (delayed, conditional, optional), subprocess (conditional), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named winreg - imported by platform (delayed, optional), mimetypes (optional), /home/masterlocal/code/cliexe/main.py (top-level), urllib.request (delayed, conditional, optional), pkg_resources._vendor.appdirs (delayed, conditional)
missing module named pkg_resources.extern.six - imported by pkg_resources.extern (top-level), pkg_resources (top-level), pkg_resources.py31compat (top-level), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named 'pkg_resources.extern.six.moves' - imported by pkg_resources (top-level), /home/masterlocal/code/cliexe/main.py (top-level), pkg_resources._vendor.packaging.requirements (top-level)
missing module named pkg_resources.extern.appdirs - imported by pkg_resources.extern (top-level), pkg_resources (top-level), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named pkg_resources.extern.packaging - imported by pkg_resources.extern (top-level), pkg_resources (top-level), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named __main__ - imported by pkg_resources (delayed, optional), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named 'pkg_resources.extern.pyparsing' - imported by pkg_resources._vendor.packaging.requirements (top-level), pkg_resources._vendor.packaging.markers (top-level)
missing module named 'ctypes.macholib' - imported by ctypes.util (conditional)
missing module named netbios - imported by uuid (delayed)
missing module named win32wnet - imported by uuid (delayed)
missing module named __builtin__ - imported by pkg_resources._vendor.pyparsing (conditional)
missing module named ordereddict - imported by pkg_resources._vendor.pyparsing (optional)
missing module named 'win32com.shell' - imported by pkg_resources._vendor.appdirs (conditional, optional)
missing module named 'com.sun' - imported by pkg_resources._vendor.appdirs (delayed, conditional, optional)
missing module named com - imported by pkg_resources._vendor.appdirs (delayed)
missing module named win32api - imported by pkg_resources._vendor.appdirs (delayed, conditional, optional)
missing module named win32com - imported by pkg_resources._vendor.appdirs (delayed)
missing module named StringIO - imported by pkg_resources._vendor.six (conditional)
missing module named nt - imported by os (conditional, optional), ntpath (conditional, optional), shutil (conditional), /home/masterlocal/code/cliexe/main.py (top-level)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), /home/masterlocal/code/cliexe/main.py (top-level)
missing module named 'org.python' - imported by copy (optional), /home/masterlocal/code/cliexe/main.py (top-level), xml.sax (delayed, conditional)
missing module named colorama - imported by click._compat (conditional, optional)

我是Python的新手,所以,关于它的使用经验并不多,但是根据我读过的很多文章,并没有太多的细节。我检查了有关如何安装和重新查询的文档,所有内容(不多)都符合预期。

我将不胜感激。

2 个答案:

答案 0 :(得分:0)

PyInstaller无法识别具有模板,DLL等外部依赖项的库。因此,如果要冻结此类模块,则需要手动将其提供给最终的可执行文件。

pyfiglet需要其外部font依赖性,因此可以通过add-data标志添加它。 例如:

pyinstaller -F --add-data "<python directory>/Lib/site-packages/pyfiglet/fonts;./pyfiglet/fonts" script.py

以上命令将解决在Windows上导入pyfiglet的问题。另外,我建议您始终将virtualenv与PyInstaller一起使用,因为它会创建一个全新的Python环境。

答案 1 :(得分:0)

如果我很好看,问题在于在pyfiglet中加载字体的实现。

我建议将其替换为自定义:

import pyfiglet
import pyfiglet.fonts
import pkg_resources
import os

class MyFigletFont(pyfiglet.FigletFont):
    @classmethod
    def preloadFont(cls, font):
        """
        Load font data if exist
        """
        base_path = os.path.dirname(pyfiglet.fonts.__file__)
        for extension in ('tlf', 'flf'):
            fn = '%s.%s' % (font, extension)
            """
               I chnage theese 3 lines.
               original use pkg_resources.resource_exists
            """  
            if os.path.isfile(os.path.join(base_path, fn)):
                with open(os.path.join(base_path, fn), 'rb') as f:
                    return f.read().decode('UTF-8', 'replace')
            else:
                for location in ("./", pyfiglet.SHARED_DIRECTORY):
                    full_name = os.path.join(location, fn)
                    if os.path.isfile(full_name):
                        with open(full_name, 'rb') as f:
                            return f.read().decode('UTF-8', 'replace')
        else:
            raise FontNotFound(font)

pyfiglet.FigletFont = MyFigletFont # here I change implementation of font loader 

print("Basic Work...")
ascii_banner = pyfiglet.figlet_format("Works...")
print(ascii_banner)

和规格文件(记住要更新路径)

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None
import os 
import pyfiglet.fonts

a = Analysis(['test3.py'],
             pathex=['/home/czaki/Pobrane/tmp/test_pyqt'],
             binaries=[],
             datas=[(os.path.join(os.path.dirname(pyfiglet.fonts.__file__), "*.f*"), os.path.join("pyfiglet", "fonts"))],
             hiddenimports=["pyfiglet.fonts"],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='test3',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='test3')