"""
- def copy(future: "Future[_T]") -> None:
- assert future is a
+ def copy(a: "Future[_T]") -> None:
if b.done():
return
if hasattr(a, "exc_info") and a.exc_info() is not None: # type: ignore
# the error logging (i.e. it goes to tornado.log.app_log
# instead of asyncio's log).
future.add_done_callback(
- lambda f: self._run_callback(functools.partial(callback, future))
+ lambda f: self._run_callback(functools.partial(callback, f))
)
else:
assert is_future(future)
# For concurrent futures, we use self.add_callback, so
# it's fine if future_add_done_callback inlines that call.
- future_add_done_callback(
- future, lambda f: self.add_callback(callback, future)
- )
+ future_add_done_callback(future, lambda f: self.add_callback(callback, f))
def run_in_executor(
self,
self.write("ok\n")
asyncio.run(self.run_handler(Handler))
+
+ def test_run_on_executor(self):
+ # From https://github.com/tornadoweb/tornado/issues/2620
+ #
+ # When this test was introduced it found cycles in IOLoop.add_future
+ # and tornado.concurrent.chain_future.
+ import concurrent.futures
+
+ thread_pool = concurrent.futures.ThreadPoolExecutor(1)
+
+ class Factory(object):
+ executor = thread_pool
+
+ @tornado.concurrent.run_on_executor
+ def run(self):
+ return None
+
+ factory = Factory()
+
+ async def main():
+ # The cycle is not reported on the first call. It's not clear why.
+ for i in range(2):
+ await factory.run()
+
+ with assert_no_cycle_garbage():
+ asyncio.run(main())