
コマンドラインからGoogle Cloud Storage (GCS) を操作することができる gsutil パッケージ。
GCSからファイルをコピーする際に gsutil cp コマンドを使うのだが、複数ファイルの場合直列に処理すると遅い。
そこで並列に処理するために gsutil -m cp を実行したら以下のエラーが発生した。
gsutil TypeError: cannot pickle '_io.TextIOWrapper' object
一体何が間違っているのだろうか。
今回はこの gsutil TypeError: cannot pickle '_io.TextIOWrapper' object のエラー原因と対処法について解説する。
この記事を書いている人

記事を読むメリット
エラー内容

現象としては gsutil cp で順番に1つずつコピーはできるが、並列に処理する gsutil -m cp ではエラーになる。
エラー内容を知るために今一度エラーメッセージを見てみる。
gsutil TypeError: cannot pickle '_io.TextIOWrapper' object
まず TypeError なので変数の型が合っていない。
そして cannot pickle 以下のメッセージは _io.TextIOWrapper 形式のオブジェクトをpicle、つまり変数のままファイル出力できないと言っている。


エラー原因

gsutil TypeError: cannot pickle '_io.TextIOWrapper' object の根本原因、それはPythonのバージョン。
実はこのエラーPython3.8からMacOS上での動作が一部変わった事に起因している。
Tracking this down, this error comes from a change in Python 3.8 in the multiprocessing library:
Changed in version 3.8: On macOS, the spawn start method is now the default. The fork start method should be considered unsafe as it can lead to crashes of the subprocess. See bpo-33725.
Spawn is being run for those using MacOs and Python 3.8+ by default since nothing is explicitly set either through get_context or set_start_method.


エラーの解決方法

gsutil TypeError: cannot pickle '_io.TextIOWrapper' object の原因はPythonのバージョン。
であれば解決方法はPythonのバージョンを変更する。
具体的にはPython3.8ではなくPython3.7系を使えばこのエラーは出ない。
そしてPython3.7のインストール方法だが、Linux環境にPythonをインストールする方法と変わらない。
pyenvをインストールして、pyenvを使ってPython3.7をインストールし、最後にPython3.7をデフォルトにするだけだ。
注意点があるとすればMacOSの現在のデフォルトシェルはbashではなくzshである点。
pyenvインストール後の環境変数の設定をzsh用にするか、もしくはデフォルトの起動シェルをbashに変更するかする必要がある。

自分でやるときも「Linuxと同じだなぁ」と思いながら作業してたけど、pyenvインストール後に
zsh:command not found が出て、「あれ?pyenv動かないぞ?」ってなりましたもん。

【エラー】gsutil TypeError: cannot pickle '_io.TextIOWrapper' object まとめ

gsutil TypeError: cannot pickle '_io.TextIOWrapper' object の原因は Python3.8からMacOSでの挙動が少し変わったから。
解決方法はPython3.8の代わりに3.7を使う。


ちなみにMacのターミナルの起動シェルをzshからbashに変える方法については以下にまとめたので、もし興味があれば見てみてほしい。
あわせて読みたい




