Skip to content

Commit 78ebf2c

Browse files
authored
feat(supabase): use yarl URL builder in supabase as well (#1331)
1 parent e3ddf40 commit 78ebf2c

File tree

6 files changed

+53
-34
lines changed

6 files changed

+53
-34
lines changed

src/supabase/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies = [
2828
"supabase_auth == 2.25.1", # x-release-please-version
2929
"postgrest == 2.25.1", # x-release-please-version
3030
"httpx >=0.26,<0.29",
31+
"yarl>=1.22.0",
3132
]
3233

3334
[project.urls]

src/supabase/src/supabase/_async/client.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from supabase_auth import AsyncMemoryStorage
1818
from supabase_auth.types import AuthChangeEvent, Session
1919
from supabase_functions import AsyncFunctionsClient
20+
from yarl import URL
2021

2122
from ..lib.client_options import AsyncClientOptions as ClientOptions
2223
from ..lib.client_options import AsyncHttpxClient
@@ -65,23 +66,27 @@ def __init__(
6566
if options is None:
6667
options = ClientOptions(storage=AsyncMemoryStorage())
6768

68-
self.supabase_url = supabase_url
69+
self.supabase_url = (
70+
URL(supabase_url) if supabase_url.endswith("/") else URL(supabase_url + "/")
71+
)
6972
self.supabase_key = supabase_key
7073
self.options = copy.copy(options)
7174
self.options.headers = {
7275
**options.headers,
7376
**self._get_auth_headers(),
7477
}
7578

76-
self.rest_url = f"{supabase_url}/rest/v1"
77-
self.realtime_url = f"{supabase_url}/realtime/v1".replace("http", "ws")
78-
self.auth_url = f"{supabase_url}/auth/v1"
79-
self.storage_url = f"{supabase_url}/storage/v1/"
80-
self.functions_url = f"{supabase_url}/functions/v1"
79+
self.rest_url = self.supabase_url.joinpath("rest", "v1")
80+
self.realtime_url = self.supabase_url.joinpath("realtime", "v1").with_scheme(
81+
"wss" if self.supabase_url.scheme == "https" else "ws"
82+
)
83+
self.auth_url = self.supabase_url.joinpath("auth", "v1")
84+
self.storage_url = self.supabase_url.joinpath("storage", "v1")
85+
self.functions_url = self.supabase_url.joinpath("functions", "v1")
8186

8287
# Instantiate clients.
8388
self.auth = self._init_supabase_auth_client(
84-
auth_url=self.auth_url,
89+
auth_url=str(self.auth_url),
8590
client_options=self.options,
8691
)
8792
self.realtime = self._init_realtime_client(
@@ -178,7 +183,7 @@ def rpc(
178183
def postgrest(self) -> AsyncPostgrestClient:
179184
if self._postgrest is None:
180185
self._postgrest = self._init_postgrest_client(
181-
rest_url=self.rest_url,
186+
rest_url=str(self.rest_url),
182187
headers=self.options.headers,
183188
schema=self.options.schema,
184189
timeout=self.options.postgrest_client_timeout,
@@ -191,7 +196,7 @@ def postgrest(self) -> AsyncPostgrestClient:
191196
def storage(self) -> AsyncStorageClient:
192197
if self._storage is None:
193198
self._storage = self._init_storage_client(
194-
storage_url=self.storage_url,
199+
storage_url=str(self.storage_url),
195200
headers=self.options.headers,
196201
storage_client_timeout=self.options.storage_client_timeout,
197202
http_client=self.options.httpx_client,
@@ -202,7 +207,7 @@ def storage(self) -> AsyncStorageClient:
202207
def functions(self) -> AsyncFunctionsClient:
203208
if self._functions is None:
204209
self._functions = AsyncFunctionsClient(
205-
url=self.functions_url,
210+
url=str(self.functions_url),
206211
headers=self.options.headers,
207212
timeout=(
208213
self.options.function_client_timeout
@@ -233,13 +238,15 @@ async def remove_all_channels(self) -> None:
233238

234239
@staticmethod
235240
def _init_realtime_client(
236-
realtime_url: str,
241+
realtime_url: URL,
237242
supabase_key: str,
238243
options: Optional[RealtimeClientOptions] = None,
239244
) -> AsyncRealtimeClient:
240245
realtime_options = options or {}
241246
"""Private method for creating an instance of the realtime-py client."""
242-
return AsyncRealtimeClient(realtime_url, token=supabase_key, **realtime_options)
247+
return AsyncRealtimeClient(
248+
str(realtime_url), token=supabase_key, **realtime_options
249+
)
243250

244251
@staticmethod
245252
def _init_storage_client(

src/supabase/src/supabase/_sync/client.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from supabase_auth import SyncMemoryStorage
1717
from supabase_auth.types import AuthChangeEvent, Session
1818
from supabase_functions import SyncFunctionsClient
19+
from yarl import URL
1920

2021
from ..lib.client_options import SyncClientOptions as ClientOptions
2122
from ..lib.client_options import SyncHttpxClient
@@ -64,23 +65,27 @@ def __init__(
6465
if options is None:
6566
options = ClientOptions(storage=SyncMemoryStorage())
6667

67-
self.supabase_url = supabase_url
68+
self.supabase_url = (
69+
URL(supabase_url) if supabase_url.endswith("/") else URL(supabase_url + "/")
70+
)
6871
self.supabase_key = supabase_key
6972
self.options = copy.copy(options)
7073
self.options.headers = {
7174
**options.headers,
7275
**self._get_auth_headers(),
7376
}
7477

75-
self.rest_url = f"{supabase_url}/rest/v1"
76-
self.realtime_url = f"{supabase_url}/realtime/v1".replace("http", "ws")
77-
self.auth_url = f"{supabase_url}/auth/v1"
78-
self.storage_url = f"{supabase_url}/storage/v1/"
79-
self.functions_url = f"{supabase_url}/functions/v1"
78+
self.rest_url = self.supabase_url.joinpath("rest", "v1")
79+
self.realtime_url = self.supabase_url.joinpath("realtime", "v1").with_scheme(
80+
"wss" if self.supabase_url.scheme == "https" else "ws"
81+
)
82+
self.auth_url = self.supabase_url.joinpath("auth", "v1")
83+
self.storage_url = self.supabase_url.joinpath("storage", "v1")
84+
self.functions_url = self.supabase_url.joinpath("functions", "v1")
8085

8186
# Instantiate clients.
8287
self.auth = self._init_supabase_auth_client(
83-
auth_url=self.auth_url,
88+
auth_url=str(self.auth_url),
8489
client_options=self.options,
8590
)
8691
self.realtime = self._init_realtime_client(
@@ -177,7 +182,7 @@ def rpc(
177182
def postgrest(self) -> SyncPostgrestClient:
178183
if self._postgrest is None:
179184
self._postgrest = self._init_postgrest_client(
180-
rest_url=self.rest_url,
185+
rest_url=str(self.rest_url),
181186
headers=self.options.headers,
182187
schema=self.options.schema,
183188
timeout=self.options.postgrest_client_timeout,
@@ -190,7 +195,7 @@ def postgrest(self) -> SyncPostgrestClient:
190195
def storage(self) -> SyncStorageClient:
191196
if self._storage is None:
192197
self._storage = self._init_storage_client(
193-
storage_url=self.storage_url,
198+
storage_url=str(self.storage_url),
194199
headers=self.options.headers,
195200
storage_client_timeout=self.options.storage_client_timeout,
196201
http_client=self.options.httpx_client,
@@ -201,7 +206,7 @@ def storage(self) -> SyncStorageClient:
201206
def functions(self) -> SyncFunctionsClient:
202207
if self._functions is None:
203208
self._functions = SyncFunctionsClient(
204-
url=self.functions_url,
209+
url=str(self.functions_url),
205210
headers=self.options.headers,
206211
timeout=(
207212
self.options.function_client_timeout
@@ -232,13 +237,15 @@ def remove_all_channels(self) -> None:
232237

233238
@staticmethod
234239
def _init_realtime_client(
235-
realtime_url: str,
240+
realtime_url: URL,
236241
supabase_key: str,
237242
options: Optional[RealtimeClientOptions] = None,
238243
) -> SyncRealtimeClient:
239244
realtime_options = options or {}
240245
"""Private method for creating an instance of the realtime-py client."""
241-
return SyncRealtimeClient(realtime_url, token=supabase_key, **realtime_options)
246+
return SyncRealtimeClient(
247+
str(realtime_url), token=supabase_key, **realtime_options
248+
)
242249

243250
@staticmethod
244251
def _init_storage_client(

src/supabase/tests/test_function_configuration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ def test_functions_client_initialization() -> None:
77
# Sample JWT Key
88
key = "xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxxxx"
99
sp = supabase.Client(url, key)
10-
assert sp.functions_url == f"https://{ref}.supabase.co/functions/v1"
10+
assert str(sp.functions_url) == f"https://{ref}.supabase.co/functions/v1"
1111

1212
url = "https://localhost:54322"
1313
sp_local = supabase.Client(url, key)
14-
assert sp_local.functions_url == f"{url}/functions/v1"
14+
assert str(sp_local.functions_url) == f"{url}/functions/v1"

src/supabase/tests/test_realtime.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ def test_realtime_client_initialization() -> None:
77
# Sample JWT Key
88
key = "xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxxxx"
99
sp = supabase.Client(url, key)
10-
assert sp.realtime_url == f"wss://{ref}.supabase.co/realtime/v1"
10+
assert str(sp.realtime_url) == f"wss://{ref}.supabase.co/realtime/v1"
1111

1212
url = "http://localhost:54322"
1313
sp_local = supabase.Client(url, key)
14-
assert sp_local.realtime_url == "ws://localhost:54322/realtime/v1"
14+
assert str(sp_local.realtime_url) == "ws://localhost:54322/realtime/v1"

uv.lock

Lines changed: 10 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)