Skip to content

Commit 3ca78fa

Browse files
feat: rewrite region enumerated literals as Enums (#164)
1 parent 46cadae commit 3ca78fa

File tree

8 files changed

+101
-8
lines changed

8 files changed

+101
-8
lines changed

poetry.lock

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

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ repository = "https://github.com/supabase/functions-py"
1313
[tool.poetry.dependencies]
1414
python = "^3.9"
1515
httpx = {version = ">=0.26,<0.28", extras = ["http2"]}
16+
strenum = "^0.4.15"
1617

1718
[tool.poetry.group.dev.dependencies]
1819
black = ">=23.9.1,<25.0.0"

supabase_functions/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from ._async.functions_client import AsyncFunctionsClient
66
from ._sync.functions_client import SyncFunctionsClient
7+
from .utils import FunctionRegion
78

89
__all__ = ["create_client"]
910

supabase_functions/_async/functions_client.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
from typing import Any, Dict, Literal, Optional, Union
2+
from warnings import warn
23

34
from httpx import HTTPError, Response
45

56
from ..errors import FunctionsHttpError, FunctionsRelayError
6-
from ..utils import AsyncClient, is_http_url, is_valid_jwt, is_valid_str_arg
7+
from ..utils import (
8+
AsyncClient,
9+
FunctionRegion,
10+
is_http_url,
11+
is_valid_jwt,
12+
is_valid_str_arg,
13+
)
714
from ..version import __version__
815

916

@@ -88,8 +95,13 @@ async def invoke(
8895
response_type = invoke_options.get("responseType", "text/plain")
8996

9097
region = invoke_options.get("region")
91-
if region and isinstance(region, str) and region != "any":
92-
headers["x-region"] = region.lower().strip()
98+
if region:
99+
if not isinstance(region, FunctionRegion):
100+
warn(f"Use FunctionRegion({region})")
101+
region = FunctionRegion(region)
102+
103+
if region.value != "any":
104+
headers["x-region"] = region.value
93105

94106
body = invoke_options.get("body")
95107
if isinstance(body, str):

supabase_functions/_sync/functions_client.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
from typing import Any, Dict, Literal, Optional, Union
2+
from warnings import warn
23

34
from httpx import HTTPError, Response
45

56
from ..errors import FunctionsHttpError, FunctionsRelayError
6-
from ..utils import SyncClient, is_http_url, is_valid_jwt, is_valid_str_arg
7+
from ..utils import (
8+
FunctionRegion,
9+
SyncClient,
10+
is_http_url,
11+
is_valid_jwt,
12+
is_valid_str_arg,
13+
)
714
from ..version import __version__
815

916

@@ -88,8 +95,13 @@ def invoke(
8895
response_type = invoke_options.get("responseType", "text/plain")
8996

9097
region = invoke_options.get("region")
91-
if region and isinstance(region, str) and region != "any":
92-
headers["x-region"] = region.lower().strip()
98+
if region:
99+
if not isinstance(region, FunctionRegion):
100+
warn(f"Use FunctionRegion({region})")
101+
region = FunctionRegion(region)
102+
103+
if region.value != "any":
104+
headers["x-region"] = region.value
93105

94106
body = invoke_options.get("body")
95107
if isinstance(body, str):

supabase_functions/utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
11
import re
2+
import sys
23
from urllib.parse import urlparse
34

45
from httpx import AsyncClient as AsyncClient # noqa: F401
56
from httpx import Client as BaseClient
67

8+
if sys.version_info >= (3, 11):
9+
from enum import StrEnum
10+
else:
11+
from strenum import StrEnum
12+
13+
714
DEFAULT_FUNCTION_CLIENT_TIMEOUT = 5
815
BASE64URL_REGEX = r"^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$"
916

1017

18+
class FunctionRegion(StrEnum):
19+
Any = "any"
20+
ApNortheast1 = "ap-northeast-1"
21+
ApNortheast2 = "ap-northeast-2"
22+
ApSouth1 = "ap-south-1"
23+
ApSoutheast1 = "ap-southeast-1"
24+
ApSoutheast2 = "ap-southeast-2"
25+
CaCentral1 = "ca-central-1"
26+
EuCentral1 = "eu-central-1"
27+
EuWest1 = "eu-west-1"
28+
EuWest2 = "eu-west-2"
29+
EuWest3 = "eu-west-3"
30+
SaEast1 = "sa-east-1"
31+
UsEast1 = "us-east-1"
32+
UsWest1 = "us-west-1"
33+
UsWest2 = "us-west-2"
34+
35+
1136
class SyncClient(BaseClient):
1237
def aclose(self) -> None:
1338
self.close()

tests/_async/test_function_client.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from httpx import Response
44
from jwt import encode
55

6+
from supabase_functions import FunctionRegion
67
from supabase_functions.errors import FunctionsHttpError, FunctionsRelayError
78

89
from .clients import (
@@ -40,6 +41,18 @@ async def test_invoke():
4041
assert route.called
4142

4243

44+
async def test_invoke_region():
45+
with respx.mock:
46+
route = respx.post(f"{FUNCTIONS_URL}/hello-world").mock(
47+
return_value=Response(200)
48+
)
49+
await function_client().invoke(
50+
function_name="hello-world",
51+
invoke_options={"region": FunctionRegion("us-west-2")},
52+
)
53+
assert route.called
54+
55+
4356
async def test_invoke_with_json_response():
4457
async with respx.mock:
4558
route = respx.post(f"{FUNCTIONS_URL}/hello-world").mock(

tests/_sync/test_function_client.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from httpx import Response
44
from jwt import encode
55

6+
from supabase_functions import FunctionRegion
67
from supabase_functions.errors import FunctionsHttpError, FunctionsRelayError
78

89
from .clients import (
@@ -40,6 +41,18 @@ def test_invoke():
4041
assert route.called
4142

4243

44+
def test_invoke_region():
45+
with respx.mock:
46+
route = respx.post(f"{FUNCTIONS_URL}/hello-world").mock(
47+
return_value=Response(200)
48+
)
49+
function_client().invoke(
50+
function_name="hello-world",
51+
invoke_options={"region": FunctionRegion("us-west-2")},
52+
)
53+
assert route.called
54+
55+
4356
def test_invoke_with_json_response():
4457
with respx.mock:
4558
route = respx.post(f"{FUNCTIONS_URL}/hello-world").mock(

0 commit comments

Comments
 (0)