Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions resend/automations/_automations.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,24 @@ class DeleteResponse(BaseResponse):
Whether the automation was successfully deleted.
"""

class DuplicateResponse(BaseResponse):
"""
DuplicateResponse is the class that wraps the response of the duplicate method.

Attributes:
object (str): The object type, always "automation"
id (str): The ID of the newly created automation
"""

object: str
"""
The object type, always "automation".
"""
id: str
"""
The ID of the newly created automation.
"""

class StopResponse(BaseResponse):
"""
StopResponse is the class that wraps the response of the stop method.
Expand Down Expand Up @@ -443,6 +461,24 @@ def remove(cls, automation_id: str) -> "Automations.DeleteResponse":
).perform_with_content()
return resp

@classmethod
def duplicate(cls, automation_id: str) -> "Automations.DuplicateResponse":
"""
Duplicate an automation.
see more: https://resend.com/docs/api-reference/automations/duplicate-automation

Args:
automation_id (str): The automation ID

Returns:
DuplicateResponse: The duplicate response
"""
path = f"/automations/{automation_id}/duplicate"
resp = request.Request[Automations.DuplicateResponse](
path=path, params={}, verb="post"
).perform_with_content()
return resp

@classmethod
def stop(cls, automation_id: str) -> "Automations.StopResponse":
"""
Expand Down Expand Up @@ -564,6 +600,26 @@ async def remove_async(cls, automation_id: str) -> "Automations.DeleteResponse":
).perform_with_content()
return resp

@classmethod
async def duplicate_async(
cls, automation_id: str
) -> "Automations.DuplicateResponse":
"""
Duplicate an automation (async).
see more: https://resend.com/docs/api-reference/automations/duplicate-automation

Args:
automation_id (str): The automation ID

Returns:
DuplicateResponse: The duplicate response
"""
path = f"/automations/{automation_id}/duplicate"
resp = await AsyncRequest[Automations.DuplicateResponse](
path=path, params={}, verb="post"
).perform_with_content()
return resp

@classmethod
async def stop_async(cls, automation_id: str) -> "Automations.StopResponse":
"""
Expand Down
21 changes: 21 additions & 0 deletions tests/automations_async_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ async def test_automations_remove_async_raises_when_no_content(self) -> None:
"b6d24b8e-af0b-4c3c-be0c-359bbd97381e"
)

async def test_automations_duplicate_async(self) -> None:
self.set_mock_json(
{
"object": "automation",
"id": "e169aa45-1ecf-4183-9955-b1499d5701d3",
}
)

resp = await resend.Automations.duplicate_async(
"b6d24b8e-af0b-4c3c-be0c-359bbd97381e"
)
assert resp["object"] == "automation"
assert resp["id"] == "e169aa45-1ecf-4183-9955-b1499d5701d3"

async def test_automations_duplicate_async_raises_when_no_content(self) -> None:
self.set_mock_json(None)
with pytest.raises(NoContentError):
_ = await resend.Automations.duplicate_async(
"b6d24b8e-af0b-4c3c-be0c-359bbd97381e"
)

async def test_automations_stop_async(self) -> None:
self.set_mock_json(
{
Expand Down
12 changes: 12 additions & 0 deletions tests/automations_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ def test_automations_remove(self) -> None:
assert resp["id"] == "b6d24b8e-af0b-4c3c-be0c-359bbd97381e"
assert resp["deleted"] is True

def test_automations_duplicate(self) -> None:
self.set_mock_json(
{
"object": "automation",
"id": "e169aa45-1ecf-4183-9955-b1499d5701d3",
}
)

resp = resend.Automations.duplicate("b6d24b8e-af0b-4c3c-be0c-359bbd97381e")
assert resp["object"] == "automation"
assert resp["id"] == "e169aa45-1ecf-4183-9955-b1499d5701d3"

def test_automations_stop(self) -> None:
self.set_mock_json(
{
Expand Down
Loading