I am stumped by a problem I am having with memcache on App Engine. It mostly looks like a memcache issue but I am seeing something funny when I step through the code.
I am getting an excpetion (TypeError: 'NoneType' object is not callable) when writing an instance to memcache. The instance comes from a simple class that should be pickleable, containing only strings, booleans, an int, and a datetime. The reason I am bringing this to the web2py board is that when I traced down the memcache call chain to a call to pickler.dump() and attempted to step into it, control jumped to code for web2py's _Web2pyImporter object in gluon/custom_import.py. Here is the relevant section of my pdb session. > /Users/davidp/dev/python/google/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/memcache/__init__.py(403)_do_pickle() -> pickler.dump(value) (Pdb) s --Call-- > /Users/davidp/dev/python/rage/gluon/custom_import.py(253)__call__() -> def __call__(self, name, globals=None, locals=None, I stepped through the _Web2pyImporter code, and eventually, when executing the following statement, (line 292-3), control jumped into gluaon/dal.py where it executed the __getattr__() method of the Reference class. return super(_Web2pyImporter, self).__call__(name, globals, locals, fromlist, level) The __getattr__ returns None (it was looking up something called '__getstate__') which causes something to throw an exception. I am, by this time, just scratching my head. Why is appengine's memcache code invoking gluon code? Why is class Reference involved? The object that memcache is pickling contains no DAL references. Why is "custom importing" needed at all? The 'name' parameter to the Web2pyImporter function __call__ has a value of datetime. There is a datetime field in the object I'm trying to write to memcache, but why does the code jump to custom_import.py when the call to pickler.dump() is called? Here is the memcache code that was being executed at the time: def _do_pickle(self, value): """Pickles a provided value.""" pickle_data = cStringIO.StringIO() pickler = self._pickler_factory(pickle_data, protocol=self._pickle_protocol) if self._persistent_id is not None: pickler.persistent_id = self._persistent_id pickler.dump(value) # line 403 return pickle_data.getvalue() Here is how the pdb showed the control flow as I stepped through _do_pickle(). (Pdb) n > /Users/davidp/dev/python/google/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/memcache/__init__.py(403)_do_pickle() -> pickler.dump(value) (Pdb) s --Call-- > /Users/davidp/dev/python/ragearchives/gluon/custom_import.py(253)__call__() -> def __call__(self, name, globals=None, locals=None, The stack trace from the exception is copied below. Why doesn't it show the call into pickler.dump or custom_import? I am most confused. All I want to do is to store my object in memcache and my client is getting impatient. Is this a web2py issue? App Engine's memcache? Pickle? Any help would be appreciated. File "applications/rage/modules/player.py", line 51, in __init__ memcache.set (key, self, Player.MEMCACHE_EXPIRATION) File "/Users/davidp/dev/python/google/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/memcache/__init__.py", line 778, in set namespace=namespace) File "/Users/davidp/dev/python/google/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/memcache/__init__.py", line 883, in _set_with_policy\n time, \'\', namespace) File "/Users/davidp/dev/python/google/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/memcache/__init__.py", line 962, in _set_multi_async_with_policy stored_value, flags = _validate_encode_value(value, self._do_pickle) File "/Users/davidp/dev/python/google/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/memcache/__init__.py", line 227, in _validate_encode_value stored_value = do_pickle(value) File "/Users/davidp/dev/python/google/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/memcache/__init__.py", line 403, in _do_pickle pickler.dump(value) TypeError: 'NoneType' object is not callable