Skip to main content

A Streamlit connection component for Supabase.

Project description

:electric_plug: Streamlit Supabase Connector

Downloads

A Streamlit connection component to connect Streamlit to Supabase Storage, Database, and Auth.

:student: Interactive tutorial

Open in Streamlit Web capture_2-12-2023_124639_st-supabase-connection streamlit app

:thinking: Why use this?

  • Cache functionality to cache returned results. Save time and money on your API requests
  • Same method names as the Supabase Python API. Minimum relearning required
  • Exposes more storage methods than currently supported by the Supabase Python API. For example, update(), create_signed_upload_url(), and upload_to_signed_url()
  • Less keystrokes required when integrating with your Streamlit app.
Examples with and without the connector
Without connectorWith connector
Download file to local system from Supabase storage
import mimetypes
import streamlit as st
from supabase import create_client

supabase_client = create_client(
    supabase_url="...", supabase_key="..."
)

bucket_id = st.text_input("Enter the bucket_id")
source_path = st.text_input("Enter source path")

file_name = source_path.split("/")[-1]

if st.button("Request download"):
    with open(file_name, "wb+") as f:
        response = supabase_client.storage.from_(
        bucket_id
        ).download(source_path)
        f.write(response)

    mime = mimetypes.guess_type(file_name)[0]
    data = open(file_name, "rb")

    st.download_button(
        "Download file", data=data, 
        file_name=file_name, mime=mime,
    )
import streamlit as st
from st_supabase_connection import SupabaseConnection

st_supabase_client = st.connection(
    name="supabase_connection", type=SupabaseConnection
)

bucket_id = st.text_input("Enter the bucket_id")
source_path = st.text_input("Enter source path")

if st.button("Request download"):
    file_name, mime, data = st_supabase_client.download(
        bucket_id, source_path,
    )

    st.download_button(
        "Download file", data=data, 
        file_name=file_name, mime=mime,
    )
Upload file from local system to Supabase storage
import streamlit as st
from supabase import create_client

supabase_client = create_client(
supabase_key="...", supabase_url="..."
)

bucket_id = st.text_input("Enter the bucket_id")
uploaded_file = st.file_uploader("Choose a file")
destination_path = st.text_input("Enter destination path")
overwrite = "true" if st.checkbox("Overwrite?") else "false"  

with open(uploaded_file.name, "wb") as f:
    f.write(uploaded_file.getbuffer())

if st.button("Upload"):
    with open(uploaded_file.name, "rb") as f:
        supabase_client.storage.from_(bucket_id).upload(
            path=destination_path,
            file=f,
            file_options={
            "content-type": uploaded_file.type,
            "x-upsert": overwrite,
            },
        )
import streamlit as st
from st_supabase_connection import SupabaseConnection

st_supabase_client = st.connection(
    name="supabase_connection", type=SupabaseConnection
)

bucket_id = st.text_input("Enter the bucket_id")
uploaded_file = st.file_uploader("Choose a file"):
destination_path = st.text_input("Enter destination path")
overwrite = "true" if st.checkbox("Overwrite?") else "false" 

if st.button("Upload"):
    st_supabase_client.upload(
        bucket_id, "local", uploaded_file, 
        destination_path, overwrite,
    )

:hammer_and_wrench: Setup

  1. Install st-supabase-connection
pip install st-supabase-connection
  1. Set the SUPABASE_URL and SUPABASE_KEY Streamlit secrets as described here.

[!NOTE]
For local development outside Streamlit, you can also set these as your environment variables (recommended), or pass these to the url and key args of st.connection().

:magic_wand: Usage

  1. Import
from st_supabase_connection import SupabaseConnection
  1. Initialize
st_supabase_client = st.connection(
    name="YOUR_CONNECTION_NAME",
    type=SupabaseConnection,
    ttl=None,
    url="YOUR_SUPABASE_URL", # not needed if provided as a streamlit secret
    key="YOUR_SUPABASE_KEY", # not needed if provided as a streamlit secret
)
  1. Use in your app to query tables and files. Happy Streamlit-ing! :balloon:

:ok_hand: Supported methods

Storage
  • delete_bucket()
  • empty_bucket()
  • get_bucket()
  • list_buckets()
  • create_bucket()
  • upload()
  • download()
  • update_bucket()
  • move()
  • list_objects()
  • create_signed_urls()
  • get_public_url()
  • create_signed_upload_url()
  • upload_to_signed_url()
Database
  • query() - Runs a cached SELECT query
  • All methods supported by postgrest-py.
Auth

:books: Examples

:package: Storage operations

List existing buckets

>>> st_supabase_client.list_buckets(ttl=None)
[
    SyncBucket(
        id="bucket1",
        name="bucket1",
        owner="",
        public=False,
        created_at=datetime.datetime(2023, 7, 31, 19, 56, 21, 518438, tzinfo=tzutc()),
        updated_at=datetime.datetime(2023, 7, 31, 19, 56, 21, 518438, tzinfo=tzutc()),
        file_size_limit=None,
        allowed_mime_types=None,
    ),
    SyncBucket(
        id="bucket2",
        name="bucket2",
        owner="",
        public=True,
        created_at=datetime.datetime(2023, 7, 31, 19, 56, 28, 203536, tzinfo=tzutc()),
        updated_at=datetime.datetime(2023, 7, 31, 19, 56, 28, 203536, tzinfo=tzutc()),
        file_size_limit=100,
        allowed_mime_types=["image/jpg", "image/png"],
    ),
]

Create a bucket

>>> st_supabase_client.create_bucket("new_bucket")
{'name': 'new_bucket'}

Get bucket details

>>> st_supabase_client.get_bucket("new_bucket")
SyncBucket(id='new_bucket', name='new_bucket', owner='', public=True, created_at=datetime.datetime(2023, 8, 2, 19, 41, 44, 810000, tzinfo=tzutc()), updated_at=datetime.datetime(2023, 8, 2, 19, 41, 44, 810000, tzinfo=tzutc()), file_size_limit=None, allowed_mime_types=None)

Update a bucket

>>> st_supabase_client.update_bucket(
      "new_bucket",
      file_size_limit=100,
      allowed_mime_types=["image/jpg", "image/png"],
      public=True,
    )
{'message': 'Successfully updated'}

Move files in a bucket

>>> st_supabase_client.move("new_bucket", "test.png", "folder1/new_test.png")
{'message': 'Successfully moved'}

List objects in a bucket

>>> st_supabase_client.list_objects("new_bucket", path="folder1", ttl=0)
[
    {
        "name": "new_test.png",
        "id": "e506920e-2834-440e-85f1-1d5476927582",
        "updated_at": "2023-08-02T19:53:22.53986+00:00",
        "created_at": "2023-08-02T19:52:20.404391+00:00",
        "last_accessed_at": "2023-08-02T19:53:21.833+00:00",
        "metadata": {
            "eTag": '"814a0034f5549e957ee61360d87457e5"',
            "size": 473831,
            "mimetype": "image/png",
            "cacheControl": "max-age=3600",
            "lastModified": "2023-08-02T19:53:23.000Z",
            "contentLength": 473831,
            "httpStatusCode": 200,
        },
    }
]

Empty a bucket

>>> st_supabase_client.empty_bucket("new_bucket")
{'message': 'Successfully emptied'}

Delete a bucket

>>> st_supabase_client.delete_bucket("new_bucket")
{'message': 'Successfully deleted'}

:file_cabinet: Database operations

Simple query

>>> st_supabase_client.query("*", table="countries", ttl=0).execute()
APIResponse(
    data=[
        {"id": 1, "name": "Afghanistan"},
        {"id": 2, "name": "Albania"},
        {"id": 3, "name": "Algeria"},
    ],
    count=None,
)

Query with join

>>> st_supabase_client.query("name, teams(name)", table="users",  count="exact", ttl="1h").execute()
APIResponse(
    data=[
        {"name": "Kiran", "teams": [{"name": "Green"}, {"name": "Blue"}]},
        {"name": "Evan", "teams": [{"name": "Blue"}]},
    ],
    count=None,
)

Filter through foreign tables

>>> st_supabase_client.query("name, countries(*)", count="exact", table="cities", ttl=None).eq(
        "countries.name", "Curaçao"
    ).execute()

APIResponse(
    data=[
        {
            "name": "Kralendijk",
            "countries": {
                "id": 2,
                "name": "Curaçao",
                "iso2": "CW",
                "iso3": "CUW",
                "local_name": None,
                "continent": None,
            },
        },
        {"name": "Willemstad", "countries": None},
    ],
    count=2,
)

Insert rows

>>> st_supabase_client.table("countries").insert(
        [{"name": "Wakanda", "iso2": "WK"}, {"name": "Wadiya", "iso2": "WD"}], count="None"
    ).execute()
APIResponse(
    data=[
        {
            "id": 250,
            "name": "Wakanda",
            "iso2": "WK",
            "iso3": None,
            "local_name": None,
            "continent": None,
        },
        {
            "id": 251,
            "name": "Wadiya",
            "iso2": "WD",
            "iso3": None,
            "local_name": None,
            "continent": None,
        },
    ],
    count=None,
)

:lock: Auth operations

[!NOTE]
If the call is valid, all Supabase Auth methods return the same response structure:

{
  "user": {
    "id": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544",
    "app_metadata": {
      "provider": "email",
      "providers": [
        "email"
      ]
    },
    "user_metadata": {
      "attribution": "I made it :)",
      "fname": "Siddhant"
    },
    "aud": "authenticated",
    "confirmation_sent_at": null,
    "recovery_sent_at": null,
    "email_change_sent_at": null,
    "new_email": null,
    "invited_at": null,
    "action_link": null,
    "email": "test.user@abc.com",
    "phone": "",
    "created_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 365359, tzinfo=datetime.timezone.utc)",
    "confirmed_at": null,
    "email_confirmed_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 373966, tzinfo=datetime.timezone.utc)",
    "phone_confirmed_at": null,
    "last_sign_in_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 377070, tzinfo=datetime.timezone.utc)",
    "role": "authenticated",
    "updated_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 381584, tzinfo=datetime.timezone.utc)",
    "identities": [
      {
        "id": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544",
        "user_id": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544",
        "identity_data": {
          "email": "siddhant.sadangi@gmail.com",
          "sub": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544"
        },
        "provider": "email",
        "created_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 370040, tzinfo=datetime.timezone.utc)",
        "last_sign_in_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 370002, tzinfo=datetime.timezone.utc)",
        "updated_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 370040, tzinfo=datetime.timezone.utc)"
      }
    ],
    "factors": null
  },
  "session": {
    "provider_token": null,
    "provider_refresh_token": null,
    "access_token": "***",
    "refresh_token": "***",
    "expires_in": 3600,
    "expires_at": 1696800390,
    "token_type": "bearer",
    "user": {
      "id": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544",
      "app_metadata": {
        "provider": "email",
        "providers": [
          "email"
        ]
      },
      "user_metadata": {
        "attribution": "I made it :)",
        "fname": "Siddhant"
      },
      "aud": "authenticated",
      "confirmation_sent_at": null,
      "recovery_sent_at": null,
      "email_change_sent_at": null,
      "new_email": null,
      "invited_at": null,
      "action_link": null,
      "email": "test.user@abc.com",
      "phone": "",
      "created_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 365359, tzinfo=datetime.timezone.utc)",
      "confirmed_at": null,
      "email_confirmed_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 373966, tzinfo=datetime.timezone.utc)",
      "phone_confirmed_at": null,
      "last_sign_in_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 377070, tzinfo=datetime.timezone.utc)",
      "role": "authenticated",
      "updated_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 381584, tzinfo=datetime.timezone.utc)",
      "identities": [
        {
          "id": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544",
          "user_id": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544",
          "identity_data": {
            "email": "siddhant.sadangi@gmail.com",
            "sub": "e1f550fd-9cd1-44e4-bbe4-c04e91cf5544"
          },
          "provider": "email",
          "created_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 370040, tzinfo=datetime.timezone.utc)",
          "last_sign_in_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 370002, tzinfo=datetime.timezone.utc)",
          "updated_at": "datetime.datetime(2023, 10, 8, 20, 26, 30, 370040, tzinfo=datetime.timezone.utc)"
        }
      ],
      "factors": null
    }
  }
}

Create new user

>>> st_supabase_client.auth.sign_up(dict(email='test.user@abc.com', password='***', options=dict(data=dict(fname='Siddhant',attribution='I made it :)'))))

Sign in with password

>>> st_supabase_client.auth.sign_in_with_password(dict(email='test.user@abc.com', password='***'))

Retrieve session

>>> st_supabase.auth.get_session()

Retrieve user

>>> st_supabase.auth.get_user()

Sign out

>>> st_supabase.auth.sign_out()

[!NOTE]
Check the Supabase Python API reference for more examples.

:star: Explore all options in a demo app

Open in Streamlit

:bow: Acknowledgements

This connector builds upon the awesome work done by the open-source community in general and the Supabase Community in particular. I cannot be more thankful to all the authors whose work I have used either directly or indirectly.

:hugs: Want to support my work?

Buy Me A Coffee

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

st-supabase-connection-1.2.2.tar.gz (15.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

st_supabase_connection-1.2.2-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

File details

Details for the file st-supabase-connection-1.2.2.tar.gz.

File metadata

  • Download URL: st-supabase-connection-1.2.2.tar.gz
  • Upload date:
  • Size: 15.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.12.0

File hashes

Hashes for st-supabase-connection-1.2.2.tar.gz
Algorithm Hash digest
SHA256 3e6508f96cb7edba69b06b80d65086bedc4baeac989780405556ca4b32862053
MD5 798f39bdd431280c257c4e1b2b0884e7
BLAKE2b-256 6a7cbb6e5b7a521fbe264c0b22287adb0663747d5b4777fc285498ae27278673

See more details on using hashes here.

File details

Details for the file st_supabase_connection-1.2.2-py3-none-any.whl.

File metadata

File hashes

Hashes for st_supabase_connection-1.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 7a2d3ea32f69c2160315d52b7c0017a213772cdccc357b1f4020db468d5e4324
MD5 660d1e62ef84f7aeddb84c8c4f8a0f47
BLAKE2b-256 874aa50896b02bf51c06ae8c42e76e1e90969fb02607e6a5acafa750749c456d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page