Fix Python 3.12+, Tornado 6.3+ event loop deprecation warnings#492
Merged
martindurant merged 4 commits intopython-streamz:masterfrom Dec 18, 2025
Merged
Conversation
https://www.tornadoweb.org/en/stable/ioloop.html#tornado.ioloop.IOLoop.clear_instance clear_instance is now an alias for clear_current and has been deprecated since Tornado 5.0
Tornado 4.2 add an optional keyword to IOLoop(make_current=False) Tornado 6.3 changes that to make_current=True so the default behavior is to install the loop as the current thread's loop.
IOLoop.clear_current is deprecated since Tornado 6.2 If proactive manipulation of the running loop is required, the API docs say to use asyncio.set_event_loop()
* Go back to IOLoop(make_current=False) to avoid proactively starting the loop when the underlying asyncio system is not ready. * Turn streamz/tests/test_core.py::test_timed_window_timedelta into a coroutine as the underlying event loop needs to be live.
Member
|
Thank you for the deep digging here! From your description, I was worried it would be more involved code changes than it actually is. One thing that you noticed here, and I think it indeed in the documentation, is that asynchronous=True should only be used from within asynchronous code; and we could enforce this. fsspec faces a similar situation. I had spent some effort in the past converting tornado->asyncio, but there has been a decent amount of leftover legacy code left in the package. There is no reason to have tornado in here at all these days. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tornado deprecated and changed semantics around their IOLoop in major ways in 5.0, 6.2 and 6.3:
IOLoop.*_instanceas they are just aliases for the analogous_currentcall.asyncio.set_event_loopcall to establish the operant loop. Note that in Python 3.13+ this is bad advice as written becauseasyncio.set_event_looprequires the loop instance to be anasyncio.AbstractEventLoopand Tornado's IOLoop is not. If you want to manually install it, the correct call seems to beasyncio.set_event_loop(my_io_loop.asyncio_loop)but this largely unnecessary as IOLoop is mostly just a wrapper around the default loops and gets things in the right place when its API is used.make_currenton the IOLoop constructor toTrueinstead ofFalseso callingIOLoop()greedily tries to establish itself as the loop of the current thread. This invalidates the intended semantics behindcore.py:get_io_loopfor binding to the new thread.Once I removed the deprecated calls to Tornado APIs and fixed the default parameters (all test plumbing except the noted
get_io_loop), this change inasyncioitself popped up:get_event_loopand in 3.14 that is a runtime error. This required makingtest_core.py:test_timed_window_timedeltainto a coroutine and running it viapytest-asyncioexplicitly to get a loop in place as callingget_io_loop(asynchronous=True)callsIOLoop.current()which is just a wrapper aroundasyncio.get_event_loop()