Avaiga / taipy

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

[🐛 BUG] cannot access sequences attribute #1359

Closed FredLL-Avaiga closed 4 months ago

FredLL-Avaiga commented 4 months ago

What went wrong? 🤔

When I start the server, sometimes, I get an error saying that the scenario does not have a sequences attribute. The error is fired when accessing the sequence on receiving a creation event for that sequence.

Steps to Reproduce Issue

import datetime as dt

import numpy as np
import pandas as pd

import taipy as tp

# from taipy.auth import Authenticator, Authorize, IsAuthenticated
from taipy.config import Config, Frequency, Scope
from taipy.core import DataNode, Task

# from taipy.enterprise.gui import AuthorizedPage, get_credentials, login, logout
from taipy.gui import Html, State, notify

# from taipy.gui_core._GuiCoreLib import _GuiCore

# Config.configure_authentication("taipy", "my_secret_key", 1200)

# roles = {"user": ["TAIPY_READER", "TAIPY_ADMIN"]}
# auth = Authenticator("taipy", roles=roles)

Config.configure_job_executions(mode="standalone")

training_data = pd.DataFrame(
    {
        "year": [1789] * 61,
        "month": [6] * 30 + [7] * 31,
        "day": list(range(1, 31)) + list(range(1, 32)),
        "x": np.random.normal(0, 1, 61),
    }
)

# ############################################################
# Algos
# ############################################################
def clean_data(initial_dataset: pd.DataFrame):
    print("     Cleaning data")

    def build_date(row):
        return dt.datetime(int(row["year"]), int(row["month"]), int(row["day"]))

    return pd.DataFrame({"Date": initial_dataset.apply(build_date, axis=1), "Value": initial_dataset["x"]})

def predict(cleaned_dataset: pd.DataFrame, day: dt.datetime):
    print("     Predicting")
    train_dataset = cleaned_dataset[cleaned_dataset["Date"] < day]
    predictions = train_dataset["Value"][-30:].reset_index(drop=True)
    return predictions

def evaluate(predictions, cleaned_dataset, day):
    print("     Evaluating")
    expected = cleaned_dataset.loc[cleaned_dataset["Date"] >= day, "Value"][:30].reset_index(drop=True)
    mae = ((predictions - expected) ** 2).mean()
    return mae

def on_change(state: State, var: str, val):
    print(f"on_change(state, var={var}, val={val}) (type={type(val).__name__})")

def on_dag_action(state: State, entity: Task | DataNode):
    print(f"on_dag_action(state, {entity})")

# ############################################################
# Config
# ############################################################
## Input Data Nodes
initial_dataset_cfg = Config.configure_data_node(id="initial_dataset", scope=Scope.GLOBAL)

# We assume the current day is the 26th of July 2021.
# This day can be changed to simulate multiple executions of scenarios on different days
day_cfg = Config.configure_data_node(id="day", default_data=dt.datetime(2021, 7, 26))

## Remaining Data Node
cleaned_dataset_cfg = Config.configure_data_node(id="cleaned_dataset", scope=Scope.GLOBAL)
predictions_cfg = Config.configure_data_node(id="predictions")

# Task config objects
clean_data_task_cfg = Config.configure_task(
    id="clean_data", function=clean_data, input=initial_dataset_cfg, output=cleaned_dataset_cfg, skippable=True
)

predict_task_cfg = Config.configure_task(
    id="predict", function=predict, input=[cleaned_dataset_cfg, day_cfg], output=predictions_cfg
)

evaluation_cfg = Config.configure_data_node(id="evaluation")
evaluate_task_cfg = Config.configure_task(
    id="evaluate", function=evaluate, input=[predictions_cfg, cleaned_dataset_cfg, day_cfg], output=evaluation_cfg
)

# Configure our scenario config.
scenario_cfg = Config.configure_scenario(
    id="scenario",
    task_configs=[clean_data_task_cfg, predict_task_cfg, evaluate_task_cfg],
    sequences={"baseline": [clean_data_task_cfg, predict_task_cfg, evaluate_task_cfg]},
    frequency=Frequency.MONTHLY,
    authorized_tags=["tata", "toto"]
)

# ############################################################
# App
# ############################################################
scenario = None
df_metrics = None
data_node = None
default_data = {"x": [0], "y": [0]}

cred = None

def on_init(state):
    s1 = tp.create_scenario(scenario_cfg, dt.datetime(1789, 7, 14), "First")
    s1.properties["toto"] = "tata"
    s1.initial_dataset.write(training_data)
    s1.data = dt.date(year=1789, month=7, day=14)
    s2 = tp.create_scenario(scenario_cfg, dt.datetime(1789, 7, 15), "Second")
    s2.initial_dataset.write(training_data)
    s2.data = dt.date(year=1789, month=7, day=15)
    s3 = tp.create_scenario(scenario_cfg, dt.datetime(1789, 7, 16), "Third")
    s3.initial_dataset.write(training_data)
    s3.data = dt.date(year=1789, month=7, day=16)
    s4 = tp.create_scenario(scenario_cfg, dt.datetime(1789, 7, 17), "Fourth")
    s4.initial_dataset.write(training_data)
    s4.data = dt.date(year=1789, month=7, day=17)

    maes = []
    names = []

    for scenario in tp.get_scenarios():
        evaluation = scenario.evaluation.read()
        maes.append(evaluation)
        names.append(scenario.name)

    seq = s1.sequences["baseline"]
    try:
        s1.add_sequence("baseline1", list(seq.tasks.values()))
    except Exception as e:
        print(f"add_sequence {type(e)} {e}")

    state.df_metrics = pd.DataFrame({"Names": names, "MAE": maes})

def on_submission_change(state: State, entity, details: dict):
    notify(state, "I", f"on_submission_change(state, entity={entity}, details={details})")

def on_add_seq(state: State):
    if state.scenario:
        with state.scenario:
            seqs = state.scenario.sequences
            state.scenario.add_sequence(f"Sequence{len(seqs) +1}", list(seqs["baseline"].tasks.values()))

dn = None

# Scenario Page
scenario_md = """
<|{scenario}|scenario_selector|multiple|sort=day.last_edit_date;*|>
<|Add Sequence|button|on_action=on_add_seq|>
<|{dn}|data_node_selector|scenario={scenario}|>
<|{scenario}|scenario|on_submission_change=on_submission_change|>
<|{scenario}|scenario_dag|width=100%|on_action=on_dag_action|>
"""
scenario_html = """
<h1>Scenario html</h1>
<taipy_gui_core:scenario_selector>{scenario}</taipy_gui_core:scenario_selector>
<taipy_gui_core:scenario>{scenario}</taipy_gui_core:scenario>
<taipy_gui_core:scenario_dag width="100%" on_action="">{scenario}</taipy_gui_core:scenario_dag>
"""

toggles = {f"_{i}": None for i in range(10)}

multi_toggle = "# Multi toggle"
for count in range(10):
    multi_toggle += f"\n<|{{toggles._{count}}}|toggle|lov=item 1;item 2;item 3|>"

num_lov = list(range(10))
num_val = 3
num_lov_page="""
# Num LoV
<|{num_val}|selector|lov={num_lov}|adapter={str}|>
"""

# Data Node Page
def is_dataframe(obj):
    if obj is not None:
        return isinstance(obj.read(), pd.DataFrame) or isinstance(obj.read(), pd.Series)
    return False

def return_dataframe(obj):
    return pd.DataFrame(obj.read()) if is_dataframe(obj) else default_data

def return_text(obj):
    if obj is not None:
        return obj.read() if not (is_dataframe(obj)) else ""
    return ""

datanode_selector = """
<|{data_node}|data_node_selector|scenario={scenario}|>

------

<|part|render={data_node}|
<|{data_node}|data_node|>
|>
"""

pages = {
    "/": "<|toggle|theme|><br/><br/><|navbar|>",
    "Scenario": scenario_md,
    "ScenarioHtml": Html(scenario_html),
    "Datanode": datanode_selector,
    "MutiToggle": multi_toggle,
    "Num_LoV": num_lov_page,
    # "Comparison": comparison_md,
}
if __name__ == "__main__":
    tp.Core().run()

    gui = tp.Gui(pages=pages)
    gui.run(debug=True)

Screenshots

DESCRIPTION

Version of Taipy

develop

Acceptance Criteria

Code of Conduct

jrobinAV commented 4 months ago

@FredLL-Avaiga I cannot get a message saying "the scenario does not have a sequences attribute". I got this error. Is that what you are talking about?

EDITED: Removed wrong stacktrace

...
AttributeError: 'types.SimpleNamespace' object has no attribute '_TpL_tp_TpExPr_gui_get_adapted_lov_taipy_gui_core_Ctx_get_datanodes_tree_scenario_tgc_datanode_TPMDL_3_0'
FredLL-Avaiga commented 4 months ago

No it's not

jrobinAV commented 4 months ago

So I cannot reproduce your issue.

trgiangdo commented 4 months ago

Hello @FredLL-Avaiga @jrobinAV, I tried to reproduce the bug.

It happens when it first tried to run the code with taipy 3.1.1, and taipy develop as well. However, after tinkering with the code, it disappears. Then, I tried to delete the pycache, it reappears 😣

I will continue investigating the problem.