callbackinvoketaipy

invoke_long_callback in Taipy


I need run a "long_callback fuction" for long time task. I didn´t understand well about the callback details(link: https://docs.taipy.io/en/latest/manuals/gui/callbacks/.)

I have the button:

<|INICIAR|button|on_action={on_iniciar_ini}|id=btn01|>

and the callbacks

def on_iniciar_ini(state, id, action):
    notify(state, "info", "Heavy task started...")
    invoke_long_callback(state, on_iniciar, [...heavy_function arguments...])

def on_iniciar(state, id, action):

    C4=state.Jiga.Status_AI0()  #with Pulldown 
    C3=state.Jiga.Status_AI1()  #with Pulldown 
    ...more code

When I use without "heavy_function arguments"

 invoke_long_callback(state, on_iniciar, [])

I had the error

TaipyGuiWarning: invoke_long_callback(): Exception raised in function on_iniciar(). on_iniciar() missing 3 required positional arguments: 'state', 'id', and 'action'

I dont understand if i need pass again the parameters in the "heavy_function arguments", this is, the state, ID or especify all state variables that I use inner the on_iniciar function, for example state.Jiga

enter image description here

When I use:

def on_iniciar_ini(state, id, action):
    notify(state, "info", "Heavy task started...")
    invoke_long_callback(state,on_iniciar(state))
    #invoke_long_callback(state, on_iniciar, [])


def on_iniciar(state):

    C4=state.Jiga.Status_AI0()   
    C3=state.Jiga.Status_AI1()  #with Pulldown
... more code

My code run, but I have an exception in thread

Exception in thread Thread-64 (user_function_in_thread): Traceback (most recent call last): File "C:\Users\jaime.rodriguez\MULTELETRONIC\SoftJigas\PP000938_SoftJig.venv\lib\site-packages\taipy\gui\gui_actions.py", line 341, in user_function_in_thread res = user_function(*uf_args) TypeError: 'NoneType' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\threading.py", line 1016, in _bootstrap_inner self.run() File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\threading.py", line 953, in run self._target(*self._args, **self._kwargs) File "C:\Users\jaime.rodriguez\XXXX\XXXX\PP000938_SoftJig.venv\lib\site-packages\taipy\gui\gui_actions.py", line 344, in user_function_in_thread callback_on_status(False, e, user_function.name) AttributeError: 'NoneType' object has no attribute 'name'. Did you mean: 'ne'?

Someone please help me to understand how make the long callback!


Solution

  • The goal of the invoke_long_callback is typically to handle long functions without blocking the GUI (asynchronous call). Two functions usually are passed to the invoke_long_callback.

    1. The first is your heavy task, which will take a lot of time. This function cannot have the state as an argument. You can put all the parameters that you want before calling this function.

    2. The second function is the function that is called with the state. The goal is that this function will be called at the end of the heavy task function. It can also be called at a specific frequency if wanted. The goal is to be able to actualize the web page after the execution of the heavy task.

    In your example, on_iniciar() is your heavy function and should not have the state in its parameters. Its parameters should be whatever you want and be transferred in the heavy function through the invoke_long_callback:

    def on_iniciar_ini(state, id, action):
        notify(state, "info", "Heavy task started...")
        C4=state.Jiga.Status_AI0()  #with Pulldown 
        C3=state.Jiga.Status_AI1()  #with Pulldown
        ... 
        invoke_long_callback(state, on_iniciar, [C4, C3, ...], on_iniciar_finished)
    
    def on_iniciar(C4, C3):
       # more code that does your heavy task
       ...
    
    def on_iniciar_finished(state, status):
        # code that will be executed at the end of the task
        if status:
            notify(state, "success", f"The heavy task has finished!")
        else:
            notify(state, "error", f"The heavy task has failed somehow.")
    
    
    

    You can get the result of your heavy function in on_iniciar_finished if needed.

    Example of code using invoke_long_callback:

    from taipy.gui import Gui, Markdown, invoke_long_callback, notify
    import numpy as np
    
    status = 0
    num_iterations = 10_000_000
    pi_list = []
    
    def pi_approx(num_iterations):
        k, s = 3.0, 1.0
        pi_list = []
        for i in range(num_iterations):
            s = s-((1/k) * (-1)**i)
            k += 2
            if (i+1)%(int(num_iterations/1_000)+1) == 0:
                pi_list += [np.abs(4*s-np.pi)]
    
        return pi_list
    
        
    def heavy_status(state, status, pi_list):
        notify(state, 'i', f"Status parameter: {status}")
        if isinstance(status, bool):
            if status:
                notify(state, 'success', "Finished")
                state.pi_list = pi_list
            else:
                notify(state, 'error', f"An error was raised")
        else:
            state.status += 1
        
    def on_action(state):
        invoke_long_callback(state,
                             pi_approx, [int(state.num_iterations)],
                             heavy_status, [],
                             2000)  
            
    page = Markdown("""
    How many times was the status function called? <|{status}|>
    
    ## Number of approximation
    
    <|{num_iterations}|number|label=# of approximation|>
    
    <|Approximate pie|button|on_action=on_action|>
    
    ## Evolution of approximation
    <|{pi_list}|chart|layout={layout}|>
    """)
    
    layout = {
        "yaxis": {
        "type": 'log',
        "autorange": True
        }
      }
    
    Gui(page).run()