Python 对象实例未保存在 Flask 应用程序上下文中
Python object instance is not being saved in Flask application context
我制作了简单的 Flask 扩展包 Google API Client for Python:
class ProximityBeaconAPI:
'''
Simple Flask extension for accessing Google Proxmity Beacon API.
https://developers.google.com/resources/api-libraries/documentation/proximitybeacon/v1beta1/python/latest/
'''
def __init__(self, app=None, credentials=None):
if app:
self.init_app(app)
if credentials:
self.init_api(credentials)
def init_app(self, app):
'''
Initialize Flask app for extension
'''
self.app = app
self._project_id = app.config.PROJECT_ID
@property
def is_initialized(self):
'''
Checks if Proximity Beacon API is initialized.
:return: bool
'''
ctx = _app_ctx_stack.top
return hasattr(ctx, 'proximitybeaconapi')
def init_api(self, credentials):
''' Initialize Proximity Beacon API
:param credentials: google.oauth2.credentials.Credentials object
'''
proximitybeaconapi = discovery.build(
OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
ctx = _app_ctx_stack.top
if ctx is not None:
if not hasattr(ctx, 'proximitybeaconapi'):
ctx.proximitybeaconapi = proximitybeaconapi
def get_utoken(self):
''' Checks if for beacon with given name u_token attachment
is set.
:param beacon_name: name of the beacon
:param namespace: namespace
'''
beacon_name = self.get_default_auth_beacon_name()
ctx = _app_ctx_stack.top
namespace = self.get_default_project_namespace().split('/')[1]
namespaced_type = '{}/u_token'.format(namespace)
query = {
'beaconName': beacon_name,
'namespacedType': namespaced_type
}
resp = ctx.proximitybeaconapi.beacons().attachments().list(**query).execute()
b64_data = resp['attachments'][0]['data']
return self._base64_to_str(b64_data)
def is_utoken_valid(self, u_token):
''' Checks if recieved token is valid with current
u_token attachment.
:param u_token: incomming u_token
:return: True or False
'''
incomming_token = self._base64_to_str(u_token)
current_token = self.get_utoken()
return incomming_token == current_token
在我的 oauth2 回调视图中,我通过调用 init_api
方法初始化 Google API,该方法基于凭证创建一个 API 客户端实例:
def init_api(self, credentials):
''' Initialize Proximity Beacon API
:param credentials: google.oauth2.credentials.Credentials object
'''
proximitybeaconapi = discovery.build(
OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
ctx = _app_ctx_stack.top
if ctx is not None:
if not hasattr(ctx, 'proximitybeaconapi'):
ctx.proximitybeaconapi = proximitybeaconapi
然后在我的另一个端点中调用使用初始化的早期客户端库的方法 get_token
。
我的端点
def post(self):
data = api.payload
u_token = data.pop('u_token')
token = beaconapi.get_utoken()
# other code ...
get_utoken
使用客户端的方法:
def get_utoken(self):
''' Checks if for beacon with given name u_token attachment
is set.
:param beacon_name: name of the beacon
:param namespace: namespace
'''
beacon_name = self.get_default_auth_beacon_name()
ctx = _app_ctx_stack.top # getting client from application context
# ...
response = ctx.proximitybeaconapi.beacons().attachments().list(**query)
return response
但是我得到 AttributeError: 'AppContext' object has no attribute 'proximitybeaconapi'
错误尽管我之前在应用程序上下文中设置了这个属性:
File "/home/devaerial/Source/automoticz-server/automoticz/utils/beacons.py", line 61, in get_default_auth_beacon_name
response = ctx.proximitybeaconapi.beacons().list(q=query).execute()
AttributeError: 'AppContext' object has no attribute 'proximitybeaconapi'
当我在调用最后一个端点
时使用init_api
设置它时,看起来ctx
上下文没有保存我的proximitybeaconapi
客户端实例
我做错了什么?
P.S:我正在关注官方 Flask 文档中的 this 示例。
找到问题的解决方案而不使用 _app_ctx_stack
。使用 this 方法使用 app.extensions
对象,其中 Flask 应用程序存储所有对扩展的引用并稍微重建我的代码:
def init_api(self, credentials):
''' Initialize Proximity Beacon API
:param credentials: google.oauth2.credentials.Credentials object
'''
proximitybeaconapi = discovery.build(
OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
self.app.extensions['api'] = proximitybeaconapi
现在,如果我想调用 Goolge API 客户端,我只需从 extensions
获取其引用
def get_pin(self):
''' Checks if for beacon with given name pin attachment
is set.
:param beacon_name: name of the beacon
:param namespace: namespace
'''
beacon_name = self.get_default_auth_beacon_name()
api = self.app.extensions.get('api')
namespace = self.get_default_project_namespace().split('/')[1]
namespaced_type = '{}/pin'.format(namespace)
query = {'beaconName': beacon_name, 'namespacedType': namespaced_type}
resp = api.beacons().attachments().list(**query).execute()
b64_data = resp['attachments'][0]['data']
return self._base64_to_str(b64_data)
我制作了简单的 Flask 扩展包 Google API Client for Python:
class ProximityBeaconAPI:
'''
Simple Flask extension for accessing Google Proxmity Beacon API.
https://developers.google.com/resources/api-libraries/documentation/proximitybeacon/v1beta1/python/latest/
'''
def __init__(self, app=None, credentials=None):
if app:
self.init_app(app)
if credentials:
self.init_api(credentials)
def init_app(self, app):
'''
Initialize Flask app for extension
'''
self.app = app
self._project_id = app.config.PROJECT_ID
@property
def is_initialized(self):
'''
Checks if Proximity Beacon API is initialized.
:return: bool
'''
ctx = _app_ctx_stack.top
return hasattr(ctx, 'proximitybeaconapi')
def init_api(self, credentials):
''' Initialize Proximity Beacon API
:param credentials: google.oauth2.credentials.Credentials object
'''
proximitybeaconapi = discovery.build(
OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
ctx = _app_ctx_stack.top
if ctx is not None:
if not hasattr(ctx, 'proximitybeaconapi'):
ctx.proximitybeaconapi = proximitybeaconapi
def get_utoken(self):
''' Checks if for beacon with given name u_token attachment
is set.
:param beacon_name: name of the beacon
:param namespace: namespace
'''
beacon_name = self.get_default_auth_beacon_name()
ctx = _app_ctx_stack.top
namespace = self.get_default_project_namespace().split('/')[1]
namespaced_type = '{}/u_token'.format(namespace)
query = {
'beaconName': beacon_name,
'namespacedType': namespaced_type
}
resp = ctx.proximitybeaconapi.beacons().attachments().list(**query).execute()
b64_data = resp['attachments'][0]['data']
return self._base64_to_str(b64_data)
def is_utoken_valid(self, u_token):
''' Checks if recieved token is valid with current
u_token attachment.
:param u_token: incomming u_token
:return: True or False
'''
incomming_token = self._base64_to_str(u_token)
current_token = self.get_utoken()
return incomming_token == current_token
在我的 oauth2 回调视图中,我通过调用 init_api
方法初始化 Google API,该方法基于凭证创建一个 API 客户端实例:
def init_api(self, credentials):
''' Initialize Proximity Beacon API
:param credentials: google.oauth2.credentials.Credentials object
'''
proximitybeaconapi = discovery.build(
OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
ctx = _app_ctx_stack.top
if ctx is not None:
if not hasattr(ctx, 'proximitybeaconapi'):
ctx.proximitybeaconapi = proximitybeaconapi
然后在我的另一个端点中调用使用初始化的早期客户端库的方法 get_token
。
我的端点
def post(self):
data = api.payload
u_token = data.pop('u_token')
token = beaconapi.get_utoken()
# other code ...
get_utoken
使用客户端的方法:
def get_utoken(self):
''' Checks if for beacon with given name u_token attachment
is set.
:param beacon_name: name of the beacon
:param namespace: namespace
'''
beacon_name = self.get_default_auth_beacon_name()
ctx = _app_ctx_stack.top # getting client from application context
# ...
response = ctx.proximitybeaconapi.beacons().attachments().list(**query)
return response
但是我得到 AttributeError: 'AppContext' object has no attribute 'proximitybeaconapi'
错误尽管我之前在应用程序上下文中设置了这个属性:
File "/home/devaerial/Source/automoticz-server/automoticz/utils/beacons.py", line 61, in get_default_auth_beacon_name
response = ctx.proximitybeaconapi.beacons().list(q=query).execute()
AttributeError: 'AppContext' object has no attribute 'proximitybeaconapi'
当我在调用最后一个端点
时使用init_api
设置它时,看起来ctx
上下文没有保存我的proximitybeaconapi
客户端实例
我做错了什么?
P.S:我正在关注官方 Flask 文档中的 this 示例。
找到问题的解决方案而不使用 _app_ctx_stack
。使用 this 方法使用 app.extensions
对象,其中 Flask 应用程序存储所有对扩展的引用并稍微重建我的代码:
def init_api(self, credentials):
''' Initialize Proximity Beacon API
:param credentials: google.oauth2.credentials.Credentials object
'''
proximitybeaconapi = discovery.build(
OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
self.app.extensions['api'] = proximitybeaconapi
现在,如果我想调用 Goolge API 客户端,我只需从 extensions
def get_pin(self):
''' Checks if for beacon with given name pin attachment
is set.
:param beacon_name: name of the beacon
:param namespace: namespace
'''
beacon_name = self.get_default_auth_beacon_name()
api = self.app.extensions.get('api')
namespace = self.get_default_project_namespace().split('/')[1]
namespaced_type = '{}/pin'.format(namespace)
query = {'beaconName': beacon_name, 'namespacedType': namespaced_type}
resp = api.beacons().attachments().list(**query).execute()
b64_data = resp['attachments'][0]['data']
return self._base64_to_str(b64_data)