Search code examples
pythongoogle-app-enginesuperclassoverriding

Overriding db.Model.all() in python google app engine


I'm trying to start using memcache in my Google App Engine app. Instead of creating a function that checks memcache and then maybe queries the database, I decided to just override my Model's all() class method. Here's my code so far:

def all(cls, order=None):
    result = memcache.get("allitems")
    if not result or not memcache.get("updateitems"):
        logging.info(list(super(Item, cls.all())))
        result = list(super(Item, cls).all()).sort(key=lambda x: getattr(x, order) if order else str(x))
        memcache.set("allitems", result)
        memcache.set("updateitems", True)
        logging.info("DB Query for items")
    return result

I had figured this would work. But instead I get a RuntimeError saying that recursion depth was exceeded. I think this comes from a misunderstanding of the super() method. Sorry for cluttering the code up with the ordering thing. But maybe the problem lies somewhere in there too. One place I found said that the super method should be called like this:

super(supercls, cls_or_self)

But this wouldn't work with GAE's API:

super(db.Model, cls)

This wouldn't know which model to query. Someone please tell me what I'm doing wrong, and maybe give me a better understanding super().

EDIT: Thanks to @Matthew, the problem turned out to be a misplaced parentheses in the first logging.info() call. Now I have another problem, the method is just returning None. I don't know if that means that the super implementation of all() returns None (Maybe it doesn't know what entity is calling it?) or just there is some other bug with my code.


Solution

  • I think the error might be here:

    logging.info(list(super(Item, cls.all())))
    

    If there's an error in cls.all(), you then call it again as part of the super constructor, rather than calling it on the result:

    logging.info(list(super(Item, cls).all()))
    

    So if an error would call all again it would still meet the logging branch conditions, which would call all again, which would still etc etc until you hit the recursion limit.

    The other possible problem is that Model.all() returns a Query object, and I'm not sure if list(query) works. It also provides it's own sorting, so you might be able to use this instead:

        query = super(Item, cls).all()
        query.order( order )
        ...
    return list(query)
    

    Or just return query, as it's already iterable.