From f3529a82f13bf9b68c1bd75df4ace2516fee38c8 Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Thu, 3 Apr 2025 02:06:21 +0900 Subject: [PATCH 01/10] bug fixed mutable-reference-headers --- supabase-py.ipynb | 85 +++++++++++++++++++++++++++++++++++++++ supabase/_async/client.py | 10 +++-- supabase/_sync/client.py | 18 ++++----- tests/test_client.py | 2 - 4 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 supabase-py.ipynb diff --git a/supabase-py.ipynb b/supabase-py.ipynb new file mode 100644 index 00000000..9b7843a8 --- /dev/null +++ b/supabase-py.ipynb @@ -0,0 +1,85 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "cfcfd082-5f3b-4112-bf67-97dd7b3a40d3", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ModifiedValue1\n", + "ModifiedValue2\n" + ] + } + ], + "source": [ + "\n", + "from supabase import create_client\n", + "from supabase.lib.client_options import SyncClientOptions \n", + "class settings:\n", + " SUPABASE_URL = \"https://kdfdmfosctjrymkhebmv.supabase.co\"\n", + " SUPABASE_KEY = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImtkZmRtZm9zY3Rqcnlta2hlYm12Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDEzMzA1NDAsImV4cCI6MjA1NjkwNjU0MH0.FkBK4a5D-qEVH81sNh9A2OFFpVlgK0uWg8OqyxuEXks\"\n", + "from supabase._sync.client import create_client, ClientOptions\n", + "from gotrue import SyncMemoryStorage\n", + "\n", + "# 同じ ClientOptions インスタンスを複数のクライアントで共有\n", + "shared_options = ClientOptions(storage=SyncMemoryStorage(), headers={\"Custom-Header\": \"InitialValue\"})\n", + "\n", + "# クライアント1を作成\n", + "client1 = create_client(settings.SUPABASE_URL, settings.SUPABASE_KEY, options=shared_options)\n", + "\n", + "# クライアント2を作成\n", + "client2 = create_client(settings.SUPABASE_URL, settings.SUPABASE_KEY, options=shared_options)\n", + "\n", + "# クライアント1のヘッダーを変更\n", + "client1.options.headers[\"Custom-Header\"] = \"ModifiedValue1\"\n", + "client2.options.headers[\"Custom-Header\"] = \"ModifiedValue2\"\n", + "# クライアント2のヘッダーを確認\n", + "print(client1.options.headers[\"Custom-Header\"])\n", + "print(client2.options.headers[\"Custom-Header\"])# \"ModifiedValue\" と表示される\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6b066af-d553-4b3c-be92-5c51e6ed988d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d86256ee-edbb-4b53-927a-73ddd384c28a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/supabase/_async/client.py b/supabase/_async/client.py index 7fc722f6..6f956656 100644 --- a/supabase/_async/client.py +++ b/supabase/_async/client.py @@ -1,4 +1,5 @@ import asyncio +import copy import re from typing import Any, Dict, List, Optional, Union @@ -69,7 +70,7 @@ def __init__( self.supabase_url = supabase_url self.supabase_key = supabase_key - self.options = options + self.options = copy.deepcopy(options) options.headers.update(self._get_auth_headers()) self.rest_url = f"{supabase_url}/rest/v1" self.realtime_url = f"{supabase_url}/realtime/v1".replace("http", "ws") @@ -294,8 +295,11 @@ def _listen_to_auth_events( self._storage = None self._functions = None access_token = session.access_token if session else self.supabase_key - - self.options.headers["Authorization"] = self._create_auth_header(access_token) + headers = copy.deepcopy(self._create_auth_header(access_token)) + self.options.headers["Authorization"] = headers + self.auth._headers["Authorization"] = headers + self.postgrest.session.headers["Authorization"] = headers + self.storage.session.headers["Authorization"] = headers asyncio.create_task(self.realtime.set_auth(access_token)) diff --git a/supabase/_sync/client.py b/supabase/_sync/client.py index d8da3a09..a366f933 100644 --- a/supabase/_sync/client.py +++ b/supabase/_sync/client.py @@ -1,3 +1,4 @@ +import copy import re from typing import Any, Dict, List, Optional, Union @@ -62,13 +63,11 @@ def __init__( r"^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$", supabase_key ): raise SupabaseException("Invalid API key") - if options is None: options = ClientOptions(storage=SyncMemoryStorage()) - self.supabase_url = supabase_url self.supabase_key = supabase_key - self.options = options + self.options = copy.deepcopy(options) options.headers.update(self._get_auth_headers()) self.rest_url = f"{supabase_url}/rest/v1" self.realtime_url = f"{supabase_url}/realtime/v1".replace("http", "ws") @@ -100,7 +99,7 @@ def create( ): auth_header = options.headers.get("Authorization") if options else None client = cls(supabase_url, supabase_key, options) - + session_access_token = None if auth_header is None: try: session = client.auth.get_session() @@ -108,9 +107,7 @@ def create( except Exception as err: session_access_token = None - client.options.headers.update( - client._get_auth_headers(session_access_token) - ) + client.options.headers.update(client._get_auth_headers(session_access_token)) return client @@ -293,8 +290,11 @@ def _listen_to_auth_events( self._storage = None self._functions = None access_token = session.access_token if session else self.supabase_key - - self.options.headers["Authorization"] = self._create_auth_header(access_token) + header = copy.deepcopy(self._create_auth_header(access_token)) + self.options.headers["Authorization"] = header + self.auth._headers["Authorization"] = header + self.postgrest.session.headers["Authorization"] = header + self.storage.session.headers["Authorization"] = header def create_client( diff --git a/tests/test_client.py b/tests/test_client.py index d8f0be0c..eb34fa70 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -101,7 +101,6 @@ def test_updates_the_authorization_header_on_auth_events() -> None: mock_session = MagicMock(access_token="secretuserjwt") realtime_mock = MagicMock() client.realtime = realtime_mock - client._listen_to_auth_events("SIGNED_IN", mock_session) updated_authorization = f"Bearer {mock_session.access_token}" @@ -113,7 +112,6 @@ def test_updates_the_authorization_header_on_auth_events() -> None: assert ( client.postgrest.session.headers.get("Authorization") == updated_authorization ) - assert client.auth._headers.get("apiKey") == key assert client.auth._headers.get("Authorization") == updated_authorization From d5302d5562a5cbf9d8cbd3f28221481b63ecbbaa Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Thu, 3 Apr 2025 02:07:19 +0900 Subject: [PATCH 02/10] delete jupytor notebook --- supabase-py.ipynb | 85 ----------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 supabase-py.ipynb diff --git a/supabase-py.ipynb b/supabase-py.ipynb deleted file mode 100644 index 9b7843a8..00000000 --- a/supabase-py.ipynb +++ /dev/null @@ -1,85 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "cfcfd082-5f3b-4112-bf67-97dd7b3a40d3", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ModifiedValue1\n", - "ModifiedValue2\n" - ] - } - ], - "source": [ - "\n", - "from supabase import create_client\n", - "from supabase.lib.client_options import SyncClientOptions \n", - "class settings:\n", - " SUPABASE_URL = \"https://kdfdmfosctjrymkhebmv.supabase.co\"\n", - " SUPABASE_KEY = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImtkZmRtZm9zY3Rqcnlta2hlYm12Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDEzMzA1NDAsImV4cCI6MjA1NjkwNjU0MH0.FkBK4a5D-qEVH81sNh9A2OFFpVlgK0uWg8OqyxuEXks\"\n", - "from supabase._sync.client import create_client, ClientOptions\n", - "from gotrue import SyncMemoryStorage\n", - "\n", - "# 同じ ClientOptions インスタンスを複数のクライアントで共有\n", - "shared_options = ClientOptions(storage=SyncMemoryStorage(), headers={\"Custom-Header\": \"InitialValue\"})\n", - "\n", - "# クライアント1を作成\n", - "client1 = create_client(settings.SUPABASE_URL, settings.SUPABASE_KEY, options=shared_options)\n", - "\n", - "# クライアント2を作成\n", - "client2 = create_client(settings.SUPABASE_URL, settings.SUPABASE_KEY, options=shared_options)\n", - "\n", - "# クライアント1のヘッダーを変更\n", - "client1.options.headers[\"Custom-Header\"] = \"ModifiedValue1\"\n", - "client2.options.headers[\"Custom-Header\"] = \"ModifiedValue2\"\n", - "# クライアント2のヘッダーを確認\n", - "print(client1.options.headers[\"Custom-Header\"])\n", - "print(client2.options.headers[\"Custom-Header\"])# \"ModifiedValue\" と表示される\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6b066af-d553-4b3c-be92-5c51e6ed988d", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d86256ee-edbb-4b53-927a-73ddd384c28a", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 02eca96a9fa801b8594ae0560252faf4c5c0c681 Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Thu, 3 Apr 2025 23:17:05 +0900 Subject: [PATCH 03/10] add test case --- tests/test_client.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index eb34fa70..0ddfcc56 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -5,6 +5,7 @@ from unittest.mock import MagicMock import pytest +from gotrue import SyncMemoryStorage from supabase import Client, ClientOptions, SupabaseException, create_client @@ -117,3 +118,36 @@ def test_updates_the_authorization_header_on_auth_events() -> None: assert client.storage.session.headers.get("apiKey") == key assert client.storage.session.headers.get("Authorization") == updated_authorization + + +def test_mutable_headers_issue(): + url = os.environ.get("SUPABASE_TEST_URL") + key = os.environ.get("SUPABASE_TEST_KEY") + + shared_options = ClientOptions( + storage=SyncMemoryStorage(), headers={"Authorization": "Bearer initial-token"} + ) + + client1 = create_client(url, key, shared_options) + + client2 = create_client(url, key, shared_options) + + client1.options.headers["Authorization"] = "Bearer modified-token" + + assert client2.options.headers["Authorization"] == "Bearer initial-token" + + +# +def test_global_authorization_header_issue(): + url = os.environ.get("SUPABASE_TEST_URL") + key = os.environ.get("SUPABASE_TEST_KEY") + + authorization = "Bearer secretuserjwt" + options = ClientOptions(headers={"Authorization": authorization}) + + client = create_client(url, key, options) + + assert client.options.headers.get("apiKey") == key + + +# 実行 From 505bf6d888b2d4b0b57992d8d69a2e5c6ef16139 Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Fri, 4 Apr 2025 01:30:14 +0900 Subject: [PATCH 04/10] remove unnecessary code --- supabase/_async/client.py | 8 +++----- supabase/_sync/client.py | 2 -- tests/test_client.py | 3 --- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/supabase/_async/client.py b/supabase/_async/client.py index 6f956656..803499bc 100644 --- a/supabase/_async/client.py +++ b/supabase/_async/client.py @@ -295,11 +295,9 @@ def _listen_to_auth_events( self._storage = None self._functions = None access_token = session.access_token if session else self.supabase_key - headers = copy.deepcopy(self._create_auth_header(access_token)) - self.options.headers["Authorization"] = headers - self.auth._headers["Authorization"] = headers - self.postgrest.session.headers["Authorization"] = headers - self.storage.session.headers["Authorization"] = headers + header = copy.deepcopy(self._create_auth_header(access_token)) + self.options.headers["Authorization"] = header + self.auth._headers["Authorization"] = header asyncio.create_task(self.realtime.set_auth(access_token)) diff --git a/supabase/_sync/client.py b/supabase/_sync/client.py index a366f933..f4f1b504 100644 --- a/supabase/_sync/client.py +++ b/supabase/_sync/client.py @@ -293,8 +293,6 @@ def _listen_to_auth_events( header = copy.deepcopy(self._create_auth_header(access_token)) self.options.headers["Authorization"] = header self.auth._headers["Authorization"] = header - self.postgrest.session.headers["Authorization"] = header - self.storage.session.headers["Authorization"] = header def create_client( diff --git a/tests/test_client.py b/tests/test_client.py index 0ddfcc56..417ad831 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -148,6 +148,3 @@ def test_global_authorization_header_issue(): client = create_client(url, key, options) assert client.options.headers.get("apiKey") == key - - -# 実行 From a4291bcee3823d25a58478b39dd4bae1f553188e Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Fri, 4 Apr 2025 01:50:20 +0900 Subject: [PATCH 05/10] rename auth_header --- supabase/_async/client.py | 6 +++--- supabase/_sync/client.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/supabase/_async/client.py b/supabase/_async/client.py index 803499bc..004ca3ce 100644 --- a/supabase/_async/client.py +++ b/supabase/_async/client.py @@ -295,9 +295,9 @@ def _listen_to_auth_events( self._storage = None self._functions = None access_token = session.access_token if session else self.supabase_key - header = copy.deepcopy(self._create_auth_header(access_token)) - self.options.headers["Authorization"] = header - self.auth._headers["Authorization"] = header + auth_header = copy.deepcopy(self._create_auth_header(access_token)) + self.options.headers["Authorization"] = auth_header + self.auth._headers["Authorization"] = auth_header asyncio.create_task(self.realtime.set_auth(access_token)) diff --git a/supabase/_sync/client.py b/supabase/_sync/client.py index f4f1b504..06a88457 100644 --- a/supabase/_sync/client.py +++ b/supabase/_sync/client.py @@ -290,9 +290,9 @@ def _listen_to_auth_events( self._storage = None self._functions = None access_token = session.access_token if session else self.supabase_key - header = copy.deepcopy(self._create_auth_header(access_token)) - self.options.headers["Authorization"] = header - self.auth._headers["Authorization"] = header + auth_header = copy.deepcopy(self._create_auth_header(access_token)) + self.options.headers["Authorization"] = auth_header + self.auth._headers["Authorization"] = auth_header def create_client( From 34ed12c31271839b50df3a4348f5ef49d9e25853 Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Fri, 4 Apr 2025 01:56:23 +0900 Subject: [PATCH 06/10] delete # --- tests/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_client.py b/tests/test_client.py index 417ad831..bb1de3f7 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -137,7 +137,7 @@ def test_mutable_headers_issue(): assert client2.options.headers["Authorization"] == "Bearer initial-token" -# + def test_global_authorization_header_issue(): url = os.environ.get("SUPABASE_TEST_URL") key = os.environ.get("SUPABASE_TEST_KEY") From b804c298712011c4332f2ae0c608bf6425b53589 Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Sat, 5 Apr 2025 03:51:34 +0900 Subject: [PATCH 07/10] rewrite rewrite class props --- supabase/_sync/client.py | 10 +++++----- tests/test_client.py | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/supabase/_sync/client.py b/supabase/_sync/client.py index 06a88457..bb33f796 100644 --- a/supabase/_sync/client.py +++ b/supabase/_sync/client.py @@ -65,10 +65,11 @@ def __init__( raise SupabaseException("Invalid API key") if options is None: options = ClientOptions(storage=SyncMemoryStorage()) + self.supabase_url = supabase_url self.supabase_key = supabase_key self.options = copy.deepcopy(options) - options.headers.update(self._get_auth_headers()) + self.options.headers.update(self._get_auth_headers()) self.rest_url = f"{supabase_url}/rest/v1" self.realtime_url = f"{supabase_url}/realtime/v1".replace("http", "ws") self.auth_url = f"{supabase_url}/auth/v1" @@ -78,12 +79,12 @@ def __init__( # Instantiate clients. self.auth = self._init_supabase_auth_client( auth_url=self.auth_url, - client_options=options, + client_options=self.options, ) self.realtime = self._init_realtime_client( realtime_url=self.realtime_url, supabase_key=self.supabase_key, - options=options.realtime if options else None, + options=self.options.realtime if self.options else None, ) self._postgrest = None self._storage = None @@ -106,9 +107,7 @@ def create( session_access_token = client._create_auth_header(session.access_token) except Exception as err: session_access_token = None - client.options.headers.update(client._get_auth_headers(session_access_token)) - return client def table(self, table_name: str) -> SyncRequestBuilder: @@ -326,6 +325,7 @@ def create_client( ------- Client """ + return SyncClient.create( supabase_url=supabase_url, supabase_key=supabase_key, options=options ) diff --git a/tests/test_client.py b/tests/test_client.py index bb1de3f7..78ddc6ac 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -137,7 +137,6 @@ def test_mutable_headers_issue(): assert client2.options.headers["Authorization"] == "Bearer initial-token" - def test_global_authorization_header_issue(): url = os.environ.get("SUPABASE_TEST_URL") key = os.environ.get("SUPABASE_TEST_KEY") From c6d4cdf25cdc30363032f502dd841a0f5b1b86af Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Tue, 8 Apr 2025 00:43:54 +0900 Subject: [PATCH 08/10] fix _async/client.py --- supabase/_async/client.py | 7 ++++--- supabase/_sync/auth_client.py | 6 +++--- supabase/_sync/client.py | 13 +++++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/supabase/_async/client.py b/supabase/_async/client.py index 004ca3ce..bd34b084 100644 --- a/supabase/_async/client.py +++ b/supabase/_async/client.py @@ -71,7 +71,8 @@ def __init__( self.supabase_url = supabase_url self.supabase_key = supabase_key self.options = copy.deepcopy(options) - options.headers.update(self._get_auth_headers()) + self.options.headers.update(self._get_auth_headers()) + self.rest_url = f"{supabase_url}/rest/v1" self.realtime_url = f"{supabase_url}/realtime/v1".replace("http", "ws") self.auth_url = f"{supabase_url}/auth/v1" @@ -81,12 +82,12 @@ def __init__( # Instantiate clients. self.auth = self._init_supabase_auth_client( auth_url=self.auth_url, - client_options=options, + client_options=self.options, ) self.realtime = self._init_realtime_client( realtime_url=self.realtime_url, supabase_key=self.supabase_key, - options=options.realtime if options else None, + options=self.options.realtime if self.options else None, ) self._postgrest = None self._storage = None diff --git a/supabase/_sync/auth_client.py b/supabase/_sync/auth_client.py index cd2836c3..65b5fca6 100644 --- a/supabase/_sync/auth_client.py +++ b/supabase/_sync/auth_client.py @@ -10,7 +10,7 @@ class SyncSupabaseAuthClient(SyncGoTrueClient): - """Supabase Auth Client for synchronous operations.""" + """Supabase Auth Client for asynchronous operations.""" def __init__( self, @@ -35,8 +35,8 @@ def __init__( storage_key (Optional[str]): Key to store session information. auto_refresh_token (bool): Whether to automatically refresh the token. Defaults to True. persist_session (bool): Whether to persist the session. Defaults to True. - storage (SyncSupportedStorage): Storage mechanism. Defaults to SyncMemoryStorage(). - http_client (Optional[SyncClient]): HTTP client for making requests. Defaults to None. + storage (AsyncSupportedStorage): Storage mechanism. Defaults to AsyncMemoryStorage(). + http_client (Optional[AsyncClient]): HTTP client for making requests. Defaults to None. flow_type (AuthFlowType): Type of authentication flow. Defaults to "implicit". verify (bool): Whether to verify SSL certificates. Defaults to True. proxy (Optional[str]): Proxy URL. Defaults to None. diff --git a/supabase/_sync/client.py b/supabase/_sync/client.py index bb33f796..a477f843 100644 --- a/supabase/_sync/client.py +++ b/supabase/_sync/client.py @@ -63,6 +63,7 @@ def __init__( r"^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$", supabase_key ): raise SupabaseException("Invalid API key") + if options is None: options = ClientOptions(storage=SyncMemoryStorage()) @@ -70,6 +71,7 @@ def __init__( self.supabase_key = supabase_key self.options = copy.deepcopy(options) self.options.headers.update(self._get_auth_headers()) + self.rest_url = f"{supabase_url}/rest/v1" self.realtime_url = f"{supabase_url}/realtime/v1".replace("http", "ws") self.auth_url = f"{supabase_url}/auth/v1" @@ -100,14 +102,18 @@ def create( ): auth_header = options.headers.get("Authorization") if options else None client = cls(supabase_url, supabase_key, options) - session_access_token = None + if auth_header is None: try: session = client.auth.get_session() session_access_token = client._create_auth_header(session.access_token) except Exception as err: session_access_token = None - client.options.headers.update(client._get_auth_headers(session_access_token)) + + client.options.headers.update( + client._get_auth_headers(session_access_token) + ) + return client def table(self, table_name: str) -> SyncRequestBuilder: @@ -290,8 +296,8 @@ def _listen_to_auth_events( self._functions = None access_token = session.access_token if session else self.supabase_key auth_header = copy.deepcopy(self._create_auth_header(access_token)) + self.options.headers["Authorization"] = auth_header - self.auth._headers["Authorization"] = auth_header def create_client( @@ -325,7 +331,6 @@ def create_client( ------- Client """ - return SyncClient.create( supabase_url=supabase_url, supabase_key=supabase_key, options=options ) From d1495bcef1a8a02a74437667a0d2f815efab0752 Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Tue, 8 Apr 2025 00:47:30 +0900 Subject: [PATCH 09/10] test passed --- tests/test_client.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 78ddc6ac..de7a3cae 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -147,3 +147,20 @@ def test_global_authorization_header_issue(): client = create_client(url, key, options) assert client.options.headers.get("apiKey") == key + + +def test_mutable_headers_issue(): + url = os.environ.get("SUPABASE_TEST_URL") + key = os.environ.get("SUPABASE_TEST_KEY") + + shared_options = ClientOptions( + headers={"Authorization": "Bearer initial-token", "x-site": "supanew.site"} + ) + + client1 = create_client(url, key, shared_options) + client2 = create_client(url, key, shared_options) + client1.options.replace({"headers": {"Authorization": "Bearer modified-token"}}) + + assert client2.options.headers["Authorization"] == "Bearer initial-token" + assert client2.options.headers["x-site"] == "supanew.site" + assert client1.options.headers["x-site"] == "supanew.site" From 7ac3df2f2a1b860ffb8d1a19681a4c67df1ebb3e Mon Sep 17 00:00:00 2001 From: AsahiSoftWareEngineer Date: Wed, 9 Apr 2025 22:23:06 +0900 Subject: [PATCH 10/10] fix _sync/auth_client.py --- supabase/_sync/auth_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/supabase/_sync/auth_client.py b/supabase/_sync/auth_client.py index 65b5fca6..cd2836c3 100644 --- a/supabase/_sync/auth_client.py +++ b/supabase/_sync/auth_client.py @@ -10,7 +10,7 @@ class SyncSupabaseAuthClient(SyncGoTrueClient): - """Supabase Auth Client for asynchronous operations.""" + """Supabase Auth Client for synchronous operations.""" def __init__( self, @@ -35,8 +35,8 @@ def __init__( storage_key (Optional[str]): Key to store session information. auto_refresh_token (bool): Whether to automatically refresh the token. Defaults to True. persist_session (bool): Whether to persist the session. Defaults to True. - storage (AsyncSupportedStorage): Storage mechanism. Defaults to AsyncMemoryStorage(). - http_client (Optional[AsyncClient]): HTTP client for making requests. Defaults to None. + storage (SyncSupportedStorage): Storage mechanism. Defaults to SyncMemoryStorage(). + http_client (Optional[SyncClient]): HTTP client for making requests. Defaults to None. flow_type (AuthFlowType): Type of authentication flow. Defaults to "implicit". verify (bool): Whether to verify SSL certificates. Defaults to True. proxy (Optional[str]): Proxy URL. Defaults to None.