Issue 21326: asyncio: request clearer error message when event loop closed (original) (raw)

Created on 2014-04-22 08:12 by mark.dickinson, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (12)

msg216994 - (view)

Author: Mark Dickinson (mark.dickinson) * (Python committer)

Date: 2014-04-22 08:12

In the new asyncio library, it's easy for newbies (like me) to accidentally try to run a coroutine on a closed event loop. Doing so leads to a rather inscrutable exception and traceback:

loop.run_until_complete(compute()) Traceback (most recent call last): File "", line 1, in File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 203, in run_until_complete self.run_forever() File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 184, in run_forever self._run_once() File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 778, in _run_once event_list = self._selector.select(timeout) AttributeError: 'NoneType' object has no attribute 'select'

Is it possible to replace this with something clearer? For example, something like: RuntimeError("Can't schedule coroutine on closed event loop.")

Here's the full code snippet:

Python 3.4.0 (default, Mar 25 2014, 11:07:05) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38)] on darwin Type "help", "copyright", "credits" or "license" for more information.

import asyncio @asyncio.coroutine ... def compute(): ... print("Starting computation") ... yield from asyncio.sleep(2.0) ... print("Complete") ... loop = asyncio.get_event_loop() loop.run_until_complete(compute()) Starting computation Complete loop.close() # whoops

some time later

... loop = asyncio.get_event_loop() loop.run_until_complete(compute()) Traceback (most recent call last): File "", line 1, in File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 203, in run_until_complete self.run_forever() File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 184, in run_forever self._run_once() File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 778, in _run_once event_list = self._selector.select(timeout) AttributeError: 'NoneType' object has no attribute 'select'

msg217007 - (view)

Author: Guido van Rossum (gvanrossum) * (Python committer)

Date: 2014-04-22 14:33

Hm, I've never hear from someone who did this before. It might be easy to fix, but it would be ugly too (every EventLoop method would have to check this), and not very useful (you'll only make this mistake once in your life).

How much time did you waste debugging this?

Maybe we can just change repr(loop) to make it clear that it's closed?

msg217008 - (view)

Author: Mark Dickinson (mark.dickinson) * (Python committer)

Date: 2014-04-22 14:44

How much time did you waste debugging this?

Not much: less than 5 minutes. While I probably won't make this mistake again (though I'm not going to make any promises on that front), it would be nice to prevent other people from doing so.

More info: I got to the issue by randomly pasting examples from the asyncio docs, one of which had a .close call in, without taking the time to read and understand those docs properly first - I was keen to get to the coroutine part of it and didn't want to spend time on the event loop details. Without having thought about it, I wasn't expecting the result of get_event_loop to be a singleton; once I figured that bit out it was clear what was going on.

So yes, stupidity on my part. I'd like to bet that I won't be the only person who runs into this, though.

msg217009 - (view)

Author: Mark Dickinson (mark.dickinson) * (Python committer)

Date: 2014-04-22 14:45

Maybe we can just change repr(loop) to make it clear that it's closed?

That sounds good to me.

msg219319 - (view)

Author: STINNER Victor (vstinner) * (Python committer)

Date: 2014-05-28 22:56

I proposed a patch upstream (in Tulip) to solve this issue: http://code.google.com/p/tulip/issues/detail?id=169

msg219731 - (view)

Author: Roundup Robot (python-dev) (Python triager)

Date: 2014-06-03 23:08

New changeset 690b6ddeee9c by Victor Stinner in branch 'default': Issue #21326: Add asyncio.BaseEventLoop.is_closed() method http://hg.python.org/cpython/rev/690b6ddeee9c

msg219732 - (view)

Author: STINNER Victor (vstinner) * (Python committer)

Date: 2014-06-03 23:17

I fixed the issue in Python 3.5 by adding a new BaseEventLoop.is_closed() method. Calling run_forever() or run_until_complete() now raises an error.

I don't know yet if this issue should be fixed in Python 3.4. If it should be fixed, I don't know how it should be fixed. Guido was unhappy with subclasses of BaseEventLoop accessing the private attribute BaseEventLoop._closed in the review of my patch.

msg219734 - (view)

Author: STINNER Victor (vstinner) * (Python committer)

Date: 2014-06-03 23:47

Attached asyncio_closed_py34.patch: minimum patch to fix this issue. run_forever() and run_until_complete() raises a RuntimeError if the event loop was closed.

The patch only uses the private attribute BaseEventLoop._closed in the BaseEventLoop class, not outside.

msg219851 - (view)

Author: Guido van Rossum (gvanrossum) * (Python committer)

Date: 2014-06-05 22:26

I don't want the 3.4 and 3.5 versions of asyncio to be different. You should just copy the 3.5 code back into the 3.4 tree. A new method is fine. Really.

msg220149 - (view)

Author: Roundup Robot (python-dev) (Python triager)

Date: 2014-06-10 08:27

New changeset 7912179335cc by Victor Stinner in branch '3.4': Issue #21326: Add a new is_closed() method to asyncio.BaseEventLoop http://hg.python.org/cpython/rev/7912179335cc

msg220151 - (view)

Author: STINNER Victor (vstinner) * (Python committer)

Date: 2014-06-10 08:30

This issue was discussed on the python-dev mailing list. The conclusion is that adding a new method to asyncio is safe because asyncio has a "provisional API" (whereas the selectors module doesn't).

Ok, Python 3.4.2 will have the new method BaseEventLoop.is_closed(), that's all.

msg220967 - (view)

Author: STINNER Victor (vstinner) * (Python committer)

Date: 2014-06-19 11:11

The initial issue is now fixed, thanks for the report Mark Dickinson.

History

Date

User

Action

Args

2022-04-11 14:58:02

admin

set

github: 65525

2014-06-19 11:11:26

vstinner

set

status: open -> closed
resolution: fixed
messages: +

2014-06-10 08:30:31

vstinner

set

messages: +
versions: + Python 3.4

2014-06-10 08:27:23

python-dev

set

messages: +

2014-06-06 11:11:11

giampaolo.rodola

set

components: + asyncio

2014-06-05 22:26:11

gvanrossum

set

messages: +

2014-06-03 23:47:15

vstinner

set

files: + asyncio_closed_py34.patch
keywords: + patch
messages: +

2014-06-03 23:37:54

yselivanov

set

nosy: + yselivanov

2014-06-03 23:17:55

vstinner

set

messages: +

2014-06-03 23:08:03

python-dev

set

nosy: + python-dev
messages: +

2014-05-28 22:56:54

vstinner

set

nosy: + vstinner
messages: +

2014-04-22 14:45:48

mark.dickinson

set

messages: +

2014-04-22 14:44:53

mark.dickinson

set

messages: +

2014-04-22 14:33:10

gvanrossum

set

priority: normal -> low

messages: +

2014-04-22 08:12:42

mark.dickinson

create