From e95b4dd329945ab969e078e6d7f9cb65edc20fd7 Mon Sep 17 00:00:00 2001 From: snehankekre Date: Tue, 12 Sep 2023 13:45:34 +0530 Subject: [PATCH 1/4] Update supabase tutorial for st.connection --- content/kb/tutorials/databases/supabase.md | 105 +++++++++++++++++---- 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/content/kb/tutorials/databases/supabase.md b/content/kb/tutorials/databases/supabase.md index 1fc454408..60784c48e 100644 --- a/content/kb/tutorials/databases/supabase.md +++ b/content/kb/tutorials/databases/supabase.md @@ -7,7 +7,13 @@ slug: /knowledge-base/tutorials/databases/supabase ## Introduction -This guide explains how to securely access a Supabase instance from Streamlit Community Cloud. It uses the [Supabase Python Client Library](https://github.com/supabase-community/supabase-py) and Streamlit's [Secrets management](/streamlit-community-cloud/deploy-your-app/secrets-management). Supabase is the open source Firebase alternative and is based on PostgreSQL. +This guide explains how to securely access a Supabase instance from Streamlit Community Cloud. It uses [st.experimental_connection](/library/api-reference/connections/st.experimental_connection), [Streamlit Supabase Connector](https://github.com/SiddhantSadangi/st_supabase_connection/tree/main) (a community-built connection developed by [@SiddhantSadangi](https://github.com/SiddhantSadangi)) and Streamlit's [Secrets management](/streamlit-community-cloud/deploy-your-app/secrets-management). Supabase is the open source Firebase alternative and is based on PostgreSQL. + + + +Community-built connections, such as the [Streamlit Supabase Connector](https://github.com/SiddhantSadangi/st_supabase_connection/tree/main), extend and build on the `st.experimental_connection` interface and make it easier than ever to build Streamlit apps with a wide variety of data sources. These type of connections work exactly the same as [the ones built into Streamlit](/library/api-reference/connections) and have access to all the same capabilities. + + ## Sign in to Supabase and create a project @@ -68,13 +74,14 @@ With your Supabase database created, you can now connect to it from Streamlit! ### Add Supabase Project URL and API key to your local app secrets -Your local Streamlit app will read secrets from a file `.streamlit/secrets.toml` in your app's root directory. Create this file if it doesn't exist yet and add the `supabase_url` and `supabase_key` here: +Your local Streamlit app will read secrets from a file `.streamlit/secrets.toml` in your app's root directory. Create this file if it doesn't exist yet and add the `SUPABASE_URL` and `SUPABASE_KEY` here: ```toml # .streamlit/secrets.toml -supabase_url = "xxxx" -supabase_key = "xxxx" +[connections.supabase] +SUPABASE_URL = "xxxx" +SUPABASE_KEY = "xxxx" ``` Replace `xxxx` above with your Project URL and API key from [Step 1](/knowledge-base/tutorials/databases/supabase#sign-in-to-supabase-and-create-a-project). @@ -91,15 +98,23 @@ As the `secrets.toml` file above is not committed to GitHub, you need to pass it ![Secrets manager screenshot](/images/databases/edit-secrets.png) -## Add supabase to your requirements file +## Add st-supabase-connection to your requirements file -Add the [`supabase`](https://github.com/supabase-community/supabase-py) Python Client Library to your `requirements.txt` file, preferably pinning its version (replace `x.x.x` with the version you want installed): +Add the [`st-supabase-connection`](https://pypi.org/project/st-supabase-connection/) community-built connection library to your `requirements.txt` file, preferably pinning its version (replace `x.x.x` with the version you want installed): ```bash # requirements.txt -supabase==x.x.x +st-supabase-connection==x.x.x ``` + + +We've used the `st-supabase-connection` library here in combination with `st.experimental_connection` to benefit from the ease of setting up the data connection, managing your credentials, and Streamlit's caching capabilities that native and community-built connections provide. + +You can however still directly use the [Supabase Python Client Library](https://pypi.org/project/supabase/) library if you prefer, but you'll need to write more code to set up the connection and cache the results. See [Using the Supabase Python Client Library](/knowledge-base/tutorials/databases/supabase#using-the-supabase-python-client-library) below for an example. + + + ## Write your Streamlit app Copy the code below to your Streamlit app and run it. @@ -108,23 +123,14 @@ Copy the code below to your Streamlit app and run it. # streamlit_app.py import streamlit as st -from supabase import create_client, Client +from st_supabase_connection import SupabaseConnection # Initialize connection. -# Uses st.cache_resource to only run once. -@st.cache_resource -def init_connection(): - url = st.secrets["supabase_url"] - key = st.secrets["supabase_key"] - return create_client(url, key) - -supabase = init_connection() +supabase = st.experimental_connection("supabase",type=SupabaseConnection) # Perform query. -# Uses st.cache_data to only rerun when the query changes or after 10 min. -@st.cache_data(ttl=600) def run_query(): - return supabase.table("mytable").select("*").execute() + return supabase.query("*", table="mytable", ttl=600).execute() rows = run_query() @@ -134,10 +140,69 @@ for row in rows.data: ``` -See `st.cache_data` above? Without it, Streamlit would run the query every time the app reruns (e.g. on a widget interaction). With `st.cache_data`, it only runs when the query changes or after 10 minutes (that's what `ttl` is for). Watch out: If your database updates more frequently, you should adapt `ttl` or remove caching so viewers always see the latest data. Learn more in [Caching](/library/advanced-features/caching). +See `st.experimental_connection` above? This handles secrets retrieval, setup, query caching and retries. By default, `query()` results are cached without expiring. In this case, we set `ttl=600` to ensure the query result is cached for no longer than 10 minutes. You can also set `ttl=0` to disable caching. Learn more in [Caching](/library/advanced-features/caching). If everything worked out (and you used the example table we created above), your app should look like this: ![Finished app screenshot](/images/databases/supabase-10.png) As Supabase uses PostgresSQL under the hood, you can also connect to Supabase by using the connection string Supabase provides under Settings > Databases. From there, you can refer to the [PostgresSQL tutorial](/knowledge-base/tutorials/databases/postgresql) to connect to your database. + +## Using the Supabase Python Client Library + +If you prefer to use the [Supabase Python Client Library](https://pypi.org/project/supabase/) directly, you can do so by following the steps below. + +1. Add your Supabase Project URL and API key to your local app secrets: + + Your local Streamlit app will read secrets from a file `.streamlit/secrets.toml` in your app's root directory. Create this file if it doesn't exist yet and add the SUPABASE_URL and SUPABASE_KEY here: + + ```toml + # .streamlit/secrets.toml + + SUPABASE_URL = "xxxx" + SUPABASE_KEY = "xxxx" + ``` + +2. Add `supabase` to your requirements file: + + Add the [`supabase`](https://github.com/supabase-community/supabase-py) Python Client Library to your `requirements.txt` file, preferably pinning its version (replace `x.x.x` with the version you want installed): + + ```bash + # requirements.txt + supabase==x.x.x + ``` + +3. Write your Streamlit app: + + Copy the code below to your Streamlit app and run it. + + ```python + # streamlit_app.py + + import streamlit as st + from supabase import create_client, Client + + # Initialize connection. + # Uses st.cache_resource to only run once. + @st.cache_resource + def init_connection(): + url = st.secrets["SUPABASE_URL"] + key = st.secrets["SUPABASE_KEY"] + return create_client(url, key) + + supabase = init_connection() + + # Perform query. + # Uses st.cache_data to only rerun when the query changes or after 10 min. + @st.cache_data(ttl=600) + def run_query(): + return supabase.table("mytable").select("*").execute() + + rows = run_query() + + # Print results. + for row in rows.data: + st.write(f"{row['name']} has a :{row['pet']}:") + ``` + + See `st.cache_data` above? Without it, Streamlit would run the query every time the app reruns (e.g. on a widget interaction). With `st.cache_data`, it only runs when the query changes or after 10 minutes (that's what `ttl` is for). Watch out: If your database updates more frequently, you should adapt `ttl` or remove caching so viewers always see the latest data. Learn more in [Caching](/library/advanced-features/caching). From d1e2e9b26b877f6c3138bbb28f9c93371f944ebb Mon Sep 17 00:00:00 2001 From: snehankekre Date: Tue, 12 Sep 2023 19:03:34 +0530 Subject: [PATCH 2/4] Update postgresql tutorial for st.connection --- content/kb/tutorials/databases/postgresql.md | 41 +++++++------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/content/kb/tutorials/databases/postgresql.md b/content/kb/tutorials/databases/postgresql.md index edf5814ba..21f413c24 100644 --- a/content/kb/tutorials/databases/postgresql.md +++ b/content/kb/tutorials/databases/postgresql.md @@ -7,7 +7,7 @@ slug: /knowledge-base/tutorials/databases/postgresql ## Introduction -This guide explains how to securely access a **_remote_** PostgreSQL database from Streamlit Community Cloud. It uses the [psycopg2](https://www.psycopg.org/) library and Streamlit's [Secrets management](/streamlit-community-cloud/deploy-your-app/secrets-management). +This guide explains how to securely access a **_remote_** PostgreSQL database from Streamlit Community Cloud. It uses [st.experimental_connection](/library/api-reference/connections/st.experimental_connection) and Streamlit's [Secrets management](/library/advanced-features/secrets-management). The below example code will **only work on Streamlit version >= 1.22**, when `st.experimental_connection` was added. ## Create a PostgreSQL database @@ -36,17 +36,18 @@ Your local Streamlit app will read secrets from a file `.streamlit/secrets.toml` ```toml # .streamlit/secrets.toml -[postgres] +[connections.postgresql] +dialect = "postgresql" host = "localhost" -port = 5432 -dbname = "xxx" -user = "xxx" +port = "5432" +database = "xxx" +username = "xxx" password = "xxx" ``` -When copying your app secrets to Streamlit Community Cloud, be sure to replace the values of **host**, **port**, **dbname**, **user**, and **password** with those of your _remote_ PostgreSQL database! +When copying your app secrets to Streamlit Community Cloud, be sure to replace the values of **host**, **port**, **database**, **user**, and **password** with those of your _remote_ PostgreSQL database! Add this file to `.gitignore` and don't commit it to your GitHub repo! @@ -58,13 +59,14 @@ As the `secrets.toml` file above is not committed to GitHub, you need to pass it ![Secrets manager screenshot](/images/databases/edit-secrets.png) -## Add psycopg2 to your requirements file +## ## Add dependencies to your requirements file -Add the [psycopg2](https://www.psycopg.org/) package to your `requirements.txt` file, preferably pinning its version (replace `x.x.x` with the version you want installed): +Add the [psycopg2-binary](https://www.psycopg.org/) and [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy) packages to your `requirements.txt` file, preferably pinning its version (replace `x.x.x` with the version you want installed): ```bash # requirements.txt psycopg2-binary==x.x.x +sqlalchemy==x.x.x ``` ## Write your Streamlit app @@ -75,32 +77,19 @@ Copy the code below to your Streamlit app and run it. Make sure to adapt `query` # streamlit_app.py import streamlit as st -import psycopg2 # Initialize connection. -# Uses st.cache_resource to only run once. -@st.cache_resource -def init_connection(): - return psycopg2.connect(**st.secrets["postgres"]) - -conn = init_connection() +conn = st.experimental_connection("postgresql", type="sql") # Perform query. -# Uses st.cache_data to only rerun when the query changes or after 10 min. -@st.cache_data(ttl=600) -def run_query(query): - with conn.cursor() as cur: - cur.execute(query) - return cur.fetchall() - -rows = run_query("SELECT * from mytable;") +df = conn.query('SELECT * FROM mytable;', ttl=600) # Print results. -for row in rows: - st.write(f"{row[0]} has a :{row[1]}:") +for row in df.itertuples(): + st.write(f"{row.name} has a :{row.pet}:") ``` -See `st.cache_data` above? Without it, Streamlit would run the query every time the app reruns (e.g. on a widget interaction). With `st.cache_data`, it only runs when the query changes or after 10 minutes (that's what `ttl` is for). Watch out: If your database updates more frequently, you should adapt `ttl` or remove caching so viewers always see the latest data. Learn more in [Caching](/library/advanced-features/caching). +See `st.experimental_connection` above? This handles secrets retrieval, setup, query caching and retries. By default, `query()` results are cached without expiring. In this case, we set `ttl=600` to ensure the query result is cached for no longer than 10 minutes. You can also set `ttl=0` to disable caching. Learn more in [Caching](/library/advanced-features/caching). If everything worked out (and you used the example table we created above), your app should look like this: From 410f3ff27586ce0879fb6e96d7016d606c168462 Mon Sep 17 00:00:00 2001 From: Snehan Kekre Date: Tue, 12 Sep 2023 20:55:17 +0530 Subject: [PATCH 3/4] Update content/kb/tutorials/databases/postgresql.md Co-authored-by: Debbie Matthews --- content/kb/tutorials/databases/postgresql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/kb/tutorials/databases/postgresql.md b/content/kb/tutorials/databases/postgresql.md index 21f413c24..e49b68e72 100644 --- a/content/kb/tutorials/databases/postgresql.md +++ b/content/kb/tutorials/databases/postgresql.md @@ -59,7 +59,7 @@ As the `secrets.toml` file above is not committed to GitHub, you need to pass it ![Secrets manager screenshot](/images/databases/edit-secrets.png) -## ## Add dependencies to your requirements file +## Add dependencies to your requirements file Add the [psycopg2-binary](https://www.psycopg.org/) and [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy) packages to your `requirements.txt` file, preferably pinning its version (replace `x.x.x` with the version you want installed): From 3d242075e9d7bdd704c9975d09755452d7d52108 Mon Sep 17 00:00:00 2001 From: snehankekre Date: Tue, 12 Sep 2023 20:59:53 +0530 Subject: [PATCH 4/4] Implement feedback --- content/kb/tutorials/databases/postgresql.md | 6 +++--- content/kb/tutorials/databases/supabase.md | 9 +++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/content/kb/tutorials/databases/postgresql.md b/content/kb/tutorials/databases/postgresql.md index e49b68e72..b2be3bdfb 100644 --- a/content/kb/tutorials/databases/postgresql.md +++ b/content/kb/tutorials/databases/postgresql.md @@ -47,7 +47,7 @@ password = "xxx" -When copying your app secrets to Streamlit Community Cloud, be sure to replace the values of **host**, **port**, **database**, **user**, and **password** with those of your _remote_ PostgreSQL database! +When copying your app secrets to Streamlit Community Cloud, be sure to replace the values of **host**, **port**, **database**, **username**, and **password** with those of your _remote_ PostgreSQL database! Add this file to `.gitignore` and don't commit it to your GitHub repo! @@ -82,14 +82,14 @@ import streamlit as st conn = st.experimental_connection("postgresql", type="sql") # Perform query. -df = conn.query('SELECT * FROM mytable;', ttl=600) +df = conn.query('SELECT * FROM mytable;', ttl="10m") # Print results. for row in df.itertuples(): st.write(f"{row.name} has a :{row.pet}:") ``` -See `st.experimental_connection` above? This handles secrets retrieval, setup, query caching and retries. By default, `query()` results are cached without expiring. In this case, we set `ttl=600` to ensure the query result is cached for no longer than 10 minutes. You can also set `ttl=0` to disable caching. Learn more in [Caching](/library/advanced-features/caching). +See `st.experimental_connection` above? This handles secrets retrieval, setup, query caching and retries. By default, `query()` results are cached without expiring. In this case, we set `ttl="10m"` to ensure the query result is cached for no longer than 10 minutes. You can also set `ttl=0` to disable caching. Learn more in [Caching](/library/advanced-features/caching). If everything worked out (and you used the example table we created above), your app should look like this: diff --git a/content/kb/tutorials/databases/supabase.md b/content/kb/tutorials/databases/supabase.md index 60784c48e..42d381981 100644 --- a/content/kb/tutorials/databases/supabase.md +++ b/content/kb/tutorials/databases/supabase.md @@ -126,13 +126,10 @@ import streamlit as st from st_supabase_connection import SupabaseConnection # Initialize connection. -supabase = st.experimental_connection("supabase",type=SupabaseConnection) +conn = st.experimental_connection("supabase",type=SupabaseConnection) # Perform query. -def run_query(): - return supabase.query("*", table="mytable", ttl=600).execute() - -rows = run_query() +rows = conn.query("*", table="mytable", ttl="10m").execute() # Print results. for row in rows.data: @@ -140,7 +137,7 @@ for row in rows.data: ``` -See `st.experimental_connection` above? This handles secrets retrieval, setup, query caching and retries. By default, `query()` results are cached without expiring. In this case, we set `ttl=600` to ensure the query result is cached for no longer than 10 minutes. You can also set `ttl=0` to disable caching. Learn more in [Caching](/library/advanced-features/caching). +See `st.experimental_connection` above? This handles secrets retrieval, setup, query caching and retries. By default, `query()` results are cached without expiring. In this case, we set `ttl="10m"` to ensure the query result is cached for no longer than 10 minutes. You can also set `ttl=0` to disable caching. Learn more in [Caching](/library/advanced-features/caching). If everything worked out (and you used the example table we created above), your app should look like this: