PythonでGoogle Cloud Storageを使うにはどのライブラリを使えばいいのか

- [google-cloud-storage]&nbsp;([google-cloud]の一部)
- [google-api-python-client]
- [GoogleAppEngineCloudStorageClient]

…公式ライブラリだけでもいっぱいありすぎて訳がわかりません。なので、どういう要件ならどれが使えるのかを表にまとめました。

とはいえ全ての組み合わせをテストしたわけではないので、間違いがあれば教えてください。

# 比較表

| ライブラリ | Python 2 | Python 3 | App Engine以外 | App Engine | AppEngine Dev Server | 基本機能 <sup>[※3]</sup> | 高度な機能 <sup>[※3]</sup> | 推奨状況 |
| --------------------------------------- | --- | --- | --- | --- | --- | --- | --- | --- |
| [google-cloud-storage] | × | ○ | ○ | ○ | △ <sup>[※2]</sup> | ○ | ○ | ○ |
| [GoogleAppEngineCloudStorageClient] | ○ | × <sup>[※5]</sup> | × | ○ | ○ | ○ | × | ○ |
| [google-api-python-client] + [google-auth] <sup>[※1]</sup> | × | ○ | ○ | ○ | △ <sup>[※2]</sup> | ○ | ○ | △ <sup>[※4]</sup> |
| [google-api-python-client] + [oauth2client] <sup>[※1]</sup> | ○ | ○ | ○ | ○ | △ <sup>[※2]</sup> | ○ | ○ | × <sup>[※4]</sup> |

各ライブラリの呼び方はいろいろありますが、ここではPyPIのパッケージ名で表記します。

[oauth2client]: https://oauth2client.readthedocs.io/
[google-auth]: https://google-auth.readthedocs.io/
[google-api-python-client]: https://developers.google.com/api-client-library/python/apis/storage/v1
[google-cloud-storage]: https://github.com/googleapis/google-cloud-python/tree/master/storage
[GoogleAppEngineCloudStorageClient]: https://cloud.google.com/appengine/docs/standard/python/googlecloudstorageclient/read-write-to-cloud-storage
[google-cloud]: https://googleapis.github.io/google-cloud-python/

[※1]: #1-google-api-python-client
[※2]: #2-app-engine-dev-server
[※3]: #3-%E5%9F%BA%E6%9C%AC%E6%A9%9F%E8%83%BD--%E9%AB%98%E5%BA%A6%E3%81%AA%E6%A9%9F%E8%83%BD
[※4]: #4-%E6%8E%A8%E5%A5%A8%E7%8A%B6%E6%B3%81
[※5]: #5-googleappenginecloudstorageclient-on-python-3

## ※1: google-api-python-client

google-api-python-clientには認証用ライブラリとしてgoogle-authまたはoauth2clientを組み合わせる必要があります。

## ※2: App Engine Dev Server

App Engine Dev Serverは基本的にはただのローカルPython環境なので、バケット名とそれにアクセス可能なcredentialsをきちんと与えてやれば、どのライブラリも問題なく動作します。

ではGoogleAppEngineCloudStorageClient以外は何が△かというと、[App Engineのデフォルトバケット](https://cloud.google.com/appengine/docs/standard/python/googlecloudstorageclient/setting-up-cloud-storage?hl=ja#activating_a_cloud_storage_bucket)を使っている場合です。App Engineでは`app_identity.get_default_gcs_bucket_name()`を使ってApp Engineプロジェクトのデフォルトバケット名を取得できるのですが、これが通常Dev Server環境では使えません。

GoogleAppEngineCloudStorageClientだけは、`app_identity.get_default_gcs_bucket_name()`を使ったコードがDev Serverでもそのまま動作します。これは、Cloud Stoargeをローカルストレージを使ってエミュレーションしてくれるからです。

## ※3: 基本機能 / 高度な機能

基本機能とは、オブジェクトの作成(アップロード)、更新、ダウンロード、削除、コピー、メタデータの取得、オブジェクト一覧の取得のことです。

高度な機能とは、バケット自体に対する操作(作成、削除、メタデータの取得/設定、一覧の取得)、オブジェクトのcompose(結合)、変更通知など、上の基本機能以外の機能です。

GoogleAppEngineCloudStorageClientは基本機能だけをサポートしています。

## ※4: 推奨状況

[oauth2client]には

> oauth2client is now deprecated. ... We recommend you use google-auth and oauthlib.

とあります。しかしgoogle-authは(明記されてないものの、試した限りでは)Python 2では動作しません。Python 2では諦めてoauth2clientを使いましょう。

[google-api-python-client]には

> While this library is still supported, we suggest trying the newer Cloud Client Library for Cloud Storage JSON, especially for new projects. 

とあります。the newer Cloud Client Library for Cloud Storage JSONというのはgoogle-cloud-storageのことです。しかしgoogle-cloud-storageもPython 2では動作しません。Python 2では諦めてgoogle-api-python-clientを使いましょう。

## ※5: GoogleAppEngineCloudStorageClient on Python 3

[対応する気](https://github.com/GoogleCloudPlatform/appengine-gcs-client/issues/78)はあるようです。

# サンプルコード

サンプルコードは、他の記事や公式ドキュメントに譲ります。公式ドキュメントは、上の表のライブラリ名からリンクしてあります。

cloud-storage: [【GoogleCloudPlatform】pythonでGCSバケットのデータを読み出す/書き出す](https://qiita.com/Gri_Gra/items/8a0a35225058aca71dc8)
GoogleAppEngineCloudStorageClient: [Google App Engine + Python アプリから Cloud Storage を利用する](https://qiita.com/syousei/items/85f80291e7b4a95156ea)

google-api-python-clientを使うサンプルコードは、公式ドキュメントを含めていいものが見当たらなかったので、簡単なサンプルコードを載せておきます。Python 2で、oauth2clientと組み合わせた例です。

```python
from StringIO import StringIO

from apiclient.http import MediaIoBaseUpload
from googleapiclient.discovery import build
from oauth2client.client import GoogleCredentials


# Application default credentialsを使う。
credentials = GoogleCredentials.get_application_default()
service = build('storage', 'v1', credentials=credentials)
# 自分で作ったバケット名に書き換えてください。
bucket_name = 'my-bucket-name'

# オブジェクトのアップロード。
media = MediaIoBaseUpload(StringIO('Hello world'), mimetype='text/plain')
service.objects().insert(
    bucket=bucket_name,
    name='hello.txt',
    media_body=media).execute()

# オブジェクトのダウンロード。
print service.objects().get_media(
    bucket=bucket_name, object='hello.txt').execute()
```

# 自分の場合

環境がApp Engine Python 2で、上記「高度な機能」が必要なケースだったので、google-api-python-client + oauth2clientが要件を満たす唯一の選択肢でした。実際には、表の上から順番に試していって、一番下にたどり着いたのでした…。