0

我想构建一个独立的可执行 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 新手,所以没有太多关于如何操作的经验,但是根据我阅读的许多帖子,没有太多细节。我已经检查了有关如何安装和要求的文档,并且所有内容(不多)都符合预期。

我将不胜感激任何帮助。

4

2 回答 2

0

PyInstaller 不会识别具有外部依赖项的库,如模板、DLL 等。因此,如果您要冻结这样的模块,则需要手动将它们提供给最终的可执行文件。

pyfiglet需要它的外部font依赖,所以你可以通过add-data标志添加它。例如:

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

上述命令将解析为pyfiglet在 Windows 上导入。另外,我建议您始终使用virtualenvwith PyInstaller,因为它会创建一个全新的 Python 环境。

于 2019-07-12T06:22:45.173 回答
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')
于 2019-07-12T07:20:22.773 回答