Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asyncio: request clearer error message when event loop closed #65525

Closed
mdickinson opened this issue Apr 22, 2014 · 12 comments
Closed

asyncio: request clearer error message when event loop closed #65525

mdickinson opened this issue Apr 22, 2014 · 12 comments
Labels
stdlib Python modules in the Lib dir topic-asyncio type-feature A feature request or enhancement

Comments

@mdickinson
Copy link
Member

BPO 21326
Nosy @gvanrossum, @mdickinson, @vstinner, @1st1
Files
  • asyncio_closed_py34.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2014-06-19.11:11:26.259>
    created_at = <Date 2014-04-22.08:12:42.964>
    labels = ['type-feature', 'library', 'expert-asyncio']
    title = 'asyncio: request clearer error message when event loop closed'
    updated_at = <Date 2014-06-19.11:11:26.257>
    user = 'https://github.com/mdickinson'

    bugs.python.org fields:

    activity = <Date 2014-06-19.11:11:26.257>
    actor = 'vstinner'
    assignee = 'none'
    closed = True
    closed_date = <Date 2014-06-19.11:11:26.259>
    closer = 'vstinner'
    components = ['Library (Lib)', 'asyncio']
    creation = <Date 2014-04-22.08:12:42.964>
    creator = 'mark.dickinson'
    dependencies = []
    files = ['35474']
    hgrepos = []
    issue_num = 21326
    keywords = ['patch']
    message_count = 12.0
    messages = ['216994', '217007', '217008', '217009', '219319', '219731', '219732', '219734', '219851', '220149', '220151', '220967']
    nosy_count = 5.0
    nosy_names = ['gvanrossum', 'mark.dickinson', 'vstinner', 'python-dev', 'yselivanov']
    pr_nums = []
    priority = 'low'
    resolution = 'fixed'
    stage = 'needs patch'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue21326'
    versions = ['Python 3.4', 'Python 3.5']

    @mdickinson
    Copy link
    Member Author

    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 "<stdin>", line 1, in <module>
      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 "<stdin>", line 1, in <module>
      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'

    @mdickinson mdickinson added stdlib Python modules in the Lib dir type-feature A feature request or enhancement labels Apr 22, 2014
    @gvanrossum
    Copy link
    Member

    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?

    @mdickinson
    Copy link
    Member Author

    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.

    @mdickinson
    Copy link
    Member Author

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

    That sounds good to me.

    @vstinner
    Copy link
    Member

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

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jun 3, 2014

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

    @vstinner
    Copy link
    Member

    vstinner commented Jun 3, 2014

    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.

    @vstinner
    Copy link
    Member

    vstinner commented Jun 3, 2014

    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.

    @gvanrossum
    Copy link
    Member

    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.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jun 10, 2014

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

    @vstinner
    Copy link
    Member

    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.

    @vstinner
    Copy link
    Member

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

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir topic-asyncio type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    4 participants