falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.51k stars 937 forks source link

`DefaultEventLoopPolicy.get_event_loop()` is deprecated (in the case of no loop) #2178

Closed vytas7 closed 6 months ago

vytas7 commented 11 months ago

As of Python 3.12, if there is no event loop, DefaultEventLoopPolicy.get_event_loop() emits a deprecation warning, and threatens to raise an error in future Python versions.

No replacement is suggested by the official docs. When it does start raising an error, I suppose one can catch it, and create a new loop instead.

We have already updated our code to use this method to combat another deprecation... it seems Python wants to make it harder and harder obtaining the current loop from sync code (which makes no sense to me).

CaselIT commented 10 months ago

seems that what they want you to do for #reasons is the following

try:
  loop = asyncio.get_running_loop()
except RuntimeError: # lol custom exception are for noobs
  loop = asyncio.new_event_loop()
  asyncio.set_event_loop(loop)

I have no idea how someone looked at this and thought "yeah that's a great api to replace get_event_loop" -.-'

CaselIT commented 10 months ago

seems that what they want you to do for #reasons is the following

try:
  loop = asyncio.get_running_loop()
except RuntimeError: # lol custom exception are for noobs
  loop = asyncio.new_event_loop()
  asyncio.set_event_loop(loop)

I have no idea how someone looked at this and thought "yeah that's a great api to replace get_event_loop" -.-'

nope that's too simple. the following seems correct

def get_event_loop() -> asyncio.AbstractEventLoop:
    try:
        return asyncio.get_running_loop()
    except RuntimeError:
        # avoid "During handling of the above exception, another exception..."
        pass
    if sys.version_info < (3,12):
        return asyncio.get_event_loop()
    else:
        with warnings.catch_warnings(action='error'):
            loop = None
            try:
                loop = asyncio.get_event_loop()
            except (DeprecationWarning, RuntimeError):
                # avoid "During handling of the above exception,
                # another exception..."
                pass
            if loop is None:
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)
            return loop
vytas7 commented 10 months ago

See also the discussion on https://github.com/python/cpython/issues/100160