Google API类设计中的AccessTokenRefreshError

时间:2012-11-30 18:40:26

标签: python google-app-engine google-api-python-client

我正在尝试为我的Google API调用的基本样板初始化创建一个Base类。通过在线阅读教程,我认为应该重新使用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&amp; 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

我做错了吗?我的设计是否存在缺陷,是否有更好的方法来实现我想要做的事情?我想我不必每次都构建服务接口,但如果我不这样做就会线程安全吗?这种方法甚至是线程安全的吗?

任何帮助将不胜感激!

0 个答案:

没有答案