0

我在 Google App Engine 上使用 Flask 和 flask-restful 编写了一个非常简单的 REST API。该 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

我在 POST 到该 API URL 的时间大约有 50% 会收到此错误。其他 50% 的时间它工作正常。我使用 App Engine SDk 在本地机器上运行并部署到 App Engine 的失败率大致相同。但是,当我附加调试器时,我没有得到它给出错误。通过添加调试打印调用,我确定当它失败时,它在通过 for 循环的第一次迭代中失败,并且 d 确实是一个包含我试图访问的键和值的字典。

我对 Python、Flask 和 App Engine 非常陌生,所以我肯定会在这里遗漏一些东西,但我已经阅读了我找到的所有“对象不可调用”帖子,但我没有找到任何似乎适用的内容,即我不是缺少构造函数的一部分,我没有将对象重新分配给另一种类型,也没有覆盖基类型(无论如何我都能找到)。

我不知道这是 FLASK 问题、Python 问题、flask-restful 问题、App Engine 问题还是我的问题,所以我的下一步是仅使用 Flask 重做 API,看看它是否更可靠地工作。在此期间,任何帮助都将不胜感激。

4

1 回答 1

0

如上面评论中所述,在进一步考虑了 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]})

我对导致问题的原因的理解如下:这种模式导致将Models.RiderStatus的实例分配给名为 Models.RiderStatus 的对象。随后对 Models.RiderStatus 的调用尝试访问该实例,就好像它是导致类型错误的类一样。上面的最后一行实际上应该是这样的:

return jsonify({'statuses': [s.to_dict() for s in statuses]})

Martijn 的评论暗示第一个模式在 Python 3 中可能没问题,但在 Python 2 中是一个错误。我知道在 Python 3 中处理类对象的方式发生了广泛的变化,但我不知道足以验证或扩展该评论​​。

问题的间歇性与访问 URI 的顺序有关。使用“正确”的顺序,问题变得更加明显。

再次感谢 Martijn 为我指明了正确的方向!

于 2014-07-06T21:24:01.347 回答