1

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

私が間違っていることはありますか?私の設計に欠陥はありますか?また、私がやりたいことを実装するためのより良い方法はありますか? 毎回サービス インターフェイスを構築する必要はないと思いますが、構築しなければスレッドセーフでしょうか? このメソッドはスレッドセーフですか?

どんな助けでも大歓迎です!

4

0 に答える 0