Ошибка прерывистого типа Flask / Flask-restful, GAE ‘Object» не вызываемый тип

#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 за то, что указал мне правильное направление!