テクノロジー · 実用ガイド

Python の charmap UnicodeEncodeError?まず出力先を監査する

UTF-8 の強制、全体設定の変更、文字の破棄より先に、どの writer・出力先・consumer が codec を選んだかを証明します。

Unicode text が writer を経て consumer bytes になる流れのオリジナル図。
Watch at Ease オリジナルイラスト:文字を表現できない writer の実行時契約を先に証明します。 Watch at Ease

charmap UnicodeEncodeError は出力境界の障害です。Python の Unicode 文字列は正しくても、writer の codec が文字を表現できません。

この監査では実際の出力先を特定し、コンソールとリダイレクトを分離し、形式を所有する境界だけを修正して consumer が受け取る byte を検証します。

失敗した出力先と実行時契約を固定する

正確なコマンド、traceback、文字列、Python 版を保存し、sys.stdout.encoding、errors、isatty() を記録します。file object なら開き方と encoding 引数も残します。例外の codec はその境界で使われた encoder であり、入力が壊れた証拠ではありません。

console、shell redirection、pipe、IDE、scheduled job、明示的 file という実際の出力先で同じ payload を再現します。一つだけ失敗すれば契約差の証拠です。repr() や stderr の escape 診断で code point を保存しますが、調査中に元データを置換しません。

text・character・encoded bytes を分離する

Python の str は Unicode text です。text writer が byte に変換するとき codec が文字を表現できず UnicodeEncodeError になります。print、text file、bytes 送信は別境界です。既に decode 済みの text に decode() を重ねず、型、code point、writer encoding を見ます。

同じ文字と出力先の最小 probe を作ります。file は意図した encoding で開き、byte を読み戻します。stream は同じ consumer に渡して期待形式を検証します。encoder と consumer の双方を証明することが目的です。

Windows console・redirection・wrapper の差を証明する

Python 文書では standard stream の encoding が console 接続、file redirection、wrapper 置換で変わり得ます。Windows の console device と非 console file は同じ経路とは限りません。Microsoft の code page は console I/O の性質で、全 file の万能 encoding ではありません。

console、redirect、失敗する IDE/service で同じ command を実行し、三つの runtime field を比較します。sys.stdout が置換されていれば型と設定を調べます。chcp だけで file encoding を決めず、terminal 成功だけで downstream file が UTF-8 と断定しません。

形式を所有する境界に修正を置く

UTF-8 text file を作るなら encoding='utf-8' で明示的に開き形式を記録します。subprocess が UTF-8 を要求するならその境界を設定し byte を確認します。CLI の global UTF-8 mode や PYTHONIOENCODING は stdout/stderr の全 consumer を確認してからです。

sys.stdout.reconfigure() は application が stream を所有し、非互換な buffered data をまだ出していない場合だけにします。library は host の global policy を勝手に変えません。framework や notebook が writer を提供するなら、その owner を設定します。

lossy suppression を既定の修正にしない

errors='ignore' は文字を削除し、errors='replace' は置換します。name、path、identifier、export record を壊したまま test が通る可能性があります。出力契約が明示的に許す場合だけ使い、変化する文字を記録します。

UTF-8 に encode した直後に無関係な legacy codec で decode してはいけません。明確な境界エラーが mojibake に変わるだけです。system locale や全 Python process の変更より、consumer 契約が既知の最小 writer を修正します。

byte・consumer・rollback を検証する

ASCII、元の失敗文字、local code page 外の文字、混合言語行を含む matrix を作り、console、redirect file、実 downstream で試します。正確な byte または hash を記録し、宣言形式で decode して同じ text を表示・解析するか確認します。

runtime field、sample、boundary、encoding、error policy、consumer result を保存します。rollback は他 stream を変えず元の writer 設定だけ戻します。Python、Windows、IDE、service wrapper の更新後も既定値変更に備えて再実行します。

所有境界に限定した encoding 修正と lossless 検証のオリジナル図。
Watch at Ease オリジナルイラスト:出力先を分類し、形式と byte を検証して無言の損失を拒否します。 Watch at Ease