Robotex
Robotex

Reputation: 1026

Python: how to return from generator function using tornado?

I use yield and task to get four jsons asynchronously:

@gen.engine
def get_user_data(self, sn, snid, fast_withdrawals):
    end_timestamp = time.time()
    start_timestamp = end_timestamp - CONFIG.LOYALITY_LEVELS.PERIOD

    active_apps_response, total_payments_response, payments_for_period_response, withdrawals_response = yield [
        gen.Task(self.http_client.fetch, self.__get_active_apps_url(sn, snid)), gen.Task(self.http_client.fetch, self.__get_total_payments_url(sn, snid)),
        gen.Task(self.http_client.fetch, self.__get_payments_sum_for_period_url(sn, snid, start_timestamp, end_timestamp)),
        gen.Task(self.http_client.fetch, self.__get_total_withdrawals_url(sn, snid, fast_withdrawals))
    ]

    active_apps = self.__active_apps_handler(active_apps_response)
    total_payments = self.__get_total_payments_handler(total_payments_response)
    payments_for_period = self.__payments_sum_for_period_handler(payments_for_period_response)
    withdrawals = self.__get_total_withdrawals_handler(withdrawals_response)

    yield gen.Return(active_apps, total_payments, payments_for_period, withdrawals)

But if I using yield instead return upper function became generator too and I can't use return in it too. So, how to return results from function in tornado without making caller function generator? I'm using Python 2.7

Upvotes: 2

Views: 1633

Answers (2)

cloudaice
cloudaice

Reputation: 1

maybe you can write like this:

@gen.coroutine
def get_user_data(self, sn, snid, fast_withdrawals):
    end_timestamp = time.time()
    start_timestamp = end_timestamp - CONFIG.LOYALITY_LEVELS.PERIOD

    active_apps_response, total_payments_response, payments_for_period_response, withdrawals_response = yield [
    self.http_client.fetch(self.__get_active_apps_url(sn, snid)),
    self.http_client.fetch(self.__get_total_payments_url(sn, snid)),
    self.http_client.fetch(self.__get_payments_sum_for_period_url(sn, snid, start_timestamp, end_timestamp)),
    self.http_client.fetch(self.__get_total_withdrawals_url(sn, snid, fast_withdrawals))
]

active_apps = self.__active_apps_handler(active_apps_response)
total_payments = self.__get_total_payments_handler(total_payments_response)
payments_for_period = self.__payments_sum_for_period_handler(payments_for_period_response)
withdrawals = self.__get_total_withdrawals_handler(withdrawals_response)

raise gen.Return(active_apps, total_payments, payments_for_period, withdrawals)

the engine is an older interface; more about this you can see tornado 3.0 document.

Upvotes: 0

Gareth Latty
Gareth Latty

Reputation: 89087

You can't both return values and yield values. When you yield values the function returns a generator - so it has already returned a value and can't return more. It simply doesn't make sense to do so.

You can call return without any value to cause a StopIteration exception and end the generator, but returning a value doesn't make sense semantically from within a generator.

If you want to sometimes return a generator, and sometimes return a value, wrap your function with another one that returns either a generator (created by calling this function) or the alternative value, although I'd not such a thing is generally a bad idea from a design point of view.

Upvotes: 5

Related Questions