PyInstaller ライブラリを利用して Python コードを実行形式に変換する手順を以下に記載します。
発生したエラーと対処方法についても備忘録として残しておきます。
動作環境
- Windows 11 / macOS 15.7.2
- Python 3.12.3
- PyInstaller 6.16.0
- uv 0.9.9 (Homebrew 2025-11-12)
サンプルコード
キーを押すとカウントする簡単なプログラムです。
git clone https://github.com/tamaohome/practice-pyinstaller.git
ディレクトリ構成
practice-pyinstaller
├─ main.spec
└─ app/
├─ __init__.py
├─ counter.py
└─ main.py
-
main.specは PyInstaller 実行時に自動生成される (後述) -
__init__.pyは空ファイル -
pyproject.tomlなどプロジェクト固有のファイルは省略
app/main.py
from readchar import readkey
from app.counter import Counter
def main():
counter = Counter()
print("任意のキーでカウント, Rキーでリセット, Qキーで終了")
while True:
print(f"\r{counter.format_count()}", end="", flush=True)
k = readkey()
if k == "r":
counter.reset()
elif k == "q":
break
else:
counter.count_up()
print("\n終了")
if __name__ == "__main__":
main()
app/counter.py
class Counter:
MAX_COUNT = 10000 # 最大カウント
DIGITS = len(str(MAX_COUNT - 1)) # 表示桁数
def __init__(self):
self._count = 0
def count_up(self):
self._count = (self._count + 1) % self.MAX_COUNT
def reset(self):
self._count = 0
def format_count(self):
return f"カウント: [{self._count:0{self.DIGITS}d}]"
PyInstaller による変換手順
以下の手順ではプロジェクト管理に uv を使用します。
(1) pyinstaller ライブラリを追加
以下のコマンドでライブラリを追加します。
uv add --dev pyinstaller
確認のため where コマンドを実行します。
where pyinstaller
pyinstaller がプロジェクト内の仮想環境 .venv/ 以下に存在していれば OK
(2) PyInstaller の初回実行
以下のコマンドを実行します。引数にはエントリーポイントの Python パスを指定します(今回は app/main.py)。
pyinstaller app/main.py
実行後、プロジェクトルートに main.spec(PyInstallerの設定ファイル)が作成されます。
main.spec
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['app/main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
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,
)
(3) 設定ファイル main.spec の編集
使用するライブラリによっては起動時にエラーが発生するため、以下のようにライブラリ名を追加します。
# -*- mode: python ; coding: utf-8 -*-
+ from PyInstaller.utils.hooks import copy_metadata
a = Analysis(
['app/main.py'],
pathex=[],
binaries=[],
- datas=[],
+ datas=copy_metadata("readchar"),
hiddenimports=[],
...
(4) PyInstaller を実行
引数に設定ファイルを指定します。
pyinstaller main.spec
PyInstaller の実行が完了すると dist/ に実行ファイルが作成されます。
ビルドエラーの原因および対処方法
その1
PyInstaller 実行ファイル起動時に以下のエラーが発生
Traceback (most recent call last):
File "importlib/metadata/__init__.py", line 397, in from_name
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "main.py", line 1, in <module>
File "pyimod02_importers.py", line 457, in exec_module
File "readchar/__init__.py", line 6, in <module>
File "importlib/metadata/__init__.py", line 889, in version
File "importlib/metadata/__init__.py", line 862, in distribution
File "importlib/metadata/__init__.py", line 399, in from_name
importlib.metadata.PackageNotFoundError: No package metadata was found for readchar
[PYI-26825:ERROR] Failed to execute script 'main' due to unhandled exception!
原因:
インポートするライブラリによっては PyInstaller に対応していないため、上記のようなエラーが発生します。
対処方法:
datas= に使用するライブラリを明記します(本稿では修正済み)。
main.spec
from PyInstaller.utils.hooks import collect_metadata
a = Analysis(
['app/main.py'],
pathex=[],
binaries=[],
datas=collect_metadata("readchar"),
...
その2
PyInstaller 実行ファイル起動時に ImportError が発生
Traceback (most recent call last):
File "main.py", line 2, in <module>
ImportError: attempted relative import with no known parent package
[PYI-46653:ERROR] Failed to execute script 'main' due to unhandled exception!
原因・対処方法:
相対インポートの使用が原因のため、絶対インポートに変更します(本稿では修正済み)。
-from .counter import Counter
+from app.counter import Counter
その3
PyInstaller 実行ファイル起動時に ModuleNotFoundError が発生
Traceback (most recent call last):
File "main.py", line 2, in <module>
ModuleNotFoundError: No module named 'app'
[PYI-47123:ERROR] Failed to execute script 'main' due to unhandled exception!
原因・対処方法:
app/__init__.py が存在しない場合、app ディレクトリがモジュールと認識されずにエラーとなります。
ディレクトリ内に __init__.py(空ファイルでOK)を置くことで解決できます。
参考資料