Google API 呼び出しの基本的なボイラー プレートの初期化のための基本クラスを作成しようとしています。オンラインでチュートリアルを読むと、呼び出しごとに再初期化するのではなく、http トランスポート オブジェクトを再利用する必要があると思います。
基本情報:
プラットフォーム: Google の AppEngine - スレッドが有効になっている Python 2.7
エラー:
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/kay/app.py", line 371, in get_response response = view_func(request, **values)
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/kay/handlers/__init__.py", line 34, in __call__ return func(**kwargs)
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 1047, in add_context_wrapper return synctasklet(func)(*args,
**kwds)
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 1029, in synctasklet_wrapper return taskletfunc(*args,
**kwds).get_result()
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 325, in get_result self.check_success()
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 371, in _help_tasklet_along value = gen.send(val)
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/<app-name-removed>/backoffice/__init__.py", line 64, in post bigquery = BigQueryClient()
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/<app-name-removed>/api/google/base.py", line 68, in __init__ self.service = build(self.serviceName, self.version, http=credentials.authorize(http))
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/oauth2client/util.py", line 120, in positional_wrapper return wrapped(*args, **kwargs)
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/apiclient/discovery.py", line 193, in build resp, content = http.request(requested_url)
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/oauth2client/util.py", line 120, in positional_wrapper return wrapped(*args, **kwargs)
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/oauth2client/client.py", line 405, in new_request self._refresh(request_orig)
File "/base/data/home/apps/s~<app-name-removed>/gapitest.363541807102146863/oauth2client/appengine.py", line 162, in _refresh raise AccessTokenRefreshError(str(e))
AccessTokenRefreshError
基本クラスの実装:
import os, httplib2, abc, logging
from apiclient.discovery import build
from oauth2client.appengine import AppAssertionCredentials
from oauth2client.client import Storage, Credentials
from google.appengine.api import memcache
http = None
class FileStorage(Storage):
def __init__(self, filepath):
self._filepath = filepath
def locked_get(self):
with open(self._filepath, 'r') as f:
json = f.read()
credentials = Credentials.new_from_json(json)
return credentials
class BaseGoogleAPIClient(object):
__metaclass__ = abc.ABCMeta
"""The following is not ideal, would prefer abstract class properties"""
@classmethod
def get_scope(cls):
raise NotImplementedError("Must define the authorization scope required for this class (multiple scopes should be seperated by a space)")
@abc.abstractproperty
def serviceName(self):
"""Define the Service this class will interface with"""
return
@abc.abstractproperty
def version(self):
"""Define the Version of the API we will interface with"""
return
def __init__(self):
global http
if not http:
if not os.environ['SERVER_SOFTWARE'].startswith('Development'):
scopes = []
for sc in BaseGoogleAPIClient.__subclasses__():
for scope in sc.get_scope().split(' '):
if not scope in scopes:
scopes.append(scope)
logging.debug("Scopes {scopes}".format(scopes=scopes))
credentials = AppAssertionCredentials(scope=scopes)
else:
"""USED FOR LOCAL TESTING"""
filepath = #PATH REMOVED
storage = FileStorage(filepath)
credentials = storage.get()
http = credentials.authorize(httplib2.Http(memcache))
self.service = build(self.serviceName, self.version, http=http)
私は何かを誤解しているに違いないか、私のデザインに欠陥があります。接続したい API (BigQuery と Storage) ごとに個別のクラスを専用にすると、まったく問題なく動作しました。クラス間でコンストラクターを共有しようとしています。
この方法は、別の資格情報メカニズムを使用していますが、ローカルでは問題なく機能します。
このクラスの実装例:
class BigQueryClient(BaseGoogleAPIClient):
@classmethod
def get_scope(cls):
return 'https://www.googleapis.com/auth/bigquery'
@property
def serviceName(self):
return 'bigquery'
@property
def version(self):
return 'v2'
#METHODS REMOVED
私が間違っていることはありますか?私の設計に欠陥はありますか?また、私がやりたいことを実装するためのより良い方法はありますか? 毎回サービス インターフェイスを構築する必要はないと思いますが、構築しなければスレッドセーフでしょうか? このメソッドはスレッドセーフですか?
どんな助けでも大歓迎です!