Open
Description
Dear All,
I am trying to use response marshaling but I get an error. I managed to make the fields/marshal work as indicate in the example - Nested fields
Code
import hashlib, hmac, time
try:
from urllib.parse import urlencode
except ImportError:
from urllib import urlencode
import requests
from flask_restx import Namespace, Resource, fields
from dataenhancer.secret.config import ENDPOINT_ROOMS, INDICO_SERVER, API_KEY, SECRET_KEY
namespace = Namespace('indico', description="Contrast information with Indico endpoint")
timing_fields = {}
timing_fields['date'] = fields.String(readOnly=True, description='aa')
timing_fields['tz'] = fields.String(readOnly=True, description='aa')
timing_fields['time'] = fields.String(readOnly=True, description='aa')
booking_fields = {}
booking_fields['url'] = fields.String(readOnly=True, description='aa')
booking_fields['id'] = fields.String(readOnly=True, description='aa')
booking_fields['creator'] = fields.String(readOnly=True, description='aa')
booking_fields['start_dt'] = fields.Nested(timing_fields)
booking_fields['end_dt'] = fields.Nested(timing_fields)
resource_fields = {'vc_room': fields.String(readOnly=True, description='aa')}
resource_fields['event'] = fields.String(readOnly=True, description='aa')
resource_fields['booking'] = fields.Nested(booking_fields)
indico_model = namespace.model('indicoevents', resource_fields)
def _build_indico_request(path, params, api_key=None, secret_key=None, only_public=False, persistent=False):
items = list(params.items()) if hasattr(params, 'items') else list(params)
if api_key:
items.append(('apikey', api_key))
if only_public:
items.append(('onlypublic', 'yes'))
if secret_key:
if not persistent:
items.append(('timestamp', str(int(time.time()))))
items = sorted(items, key=lambda x: x[0].lower())
url = '%s?%s' % (path, urlencode(items))
signature = hmac.new(secret_key.encode('utf-8'), url.encode('utf-8'),
hashlib.sha1).hexdigest()
items.append(('signature', signature))
if not items:
return path
return '%s?%s' % (path, urlencode(items))
@namespace.doc('class')
@namespace.route('/<string:office>')
class IndicoEventsEndpoint(Resource):
#decorators = [require_token]
@namespace.doc('Get_all_possible_events')
@namespace.marshal_with(indico_model)
def get(self, office):
params = {
'from': 'today',
'to': 'today'
}
query = _build_indico_request('{}{}.json'.format(ENDPOINT_ROOMS, office), params, api_key=API_KEY, secret_key=SECRET_key,
persistent=True)
res = requests.get('{}/{}'.format(INDICO_SERVER, query))
res.raise_for_status()
return res.json()
I get always the following exception:
Unable to render schema
Traceback (most recent call last):
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/api.py", line 500, in __schema__
self._schema = Swagger(self).as_dict()
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 202, in as_dict
**kwargs
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 391, in serialize_resource
path[method] = self.serialize_operation(doc, method)
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 397, in serialize_operation
'responses': self.responses_for(doc, method) or None,
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 510, in responses_for
schema = self.serialize_schema(model)
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 563, in serialize_schema
self.register_model(model)
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 592, in register_model
self.register_field(field)
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 600, in register_field
self.register_model(field.nested)
File "/Users/r/.pyenv/versions/3.6.5/lib/python3.6/site-packages/flask_restx/swagger.py", line 583, in register_model
if name not in self.api.models:
TypeError: unhashable type: 'dict'
127.0.0.1 - - [04/Feb/2020 23:07:01] "GET /api/v1/swagger.json HTTP/1.1" 500 -
127.0.0.1 - - [04/Feb/2020 23:07:01] "GET /swaggerui/favicon-32x32.png HTTP/1.1" 200 -
By doing:
$ python
Python 3.6.5 (default, Apr 28 2019, 21:42:51)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.10.44.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from flask_restx import fields, marshal
>>> import json
>>> timing_fields = {}
timing_fields['date'] = fields.String(readOnly=True, description='aa')
timing_fields['tz'] = fields.String(readOnly=True, description='aa')
timing_fields['time'] = fields.String(readOnly=True, description='aa')
booking_fields = {}
booking_fields['url'] = fields.String(readOnly=True, description='aa')
booking_fields['id'] = fields.String(readOnly=True, description='aa')
booking_fields['creator'] = fields.String(readOnly=True, description='aa')
booking_fields['start_dt'] = fields.Nested(timing_fields)
booking_fields['end_dt'] = fields.Nested(timing_fields)
resource_fields = {'vc_room': fields.String(readOnly=True, description='aa')}
resource_fields['event'] = fields.String(readOnly=True, description='aa')
resource_fields['booking'] = fields.Nested(booking_fields)>>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>>
>>>
>>> data = {
"vc_room": "dafdafds",
"event": "afdasfdsfda",
"booking": {
"url": "https://indico-staging.xx.xx/rooms/booking/402627",
"start_dt": {
"date": "2020-02-03",
"tz": "None",
"time": "13:00:00"
},
"end_dt": {
"date": "2020-02-03",
"tz": "None",
"time": "17:00:00"
},
"id": 402627,
"creator": "R"
}
}... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
>>>
>>>
>>> json.dumps(marshal(data, resource_fields))
'{"vc_room": "dafdafds", "event": "afdasfdsfda", "booking": {"url": "https://indico-staging.cern.ch/rooms/booking/402627", "id": "402627", "creator": "R", "start_dt": {"date": "2020-02-03", "tz": "None", "time": "13:00:00"}, "end_dt": {"date": "2020-02-03", "tz": "None", "time": "17:00:00"}}}'
>>> ^C
Is this a bug? I can provide further evidences or reduce the code to reach this issue, but it looks to me quite a general one.
Running python 3.6.5:
Flask==1.1.1
Flask-Cors==3.0.8
flask-restplus==0.13.0
flask-restx==0.1.0
Apologies if I am missing something trivial.
Thank you.