Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Ask HN: Ways to deal with Python 3.11 breaking change to asyncio
12 points by m3047 on Nov 24, 2022 | hide | past | favorite | 9 comments
AFAICT 3.11 requires your code to call asyncio.run(), whereas earlier versions (for some definition of "earlier") required you to inject your coroutines and then call loop.run_forever().

Basically it smells to me like this is going to require two distinct main()s. This is ugly. How do I make it not butt ugly and minimize the general odor?



You don’t need two different mains. My asyncio code runs just fine on both and didn’t require changes when moving from 3.10 to 3.11 possibly because the way I always do it is asyncio.run(main()) from the body of the code (“actual main”) to an

   async def main
async callable and the last real line of that is pretty much always just an asyncio.gather over a bunch of other stuff that I want to run. My understanding is that’s been the recommended method for a very long time rather than get_event_loop or run_forever or anything like that.

edit: that is to say, asyncio.run() may be required now but the method of injecting coroutines and then doing run_forever was definitely not required before. Asyncio.run was available before 3.11.


> ... the method of injecting coroutines and then doing run_forever was definitely not required before.

Carefully preserved punctuation there: the full stop. If you run asyncio.start_server(), today, on 3.11, it does not return an awaitable.


asyncio.run() is not in 3.6


get_event_loop was deprecated in Python 3.10

  loop = asyncio.get_event_loop()
  loop.run_until_complete(main())
https://docs.python.org/3.10/library/asyncio-eventloop.html


Let me break it down for you:

Suppose I run asyncio.start_server() and I want it to run forever. What am I supposed to asyncio.gather()) on without making stuff up?

[Edit] Production code or it didn't happen.


Given this:

    server = await asyncio.start_server(
            context.handle_requests, str(config.host), config.port, limit=MAX_READ_SIZE
        )
as stated, you can't use gather(). There are sleight of hand "coincidences", such as waiting on a watchdog which runs forever.

I stumbled on this as something that works:

    useless_lock = asyncio.Lock()
    while True:
        await useless_lock.acquire()
Which demonstrates that the following is, ahem, sleight of hand:

    async with server:
        await server.serve_forever()
although supposedly it guarantees some cleanup which I don't care about. Both options respond identically (at least with 3.11.0) to ^C.

I reiterate that serve_forever() is not in 3.6.


An example and references to the 3.11 changelog would be helpful...


I'll be more brazen and say I would have expected some working, production code examples by now. What I've got is someone throwing it over the wall: ok, thanks, I guess. I'd rather know than not. But the code is smelly, internally it would appear to be failing because it tried to pass a loop kwarg which another part of it doesn't recognize: I didn't pass that arg.

From what I can see so far asyncio.gather() would seem to be the canonical refactor.

I'm not sure that I'm down with the philosophy of the loop stopping running AT ALL unless I ask for it. I've got long-running processes. I spew stack traces from within coroutines, and if the situation is dire enough I call stop() myself.

I always thought that being able to leave coroutines in the queue when the loop isn't running was a feature, not a bug.


> An example and references to the 3.11 changelog would be helpful...

Can't tell from that remark whether you're asking or telling...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: