Skip to content

Commit b626f00

Browse files
committed
feat: audiences module async
1 parent e741f0a commit b626f00

3 files changed

Lines changed: 217 additions & 0 deletions

File tree

examples/audiences_async.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import asyncio
2+
import os
3+
from typing import List
4+
5+
import resend
6+
7+
if not os.environ["RESEND_API_KEY"]:
8+
raise EnvironmentError("RESEND_API_KEY is missing")
9+
10+
# Set up async HTTP client
11+
resend.default_http_client = resend.HTTPXClient()
12+
13+
14+
async def main() -> None:
15+
create_params: resend.Audiences.CreateParams = {
16+
"name": "New Audience from Python SDK (Async)",
17+
}
18+
audience: resend.Audience = await resend.Audiences.create_async(create_params)
19+
print(f"Created audience: {audience['id']}")
20+
print(audience)
21+
22+
aud: resend.Audience = await resend.Audiences.get_async(audience["id"])
23+
print("Retrieved audience: ", aud)
24+
25+
audiences: resend.Audiences.ListResponse = await resend.Audiences.list_async()
26+
print("List of audiences:", [a["id"] for a in audiences["data"]])
27+
28+
rmed: resend.Audience = await resend.Audiences.remove_async(id=audience["id"])
29+
print(f"Deleted audience")
30+
print(rmed)
31+
32+
33+
if __name__ == "__main__":
34+
asyncio.run(main())

resend/audiences/_audiences.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66

77
from ._audience import Audience
88

9+
# Async imports (optional - only available with pip install resend[async])
10+
try:
11+
from resend.async_request import AsyncRequest
12+
except ImportError:
13+
pass
14+
915

1016
class _ListResponse(TypedDict):
1117
data: List[Audience]
@@ -98,3 +104,72 @@ def remove(cls, id: str) -> Audience:
98104
path=path, params={}, verb="delete"
99105
).perform_with_content()
100106
return resp
107+
108+
@classmethod
109+
async def create_async(cls, params: CreateParams) -> Audience:
110+
"""
111+
Create a list of contacts (async).
112+
see more: https://resend.com/docs/api-reference/audiences/create-audience
113+
114+
Args:
115+
params (CreateParams): The audience creation parameters
116+
117+
Returns:
118+
Audience: The new audience object
119+
"""
120+
path = "/audiences"
121+
resp = await AsyncRequest[Audience](
122+
path=path, params=cast(Dict[Any, Any], params), verb="post"
123+
).perform_with_content()
124+
return resp
125+
126+
@classmethod
127+
async def list_async(cls) -> ListResponse:
128+
"""
129+
Retrieve a list of audiences (async).
130+
see more: https://resend.com/docs/api-reference/audiences/list-audiences
131+
132+
Returns:
133+
ListResponse: A list of audience objects
134+
"""
135+
path = "/audiences/"
136+
resp = await AsyncRequest[_ListResponse](
137+
path=path, params={}, verb="get"
138+
).perform_with_content()
139+
return resp
140+
141+
@classmethod
142+
async def get_async(cls, id: str) -> Audience:
143+
"""
144+
Retrieve a single audience (async).
145+
see more: https://resend.com/docs/api-reference/audiences/get-audience
146+
147+
Args:
148+
id (str): The audience ID
149+
150+
Returns:
151+
Audience: The audience object
152+
"""
153+
path = f"/audiences/{id}"
154+
resp = await AsyncRequest[Audience](
155+
path=path, params={}, verb="get"
156+
).perform_with_content()
157+
return resp
158+
159+
@classmethod
160+
async def remove_async(cls, id: str) -> Audience:
161+
"""
162+
Delete a single audience (async).
163+
see more: https://resend.com/docs/api-reference/audiences/delete-audience
164+
165+
Args:
166+
id (str): The audience ID
167+
168+
Returns:
169+
Audience: The audience object
170+
"""
171+
path = f"/audiences/{id}"
172+
resp = await AsyncRequest[Audience](
173+
path=path, params={}, verb="delete"
174+
).perform_with_content()
175+
return resp

tests/audiences_async_test.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import resend
2+
from resend.exceptions import NoContentError
3+
from tests.conftest import ResendBaseTest
4+
5+
# flake8: noqa
6+
7+
8+
class TestResendAudiencesAsync(ResendBaseTest):
9+
async def test_audiences_create_async(self) -> None:
10+
self.set_mock_json(
11+
{
12+
"object": "audience",
13+
"id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
14+
"name": "Registered Users",
15+
}
16+
)
17+
18+
params: resend.Audiences.CreateParams = {
19+
"name": "Python SDK Audience",
20+
}
21+
audience = await resend.Audiences.create_async(params)
22+
assert audience["id"] == "78261eea-8f8b-4381-83c6-79fa7120f1cf"
23+
assert audience["name"] == "Registered Users"
24+
25+
async def test_should_create_audiences_async_raise_exception_when_no_content(
26+
self,
27+
) -> None:
28+
self.set_mock_json(None)
29+
params: resend.Audiences.CreateParams = {
30+
"name": "Python SDK Audience",
31+
}
32+
with self.assertRaises(NoContentError):
33+
_ = await resend.Audiences.create_async(params)
34+
35+
async def test_audiences_get_async(self) -> None:
36+
self.set_mock_json(
37+
{
38+
"object": "audience",
39+
"id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
40+
"name": "Registered Users",
41+
"created_at": "2023-10-06T22:59:55.977Z",
42+
}
43+
)
44+
45+
audience = await resend.Audiences.get_async(
46+
id="78261eea-8f8b-4381-83c6-79fa7120f1cf"
47+
)
48+
assert audience["id"] == "78261eea-8f8b-4381-83c6-79fa7120f1cf"
49+
assert audience["name"] == "Registered Users"
50+
assert audience["created_at"] == "2023-10-06T22:59:55.977Z"
51+
52+
async def test_should_get_audiences_async_raise_exception_when_no_content(
53+
self,
54+
) -> None:
55+
self.set_mock_json(None)
56+
with self.assertRaises(NoContentError):
57+
_ = await resend.Audiences.get_async(
58+
id="78261eea-8f8b-4381-83c6-79fa7120f1cf"
59+
)
60+
61+
async def test_audiences_remove_async(self) -> None:
62+
self.set_mock_json(
63+
{
64+
"object": "audience",
65+
"id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
66+
"deleted": True,
67+
}
68+
)
69+
70+
rmed = await resend.Audiences.remove_async(
71+
"78261eea-8f8b-4381-83c6-79fa7120f1cf"
72+
)
73+
assert rmed["id"] == "78261eea-8f8b-4381-83c6-79fa7120f1cf"
74+
assert rmed["deleted"] is True
75+
76+
async def test_should_remove_audiences_async_raise_exception_when_no_content(
77+
self,
78+
) -> None:
79+
self.set_mock_json(None)
80+
with self.assertRaises(NoContentError):
81+
_ = await resend.Audiences.remove_async(
82+
id="78261eea-8f8b-4381-83c6-79fa7120f1cf"
83+
)
84+
85+
async def test_audiences_list_async(self) -> None:
86+
self.set_mock_json(
87+
{
88+
"object": "list",
89+
"data": [
90+
{
91+
"id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
92+
"name": "Registered Users",
93+
"created_at": "2023-10-06T22:59:55.977Z",
94+
}
95+
],
96+
}
97+
)
98+
99+
audiences: resend.Audiences.ListResponse = await resend.Audiences.list_async()
100+
assert audiences["data"][0]["id"] == "78261eea-8f8b-4381-83c6-79fa7120f1cf"
101+
assert audiences["data"][0]["name"] == "Registered Users"
102+
103+
async def test_should_list_audiences_async_raise_exception_when_no_content(
104+
self,
105+
) -> None:
106+
self.set_mock_json(None)
107+
with self.assertRaises(NoContentError):
108+
_ = await resend.Audiences.list_async()

0 commit comments

Comments
 (0)