我正在尝试为我的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
我做错了吗?我的设计是否存在缺陷,是否有更好的方法来实现我想要做的事情?我想我不必每次都构建服务接口,但如果我不这样做就会线程安全吗?这种方法甚至是线程安全的吗?
任何帮助将不胜感激!