はじめに
Windows環境で Python GUI アプリ(tkinter)を PyInstaller で exe化したところ、mariadb接続でエラーになりました。
mariadb接続にはpipのmysql-connector-pythonを使用していましたが、どうもこのライブラリをPyInstallerで読めていないようでした。
基本情報
- DBサーバ:MariaDB Ver 15.1(Ubuntu24で構築)
- 開発マシン:Windows11
- 開発環境:VSCode
- プロジェクトのフォルダ:D:\python\myproject
- 対象スクリプトファイル:D:\python\myproject\main_form.py
- 仮想環境:D:\python\myproject\.venv
前提条件
- python仮想環境でPyInstallerを実行
- デバッグ環境ではDB接続できているが、exe化すると接続できない(DB接続で例外)
-
--hidden-importや--collect-submodulesを使っても改善せず
うまくいかなかった方法
--hidden-import、 --collect-submodulesオプションで明示的に指定
pyinstaller --onefile .\main_form.py --hidden-import=mysql.connector
pyinstaller --onefile .\main_form.py --collect-submodules mysql.connector
ビルドエラーは出ないが、作成されたexeでDBに接続できずエラーになる。
解決した方法
.spec ファイルで完全制御
上記で作成されたmain_form.specを下記の通り編集し、mysql.connectorを明示的にインポートさせる。
1. spec ファイルの先頭に追加
main_form.spec
from PyInstaller.utils.hooks import collect_all
datas, binaries, hiddenimports_all = collect_all('mysql')
2. hiddenimports に統合
main_form.spec
hiddenimports = [
'mysql.connector',
'mysql.connector.connection'
hiddenimports = [
'mysql.connector',
'mysql.connector.connection',
'mysql.connector.cursor',
'mysql.connector.errors',
'mysql.connector.authentication',
'mysql.connector.network',
'mysql.connector.dbapi',
'mysql.connector.pooling'
] + hiddenimports_all
3. Analysis() に反映
main_form.spec
a = Analysis(
...,
datas=datas,
binaries=binaries,
hiddenimports=hiddenimports,
...
)
4. .spec ファイルでビルド
pyinstaller main_form.spec
結果
上記でビルドしたexeファイルの実行で無事DBに接続できました!
.spec ファイル全文
参考までに今回作成した.spec ファイル全文を載せます。
main_form.spec
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_submodules
from PyInstaller.utils.hooks import collect_all
datas, binaries, hiddenimports_all = collect_all('mysql')
hiddenimports = [
'mysql.connector',
'mysql.connector.connection',
'mysql.connector.cursor',
'mysql.connector.errors',
'mysql.connector.authentication',
'mysql.connector.network',
'mysql.connector.dbapi',
'mysql.connector.pooling'
] + hiddenimports_all
hiddenimports += collect_submodules('mysql.connector')
a = Analysis(
['main_form.py'],
pathex=[],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=True,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[('v', None, 'OPTION')],
name='main_form',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='myProj.ico',
)