#google-app-engine #python-2.7 #flask #flask-restful
#google-app-engine #python-2.7 #flask #flask-restful
Вопрос:
Я написал очень простой REST API с использованием Flask и flask-restful в Google App Engine. API предназначен для представления данных о благотворительном мероприятии по сбору средств. В данном случае поездка на велосипеде.
Кажется, все работает, за исключением того, что я периодически получаю ошибку типа, показанную в следующей трассировке стека из журналов App Engine:
Internal Error
Traceback (most recent call last):
File "/base/data/home/apps/s~agonytrackertest/1.376935219653445037/lib/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/base/data/home/apps/s~agonytrackertest/1.376935219653445037/lib/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/base/data/home/apps/s~agonytrackertest/1.376935219653445037/lib/flask_restful/__init__.py", line 397, in wrapper
resp = resource(*args, **kwargs)
File "/base/data/home/apps/s~agonytrackertest/1.376935219653445037/lib/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/base/data/home/apps/s~agonytrackertest/1.376935219653445037/lib/flask_restful/__init__.py", line 487, in dispatch_request
resp = meth(*args, **kwargs)
File "/base/data/home/apps/s~agonytrackertest/1.376935219653445037/main.py", line 268, in post
supersedes=d['Supersedes'])
TypeError: 'RiderStatus' object is not callable
Объект RiderStatus определяется следующим образом:
class RiderStatus(ndb.Model):
""" Models a status for a Rider with rider_id, location, action, time_stamp
status_id
"""
rider_number = ndb.IntegerProperty(indexed=True, required=True)
location = ndb.StringProperty(indexed=False, required=True)
state = ndb.StringProperty(indexed=False, required=True)
time_recorded = ndb.DateTimeProperty(auto_now_add=True)
time_occurred = ndb.IntegerProperty(indexed=False, required=True)
status_id = ndb.StringProperty(indexed=True, required=True)
status_origin = ndb.StringProperty(indexed=True, required=True)
supersedes = ndb.StringProperty(indexed=False, required=True)
Вызываемый в журнале раздел кода является созданием нового объекта RiderStatus и выглядит следующим образом:
for d in statuses:
created_count = 1
status = Models.RiderStatus(rider_number=d['RiderNumber'],
location=d['Location'], state=d['State'], time_occurred=d['TimeStamp'],
status_id=d['StatusId'], status_origin=d['StatusOrigin'],
supersedes=d['Supersedes'])
status.put()
return {"created":str(created_count)}, 201
Я подумал, что, возможно, так я инициализировал объект, хотя я понимаю, что предыдущий обычно используется в Python, поэтому я создал явный конструктор для класса и метод инициализации. Затем класс выглядел следующим образом:
class RiderStatus(ndb.Model):
""" Models a status for a Rider with rider_id, location, action, time_stamp
status_id
"""
def __init__(self, rider_number=0, location='', state='', time_occurred=0, status_id='', status_origin='',
supersedes=''):
super(RiderStatus, self).__init__()
self.rider_number = rider_number
self.location = location
self.state = state
self.time_occurred = time_occurred
self.status_id = status_id
self.status_origin = status_origin
self.supersedes = supersedes
rider_number = ndb.IntegerProperty(indexed=True, required=True)
location = ndb.StringProperty(indexed=False, required=True)
state = ndb.StringProperty(indexed=False, required=True)
time_recorded = ndb.DateTimeProperty(auto_now_add=True)
time_occurred = ndb.IntegerProperty(indexed=False, required=True)
status_id = ndb.StringProperty(indexed=True, required=True)
status_origin = ndb.StringProperty(indexed=True, required=True)
supersedes = ndb.StringProperty(indexed=False, required=True)
def make_rider_status(self, in_dict):
self.rider_number = in_dict['RiderNumber']
self.location = in_dict['Location']
self.state = in_dict['State']
self.time_occurred = in_dict['TimeStamp']
self.status_id = in_dict['StatusId']
self.status_origin = in_dict['StatusOrigin']
self.supersedes = in_dict['Supersedes']
И создание выглядело следующим образом:
for d in statuses:
created_count = 1
status = Models.RiderStatus()
status.make_rider_status(d)
status.put()
return {"created":str(created_count)}, 201
И я получаю аналогичную ошибку:
Internal Error
Traceback (most recent call last):
File "/base/data/home/apps/s~agonytrackermain/1.377017814438367636/lib/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/base/data/home/apps/s~agonytrackermain/1.377017814438367636/lib/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/base/data/home/apps/s~agonytrackermain/1.377017814438367636/lib/flask_restful/__init__.py", line 397, in wrapper
resp = resource(*args, **kwargs)
File "/base/data/home/apps/s~agonytrackermain/1.377017814438367636/lib/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/base/data/home/apps/s~agonytrackermain/1.377017814438367636/lib/flask_restful/__init__.py", line 487, in dispatch_request
resp = meth(*args, **kwargs)
File "/base/data/home/apps/s~agonytrackermain/1.377017814438367636/main.py", line 283, in post
status = Models.RiderStatus()
TypeError: 'RiderStatus' object is not callable
Я получаю эту ошибку, вероятно, примерно в 50% случаев, когда отправляю сообщение по этому URL-адресу API. Остальные 50% времени он работает нормально. Я получаю примерно такую же частоту отказов, запущенную на моем локальном компьютере с SDK App Engine и развернутую в App Engine. Тем не менее, я не получил его, выдает ошибку, когда у меня подключен отладчик. Добавив вызовы debug print, я определил, что при сбое он завершается неудачей на первой итерации цикла for и что d действительно является dict с ключами и значениями, к которым я пытаюсь получить доступ.
Я очень новичок в Python, Flask и App Engine, поэтому я определенно мог что-то здесь упустить, но я прочитал все найденные мной сообщения «Object not callable», и я не нашел ничего, что, казалось бы, применимо, т. Е. я не пропускаю часть конструктора, я не переназначал объект другому типу, и я не переопределял базовый тип (который я все равно смог найти).
Я не знаю, является ли это проблемой FLASK, проблемой Python, проблемой flask-restful, проблемой App Engine или проблемой me, поэтому мой следующий шаг — переделать API, используя только Flask, и посмотреть, работает ли он более надежно. В то же время, любая помощь приветствуется.
Комментарии:
1. Это звучит так, как будто вы назначили экземпляр
Models.RiderStatus
; например, в другом месте вашего кода, которое вы в конечном итоге выполняетеModels.RiderStatus = Models.RiderStatus()
, прямо или косвенно. С этого момента этот процесс прерывается и будет продолжать выдавать это исключение.2. Возможно ли, что это проблема? Это определено в том же классе, что и URL, который чаще всего завершается ошибкой:
def get(self, rider_id): statuses = Models.RiderStatus.last_status(rider_id).fetch() return jsonify({'statuses': [Models.RiderStatus.to_dict() for Models.RiderStatus in statuses]})
Я изменил последнюю строку на:return jsonify({'statuses': [s.to_dict() for s in statuses]})
3. Да, в Python 2 это, безусловно, может это сделать. Имя
Model.RiderStatus
не является локальным для понимания списка.
Ответ №1:
Как отмечено в комментариях выше, я нашел свой ответ после дальнейшего рассмотрения того, что предложил Martijn Pieters. Ответ находится в комментариях к вопросу, но я подумал, что сделаю его более заметным в надежде, что он может быть полезен кому-то еще.
Я создал понимание списка, используя код:
def get(self, rider_id):
statuses = Models.RiderStatus.last_status(rider_id).fetch()
return jsonify({'statuses': [Models.RiderStatus.to_dict() for Models.RiderStatus in
statuses]})
Мое понимание того, почему это вызвало проблему, заключается в следующем: этот шаблон вызвал присвоение экземпляра модели класса.RiderStatus для объекта с именем Models.RiderStatus. Последующие вызовы моделей.Затем RiderStatus попытался получить доступ к экземпляру, как если бы это был класс, вызывающий ошибку типа. Последняя строка в приведенном выше на самом деле должна быть чем-то вроде:
return jsonify({'statuses': [s.to_dict() for s in statuses]})
Комментарий Martijn подразумевает, что первый шаблон может быть в порядке в Python 3, но является ошибкой в Python 2. Я понимаю, что произошли широкомасштабные изменения в том, как обрабатывались объекты класса в Python 3, но я не знаю достаточно, чтобы подтвердить или расширить этот комментарий.
Прерывистый характер проблемы был связан с порядком, в котором осуществлялся доступ к URI. При «правильном» порядке проблема стала более заметной.
Еще раз спасибо Martijn за то, что указал мне правильное направление!