Issue accessing my Google Cloud SQL database from Streamlit

Hello everyone!

I am currently facing an issue when trying to access my Google Cloud SQL database from my Streamlit application. I have created an instance and a database on Google Cloud SQL, and I want to establish a connection to this cloud database through my Streamlit code.

Here is an excerpt from my code:

import streamlit as st
import pymysql

db_config = st.secrets["mysql"]
db = pymysql.connect(**db_config)
cursor = db.cursor()

However, when I run the application, I encounter an error:

pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'my public ip address from GCP' (timed out)")

I am a bit lost and not sure why the connection is failing. Could someone take a look and provide guidance on how to resolve this issue? Thank you in advance for any help you can provide!

Hi @Andy2

Have you seen these tutorials in the Docs for connecting to a remote MySQL database and Google Cloud Storage:

1 Like

yes but I don’t know how to integrate it into my project

import streamlit as st
import pymysql
import re
import hashlib
import secrets

# Connexion à la base de données MySQL
db_config = st.secrets["mysql"]
db = pymysql.connect(**db_config)
cursor = db.cursor()

def validate_email(email):
    pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
    return re.match(pattern, email)

def validate_password(password):
    # Vérifier la longueur minimale du mot de passe
    if len(password) < 8:
        return False

    # Vérifier la présence d'au moins une lettre majuscule
    if not re.search(r'[A-Z]', password):
        return False

    # Vérifier la présence d'au moins une lettre minuscule
    if not re.search(r'[a-z]', password):
        return False

    # Vérifier la présence d'au moins un chiffre
    if not re.search(r'\d', password):
        return False

    # Vérifier la présence d'au moins un caractère spécial
    if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
        return False

    return True
def hash_password(password, salt):
    hashed_password = hashlib.sha256((password + salt).encode('utf-8')).hexdigest()
    return hashed_password

def create_user(user_name, user_surname, user_mail, user_number, user_club, user_level, user_password, salt):
    salt = secrets.token_hex(16)
    hashed_password = hash_password(user_password, salt)
    query = "INSERT INTO av_users (user_name, user_surname, user_mail, user_number, user_club, user_level, user_password, salt) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)"
    values = (user_name, user_surname, user_mail, user_number, user_club, user_level, hashed_password, salt)
    cursor.execute(query, values)
    db.commit()
    return salt

def get_user(user_mail, user_password):
    query = "SELECT * FROM av_users WHERE user_mail = %s AND user_password = %s"
    values = (user_mail, user_password)
    cursor.execute(query, values)
    return cursor.fetchone()

def app():
    st.set_page_config(page_title="Bienvenue", page_icon="👋")
    st.markdown("""
<style>
header
{
    visibility: hidden;
}
.css-eh5xgm.e1ewe7hr3
{
    visibility: hidden;
}
.css-cio0dv.e1g8pov61
{
    visibility: hidden;
}
</style>
""", unsafe_allow_html=True)
    if 'logged_in' not in st.session_state:
        st.session_state['logged_in'] = False

    st.title("Bienvenue sur :blue[AnalyzeVoice]")
    st.write("---")
    
    if 'username' not in st.session_state:
        st.session_state.username = ''
    if 'useremail' not in st.session_state:
        st.session_state.useremail = ''

    def login():
        with st.form("login_form", clear_on_submit=True):
            email = st.text_input(label="", value="", placeholder="E-mail")
            password_entry = st.text_input(label="", value="", placeholder="Mot de passe", type="password")
            submit_button = st.form_submit_button("Connexion")

        if submit_button:
            query = "SELECT * FROM av_users WHERE user_mail = %s"
            values = (email,)
            cursor.execute(query, values)
            user = cursor.fetchone()
            
            salt = user[8]  # Récupérez le sel de la base de données pour cet utilisateur
            hashed_password_entry = hash_password(password_entry, salt=salt)
            user = get_user(email, hashed_password_entry)
            
            if not validate_email(email):
                st.error("Veuillez saisir un email valide")
                return
            if user is None:
                st.error("E-mail ou mot de passe incorrect")
                return
            if user is not None :
                salt = user[8]
                if hashed_password_entry == user[7]:  # Vérifiez avec le mot de passe haché stocké dans la base de données
                    st.success("Connexion réussie")
                    st.session_state.username = user[1]
                    st.session_state.useremail = user[3]
                    st.session_state.signedout = True
                    st.session_state.signout = True
                    st.session_state['user_id'] = user[0]
                else:
                    st.error('Connexion échouée')
####ok ici
    def signup():
        with st.form("signup_form", clear_on_submit=True):
            user_name = st.text_input(label="", value="", placeholder="Prénom")
            user_surname = st.text_input(label="", value="", placeholder="Nom")
            user_mail = st.text_input(label="", value="", placeholder="E-mail")
            user_number = st.text_input(label="", value="", placeholder="Téléphone")
            user_club = st.text_input(label="", value="", placeholder="Club")
            user_level = st.text_input(label="", value="", placeholder="Niveau de votre équipe")
            user_password = st.text_input(label="", value="", placeholder="Mot de passe", type="password")
            st.warning("Le mot de passe doit contenir au moins 8 caractères, une lettre majuscule, une lettre minuscule, un chiffre et un caractère spécial.")

            submit_button2 = st.form_submit_button("Créer un compte")

        if submit_button2:
            if not validate_email(user_mail):
                st.error("Veuillez saisir un email valide")
                return
            if not validate_password(user_password):
                st.error("Veuillez saisir un mot de passe valide")
                return
            create_user(user_name, user_surname, user_mail, user_number, user_club, user_level, user_password, salt=secrets.token_hex(16))
            cursor.execute('SELECT id_user FROM av_users')
            id_users = cursor.fetchall()
            id = [user[0] for user in id_users]
            #id = [user['id_user'] for user in id_users]
            nom_table = "table_shortcut_" + str(id[-1])
            cursor.execute(f"CREATE TABLE IF NOT EXISTS {nom_table} (index_shorcut INT AUTO_INCREMENT PRIMARY KEY, shortcut_key CHAR(255), shortcut_letter CHAR(1))")
            st.success("Votre compte a été créé avec succès")

    if 'signedout' not in st.session_state:
        st.session_state.signedout = False
    if 'signout' not in st.session_state:
        st.session_state.signout = False

    if not st.session_state['signedout']:
        choice = st.selectbox("Connexion/S'inscrire", ["Connexion", "S'inscrire"])
        st.write("##")

        if choice == 'Connexion':
            login()
        else:
            signup()

    if st.session_state.signout:
        st.text("Nom : " + st.session_state.username)
        st.text("E-mail : " + st.session_state.useremail)
        if st.button("Déconnexion"):
            st.session_state.signout = False
            st.session_state.signedout = False
            st.session_state.username = ""
    db.close()

if __name__ == "__main__":
    app()

I’m trying, can you help me please? @dataprofessor

Hi,

I’d recommend to start by following the tutorial and using the same code as used in the tutorial. Once that works, then slowly modify the existing code that works by adding code blocks from your local app. Do this in small increments so that you’ll see exactly when the code breaks. After a few iteration, all your code should be integrated into the example app.

Hope this helps!

2 Likes

Hi,

I took your advice and it worked locally!

on Streamlit cloud I no longer have the error I showed you before but now I have another error :

AttributeError: This app has encountered an error. The original error message is redacted to prevent data leaks. Full error details have been recorded in the logs (if you're on Streamlit Cloud, click on 'Manage app' in the lower right of your app).
Traceback:
File "/home/adminuser/venv/lib/python3.9/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 552, in _run_script
    exec(code, module.__dict__)
File "/mount/src/av/1_🔐_Connexion.py", line 11, in <module>
    conn = st.connection('mysql', type='sql')

Manage app :

2023-12-12 12:06:08.352 Uncaught app exception

Traceback (most recent call last):

  File "/home/adminuser/venv/lib/python3.9/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 552, in _run_script

    exec(code, module.__dict__)

  File "/mount/src/av/1_🔐_Connexion.py", line 11, in <module>

    conn = st.connection('mysql', type='sql')

AttributeError: module 'streamlit' has no attribute 'connection'

Do you have anything like that?

  • Maybe you have pinned an older version of streamlit in your requirements?
  • Have you included the other dependencies?
  • Always make a reboot in streamlit cloud, if you change any dependencies

Ok, all this time I wanted to fend for myself but unsuccessfully… I had a problem with “mysqlclient” I went through this drift I saw here (Problem installing mysqlclient - Can not find valid pkg-config name - #11 by Daniel_Attard)

My application is displayed but when I want to access my database with streamlit cloud here is the error :

2023-12-18 22:10:18.061 Uncaught app exception

Traceback (most recent call last):

  File "/home/adminuser/venv/lib/python3.11/site-packages/pymysql/connections.py", line 644, in connect

    sock = socket.create_connection(

           ^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/socket.py", line 851, in create_connection

    raise exceptions[0]

  File "/usr/local/lib/python3.11/socket.py", line 836, in create_connection

    sock.connect(sa)

TimeoutError: timed out


During handling of the above exception, another exception occurred:


Traceback (most recent call last):

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 145, in __init__

    self._dbapi_connection = engine.raw_connection()

                             ^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 3292, in raw_connection

    return self.pool.connect()

           ^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 452, in connect

    return _ConnectionFairy._checkout(self)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 1269, in _checkout

    fairy = _ConnectionRecord.checkout(pool)

            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 716, in checkout

    rec = pool._do_get()

          ^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 169, in _do_get

    with util.safe_reraise():

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__

    raise exc_value.with_traceback(exc_tb)

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 167, in _do_get

    return self._create_connection()

           ^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 393, in _create_connection

    return _ConnectionRecord(self)

           ^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 678, in __init__

    self.__connect()

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 902, in __connect

    with util.safe_reraise():

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__

    raise exc_value.with_traceback(exc_tb)

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 898, in __connect

    self.dbapi_connection = connection = pool._invoke_creator(self)

                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/create.py", line 637, in connect

    return dialect.connect(*cargs, **cparams)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 616, in connect

    return self.loaded_dbapi.connect(*cargs, **cparams)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/home/adminuser/venv/lib/python3.11/site-packages/pymysql/connections.py", line 358, in __init__

    self.connect()

  File "/home/adminuser/venv/lib/python3.11/site-packages/pymysql/connections.py", line 711, in connect

    raise exc

pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '34.163.8.74' (timed out)")

I do not know the ip address of streamlit cloud, how to give the rights to streamlit cloud from google cloud because I hosted my database there?

I am having the same problem… It shouldn’t be this difficult to connect streamlit with google cloud. Has anyone found any solution?