LoginSignup
24
11

More than 5 years have passed since last update.

Google Cloud Functionsでgoogle-api-python-clientを利用してfile_cache is unavailableエラーになったときの対応方法

Last updated at Posted at 2018-11-06

概要

Google Cloud FunctionsでPython(Beta)を利用して、他のGCPサービスを利用する場合、google-api-python-clientを利用するのが便利です。

googleapis / google-api-python-client
https://github.com/googleapis/google-api-python-client

ただし現状、ImportError が発生するケースがあるので、その対応方法です。(2018/10/31時点)

発生するエラー

ImportError: file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth

回避策: cache_discovery を無効化する

requirements.txt
google-api-python-client
oauth2client
main.py
from googleapiclient import discovery

from httplib2 import Http

from oauth2client.client import GoogleCredentials


def check_discovery_error(request):
  # Cloud Functions環境から認証情報を取得する
  credentials = GoogleCredentials.get_application_default()

  cloudBuild = discovery.build(
    'cloudbuild', 'v1',   # Cloud Buildじゃなく、他のサービスでもおk
    http=credentials.authorize(Http()),
    cache_discovery=False)# cache_discovery=Falseしてエラーを回避する

  request = cloudBuild.projects().builds().list(projectId='[GCPのプロジェクトID]')
  response = request.execute()
  print(response)

再現してみる

前提

  • GCPプロジェクトが利用可能
  • gcloud beta が端末にインストール済みで利用可

実装の用意

> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> touch requirements.txt
> touch main.py
requirements.txt
google-api-python-client

今回はCloud Buildからジョブリストを取得する実装にしていますが、他のサービスでもおkです。

main.py(回避前)
from googleapiclient import discovery


def check_discovery_error(request):
  cloudBuild = discovery.build('cloudbuild', 'v1')
  request = cloudBuild.projects().builds().list(projectId='GCPのプロジェクトID')
  response = request.execute()
  print(response)

これをCloud Functionsにデプロイして実行します。

> gcloud beta functions deploy check_discovery_error \
    --trigger-http \
    --runtime=python37

> gcloud beta functions call check_discovery_error

実行すると、以下のようにエラーが出力されます。

ログ(一部抜粋)
> gcloud functions logs read check_discovery_error

E          from oauth2client.contrib.locked_file import LockedFile
E      ModuleNotFoundError: No module named 'oauth2client'
E      
E      During handling of the above exception, another exception occurred:
E      
E      Traceback (most recent call last):
E        File "/env/local/lib/python3.7/site-packages/googleapiclient/discovery_cache/file_cache.py", line 37, in <module>
E          from oauth2client.locked_fileimport LockedFile
E      ModuleNotFoundError: No module named 'oauth2client'
E      
E      During handling of the above exception, another exception occurred:
E      
E      Traceback (most recent call last):
E        File "/env/local/lib/python3.7/site-packages/googleapiclient/discovery_cache/__init__.py", line 41, in autodetect
E          from . import file_cache
E        File "/env/local/lib/python3.7/site-packages/googleapiclient/discovery_cache/file_cache.py", line 41, in <module>
E          'file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth')
E      ImportError: file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth
I      URL being requested: GET https://www.googleapis.com/discovery/v1/apis/cloudbuild/v1/rest
I      URL being requested: GET https://cloudbuild.googleapis.com/v1/projects/[GCPのプロジェクトID]/builds?alt=json
I      {'builds': [{'id': ()
D      Function execution took 138 ms, finished with status code: 200

原因

調べて見るとあちこちでissueが上がっていますが、いまのところ、根本的な解決はされてないようです。

file_cache is unavailable when using oauth2client >= 4.0.0
https://github.com/googleapis/google-api-python-client/issues/299

File caching for the oauth2client >= 4.0.0
https://github.com/googleapis/google-api-python-client/issues/325

回避策

issueのコメントに回避策がコメントされていました。ありがたや^^

cache_discovery を無効化する

ライブラリのインポート時にキャッシュを利用すると、oauth2clientのバージョンチェックに引っかかる?みたいなので、無効化して回避すればよいみたいです。

It seems to be the better way to silence this error, if one does not care about the cache, is to simply specify cache_discovery=False when performing discovery.build() -- this avoids the broken code path.

以下のコメントの実装方法を参考にしました。
https://github.com/googleapis/google-api-python-client/issues/299#issuecomment-427118293

discovery.buildcache_discovery パラメータ指定する場合、http パラメータも指定する必要があったので、oauth2client を用いてCredentials を取得するようにしました。

requirements.txt
google-api-python-client
oauth2client
main.py(対応版)
from googleapiclient import discovery

from httplib2 import Http

from oauth2client.client import GoogleCredentials


def check_discovery_error(request):
  # Cloud Functions環境から認証情報を取得する
  credentials = GoogleCredentials.get_application_default()

  cloudBuild = discovery.build(
    'cloudbuild', 'v1',   # Cloud Buildじゃなく、他のサービスでもおk
    http=credentials.authorize(Http()),
    cache_discovery=False)# cache_discovery=Falseしてエラーを回避する

  request = cloudBuild.projects().builds().list(projectId='[GCPのプロジェクトID]')
  response = request.execute()
  print(response)

再びデプロイと実行して、エラー出力がなくなっていることが確認できました。
やったぜ。

一部抜粋
D      Function execution started
I      URL being requested: GET https://www.googleapis.com/discovery/v1/apis/cloudbuild/v1/rest
I      URL being requested: GET https://cloudbuild.googleapis.com/v1/projects/[GCPのプロジェクトID]/builds?alt=json
I      {'builds': [{'id': ()
D      Function execution took 2352 ms, finished with status code: 200

参考

file_cache is unavailable when using oauth2client >= 4.0.0
https://github.com/googleapis/google-api-python-client/issues/299

File caching for the oauth2client >= 4.0.0
https://github.com/googleapis/google-api-python-client/issues/325

Google Driveにpythonでデータを登録する & Siderを使ってチェックしてみる
https://qiita.com/akiko-pusu/items/f05a5dcba544e97c057c

[GoogleCloudPlatform] API Client Libraryを用いてGoogle Cloud APIを利用する
https://qiita.com/j-un/items/dc46b3b766a7afb4080c

24
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
11