Error message : Data leaks

English

Summary

Hi. I’m creating a mental calculation game with streamlit. And some of my users gave me this error :

I personnaly never had it when i use the app.

This error appeared on the “survival” level (100 questions that appear one after the other). Sometime after giving 20-30 answers, sometimes just after the first one.

I searched everything in the documentation but i found nothing. If you have any idea, I take it.

Link

Here my github repository : GitHub - leoMainard/Streamlit_calcul
I can’t give you the access of my app because data are save in Deta base.

If you want to try the code, please create yourself 2 new Deta bases (https://www.deta.sh/) and change the keys in functions in code/connection_bdd.py file. I trust you on this.

My code is maybe a little bit long and complecated.

If you have questions, don’t hesitate to ask.

Français

Résumé

Bonjour, je créé actuellement un jeu de calcul mental avec streamlit et certains de mes utilisateurs m’ont fournis cette erreur que je n’ai jamais eu :

Cette erreur apparait dans le mode de jeu “Survival” (100 calculs qui apparaissent les uns après les autres). Parfois l’erreur apparait après 20-30 réponses, parfois juste après une seule.

J’ai cherché partout dans la documentation mais je n’ai rien trouvé. Si vous avez des idées pour résoudre ce problème je suis preneur.

Lien

Voici mon répertoire github : GitHub - leoMainard/Streamlit_calcul
Je ne peux pas vous donner l’accès à mon app car les données sont sauvegardés dans une base de données Deta, et je ne souhaite pas que de nombreux joueurs aillent sur mon appli pour le moment.

Si vous voulez essayer le code, créez vous 2 bases Deta (https://www.deta.sh/) et changez les clés dans les fonctions du fichier dans code/connection_bdd.py. Je vous fait confiance sur ce point.

Mon code est long et peut-être un peu compliqué.

Si vous avez des questions, n’hésitez pas.

Thanks for sharing your question! Can you please include the full error message?

The image is the full error message. This error only occured to my users and they don’t have access to the ‘Manage app’ console. And personnaly, I never had this error.

I don’t know if this error come from a problem of memory or if it’s just a bug.

If you want to try my app, I can add you, just give me your email.

Please share a minimal code snippet so we can reproduce the error

Here is my code for the game part. The error happend on the survival game, line 298 (“st.text_input(label=“survival_label”, value= […] on_change=survival_verif()) # Réponse du joueur”)

import streamlit as st
import time
import datetime
import random as rd


# ------------ FUNCTIONS

st.set_page_config(
    page_title="Calcul Master",
    page_icon="🤖",
    layout="wide",
)

def jeu(niv):
    niv = int(niv)

    if (niv == 1):
        min, max = 1, 10
    elif (niv == 2):
        min, max = 1, 100
    elif (niv == 3):
        min, max = 10, 100

    for i in range(10):

        a = rd.randint(min, max)
        b = rd.randint(min, max)

        value = rd.randint(0, 2)

        if (niv == 3):
            cal = [a * b, f'{a} x {b} = ']
        else:
            if value == 0:
                cal = [a * b, f'{a} x {b} = ']
            elif value == 1:
                cal = [a + b, f'{a} + {b} = ']
            else:
                cal = [a - b, f'{a} - {b} = ']

        st.session_state['cal_' + str(i)] = cal[0]
        st.session_state['cal_print_' + str(i)] = cal[1]



def survival_game(progression):
    if (int(progression) <= 5):
        a = rd.randint(1, 5)
        b = rd.randint(1, 5)

        value = rd.randint(0, 2)

        if value == 0:
            cal = [a - b, f'{a} - {b} = ']
        else:
            cal = [a + b, f'{a} + {b} = ']

    elif (int(progression) <= 10):
        a = rd.randint(3, 10)
        b = rd.randint(3, 10)

        value = rd.randint(0, 2)

        if value == 0:
            cal = [a * b, f'{a} x {b} = ']
        elif value == 1:
            cal = [a + b, f'{a} + {b} = ']
        else:
            cal = [a - b, f'{a} - {b} = ']

    elif (int(progression) <= 15):
        a = round(rd.random(), 1)
        b = round(rd.random(), 1)

        cal = [round(a * b,2), f'{a} x {b} = ']

    elif (int(progression) <= 20):
        a = rd.randint(10, 20)
        b = rd.randint(10, 20)

        value = rd.randint(0, 2)
        if value == 0:
            cal = [a * b, f'{a} x {b} = ']
        elif value == 1:
            cal = [a + b, f'{a} + {b} = ']
        else:
            cal = [a - b, f'{a} - {b} = ']

    elif (int(progression) <= 30):
        a = rd.randint(10, 50)
        b = rd.randint(10, 50)

        cal = [a * b, f'{a} x {b} = ']

    elif (int(progression) <= 40):
        a = rd.randint(100, 1000)
        b = rd.randint(100, 1000)
        value = rd.randint(0, 1)
        if value == 1:
            cal = [a + b, f'{a} + {b} = ']
        else:
            cal = [a - b, f'{a} - {b} = ']

    elif (int(progression) <= 45):
        a = str(rd.randint(10, 50)) + '.' + str(rd.randint(10, 50))
        b = str(rd.randint(10, 50)) + '.' + str(rd.randint(10, 50))

        value = rd.randint(0, 1)

        if value == 1:
            cal = [round(float(a) + float(b),4), f'{a} + {b} = ']
        else:
            cal = [round(float(a) - float(b),4), f'{a} - {b} = ']

    elif (int(progression) <= 50):
        a = rd.randint(100, 500)
        b = rd.randint(3, 10)

        cal = [a * b, f'{a} x {b} = ']

    elif (int(progression) <= 60):
        a = rd.randint(100, 500)
        b = rd.randint(10, 20)

        cal = [a * b, f'{a} x {b} = ']

    elif (int(progression) <= 70):
        a = rd.randint(1000, 5000)
        b = rd.randint(3, 15)

        cal = [a * b, f'{a} x {b} = ']

    elif (int(progression) <= 70):
        a = str(rd.randint(10, 50)) + '.' + str(rd.randint(10, 50))
        b = str(rd.randint(10, 50)) + '.' + str(rd.randint(10, 50))

        cal = [round(float(a) * float(b),4), f'{a} x {b} = ']

    elif (int(progression) <= 80):
        a = str(rd.randint(50, 100)) + '.' + str(rd.randint(50, 100))
        b = str(rd.randint(50, 100)) + '.' + str(rd.randint(50, 100))

        cal = [round(float(a) * float(b),6), f'{a} x {b} = ']

    elif (int(progression) <= 90):
        a = rd.randint(10, 100)
        b = rd.randint(10, 100)

        value = rd.randint(0, 1)

        if value == 1:
            cal = [(a + b) ** 2, f'({a} + {b})² = ']
        else:
            cal = [(a - b) ** 2, f'({a} - {b})² = ']

    elif (int(progression) <= 99):
        a = rd.randint(1, 10)
        b = rd.randint(1, 10)

        value = rd.randint(0, 1)

        if value == 1:
            cal = [((a ** 2) + (b ** 2)) ** 2, f'({a}² + {b}²)² = ']
        else:
            cal = [((a ** 2) - (b ** 2)) ** 2, f'({a}² - {b}²)² = ']

    else:
        cal = [1, 'exp(0) = ']

    st.session_state['survival_cal_print'] = cal[1]
    st.session_state['survival_cal'] = cal[0]



def survival_verif():
    st.session_state['survival_result'] = 1


def confirm_button():
    st.session_state['result'] = 1
    st.session_state['restart'] = 0

def get_sec(time_str):
    """Get seconds from time."""
    m, s, c = time_str.split(':')
    return int(m) * 60 + int(s) + (int(c)/10)



# Sessions pour les calculs, les print et les résultats des niveaux 1 - 2 - 3 ------------------------------------------------------------------------------------
for i in range(10):
    if 'cal_' + str(i) not in st.session_state:
        st.session_state['cal_' + str(i)] = 0
    if 'cal_joueur_' + str(i) not in st.session_state:
        st.session_state['cal_joueur_' + str(i)] = 0
    if 'cal_print_' + str(i) not in st.session_state:
        st.session_state['cal_print_' + str(i)] = 0

# Sessions pour les niveaux 1 - 2 - 3 ------------------------------------------------------------------------------------
if 'result' not in st.session_state:
    st.session_state['result'] = 0

if 'restart' not in st.session_state:
    st.session_state['restart'] = 1

# Sessions pour le niveau Survival ------------------------------------------------------------------------------------
if 'progression_bar' not in st.session_state:
    st.session_state['progression_bar'] = 0

if 'survival_result' not in st.session_state:  # verification des resultats et affichage si erreur
    st.session_state['survival_result'] = 0

if 'survival_cal' not in st.session_state:  # resultat attendu du calcul
    st.session_state['survival_cal'] = 0

if 'survival_cal_joueur' not in st.session_state:  # resultat du joueur
    st.session_state['survival_cal_joueur'] = 0

if 'survival_cal_print' not in st.session_state:  # calcul ecrit
    st.session_state['survival_cal_print'] = 0

if 'survival_score' not in st.session_state:
    st.session_state['survival_score'] = 0

# Sessions pour le calcul de temps ------------------------------------------------------------------------------------
if 'start' not in st.session_state:
    st.session_state['start'] = 1

if 'time' not in st.session_state:
    st.session_state['time'] = 1

st.title('🕹️I Want to play !')

niv = st.selectbox(
    "Choose the level of the game",
    ("---", "1", "2", "3", "Survival"),
    key='niv'
)


if (niv == '---'):

    # Explication des règles
    st.subheader("Rules : ")
    st.write("Level 1 to 3")
    st.warning("Be careful, when you chose a level, you have 3 seconds to prepare yourself.\n"
            "After that, the level start and a timer is activated. If you are not ready, you can restart by re-choosing the level or by clicking on the 'Retry' button.\n\n"
            "If you put at least one answer but decide to change the level, answers will be save.\n\n"
            "If you have 10/10, you win 5 points of score for the level 1, 10 for level 2 and 15 for level 3. But if you make mistakes, you lose 1 point of score by mistake.\n\n"
            "Good luck !")
    st.write("Survival level")
    st.info("Survival mode start when you chose it. You have all your time to complete 100 levels. Of course, the difficulty will increase. \n\n"
            "When you put an answer, you can validate it with <Enter> or <Tabulation>, and an other calculation will appear.\n\n"
            "You win 0.5 point of score by good answer.\n\n"
            "Good luck ! For real !")

    # reboot session niv 1-2-3
    st.session_state['result'] = 0
    st.session_state['restart'] = 1
    # reboot session survival
    st.session_state['progression_bar'] = 0
    st.session_state['survival_result'] = 0
    st.session_state['survival_cal'] = 0
    st.session_state['survival_cal_joueur'] = 0
    st.session_state['survival_cal_print'] = 0
    st.session_state['survival_score'] = 0



elif (niv == 'Survival'):
    # reboot session niv 1-2-3
    st.session_state['result'] = 0
    st.session_state['restart'] = 1

    if (st.session_state['survival_score'] == 0):
        st.session_state['start'] = time.time()

    if (st.session_state['survival_score'] == 100):

        st.balloons()
        st.header('Congratulations ! You are the best')

        time.sleep(3)

        st.session_state['survival_result'] = 0
        st.session_state['progression_bar'] = 0
        st.session_state['survival_score'] = 0
        st.experimental_rerun()

    if (st.session_state['survival_result'] == 0):

        st.subheader("Your progression : ")
        my_bar = st.progress(st.session_state['progression_bar'])  # On met à jour la barre de progression

        survival_game(st.session_state['progression_bar'])  # On met en place les calculs du jeu

        st.text_input(label="survival_label", value="", key='survival_cal_joueur',
                      placeholder=st.session_state['survival_cal_print'], label_visibility="hidden",
                      on_change=survival_verif())  # Réponse du joueur

    else:
        if (str(st.session_state['survival_cal_joueur']) == str(st.session_state['survival_cal'])):
            st.session_state['survival_result'] = 0
            st.session_state['progression_bar'] += 1
            st.session_state['survival_score'] += 1
            st.experimental_rerun()
        else:
            if(st.session_state['progression_bar'] != 0):
                temps = time.time() - st.session_state['start']

                minutes = temps // 60
                seconds = temps % 60
                centieme = str(seconds)
                centieme = int(centieme.split(".")[1][:2])

                temps = "%02d:%02d:%02d" % (minutes, seconds, centieme)

                err = st.session_state['survival_cal_print'] + st.session_state['survival_cal_joueur'] + ' >>> ' + \
                      st.session_state['survival_cal_print'] + str(st.session_state['survival_cal'])

                st.error(err)
                st.info(f"Your score : {st.session_state['survival_score']} / 100")
                st.info(f"Your time : {temps}")

                st.session_state['survival_result'] = 0
                st.session_state['progression_bar'] = 0
                st.session_state['survival_score'] = 0

                st.button('Try again !')
            else:
                st.session_state['survival_result'] = 0
                st.session_state['progression_bar'] = 0
                st.session_state['survival_score'] = 0
                st.experimental_rerun()
else:
    # reboot session survival
    st.session_state['progression_bar'] = 0
    st.session_state['survival_result'] = 0
    st.session_state['survival_cal'] = 0
    st.session_state['survival_cal_joueur'] = 0
    st.session_state['survival_cal_print'] = 0
    st.session_state['survival_score'] = 0

    if st.session_state['restart'] == 1:
        jeu(niv)

    if st.session_state['result'] == 1:  # Affichage des résultats
        # On regarde si le joueur a réellement joué. S'il n'a mit aucune valeur dans les input, on ne sauvegarde pas les réponses et on n'affiche pas les résultats.
        # Le niveau recommencera
        vide = 0
        for i in range(10):  # On va vérifier que tous les réponses ne sont pas nulles, sinon on en déduit que le joueur n'a pas joué
            test_joueur = str(st.session_state['cal_joueur_' + str(i)])

            if (test_joueur == ""):
                vide += 1

        if (vide != 10):  # Si le joueur a mis au moins une réponse, on lui affiche les résultats et on sauvegarde

            # Ajouter du temps ici ------------------------------------------------------------------------------------
            st.session_state['time'] = time.time()
            temps = time.time() - st.session_state['start']

            seconds = temps % 60
            minutes = temps // 60
            centieme = str(seconds)
            centieme = int(centieme.split(".")[1][:2])

            temps = "%02d:%02d:%02d" % (minutes, seconds, centieme)

            bon_rep, mauv_rep = 0, 0

            for i in range(10):
                test_cal = st.session_state['cal_' + str(i)]
                test_joueur = st.session_state['cal_joueur_' + str(i)]

                if str(test_cal) == test_joueur:
                    bon_rep += 1
                    suc = st.session_state['cal_print_' + str(i)] + st.session_state['cal_joueur_' + str(i)]
                    st.success(suc)
                else:
                    mauv_rep += 1
                    err = st.session_state['cal_print_' + str(i)] + st.session_state[
                        'cal_joueur_' + str(i)] + "\t >>> Correction : " + st.session_state[
                              'cal_print_' + str(i)] + str(st.session_state['cal_' + str(i)])
                    st.error(err)

            ratio = (bon_rep / (bon_rep + mauv_rep)) * 100
            lvl = int(niv)
            date = str(datetime.date.today())

            # Affichage du temps ------------------------------------------------------------------------------------
            st.info(f'Your time : {temps}')
            st.session_state['result'] = 0
            st.session_state['restart'] = 1
            st.button("Retry")

        else:  # Sinon on ne sauvegarde pas les résultats et on ne les affiche pas, et on le fait recommencer
            st.session_state['result'] = 0
            st.session_state['restart'] = 1
            st.experimental_rerun()

    else:  # Affichage des calculs

        with st.spinner(' Be ready !'):
            time.sleep(3)

        with st.form("my_form"):

            # Ajouter du temps ici ------------------------------------------------------------------------------------
            st.session_state['start'] = time.time()

            st.write("Try to complete each calculation, then confirm.")

            for i in range(10):
                st.text_input(label="label" + str(i), value="", placeholder=st.session_state['cal_print_' + str(i)],
                              key="cal_joueur_" + str(i), label_visibility="hidden")  # Réponse du joueur

            confirm = st.form_submit_button("Confirm", on_click=confirm_button())