pyinstaller打包后exe无法运行 遇到ModuleNotFoundError: No module named xxx,importlib.metadata.PackageNot 的问题

举例  PyInstaller 打包 Tortoise ORM 遇到的问题及解决方案

本文总结了在使用 PyInstaller 打包 Tortoise ORM 时可能遇到的问题及对应解决方案,适用于处理动态模块加载失败、数据库后端模块未包含等常见情况。

1. 问题描述

在使用 PyInstaller 打包基于 Tortoise ORM 的项目时,常见错误包括:

  1. 缺少元数据文件

    importlib.metadata.PackageNotFoundError: tortoise-orm

    原因:PyInstaller 默认不会将 tortoise-orm 的元数据(如 METADATA 文件)打包。
  2. 缺少数据库后端模块

    ModuleNotFoundError: No module named 'tortoise.backends.sqlite'

    原因:Tortoise ORM 的后端模块(如 SQLite、MySQL、PostgreSQL 等)通常通过动态加载实现,PyInstaller 无法自动识别这些模块。
  3. 未加载动态模块: 某些扩展功能或动态模块(如 tortoise.contrib.fastapitortoise.transactions)未被打包,导致运行时失败。

2. 解决方案

2.1 元数据文件(如 METADATA)是 importlib.metadata 用于获取包信息的重要部分。如果未包含该文件,会导致 PackageNotFoundError
方法1: collect_all 一站式收集  同时获取包的 元数据(datas)二进制文件(binaries) 和 隐藏导入项(hiddenimports) (推荐)√√√
from PyInstaller.utils.hooks import collect_all  

# 一次性获取 tortoise-orm 的所有资源  
tortoise_datas, tortoise_binaries, tortoise_hiddenimports = collect_all('tortoise')  
# 或使用 PyPI 包名:collect_all('tortoise-orm')(两者均可,优先用模块名)  

最终加入到
a = Analysis(  
    ['main.py'],  
    pathex=[],  
    datas=tortoise_datas,               # 包含元数据和数据文件  
    binaries=tortoise_binaries,         # 包含二进制依赖(如有)  
    hiddenimports=tortoise_hiddenimports,  # 包含所有子模块(如数据库后端)  
    hookspath=[],  
    excludes=[],  
    runtime_hooks=[],  
    cipher=block_cipher,  
)  
方法 2:使用 copy_metadata(单独引推荐) √

.spec 文件中添加:

from PyInstaller.utils.hooks import copy_metadata

datas = copy_metadata('tortoise-orm')

 .spec文件如何生成?

pyinstaller --name xxx main.py --onefile --specpath .   

方法 3:手动添加元数据路径 不推荐 ×

如果 copy_metadata 不适用,可以手动指定 tortoise-orm 的元数据路径:

datas = [
    ('D:/Python/Lib/site-packages/tortoise-orm-0.18.0.dist-info', 'tortoise-orm-0.18.0.dist-info'),
]
2.2 包含数据库后端模块 
  1. 一站式收集:同时获取包的 元数据(datas)、二进制文件(binaries) 和 隐藏导入项(hiddenimports)。推荐  一站式方案 同上已处理
  2. Tortoise ORM 的功能模块较多,推荐使用 collect_submodules 自动收集模块。推荐
from PyInstaller.utils.hooks import collect_submodules

hiddenimports = collect_submodules('tortoise')

         如果是多个包 循环加入

modules_to_collect = ['tortoise', 'pydantic', 'fastapi']
hiddenimports = []

for module in modules_to_collect:
    hiddenimports += collect_submodules(module)

手动添加到 hiddenimports。以下是 Tortoise 支持的常见后端模块:繁琐不推荐 ×

hiddenimports=[
    'tortoise.backends.sqlite',   # SQLite
    'tortoise.backends.mysql',    # MySQL
    'tortoise.backends.asyncpg',  # PostgreSQL
    'tortoise.backends.aioodbc',  # ODBC
    'tortoise.backends.db_url',   # 动态数据库 URL 解析
]

最终的.spec文件 (可以直接抄作业)

一站式加载方案
# -*- mode: python ; coding: utf-8 -*-  
from PyInstaller.utils.hooks import collect_all  

block_cipher = None  

# ----------------------  
# 1. 使用 collect_all 收集 Tortoise ORM 资源  
# ----------------------  
tortoise_datas, tortoise_binaries, tortoise_hiddenimports = collect_all('tortoise')  

# ----------------------  
# 2. 分析入口文件及依赖(合并资源)  
# ----------------------  
a = Analysis(  
    ['main.py'],  
    pathex=[],  
    datas=tortoise_datas,               # 包含元数据和数据文件  
    binaries=tortoise_binaries,         # 包含二进制依赖(如有)  
    hiddenimports=tortoise_hiddenimports,  # 包含所有子模块(如数据库后端)  
    hookspath=[],  
    excludes=[],  
    runtime_hooks=[],  
    cipher=block_cipher,  
)  

# ----------------------  
# 3. 生成可执行文件(其他配置不变)  
# ----------------------  
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)  
exe = EXE(  
    pyz,  
    a.scripts,  
    name='tortoise_app',  
    upx=True,  
    console=True,  
)  
分开加载方案
from PyInstaller.utils.hooks import copy_metadata
from PyInstaller.utils.hooks import collect_submodules


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

block_cipher = None


a = Analysis(
    ['main.py'],
    pathex=[],
    binaries=[],
    datas=copy_metadata('tortoise-orm'),
    hiddenimports=collect_submodules('tortoise'),
    hookspath=[],
    hooksconfig={},
    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,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='main',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值