Avaiga / taipy

Turns Data and AI algorithms into production-ready web applications in no time.
https://www.taipy.io
Apache License 2.0
10.94k stars 775 forks source link

`UserWarning: on_action: 'on_button_action' is not a valid function` #164

Closed saurbhc closed 9 months ago

saurbhc commented 1 year ago

Trying to follow the tutorial in docs - https://docs.taipy.io/en/latest/getting_started/getting-started-gui/step_03/ReadMe/

Not sure where this warning is coming from and notify/'Reset' is not working, to reproduce, here's the code (main.py)

from textwrap import dedent

from taipy.gui import Gui, notify

def main() -> int:
    text = "Original text"

    page = dedent("""\
    # Getting started with *Taipy*

    My text: <|{text}|>

    <|{text}|input|>

    <|Run local|button|on_action=on_button_action|>

    """)

    Gui(page=page).run(use_reloader=True)

    return 0

def on_button_action(state):
    notify(state, "info", f"The text is {state.text}")
    state.text = "Button Pressed"

def on_change(state, var_name, var_value):
    if var_name == "text" and var_value == "Reset":
        state.text = ""
        return

if __name__ == "__main__":
    raise SystemExit(main())
$ cat requirements.txt
taipy
torch
transformers

# jupyter notebook
jupyterlab
$ python --version
Python 3.11.2
$ pip freeze | grep taipy
taipy==2.2.0
taipy-config==2.2.0
taipy-core==2.2.3
taipy-gui==2.2.1
taipy-rest==2.2.1
$ python main.py --port 5001
[2023-06-04 22:22:16,655][Taipy][INFO] application is running in 'debug' mode
[2023-06-04 22:22:16,655][Taipy][INFO] 'allow_unsafe_werkzeug' has been set to True
[2023-06-04 22:22:16,655][Taipy][INFO] 'async_mode' parameter has been overridden to 'threading'. Using Flask built-in development server with debug mode
[2023-06-04 22:22:16,836][Taipy][INFO]  * Server starting on http://127.0.0.1:5001
 * Serving Flask app 'Taipy'
 * Debug mode: on
[2023-06-04 22:22:18,630][Taipy][INFO]  * Server reloaded on http://127.0.0.1:5001
WARNING:root:
--- 1 warning(s) were found for page '/' in variable 'page' ---
 - Warning 1:  button.on_action: on_button_action is not a function
----------------------------------------------------------------

UserWarning: on_action: 'on_button_action' is not a valid function
FlorianJacta commented 1 year ago

The Warning means that Taipy didn't find the function: on_button_action. It comes from the fact that the Gui is not being run directly in the Python script.

The code below works:

from textwrap import dedent

from taipy.gui import Gui, notify

text = "Original text"

page = dedent("""\
# Getting started with *Taipy*

My text: <|{text}|>

<|{text}|input|>

<|Run local|button|on_action=on_button_action|>

""")

def on_button_action(state):
    notify(state, "info", f"The text is {state.text}")
    state.text = "Button Pressed"

def on_change(state, var_name, var_value):
    if var_name == "text" and var_value == "Reset":
        state.text = ""
        return

if __name__ == "__main__":
    Gui(page=page).run(use_reloader=True)

Is there a reason why you would want to run it inside a function?

saurbhc commented 1 year ago

New setup works. Or even if I put the functions inside the main() function like this works too:

from textwrap import dedent

from taipy.gui import Gui, notify

def main() -> int:
    def on_button_action(state):
        notify(state, "info", f"The text is {state.text}")
        state.text = "Button Pressed"

    def on_change(state, var_name, var_value):
        if var_name == "text" and var_value == "Reset":
            state.text = ""
            return

    text = "Original text"

    page = dedent("""\
    # Getting started with *Taipy*

    My text: <|{text}|>

    <|{text}|input|>

    <|Run local|button|on_action=on_button_action|>

    """)

    Gui(page=page).run(use_reloader=True)

    return 0

if __name__ == "__main__":
    raise SystemExit(main())

I wonder why? After a little debugging, it looks like, taipy is looking for functions in locals() scope, not in globals() scope

In the working code, these functions are present in locals() scope

(Pdb) pp locals()
{'on_button_action': <function main.<locals>.on_button_action at 0x10cd9a520>,
 'on_change': <function main.<locals>.on_change at 0x10ce36660>}

In the previous version, they were not in locals() but in globals()

(Pdb) pp globals()
{'Gui': <class 'taipy.gui.gui.Gui'>,
 '__annotations__': {},
 '__builtins__': <module 'builtins' (built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': '/Users/saurabhchopra/dev/learnings/learn_taipy/main1.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10d0ad450>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'dedent': <function dedent at 0x10d1a63e0>,
 'main': <function main at 0x10d1a65c0>,
 'notify': <function notify at 0x137231bc0>,
 'on_button_action': <function on_button_action at 0x10d0d4b80>,
 'on_change': <function on_change at 0x10d10a520>}

The problem with this setup would be that it dosen't scale to a big project? - When these functions are imported from different .py files, they will come in globals() scope and taipy won't discover them.

Might I propose this as a new Feature Request?

FlorianJacta commented 1 year ago

This is done on purpose. We propose in Taipy a Page Scope where you can import efficiently functions or variables from other modules to decompose your code. We normally decompose the code as below:

You can find in pagex.py all the functions, the Markdown, and variables needed for a particular page. In main.py, you provide the global logic of the application as well as the creation of the multipage application.

Take a look at this repository , for example. We import in the main.py, the global functions that Taipy needs across pages. All the other variables, pages, and functions specific for a page can be found in the page folder. Like this, you can independently use the same variable name for different pages.

However, it means that the Gui has to be defined outside a function, as Taipy will not be able to look outside the function.

What do you think about this setup?

FlorianJacta commented 1 year ago

Have you had the time to check this solution? What do you think?

FlorianJacta commented 9 months ago

The documentation has totally changed. We also changed to Taipy 3.0. Were you able to test the code? Can we close the issue?

Here is the new version of this code.