Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 4506be3

Browse files
committed
test: add tests for custom httpx client
1 parent bc1d8ec commit 4506be3

File tree

10 files changed

+190
-17
lines changed

10 files changed

+190
-17
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ remove_pytest_asyncio_from_sync:
3939
sed -i 's/Async/Sync/g' tests/_sync/test_client.py
4040
sed -i 's/Async/Sync/g' postgrest/_sync/request_builder.py
4141
sed -i 's/_client\.SyncClient/_client\.Client/g' tests/_sync/test_client.py
42+
sed -i 's/SyncHTTPTransport/HTTPTransport/g' tests/_sync/test_client.py
43+
sed -i 's/SyncHTTPTransport/HTTPTransport/g' tests/_sync/client.py
4244

4345
sleep:
4446
sleep 2

postgrest/_sync/request_builder.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ def select(
287287
*columns: The names of the columns to fetch.
288288
count: The method to use to get the count of rows returned.
289289
Returns:
290-
:class:`AsyncSelectRequestBuilder`
290+
:class:`SyncSelectRequestBuilder`
291291
"""
292292
method, params, headers, json = pre_select(*columns, count=count, head=head)
293293
return SyncSelectRequestBuilder[_ReturnT](
@@ -314,7 +314,7 @@ def insert(
314314
Otherwise, use the default value for the column.
315315
Only applies for bulk inserts.
316316
Returns:
317-
:class:`AsyncQueryRequestBuilder`
317+
:class:`SyncQueryRequestBuilder`
318318
"""
319319
method, params, headers, json = pre_insert(
320320
json,
@@ -350,7 +350,7 @@ def upsert(
350350
not when merging with existing rows under `ignoreDuplicates: false`.
351351
This also only applies when doing bulk upserts.
352352
Returns:
353-
:class:`AsyncQueryRequestBuilder`
353+
:class:`SyncQueryRequestBuilder`
354354
"""
355355
method, params, headers, json = pre_upsert(
356356
json,
@@ -378,7 +378,7 @@ def update(
378378
count: The method to use to get the count of rows returned.
379379
returning: Either 'minimal' or 'representation'
380380
Returns:
381-
:class:`AsyncFilterRequestBuilder`
381+
:class:`SyncFilterRequestBuilder`
382382
"""
383383
method, params, headers, json = pre_update(
384384
json,
@@ -401,7 +401,7 @@ def delete(
401401
count: The method to use to get the count of rows returned.
402402
returning: Either 'minimal' or 'representation'
403403
Returns:
404-
:class:`AsyncFilterRequestBuilder`
404+
:class:`SyncFilterRequestBuilder`
405405
"""
406406
method, params, headers, json = pre_delete(
407407
count=count,

postgrest/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Dict, Optional
1+
from typing import Any, Dict, Optional
22

33
from pydantic import BaseModel
44

@@ -34,7 +34,7 @@ class APIError(Exception):
3434
details: Optional[str]
3535
"""The error details."""
3636

37-
def __init__(self, error: Dict[str, str]) -> None:
37+
def __init__(self, error: Dict[str, Any]) -> None:
3838
self._raw_error = error
3939
self.message = error.get("message")
4040
self.code = error.get("code")

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ furo = ">=2023.9.10,<2025.0.0"
4444

4545
[tool.pytest.ini_options]
4646
asyncio_mode = "auto"
47+
filterwarnings = [
48+
"ignore::DeprecationWarning", # ignore deprecation warnings globally
49+
]
4750

4851
[build-system]
4952
requires = ["poetry-core>=1.0.0"]

tests/_async/client.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
from httpx import AsyncHTTPTransport, Limits
2+
13
from postgrest import AsyncPostgrestClient
4+
from postgrest.utils import AsyncClient
25

36
REST_URL = "http://127.0.0.1:3000"
47

@@ -7,3 +10,20 @@ def rest_client():
710
return AsyncPostgrestClient(
811
base_url=REST_URL,
912
)
13+
14+
15+
def rest_client_httpx():
16+
transport = AsyncHTTPTransport(
17+
retries=4,
18+
limits=Limits(
19+
max_connections=1,
20+
max_keepalive_connections=1,
21+
keepalive_expiry=None,
22+
),
23+
)
24+
headers = {"x-user-agent": "my-app/0.0.1"}
25+
http_client = AsyncClient(transport=transport, headers=headers)
26+
return AsyncPostgrestClient(
27+
base_url=REST_URL,
28+
http_client=http_client,
29+
)

tests/_async/test_client.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
from unittest.mock import patch
22

33
import pytest
4-
from httpx import BasicAuth, Headers, Request, Response
4+
from httpx import (
5+
AsyncHTTPTransport,
6+
BasicAuth,
7+
Headers,
8+
Limits,
9+
Request,
10+
Response,
11+
Timeout,
12+
)
513

614
from postgrest import AsyncPostgrestClient
715
from postgrest.exceptions import APIError
16+
from postgrest.utils import AsyncClient
817

918

1019
@pytest.fixture
@@ -46,6 +55,32 @@ async def test_custom_headers(self):
4655
assert session.headers.items() >= headers.items()
4756

4857

58+
class TestHttpxClientConstructor:
59+
@pytest.mark.asyncio
60+
async def test_custom_httpx_client(self):
61+
transport = AsyncHTTPTransport(
62+
retries=10,
63+
limits=Limits(
64+
max_connections=1,
65+
max_keepalive_connections=1,
66+
keepalive_expiry=None,
67+
),
68+
)
69+
headers = {"x-user-agent": "my-app/0.0.1"}
70+
http_client = AsyncClient(transport=transport, headers=headers)
71+
async with AsyncPostgrestClient(
72+
"https://example.com", http_client=http_client, timeout=20.0
73+
) as client:
74+
session = client.session
75+
76+
assert session.base_url == "https://example.com"
77+
assert session.timeout == Timeout(
78+
timeout=5.0
79+
) # Should be the default 5 since we use custom httpx client
80+
assert session.headers.get("x-user-agent") == "my-app/0.0.1"
81+
assert isinstance(session, AsyncClient)
82+
83+
4984
class TestAuth:
5085
def test_auth_token(self, postgrest_client: AsyncPostgrestClient):
5186
postgrest_client.auth("s3cr3t")

tests/_async/test_filter_request_builder_integration.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
1-
from .client import rest_client
1+
from postgrest import CountMethod
2+
3+
from .client import rest_client, rest_client_httpx
4+
5+
6+
async def test_multivalued_param_httpx():
7+
res = (
8+
await rest_client_httpx()
9+
.from_("countries")
10+
.select("country_name, iso", count=CountMethod.exact)
11+
.lte("numcode", 8)
12+
.gte("numcode", 4)
13+
.execute()
14+
)
15+
16+
assert res.count == 2
17+
assert res.data == [
18+
{"country_name": "AFGHANISTAN", "iso": "AF"},
19+
{"country_name": "ALBANIA", "iso": "AL"},
20+
]
221

322

423
async def test_multivalued_param():
524
res = (
625
await rest_client()
726
.from_("countries")
8-
.select("country_name, iso", count="exact")
27+
.select("country_name, iso", count=CountMethod.exact)
928
.lte("numcode", 8)
1029
.gte("numcode", 4)
1130
.execute()
@@ -506,7 +525,12 @@ async def test_rpc_get_with_args():
506525
async def test_rpc_get_with_count():
507526
res = (
508527
await rest_client()
509-
.rpc("search_countries_by_name", {"search_name": "Al"}, get=True, count="exact")
528+
.rpc(
529+
"search_countries_by_name",
530+
{"search_name": "Al"},
531+
get=True,
532+
count=CountMethod.exact,
533+
)
510534
.select("nicename")
511535
.execute()
512536
)
@@ -517,7 +541,12 @@ async def test_rpc_get_with_count():
517541
async def test_rpc_head_count():
518542
res = (
519543
await rest_client()
520-
.rpc("search_countries_by_name", {"search_name": "Al"}, head=True, count="exact")
544+
.rpc(
545+
"search_countries_by_name",
546+
{"search_name": "Al"},
547+
head=True,
548+
count=CountMethod.exact,
549+
)
521550
.execute()
522551
)
523552

tests/_sync/client.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
from httpx import HTTPTransport, Limits
2+
13
from postgrest import SyncPostgrestClient
4+
from postgrest.utils import SyncClient
25

36
REST_URL = "http://127.0.0.1:3000"
47

@@ -7,3 +10,20 @@ def rest_client():
710
return SyncPostgrestClient(
811
base_url=REST_URL,
912
)
13+
14+
15+
def rest_client_httpx():
16+
transport = HTTPTransport(
17+
retries=4,
18+
limits=Limits(
19+
max_connections=1,
20+
max_keepalive_connections=1,
21+
keepalive_expiry=None,
22+
),
23+
)
24+
headers = {"x-user-agent": "my-app/0.0.1"}
25+
http_client = SyncClient(transport=transport, headers=headers)
26+
return SyncPostgrestClient(
27+
base_url=REST_URL,
28+
http_client=http_client,
29+
)

tests/_sync/test_client.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
from unittest.mock import patch
22

33
import pytest
4-
from httpx import BasicAuth, Headers, Request, Response
4+
from httpx import (
5+
BasicAuth,
6+
Headers,
7+
HTTPTransport,
8+
Limits,
9+
Request,
10+
Response,
11+
Timeout,
12+
)
513

614
from postgrest import SyncPostgrestClient
715
from postgrest.exceptions import APIError
16+
from postgrest.utils import SyncClient
817

918

1019
@pytest.fixture
@@ -45,6 +54,32 @@ def test_custom_headers(self):
4554
assert session.headers.items() >= headers.items()
4655

4756

57+
class TestHttpxClientConstructor:
58+
59+
def test_custom_httpx_client(self):
60+
transport = HTTPTransport(
61+
retries=10,
62+
limits=Limits(
63+
max_connections=1,
64+
max_keepalive_connections=1,
65+
keepalive_expiry=None,
66+
),
67+
)
68+
headers = {"x-user-agent": "my-app/0.0.1"}
69+
http_client = SyncClient(transport=transport, headers=headers)
70+
with SyncPostgrestClient(
71+
"https://example.com", http_client=http_client, timeout=20.0
72+
) as client:
73+
session = client.session
74+
75+
assert session.base_url == "https://example.com"
76+
assert session.timeout == Timeout(
77+
timeout=5.0
78+
) # Should be the default 5 since we use custom httpx client
79+
assert session.headers.get("x-user-agent") == "my-app/0.0.1"
80+
assert isinstance(session, SyncClient)
81+
82+
4883
class TestAuth:
4984
def test_auth_token(self, postgrest_client: SyncPostgrestClient):
5085
postgrest_client.auth("s3cr3t")

tests/_sync/test_filter_request_builder_integration.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
1-
from .client import rest_client
1+
from postgrest import CountMethod
2+
3+
from .client import rest_client, rest_client_httpx
4+
5+
6+
def test_multivalued_param_httpx():
7+
res = (
8+
rest_client_httpx()
9+
.from_("countries")
10+
.select("country_name, iso", count=CountMethod.exact)
11+
.lte("numcode", 8)
12+
.gte("numcode", 4)
13+
.execute()
14+
)
15+
16+
assert res.count == 2
17+
assert res.data == [
18+
{"country_name": "AFGHANISTAN", "iso": "AF"},
19+
{"country_name": "ALBANIA", "iso": "AL"},
20+
]
221

322

423
def test_multivalued_param():
524
res = (
625
rest_client()
726
.from_("countries")
8-
.select("country_name, iso", count="exact")
27+
.select("country_name, iso", count=CountMethod.exact)
928
.lte("numcode", 8)
1029
.gte("numcode", 4)
1130
.execute()
@@ -499,7 +518,12 @@ def test_rpc_get_with_args():
499518
def test_rpc_get_with_count():
500519
res = (
501520
rest_client()
502-
.rpc("search_countries_by_name", {"search_name": "Al"}, get=True, count="exact")
521+
.rpc(
522+
"search_countries_by_name",
523+
{"search_name": "Al"},
524+
get=True,
525+
count=CountMethod.exact,
526+
)
503527
.select("nicename")
504528
.execute()
505529
)
@@ -510,7 +534,12 @@ def test_rpc_get_with_count():
510534
def test_rpc_head_count():
511535
res = (
512536
rest_client()
513-
.rpc("search_countries_by_name", {"search_name": "Al"}, head=True, count="exact")
537+
.rpc(
538+
"search_countries_by_name",
539+
{"search_name": "Al"},
540+
head=True,
541+
count=CountMethod.exact,
542+
)
514543
.execute()
515544
)
516545

0 commit comments

Comments
 (0)