本記事はQiita Advent Calender 2025 わたなべの20日目です!
20日目は、私渡邊が作成します!
本記事は13日目で書いたpolarsにも関連した内容です。
polarsで集計作業などを自動化した後、都度ターミナルやjupyterから実行するのが手間だという方に向けたPyinstallerの紹介と簡単なTipsです!
ダブルクリックでPythonのコードを実行でき時短になりますので、お読みいただけると嬉しいです!
Pyinstaller使いましょう
いきなり結論。Pyinstaller使えばよいです。
python main.py
で実行できるPythonのスクリプトがあったとして。
pip install pyinstaller
pyinstaller main.py --onefile
これで、/distにwindowsは.exeファイル、それ以外は実行ファイルが出力されますので、デスクトップに置くなどしてダブルクリックしてください。
以上。
注意点・Tips
さすがにこれでは記事になりませし、webでパパッと調べれば出てくる内容なので、パパッと調べられないtipsを紹介したいとおもいます
1. hidden importに気を付ける
1.1. 概要
hidden importを無視したせいで動かないことがままあります。
例えば、polarsでexcelファイルを読み込む処理が入る場合など、まず確実に発生します。
というのも、polars自体はexcelを読み書きする機能は持っておらず、読み取りはfastexcel、書き込みはxlsxwriterという別のライブラリを利用しており、excel関連の処理(read_excel(), write_excel())を呼び出すと、これらのライブラリをinstallするように指示されます。
ですが、これらのライブラリはコード上でimport することはないため、pyinstallerでアプリ化する際に、ライブラリをバイナリに含めてもらえず、実行するとfastexcel not foundという感じのエラーが出てしまうのです。
1.2. 具体例
import glob
from modules.utils import get_company_list, get_schema, run, store_name_adjuster
import polars as pl
import datetime
from typing import TypedDict, List
class StoreNameChange(TypedDict):
base_name: str
adjusted_name: str
if __name__ == "__main__":
_year = datetime.datetime.now().year
_month = datetime.datetime.now().month
target_year = _year if _month != 1 else _year - 1
target_month = _month - 1 if _month != 1 else 12
title = f'{target_year}年{target_month}月'
schema = get_schema()
files = glob.iglob('./data/*.xlsx')
lf = None
for file in files:
tmp = pl.read_excel(file, schema_overrides=schema).lazy()
if lf is not None:
lf = pl.concat([lf, tmp], how='vertical')
else:
lf = tmp
company_list = get_company_list(lf)
lf_flagged = (
lf
.with_columns(
pl.col('店舗名').str.replace('(注文受付終了いたしました)', '').alias('店舗名'),
pl.when(pl.col('配送種別') == '置き楽')
.then(1)
.otherwise(0)
.alias('置き楽フラグ')
)
)
changed_store_names: List[StoreNameChange] = [
{"base_name": "イオンスタイル与野", "adjusted_name": "イオン与野店"}
]
for name in changed_store_names:
lf_flagged = store_name_adjuster(lf_flagged, name['base_name'], name['adjusted_name'])
run(
lf_flagged,
title,
company_list,
'./result.xlsx',
'./company_result.xlsx'
)
例えばこのようなコード。コード中でread_excelを利用していますが、import にfastexcelが含まれていません。
ターミナルからpython main.pyでは実行できても、アプリ化するとfastexcelが含まれないのです。
1.3. 対処法|main.specのhidden importに含める
次の手順で実行します。
- まずは
pyinstaller main.pyを実行 - アプリとは別に
main.specファイルが生成される -
main.specのhiddenimportsに必要なライブラリ(今回でいえばfastexcel)を記述する -
pyinstaller main.spec(main.pyではないので注意)を実行 - 生成されたアプリを実行して動けば成功
という感じで.specファイルにhiddenimportsを指定します。
具体例は次のような感じです。
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=['fastexcel'],
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,
)
こんな感じです。ちなみに、1.でpyinstaller main.pyを実行する際は--onefileのオプションをつけましたが、specの時は、その内容もspecファイルに反映されているので、pyinstaller main.specだけで大丈夫です。
2. 実行環境をそろえる
これは非常に単純。
windowsで利用するアプリ(.exeファイル)をbuildするときはwindowsで実行しましょう、ということです。
例としては、普段はwslのlinux環境で実行している場合、pyinstallerでアプリ化すると.exeが出力されません。実行OSを判別しているからですね。
3. uvを利用する場合
pythonの環境をuvで管理している方も増えてきているかと思います。
その場合は次のような感じです。
1. pyinstallerのインストール
uv add pyinstaller
で大丈夫です。
2. 仮想環境の立ち上げ
1.で、pyinstallerはuvが作成した仮想環境内のpipにインストールされています。なので、仮想を立ち上げてください。
.\.venv\Scripts\activate
. .venv/bin/activate
.がスペースをはさんで2つあるので注意してください
(py-pdf) PS C:\Users\username\.src\py_pdf>
こんな感じで()がついていれば成功です
3. pyinstallserの実行
あとは上記の通り実行してください!
自動化しましょう!
と、いう感じでターミナルやjupyterから実行していたPythonスクリプトもワンクリック、、、ではないですね(笑)。ダブルクリックで実行できるようになります!
Vibe Cordingが広まって、コーディングのハードルはさがったものの、このようなこまごまとしたTipsは調べにくくなっている気がしましたので、AI様が正しく学習してくれるよう、学んだことは発信していきたいと思います!