
Python 環境ズレ デバッグチェックリストと再発防止コマンド集
noteの自動投稿スクリプトが「完走しているのに公開されない」という状態に陥ったことがある。エラーはない。ログも綺麗。でも結果がおかしい。
原因を探るのに40分かかった。答えは (略) 一発で出た。
この記事でわかること:
– Pythonがどの環境で動いているか一発で確認する方法
– 環境ズレが起きる原因パターン4種
– launchd/cronで実行するスクリプト固有の落とし穴
– 再発防止のためのデバッグチェックリスト(コピペ可)
どのPythonが動いているか?環境別の特徴比較
| 環境 | パス例 | よくある罠 |
|---|---|---|
| システムPython | /usr/bin/python3 | macOS標準、パッケージ追加不可 |
| Homebrew Python | /opt/homebrew/bin/python3 | brew upgrade後にバージョンが上がる |
| pyenv | ~/.pyenv/shims/python3 | PYENV_VERSION設定ミスで別バージョンが動く |
| venv | /path/to/venv/bin/python3 | activate忘れ・別シェルで実行すると無効 |
| Conda | /opt/miniconda3/envs/xxx/bin/python | base環境で動いて気づかない |
問題は「動く」という点にある。エラーが出ないから気づけない。古い環境・古いライブラリで処理が進み、意図しない挙動を返す。
40分溶かした実体験——何が起きていたか
スクリプトはnoteの自動投稿処理。Playwright + Chromiumで動いている。
完走する。ログも正常終了。でも noteのダッシュボードを確認すると「下書き」のまま。公開されていない。
ログを掘り始めた。(略) のURL検出ロジックを疑った。(略) への直接遷移を実装したはずが、古い処理フローが動いていた形跡がある。(略) で座標クリックに切り替えたコードも反映されていない。
「あれ、コードを修正したはずでは?」——ここで気づいた。
(コード例は元記事を参照)
想定は (略) だった。修正を入れたコードは新しいvenvに配置済み。でも launchd の plist は古いPythonパスを参照したままだった。それだけの話。
「それだけ」に40分かかった。
環境ズレが起きる4つの原因パターン
パターン1: launchd/cron がシェル設定を読まない
(略) や (略) に書いた (略) も (略) も、launchdから実行されるスクリプトには効かない。絶対パスで Python バイナリを指定しないといけない。
(コード例は元記事を参照)
私はこれを知っていたのに、plistの更新を忘れた。
パターン2: venv を activate したのに別シェルで実行した
ターミナルのタブAで (略)、タブBで (略)。タブBにはactivateが伝播していない。特にマルチタブ作業時にやりがちで、エラーが出ないから気づかない。
パターン3: Homebrew アップデート後にパスが変わる
(略) を実行すると Python のバージョンが上がる。pyenvのシムが古いバージョンを参照し続けるケースがある。
(コード例は元記事を参照)
アップデート後は (略) を確認する習慣が必要だった。
パターン4: どの pip でインストールしたか不明
「pip install したはずなのに ModuleNotFoundError」は大体これ。(略) と (略) が一致していないと、違う環境にインストールしていることになる。
(コード例は元記事を参照)
コピペで使えるデバッグチェックリスト
「なんかおかしい」と思ったらこれを上から流す。
(コード例は元記事を参照)
スクリプトの冒頭に仕込んでおくと、ログで即確認できる:
(コード例は元記事を参照)
launchd経由のスクリプトには必ずこれを入れるようにした。ログファイルを見ればどの環境で動いたか一発でわかる。
launchd 固有の落とし穴——plist 更新忘れ
今回の事故の根本はここだった。venvを作り直したとき、plistを更新しなかった。
plistを変更したらリロードが必要:
(コード例は元記事を参照)
「unload → load」を忘れると、古いplistが有効なまま動き続ける。変更が反映されていないのに反映されたと思ってしまう。
よくある質問
venv を activate したのに効いていないのはなぜ?
(略) はそのシェルセッション内にのみ有効。launchd・cron・別プロセスからの呼び出しには伝播しない。解決策は venv内の Python バイナリを絶対パスで指定すること。(略) で直接実行するか、shebang行に書く。
(略) したのに (略) でエラーが出る
(略) と (略) の結果ディレクトリが揃っているか確認。食い違っていれば別環境にインストールしている。(略) で実行すると、今の (略) に紐づく pip が使われるので確実。
pyenv と venv はどちらを使えばいいか?
用途が違う。pyenvは「Pythonのバージョン」を切り替えるもの、venvは「同じバージョン内でパッケージを分離」するもの。私はpyenvでバージョンを固定したうえで、プロジェクト毎にvenvを切る構成にしている。launchdから実行するスクリプトはvenv内のバイナリを直接指定。
スクリプトを修正したのに古い挙動のまま
「どの環境のコードを実行しているか」と「どの環境に修正を加えたか」がズレている可能性がある。(略) でPythonのパスを確認し、そのパスの (略) に最新コードが入っているか確認する。launchd plist が古いパスを参照していないかも確認。
Homebrew の Python と pyenv が混在して混乱している
(略) で警告を確認。PATH の順番が問題のことが多い。(略) で (略) を先頭に置くと pyenv が優先される。ただし launchd は (略) を読まないので、plist には絶対パスを書く。
まとめ
- 「動いているのに結果がおかしい」ときは (略) と (略) を最初に疑う
- launchd/cronは (略) を読まない。絶対パス指定が必須で、plist変更後は必ずリロード
- venvのパスを変えたら plist も同時に更新する。片方だけ変えると今回の事故が再現する
- スクリプト冒頭に (略) ログを入れると、ログファイルで環境を即確認できる
- (略) を使うと、今の python3 に確実にインストールできる
- pip と python3 の (略) 結果ディレクトリを揃えるのが基本
40分は取り戻せないけど、チェックリストは残った。✨
この記事を読んだあなたに:
– launchd で Python スクリプトを自動実行する設定方法 /launchd-python-autorun
– pyenv + venv の環境構築を30分で終わらせる手順 /pyenv-venv-setup
– Python 自動化スクリプトのエラーログを Discord に飛ばす実装 /python-discord-error-log
(コード例は元記事を参照)