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

Support async functions for pn.bind #3262

Closed
MarcSkovMadsen opened this issue Mar 26, 2022 · 2 comments · Fixed by #3264
Closed

Support async functions for pn.bind #3262

MarcSkovMadsen opened this issue Mar 26, 2022 · 2 comments · Fixed by #3264
Labels
type: enhancement Minor feature or improvement to an existing feature
Milestone

Comments

@MarcSkovMadsen
Copy link
Collaborator

MarcSkovMadsen commented Mar 26, 2022

I would like it to be as simple as possible to create performant data apps as possible. This includes sprinkling in async once in a while.

It would make it super easy to use async if pn.bind and pn.depends supported it. But it does not.

When I run the below code I get

c:\repos\private\awesome-panel\.venv\lib\site-packages\param\parameterized.py:2000: RuntimeWarning: coroutine 'train' was never awaited
  watcher.fn(*args, **kwargs)
import panel as pn
import sys
import asyncio


pn.extension(sizing_mode="stretch_width")

terminal = pn.widgets.Terminal(height=400).servable()

sys.stdout=terminal

async def train(e, n=5):
    print("train")
    for n in range(n):
        await asyncio.sleep(1)
        print(n)

button = pn.widgets.Button(name="Train", button_type="primary").servable()

pn.bind(train, e=button, watch=True)
import panel as pn
import sys
import asyncio


pn.extension(sizing_mode="stretch_width")

terminal = pn.widgets.Terminal(height=400).servable()

sys.stdout=terminal

button = pn.widgets.Button(name="Train", button_type="primary").servable()

@pn.depends(button, watch=True)
async def train(e, n=5):
    print("train")
    for n in range(n):
        await asyncio.sleep(1)
        print(n)

My Feature Request is to support async for pn.bind and pn.depends.

@MarcSkovMadsen MarcSkovMadsen added the type: enhancement Minor feature or improvement to an existing feature label Mar 26, 2022
@MarcSkovMadsen MarcSkovMadsen added this to the Wishlist milestone Mar 26, 2022
@hoxbro
Copy link
Member

hoxbro commented Mar 26, 2022

I think I got this to work. Two changes are needed one in param and another in panel. Both are by checking if the function to watch is an async function and then making the wrapped/cb function an async function too. I will submit PR to get this implemented.

In param:
https://github.com/holoviz/param/blob/fb6f4d92d7ce9006deb269669ebe34cdaa006d4a/param/parameterized.py#L432-L435

In panel:

panel/panel/depends.py

Lines 151 to 172 in 98a63e8

@depends(**dependencies, watch=watch)
def wrapped(*wargs, **wkwargs):
combined_args = []
for arg in args:
if hasattr(arg, '_dinfo'):
arg = arg()
elif isinstance(arg, param.Parameter):
arg = getattr(arg.owner, arg.name)
combined_args.append(arg)
combined_args += list(wargs)
combined_kwargs = {}
for kw, arg in kwargs.items():
if hasattr(arg, '_dinfo'):
arg = arg()
elif isinstance(arg, param.Parameter):
arg = getattr(arg.owner, arg.name)
combined_kwargs[kw] = arg
for kw, arg in wkwargs.items():
if kw.startswith('__arg') or kw.startswith('__kwarg'):
continue
combined_kwargs[kw] = arg
return function(*combined_args, **combined_kwargs)

@philippjfr
Copy link
Member

Yeah, looks like I handled it for non-watched functions but not for watch=True.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement Minor feature or improvement to an existing feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants