blueticks 3.3.1__tar.gz → 3.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {blueticks-3.3.1/src/blueticks.egg-info → blueticks-3.3.2}/PKG-INFO +1 -1
- blueticks-3.3.2/src/blueticks/_version.py +1 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/audiences.py +9 -3
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/chats.py +4 -1
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/scheduled_messages.py +7 -4
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/webhooks.py +9 -3
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/__init__.py +4 -0
- blueticks-3.3.2/src/blueticks/types/_deleted_resource.py +20 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/chats.py +14 -2
- {blueticks-3.3.1 → blueticks-3.3.2/src/blueticks.egg-info}/PKG-INFO +1 -1
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/SOURCES.txt +1 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_audiences.py +4 -2
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_chats.py +13 -4
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_scheduled_messages.py +9 -3
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_webhooks_resource.py +5 -3
- blueticks-3.3.1/src/blueticks/_version.py +0 -1
- {blueticks-3.3.1 → blueticks-3.3.2}/LICENSE +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/README.md +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/pyproject.toml +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/setup.cfg +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/__init__.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_base_resource.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_client.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_errors.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_transport.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/py.typed +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/__init__.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/account.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/campaigns.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/contacts.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/engines.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/groups.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/messages.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/ping.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/utils.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/account.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/audiences.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/campaigns.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/contacts.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/engines.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/groups.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/messages.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/page.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/ping.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/scheduled_messages.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/utils.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/webhooks.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/webhooks.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/dependency_links.txt +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/requires.txt +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/top_level.txt +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_account.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_campaigns.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_client.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_errors.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_groups.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_messages.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_ping.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_transport.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_types.py +0 -0
- {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_webhook_verify.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "3.3.2"
|
|
@@ -4,6 +4,7 @@ import builtins
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
from blueticks._base_resource import BaseResource
|
|
7
|
+
from blueticks.types._deleted_resource import DeletedResource
|
|
7
8
|
from blueticks.types.audiences import AppendContactsResult, Audience, Contact
|
|
8
9
|
from blueticks.types.page import Page
|
|
9
10
|
|
|
@@ -47,9 +48,14 @@ class AudiencesResource(BaseResource):
|
|
|
47
48
|
data = self._client._request("PATCH", f"/v1/audiences/{audience_id}", body={"name": name})
|
|
48
49
|
return Audience.model_validate(data)
|
|
49
50
|
|
|
50
|
-
def delete(self, audience_id: str) ->
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
def delete(self, audience_id: str) -> DeletedResource:
|
|
52
|
+
"""Delete audience.
|
|
53
|
+
|
|
54
|
+
Soft-delete an audience. 409 if it`s referenced by an active campaign.
|
|
55
|
+
Returns the deleted ref. Requires ``audiences:write``.
|
|
56
|
+
"""
|
|
57
|
+
data = self._client._request("DELETE", f"/v1/audiences/{audience_id}")
|
|
58
|
+
return DeletedResource.model_validate(data)
|
|
53
59
|
|
|
54
60
|
def append_contacts(
|
|
55
61
|
self,
|
|
@@ -120,7 +120,10 @@ class ChatsResource(BaseResource):
|
|
|
120
120
|
return MessageAck.model_validate(data)
|
|
121
121
|
|
|
122
122
|
def react(self, chat_id: str, key: str, *, emoji: str) -> OkResponse:
|
|
123
|
-
"""Add or clear an emoji reaction on a message.
|
|
123
|
+
"""Add or clear an emoji reaction on a message.
|
|
124
|
+
|
|
125
|
+
Pass an empty string for ``emoji`` to clear an existing reaction.
|
|
126
|
+
"""
|
|
124
127
|
data = self._client._request(
|
|
125
128
|
"POST",
|
|
126
129
|
f"/v1/chats/{chat_id}/messages/{key}/reactions",
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from blueticks._base_resource import BaseResource
|
|
6
|
+
from blueticks.types._deleted_resource import DeletedResource
|
|
6
7
|
from blueticks.types.page import Page
|
|
7
8
|
from blueticks.types.scheduled_messages import ScheduledMessage
|
|
8
9
|
|
|
@@ -61,10 +62,12 @@ class ScheduledMessagesResource(BaseResource):
|
|
|
61
62
|
)
|
|
62
63
|
return ScheduledMessage.model_validate(data)
|
|
63
64
|
|
|
64
|
-
def delete(self, scheduled_message_id: str) ->
|
|
65
|
+
def delete(self, scheduled_message_id: str) -> DeletedResource:
|
|
65
66
|
"""Cancel scheduled message.
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
Cancel a queued scheduled message before it fires. Soft-deletes the row
|
|
69
|
+
(still queryable in audit logs). Returns the deleted ref. Requires
|
|
70
|
+
``messages:write``.
|
|
68
71
|
"""
|
|
69
|
-
self._client._request("DELETE", f"/v1/scheduled-messages/{scheduled_message_id}")
|
|
70
|
-
return
|
|
72
|
+
data = self._client._request("DELETE", f"/v1/scheduled-messages/{scheduled_message_id}")
|
|
73
|
+
return DeletedResource.model_validate(data)
|
|
@@ -4,6 +4,7 @@ import builtins
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
from blueticks._base_resource import BaseResource
|
|
7
|
+
from blueticks.types._deleted_resource import DeletedResource
|
|
7
8
|
from blueticks.types.page import Page
|
|
8
9
|
from blueticks.types.webhooks import Webhook, WebhookCreateResult
|
|
9
10
|
|
|
@@ -66,9 +67,14 @@ class WebhooksResource(BaseResource):
|
|
|
66
67
|
data = self._client._request("PATCH", f"/v1/webhooks/{webhook_id}", body=body)
|
|
67
68
|
return Webhook.model_validate(data)
|
|
68
69
|
|
|
69
|
-
def delete(self, webhook_id: str) ->
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
def delete(self, webhook_id: str) -> DeletedResource:
|
|
71
|
+
"""Delete webhook.
|
|
72
|
+
|
|
73
|
+
Delete a webhook subscription. Returns the deleted ref. Requires
|
|
74
|
+
``webhooks:write``.
|
|
75
|
+
"""
|
|
76
|
+
data = self._client._request("DELETE", f"/v1/webhooks/{webhook_id}")
|
|
77
|
+
return DeletedResource.model_validate(data)
|
|
72
78
|
|
|
73
79
|
def rotate_secret(self, webhook_id: str) -> WebhookCreateResult:
|
|
74
80
|
data = self._client._request("POST", f"/v1/webhooks/{webhook_id}/rotate-secret")
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
from blueticks.types._deleted_resource import DeletedResource
|
|
1
2
|
from blueticks.types.account import Account
|
|
2
3
|
from blueticks.types.audiences import AppendContactsResult, Audience, Contact
|
|
3
4
|
from blueticks.types.campaigns import Campaign
|
|
4
5
|
from blueticks.types.chats import (
|
|
6
|
+
BatchMessageAckEntry,
|
|
5
7
|
BatchMessageAcksResponse,
|
|
6
8
|
Chat,
|
|
7
9
|
ChatMedia,
|
|
@@ -24,6 +26,7 @@ __all__ = [
|
|
|
24
26
|
"Account",
|
|
25
27
|
"AppendContactsResult",
|
|
26
28
|
"Audience",
|
|
29
|
+
"BatchMessageAckEntry",
|
|
27
30
|
"BatchMessageAcksResponse",
|
|
28
31
|
"Campaign",
|
|
29
32
|
"Chat",
|
|
@@ -31,6 +34,7 @@ __all__ = [
|
|
|
31
34
|
"ChatMessage",
|
|
32
35
|
"ChatRef",
|
|
33
36
|
"Contact",
|
|
37
|
+
"DeletedResource",
|
|
34
38
|
"Group",
|
|
35
39
|
"GroupParticipant",
|
|
36
40
|
"LoadOlderMessagesResponse",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DeletedResource(BaseModel):
|
|
9
|
+
"""Response envelope returned by DELETE endpoints.
|
|
10
|
+
|
|
11
|
+
Returned by:
|
|
12
|
+
- DELETE /v1/audiences/{id}
|
|
13
|
+
- DELETE /v1/scheduled-messages/{id}
|
|
14
|
+
- DELETE /v1/webhooks/{id}
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
model_config = ConfigDict(extra="ignore")
|
|
18
|
+
|
|
19
|
+
id: str
|
|
20
|
+
deleted: Literal[True]
|
|
@@ -154,10 +154,22 @@ class MediaUrlResponse(BaseModel):
|
|
|
154
154
|
url: Optional[str] = None # noqa: UP045
|
|
155
155
|
|
|
156
156
|
|
|
157
|
+
class BatchMessageAckEntry(BaseModel):
|
|
158
|
+
"""One entry in :class:`BatchMessageAcksResponse.data`.
|
|
159
|
+
|
|
160
|
+
`ack` codes: -1=error, 0=pending, 1=server, 2=device, 3=read, 4=played;
|
|
161
|
+
`None` when the engine has not yet returned a status for this key.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
model_config = ConfigDict(extra="ignore")
|
|
165
|
+
|
|
166
|
+
key: str
|
|
167
|
+
ack: Optional[int] = None # noqa: UP045
|
|
168
|
+
|
|
169
|
+
|
|
157
170
|
class BatchMessageAcksResponse(BaseModel):
|
|
158
171
|
"""Response from POST /v1/chats/message_acks."""
|
|
159
172
|
|
|
160
173
|
model_config = ConfigDict(extra="ignore")
|
|
161
174
|
|
|
162
|
-
|
|
163
|
-
data: list[dict[str, object]]
|
|
175
|
+
data: list[BatchMessageAckEntry]
|
|
@@ -28,6 +28,7 @@ src/blueticks/resources/scheduled_messages.py
|
|
|
28
28
|
src/blueticks/resources/utils.py
|
|
29
29
|
src/blueticks/resources/webhooks.py
|
|
30
30
|
src/blueticks/types/__init__.py
|
|
31
|
+
src/blueticks/types/_deleted_resource.py
|
|
31
32
|
src/blueticks/types/account.py
|
|
32
33
|
src/blueticks/types/audiences.py
|
|
33
34
|
src/blueticks/types/campaigns.py
|
|
@@ -99,10 +99,12 @@ def test_delete_audience():
|
|
|
99
99
|
def handler(req: httpx.Request) -> httpx.Response:
|
|
100
100
|
assert req.method == "DELETE"
|
|
101
101
|
assert req.url.path == "/v1/audiences/aud_1"
|
|
102
|
-
return httpx.Response(
|
|
102
|
+
return httpx.Response(200, json={"id": "aud_1", "deleted": True})
|
|
103
103
|
|
|
104
104
|
client = Blueticks(api_key="bt_live_test", _http_transport=httpx.MockTransport(handler))
|
|
105
|
-
|
|
105
|
+
result = client.audiences.delete("aud_1")
|
|
106
|
+
assert result.id == "aud_1"
|
|
107
|
+
assert result.deleted is True
|
|
106
108
|
|
|
107
109
|
|
|
108
110
|
def test_append_contacts():
|
|
@@ -225,13 +225,22 @@ def test_batch_message_acks_returns_typed_model():
|
|
|
225
225
|
assert req.url.path == "/v1/chats/message_acks"
|
|
226
226
|
return httpx.Response(
|
|
227
227
|
200,
|
|
228
|
-
json={
|
|
228
|
+
json={
|
|
229
|
+
"data": [
|
|
230
|
+
{"key": "msg_a", "ack": 3},
|
|
231
|
+
{"key": "msg_b", "ack": 1},
|
|
232
|
+
{"key": "msg_c", "ack": None},
|
|
233
|
+
]
|
|
234
|
+
},
|
|
229
235
|
)
|
|
230
236
|
|
|
231
|
-
result = _client(handler).chats.batch_message_acks(message_keys=["msg_a", "msg_b"])
|
|
237
|
+
result = _client(handler).chats.batch_message_acks(message_keys=["msg_a", "msg_b", "msg_c"])
|
|
232
238
|
assert isinstance(result, BatchMessageAcksResponse)
|
|
233
|
-
assert body_seen == {"message_keys": ["msg_a", "msg_b"]}
|
|
234
|
-
assert result.data[0]
|
|
239
|
+
assert body_seen == {"message_keys": ["msg_a", "msg_b", "msg_c"]}
|
|
240
|
+
assert result.data[0].key == "msg_a"
|
|
241
|
+
assert result.data[0].ack == 3
|
|
242
|
+
assert result.data[1].ack == 1
|
|
243
|
+
assert result.data[2].ack is None
|
|
235
244
|
|
|
236
245
|
|
|
237
246
|
def test_chats_get_raises_authentication_error_on_401():
|
|
@@ -113,14 +113,20 @@ def test_update_scheduled_message(mock_client) -> None:
|
|
|
113
113
|
assert body_seen == {"text": "updated", "send_at": "2026-07-01T09:00:00Z"}
|
|
114
114
|
|
|
115
115
|
|
|
116
|
-
def
|
|
116
|
+
def test_delete_scheduled_message_returns_typed_ref(mock_client) -> None:
|
|
117
117
|
def handler(req: httpx.Request) -> httpx.Response:
|
|
118
118
|
assert req.method == "DELETE"
|
|
119
119
|
assert req.url.path == "/v1/scheduled-messages/sched_1"
|
|
120
|
-
return httpx.Response(
|
|
120
|
+
return httpx.Response(
|
|
121
|
+
200,
|
|
122
|
+
content=json.dumps({"id": "sched_1", "deleted": True}).encode(),
|
|
123
|
+
headers={"content-type": "application/json"},
|
|
124
|
+
)
|
|
121
125
|
|
|
122
126
|
with mock_client(handler) as client:
|
|
123
|
-
|
|
127
|
+
result = client.scheduled_messages.delete("sched_1")
|
|
128
|
+
assert result.id == "sched_1"
|
|
129
|
+
assert result.deleted is True
|
|
124
130
|
|
|
125
131
|
|
|
126
132
|
def test_scheduled_messages_propagates_authentication_error(mock_client) -> None:
|
|
@@ -90,14 +90,16 @@ def test_update_webhook():
|
|
|
90
90
|
assert body_seen == {"status": "disabled"}
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
def
|
|
93
|
+
def test_delete_webhook_returns_typed_ref():
|
|
94
94
|
def handler(req: httpx.Request) -> httpx.Response:
|
|
95
95
|
assert req.method == "DELETE"
|
|
96
96
|
assert req.url.path == "/v1/webhooks/wh_1"
|
|
97
|
-
return httpx.Response(
|
|
97
|
+
return httpx.Response(200, json={"id": "wh_1", "deleted": True})
|
|
98
98
|
|
|
99
99
|
client = Blueticks(api_key="bt_live_test", _http_transport=httpx.MockTransport(handler))
|
|
100
|
-
|
|
100
|
+
result = client.webhooks.delete("wh_1")
|
|
101
|
+
assert result.id == "wh_1"
|
|
102
|
+
assert result.deleted is True
|
|
101
103
|
|
|
102
104
|
|
|
103
105
|
def test_rotate_secret_returns_new_secret():
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "3.3.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|