1
votes

I have a Google App Engine NDB model called 'Bin'. I have modified the properties for 'Bin' and deleted all data entries that correspond to the older model. My goal is to query for all bins and access the attribute 'label' inside a GAE Endpoints function. However, when querying and iterating through the returned list I get AttributeError: 'Bin' object has no attribute 'label', which is clearly false. Log output shows that the returned list does in fact contain two Bin objects that have an attribute called 'label'.

What is interesting is that when I change code around the query, the code will work properly for the next run. Then it fails again.

I have cleared the memcache, restarted the app engine launcher and deleted all entries (then adding new ones) in an attempt to remove any caching.

NDB Model

class Bin(ndb.Model):
    id=ndb.IntegerProperty(required=True)
    label=ndb.StringProperty(required=True)
    items=ndb.JsonProperty()

The Query

import endpoints
from protorpc import messages
from protorpc import message_types
from protorpc import remote
from includes.models import Bin
...
@endpoints.api(name='iwora', version='v1')
class Api(remote.Service):
    @endpoints.method(message_types.VoidMessage, BinCollection,
    path='bin', http_method='GET',
    name='bin.all')
    def bin_all(self, request):
        self.user_required()

        namespace = namespace_manager.get_namespace()
        try:
            namespace_manager.set_namespace(self.user.active_org)
            bins = Bin.query().fetch()
            logging.info('BINS: %s' % bins)
            binsresponse = []
            for bin in bins:
                logging.info('BIN: %s' % bin)
                obj = {
                    'label': bin.label # error happens here
                }
                binsresponse.append(obj)
        finally:
            namespace_manager.set_namespace(namespace)

        return BinCollection(bins=binsresponse)
...

When the query is ran and I attempt to iterate through the returned bins I get the following output:

BINS: [Bin(key=Key('Bin', 'default_bin', 'Bin', 5275456790069248), id=2L, items=None, label='1-1-2'), Bin(key=Key('Bin', 'default_bin', 'Bin', 5838406743490560), id=1L, items=None, label='1-1-1')] BIN: Bin(key=Key('Bin', 'default_bin', 'Bin', 5275456790069248), id=2L, items=None, label='1-1-2') Encountered unexpected error from ProtoRPC method implementation: AttributeError ('Bin' object has no attribute 'label') Traceback (most recent call last): File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/protorpc-1.0/protorpc/wsgi/service.py", line 181, in protorpc_service_app response = method(instance, request) File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine- default.bundle/Contents/Resources/google_appengine/lib/endpoints-1.0/endpoints/api_config.py", line 1332, in invoke_remote return remote_method(service_instance, request) File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/protorpc-1.0/protorpc/remote.py", line 412, in invoke_remote_method response = method(service_instance, request) File "/Users/rlfrahm/Apps/iwora/api.py", line 524, in bin_all 'label': bin.label AttributeError: 'Bin' object has no attribute 'label'

I think (as in I believe, but have not confirmed) that this only happens once I have implemented a model, added entries into the db, and then modified the model either by changing a property name or adding a new property. Even after deleting the entries I still experience this issue. I realize that this issue is not repeatable in its current state because I do not exactly know how to reproduce the error. It seems to "just happen." I have many other functions that use this same process and work just fine. Even the interactive console in the SDK Console returns correctly.

Therefore, I am really wondering if anyone has seen this type of behavior or sees something obviously wrong with my process?

1
You're clearly showing us only part of your code (you set but never use binsresponse and obj, for example) and I suspect the damage happens in the parts you're omitting, making it impossible for us to help you debug. Please post a concise but complete failing example, maybe using testbed to make it really stand-alone...Alex Martelli
In addition looking at the first line logged you can see each of the Bin instances retrieved do in fact have a label attribute. The fact that iterating over the list of Bins and somehow you are causing ProtoRPC calls and that looks strange. You are omitting a lot of information.Tim Hoffman
@AlexMartelli - I have updated the description. The query and iteration happen within a GAE Endpoints function. There are other functions alongside this function that do similar queries on different models and they work just fine.rlfrahm
@TimHoffman - The query resides inside a GAE Endpoints function. I have updated the op with more information. Let me know what else you want to know.rlfrahm
@frahminator, I've edited the tags to include google-cloud-endpoints which you had omitted -- now I can try to reproduce your actual problem.Alex Martelli

1 Answers

3
votes

Here's my best attempt at trying to reproduce your error -- it includes all the sparse fragments of code you've deigned to share with us, and miserably fails to show any error at all.

import logging
import webapp2
from google.appengine.ext import ndb

class Bin(ndb.Model):
    id=ndb.IntegerProperty(required=True)
    label=ndb.StringProperty(required=True)
    items=ndb.JsonProperty()

class MainHandler(webapp2.RequestHandler):
    def get(self):
        bins = Bin.query().fetch()
        if not bins:
            Bin(id=1L, items=None, label='1-1-1').put()
            Bin(id=2L, items=None, label='1-1-2').put()
            bins = Bin.query().fetch()
        logging.info('BINS: %s' % bins)
        binsresponse = []
        for bin in bins:
            logging.info('BIN: %s' % bin)
            obj = {
                'label': bin.label # error happens here
            }
            binsresponse.append(obj)

        self.response.write('Hello world! ')
        self.response.write(binsresponse)


app = webapp2.WSGIApplication([
    ('/', MainHandler)
], debug=True)

Running this locally in the SDK shows, as expected:

Hello world! [{'label': u'1-1-2'}, {'label': u'1-1-1'}]

and the relevant snippet from the log is:

INFO     2014-12-21 03:15:56,721 main.py:19] BINS: [Bin(key=Key('Bin', 5066549580791808), id=2, items=None, label=u'1-1-2'), Bin(key=Key('Bin', 5629499534213120), id=1, items=None, label=u'1-1-1')]
INFO     2014-12-21 03:15:56,721 main.py:22] BIN: Bin(key=Key('Bin', 5066549580791808), id=2, items=None, label=u'1-1-2')
INFO     2014-12-21 03:15:56,722 main.py:22] BIN: Bin(key=Key('Bin', 5629499534213120), id=1, items=None, label=u'1-1-1')

IOW, no problem whatsoever.

Please add to this tiny code (which does include every single last bit you deigned to post!-) what's missing to make it reproduce your error, and edit your question to include the minimum failing example -- or else, give up all hope that anybody will ever be able to help you debug your mistakes!-)