Search code examples
python-asynciotornado

Tornado Coroutine fails with 'dict' object not callabale


Python version: 3.6

I am not super expert in Python, I was trying to use Tornado to implement a simple REST server and use non blocking coroutine to call a blocking function. When I return Json from the blocking function it fails with TypeError: 'dict' object is not callable Here's the code

@gen.coroutine
def post(self):
    jsonResponse = yield self.process_request(imageBytes)
    self.write(json.dumps(jsonResponse))

@gen.coroutine
def process_request(self, imageBytes):
    response = yield (executor.submit(self.test_func(), None))
    return response

def test_func(self):
    print('test func')
    time.sleep(1)
    jsonDataSet = {"text": "hello 123"}
    return jsonDataSet

I am not sure what I am doing wrong, followed the sample code from Tornado reference. Any pointers will be helpful?

Latest: I moved to async & await now I am getting "Object of type 'coroutine' is not JSON serializable"

async def test_func():
    print('test func')
    time.sleep(1)
    jsonDataSet = {"text": "hello 123"}
    return jsonDataSet
    #return "test"
response = await `tornado.ioloop.IOLoop.current().run_in_executor(None, test_func)`

Solution

  • TypeError: 'dict' object is not callable

    executor.submit() requires a callable, but you're already calling the test_func function. When you call test_func(), you're essentially passing its return value (which is a dict) to the submit() function.

    You need pass this function without calling:

    executor.submit(self.test_func, None)
    

    Latest: I moved to async & await now I am getting "Object of type 'coroutine' is not JSON serializable"

    run_in_executor is for running a normal function in a separate thread. It's not meant for running coroutines.

    What's happening here is run_in_executor is calling test_func() coroutine, which automatically returns an awaitable object (because it's a coroutine).

    If you want to execute test_func using run_in_executor, just make it a normal function (don't use async def).