Skip to content

change of behaviour in do_one_iteration(), and qt5 loop integration issues? #825

Closed

Description

@gsteele13

I was wondering: did something significant change in do_one_iteration() between 5.3.2 and 6.4.1?

I used to use this to process messages from ipywidgets during a loop, but this seems no longer possible:

https://stackoverflow.com/questions/70436504/problem-with-event-loops-gui-qt5-and-ipywidgets-in-a-jupyter-notebook

There was a slightly more complicated solution I found using asyncio but this also breaks if I need to use a qt5 gui loop.

I guess my questions are:

  • Is there a workflow that is still possible to how I previously was using do_one_iteration()?
  • Is there a solution to the got Future <Future pending> attached to a different loop problem when using a qt5 gui event loop?

Thanks!
Gary

Activity

  1. changed the title [-]change of behaviour in do_one_iteration() and qt5 loop integration?[/-] [+]change of behaviour in do_one_iteration(), and qt5 loop integration issues?[/+] on Dec 21, 2021
  2. blink1073 commented on Dec 24, 2021

    @blink1073
    Contributor

    @ccordoba12 might this be related to #531?

  3. gsteele13 commented on Jan 3, 2022

    @gsteele13
    Author

    Minor update from my side: I recently restarted with a new environment.

    The problem with the qt5 gui loop is still there (although warning about <Future pending> attached to a different loop is gone?)

    I've also made a video if you want to see it live:

    https://tudelft.zoom.us/rec/play/CgFo2_JIS8qdNQm8mJRwheOygc_CsCRmv4mNq4TIcvAnzPqLTzkNE0u6w0BlUrI2ckkvrQRXUlu0d3A8.TKUOmocoDlhmEG5n?continueMode=true&_x_zm_rtaid=chuscAkeT1OVGF1NZcosQQ.1641226261305.d72721c18f45943ad7e889aae4e8f2f5&_x_zm_rhtaid=584

    (and posted on the ipywidgets discourse forum, but edited post too many times too quickly and it got marked as spam...i guess a staff member will unblock it)

    I've also done some more reading into the low level implementation of the ipywidgets sync via the kernel COMMS interface. My guess is that coroutines running in the asyncio GUI event loop are somehow triggering the kernel to refresh and process received COMMS messages, but ones running in the qt5 GUI loop are not...?

  4. ccordoba12 commented on Jan 4, 2022

    @ccordoba12
    Member

    I think the problem is that do_one_iteration is now a coroutine, so you can't expect to call it and get a response immediately. However, you can make it run synchronously again with asyncio.

    A similar problem (I think) for the Tk was solved here: #830.

  5. gsteele13 commented on Jan 5, 2022

    @gsteele13
    Author

    Thanks @ccordoba12 for pointing me in the right direction!

    So if I understand correctly: if I install the latest version of ipykernel from github, then the following code should work as a replacement for my previous direct call of do_one_iteration()?

        task = loop.create_task(do_one_iteration())
        loop.run_until_complete(task)
    

    Thanks!
    Gary

  6. gsteele13 commented on Jan 5, 2022

    @gsteele13
    Author

    I guess that I don't fully understand how to solve this issue.I just cloned and installed ipykernel from github:

    Selected Jupyter core packages...
    IPython          : 7.29.0
    ipykernel        : 6.6.1
    ipywidgets       : 7.6.5
    jupyter_client   : 7.0.6
    jupyter_core     : 4.9.1
    jupyter_server   : not installed
    jupyterlab       : not installed
    nbclient         : 0.5.3
    nbconvert        : 6.1.0
    nbformat         : 5.1.3
    notebook         : 6.4.6
    qtconsole        : 5.1.1
    traitlets        : 5.1.1
    

    And I then tried the following, but apparently this is not the way:

    import ipywidgets as widgets
    from time import sleep
    import IPython
    import asyncio
    
    do_one_iteration = IPython.get_ipython().kernel.do_one_iteration
    loop = asyncio.get_running_loop()
    
    w = widgets.ToggleButton()
    display(w)
    
    i=0
    while True:
        # This one gives: "asyncio.run() cannot be called from a running event loop"
        # asyncio.run(do_one_iteration())
        
        # This one gives "QueueEmpty:"
        # await do_one_iteration()
        
        # the original one that worked, but now gives coroutine 
        # 'Kernel.do_one_iteration' was never awaited
        # and then updates are not propagated 
        # do_one_iteration()
        
        # This does not appear to be the solution results in 
        # RuntimeError: This event loop is already running
        task = loop.create_task(do_one_iteration())
        loop.run_until_complete(task)
      
        print(i, w.value, end="\r")
        w.decription = str(i)
        sleep(0.5)
        i+=1
    

    as this gives an error:

    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    /var/folders/5t/sp26pw315mnbcfyyt9l9bvpwqb6r8t/T/ipykernel_85521/4094668809.py in <module>
         26     # RuntimeError: This event loop is already running
         27     task = loop.create_task(do_one_iteration())
    ---> 28     loop.run_until_complete(task)
         29 
         30     print(i, w.value, end="\r")
    
    ~/anaconda3/envs/dec2021/lib/python3.9/asyncio/base_events.py in run_until_complete(self, future)
        616         """
        617         self._check_closed()
    --> 618         self._check_running()
        619 
        620         new_task = not futures.isfuture(future)
    
    ~/anaconda3/envs/dec2021/lib/python3.9/asyncio/base_events.py in _check_running(self)
        576     def _check_running(self):
        577         if self.is_running():
    --> 578             raise RuntimeError('This event loop is already running')
        579         if events._get_running_loop() is not None:
        580             raise RuntimeError(
    
    RuntimeError: This event loop is already running
    

    Any advice appreciated!

    Thanks,
    Gary

  7. ccordoba12 commented on Jan 5, 2022

    @ccordoba12
    Member

    Probably you need to use nest_asyncio first (sorry, I don't understand asyncio loops very well).

    @impact27, do yo know how to run do_one_iteration directly?

  8. impact27 commented on Jan 5, 2022

    @impact27
    Contributor

    Asyncio loops are not rentrant. But you can just use nest_asyncio for that. Just add to your script:

    import nest_asyncio
    nest_asyncio.apply()
    
  9. impact27 commented on Jan 5, 2022

    @impact27
    Contributor

    Or in IPython:

    In [2]: do_one_iteration = get_ipython().kernel.do_one_iteration
    
    In [3]: await do_one_iteration()
    
  10. gsteele13 commented on Jan 5, 2022

    @gsteele13
    Author

    Or in IPython:

    In [2]: do_one_iteration = get_ipython().kernel.do_one_iteration
    
    In [3]: await do_one_iteration()
    

    This one doesn't work for me:

    Screenshot 2022-01-05 at 17 52 38

    (was also one of my earlier attempts) I get an error "Queue Empty"

  11. gsteele13 commented on Jan 5, 2022

    @gsteele13
    Author

    Asyncio loops are not rentrant. But you can just use nest_asyncio for that. Just add to your script:

    import nest_asyncio
    nest_asyncio.apply()
    

    Amazing! Perfect! I don't understand it but it works :) Thanks!

  12. impact27 commented on Jan 5, 2022

    @impact27
    Contributor

    Or in IPython:

    In [2]: do_one_iteration = get_ipython().kernel.do_one_iteration
    
    In [3]: await do_one_iteration()
    

    This one doesn't work for me:

    Screenshot 2022-01-05 at 17 52 38

    (was also one of my earlier attempts) I get an error "Queue Empty"

    This is strange. You can even see in the traceback you attach where the error should be caught.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions