holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.43k stars 484 forks source link

Generator function not working #6295

Open MarcSkovMadsen opened 5 months ago

MarcSkovMadsen commented 5 months ago

I'm on panel==1.3.8. I thought generator functions worked. But it seems not.

Furthermore they just don't display anything which can make it super hard to understand for beginners.

I would suggest generator functions worked. They can be a simple way for users to create animations and progressively updating apps.

Alternative that some exception was raised.

Minimum Reproducible Example

import panel as pn
from time import sleep
pn.extension()

def generator():
    yield "hello"
    sleep(0.3)
    yield "world"

pn.pane.Str(generator).servable()

The app is just blank and no errors are shown in the terminal.

image

Additional Context

Async Generators work. But async is not for basic users.

ahuang11 commented 5 months ago

That is why I commented on https://github.com/holoviz/panel/pull/6213/files#diff-23f2a17c4d19972dadffda8107a86a3900a75f300afe3e5f518ea7e51d9552ecR45-R61

But surprisingly that works haha

MarcSkovMadsen commented 5 months ago

That is why I commented on https://github.com/holoviz/panel/pull/6213/files#diff-23f2a17c4d19972dadffda8107a86a3900a75f300afe3e5f518ea7e51d9552ecR45-R61

But surprisingly that works haha

For me generator functions are working in the chat interface. My guess is that I filed a bug back in the days and you fixed it?

philippjfr commented 5 months ago

Generators really do not seem useful here, a generator function is blocking, therefore even if this did work you'd just get the final output and never see the intermediate outputs.

philippjfr commented 5 months ago

There is clearly something wrong here though, you should see something or get an error.

MarcSkovMadsen commented 5 months ago

Generators really do not seem useful here, a generator function is blocking, therefore even if this did work you'd just get the final output and never see the intermediate outputs.

Unless you wrapped the generator in an async generator behind the scenes that did await a little bit for each yield. The benefit would be simplicity for basic users.

philippjfr commented 5 months ago

Yeah would have to be executed on a thread but with asyncify that should be easy right?

ahuang11 commented 5 months ago

Yes this is what is done in ChatInterface: https://github.com/holoviz/panel/blob/main/panel/chat/feed.py#L498-L501

Ideally, Panel has a public pn.execute_in_thread util.

MarcSkovMadsen commented 5 months ago

I'm used to generators working. For example the Migrate from Streamlit guides contains example close to the below which I will be adding to the basic tutorial.

import panel as pn
from time import sleep

pn.extension()

def classify(image):
    sleep(2)
    return "Wind Turbine"

run = pn.widgets.Button(name="Run", button_type="primary")

progress_message = pn.Row(
    pn.indicators.LoadingSpinner(
        value=True, width=25, height=25, align="center", margin=(5, 0, 5, 10)
    ),
    pn.panel("Running classifier ...", margin=0),
)

def run_classification(running):
    print(running)
    if not running:
        yield "Click Run"
        return

    yield progress_message
    prediction = classify(None)
    yield f"Its a {prediction}"

pn.Column(run, pn.bind(run_classification, run)).servable()

https://github.com/holoviz/panel/assets/42288570/aee0e381-b799-4540-bb42-ea358e1ba448

philippjfr commented 5 months ago

This will have to be implemented at the Param level. Currently Param does not recognize generators as valid refs and what's happening here is that a much older mechanism in Param is allowing the generator to be a valid value for the parameter, which seemingly does not resolve the value correctly. I fully agree that we can and should make this work.