pythontwistedtwisted.webtwisted.application

i'm getting 'nonetype' not iterable error in python /twisted


I am trying to understand why I get the following error that comes about when I try to evaluate the contents of a cell, some function is either not returning or I don't understand how this stuff works.

 2012-11-08 04:30:45-0800 [HTTPPageGetter,client] handling data: None
 2012-11-08 04:30:45-0800 [HTTPPageGetter,client] Unhandled Error
 Traceback (most recent call last):
 File "path/to/python/lib/python2.7/site-packages/twisted/internet/defer.py", line 1101, in gotResult
 _inlineCallbacks(r, g, deferred)
 File "path/to/python/lib/python2.7/site-packages/twisted/internet/defer.py", line 1048, in _inlineCallbacks
 deferred.callback(None)
 File "path/ib/python2.7/site-packages/twisted/internet/defer.py", line 368, in callback
 self._startRunCallbacks(result)
 File "path/lib/python2.7/site-packages/twisted/internet/defer.py", line 464, in _startRunCallbacks
 self._runCallbacks()
 --- <exception caught here> ---
 File "path/lib/python2.7/site-packages/twisted/internet/defer.py", line 551, in _runCallbacks
 current.result = callback(current.result, *args, **kw)
 File "/path/to/lib/python2.7/site-packages/codenode/frontend/async/backend.py", line 223, in _success
 if 'cellstyle' in data and data['cellstyle'] == 'outputimage':
 exceptions.TypeError: argument of type 'NoneType' is not iterable

 2012-11-08 04:30:45-0800 [HTTPPageGetter,client] Stopping factory

here is the relevant part of the code (I think): there is a suspicious part in the addcallback(three params none of which are data) but in the _success (three apart from self one of which is data), if this is the issue whee do I pass the data?.

def render(self, request):
    """
    This is where we un-serialize the content sent between the frontend
    and backend engine bus.
    """
    content = request.content.read()
    if content:
        msg = json.loads(content)
        log.msg('Engine message deserialized %s' % str(msg))
    else:
        return
    cellid = msg.get('cellid', '')
    d = self.engine_bus.handleRequest(self.notebook_id, msg)
    d.addCallback(self._success, request, cellid)
    d.addErrback(self._fail, request)
    return server.NOT_DONE_YET

def _success(self, data, request, cellid):
    """
    horrible. not always eval...
    """
    log.msg('handling data: %s' % str(data))
    if 'cellstyle' in data and data['cellstyle'] == 'outputimage':
        image_data = pickle.loads(data['out']).getvalue()
        image_file_name = write_image(image_data)
        data['out'] = image_file_name

    data['cellid'] = cellid
    jsobj = json.dumps(data)
    request.write(jsobj)
    request.finish()

Admittedly this is not by own work, and i have little understanding of it, and its pretty dated. here is more of the code: github python file

[EDIT] here is a little more : the initialization:

class EngineSessionAdapter(resource.Resource):
    """
    There should be a better way to do this, have to figure that out.
    """

    isLeaf = True

    def __init__(self, engine_bus, notebook_id):
        resource.Resource.__init__(self)
        self.engine_bus = engine_bus
        self.notebook_id = notebook_id
        self.putChild("", self)

and this is the engine object:

class EngineBusAdapter(resource.Resource):

    def __init__(self, engine_bus):
        resource.Resource.__init__(self)
        self.engine_bus = engine_bus
        self.putChild("", self)

    def getChild(self, path, request):
        """XXX Can this refer back to itself?
        """
        return EngineSessionAdapter(self.engine_bus, path)

[2nd Edit] here is the Enginebus definition:

class EngineBus(object):
"""
Common entry point for all engine requests. 
Look up engine client by access_id.

This is responsible for routing the engine message
from the browser/frontend to the engine by access_id.
This does not need to process the message (un-serialize, inspect, 
or otherwise).
"""

def __init__(self, backend):
    self.backend = backend

@defer.inlineCallbacks
def handleRequest(self, access_id, msg):
    """
    msg comes in as dictionary
    """
    log.msg('handling engine request for %s' % access_id)
    try:
        engine_client = yield self.backend.getEngine(access_id)
        log.msg('got engine Client %s' % str(engine_client))
    except InvalidAccessId:
        err = {'status':'ERR', 'response':'InvalidAccessId'}
        log.err('InvalidAccessId %s' % access_id)
        defer.returnValue(err)

    result = yield engine_client.send(msg)
    sucs = {'status':'OK', 'response':result}
    defer.returnValue(sucs)

EDIT: Finally solved it: here is the diff:

-        result = yield meth(engine_arg, cellid)
+        result = yield defer.maybeDeferred(meth,engine_arg, cellid)
         defer.returnValue(result)

-    @defer.inlineCallbacks
     def engine_start(self, args, arg):
         """dummy
         """
-        defer.returnValue({'result':'started'})
+        return {'result':'started'}

here it is in context: the commit diff on github for backend/engine.py


Solution

  • if 'cellstyle' in data and data['cellstyle'] == 'outputimage':
    exceptions.TypeError: argument of type 'NoneType' is not iterable
    

    'cellstyle' in data requires data to be iterable - it is not iterable, but None