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.
Files changed (61) hide show
  1. {blueticks-3.3.1/src/blueticks.egg-info → blueticks-3.3.2}/PKG-INFO +1 -1
  2. blueticks-3.3.2/src/blueticks/_version.py +1 -0
  3. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/audiences.py +9 -3
  4. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/chats.py +4 -1
  5. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/scheduled_messages.py +7 -4
  6. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/webhooks.py +9 -3
  7. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/__init__.py +4 -0
  8. blueticks-3.3.2/src/blueticks/types/_deleted_resource.py +20 -0
  9. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/chats.py +14 -2
  10. {blueticks-3.3.1 → blueticks-3.3.2/src/blueticks.egg-info}/PKG-INFO +1 -1
  11. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/SOURCES.txt +1 -0
  12. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_audiences.py +4 -2
  13. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_chats.py +13 -4
  14. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_scheduled_messages.py +9 -3
  15. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_webhooks_resource.py +5 -3
  16. blueticks-3.3.1/src/blueticks/_version.py +0 -1
  17. {blueticks-3.3.1 → blueticks-3.3.2}/LICENSE +0 -0
  18. {blueticks-3.3.1 → blueticks-3.3.2}/README.md +0 -0
  19. {blueticks-3.3.1 → blueticks-3.3.2}/pyproject.toml +0 -0
  20. {blueticks-3.3.1 → blueticks-3.3.2}/setup.cfg +0 -0
  21. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/__init__.py +0 -0
  22. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_base_resource.py +0 -0
  23. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_client.py +0 -0
  24. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_errors.py +0 -0
  25. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/_transport.py +0 -0
  26. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/py.typed +0 -0
  27. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/__init__.py +0 -0
  28. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/account.py +0 -0
  29. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/campaigns.py +0 -0
  30. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/contacts.py +0 -0
  31. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/engines.py +0 -0
  32. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/groups.py +0 -0
  33. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/messages.py +0 -0
  34. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/ping.py +0 -0
  35. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/resources/utils.py +0 -0
  36. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/account.py +0 -0
  37. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/audiences.py +0 -0
  38. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/campaigns.py +0 -0
  39. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/contacts.py +0 -0
  40. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/engines.py +0 -0
  41. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/groups.py +0 -0
  42. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/messages.py +0 -0
  43. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/page.py +0 -0
  44. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/ping.py +0 -0
  45. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/scheduled_messages.py +0 -0
  46. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/utils.py +0 -0
  47. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/types/webhooks.py +0 -0
  48. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks/webhooks.py +0 -0
  49. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/dependency_links.txt +0 -0
  50. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/requires.txt +0 -0
  51. {blueticks-3.3.1 → blueticks-3.3.2}/src/blueticks.egg-info/top_level.txt +0 -0
  52. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_account.py +0 -0
  53. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_campaigns.py +0 -0
  54. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_client.py +0 -0
  55. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_errors.py +0 -0
  56. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_groups.py +0 -0
  57. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_messages.py +0 -0
  58. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_ping.py +0 -0
  59. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_transport.py +0 -0
  60. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_types.py +0 -0
  61. {blueticks-3.3.1 → blueticks-3.3.2}/tests/test_webhook_verify.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blueticks
3
- Version: 3.3.1
3
+ Version: 3.3.2
4
4
  Summary: Official Python client for the Blueticks API.
5
5
  Author-email: Blueticks <support@blueticks.co>
6
6
  License: MIT License
@@ -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) -> None:
51
- self._client._request("DELETE", f"/v1/audiences/{audience_id}")
52
- return None
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) -> None:
65
+ def delete(self, scheduled_message_id: str) -> DeletedResource:
65
66
  """Cancel scheduled message.
66
67
 
67
- Removes the resource with id.
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 None
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) -> None:
70
- self._client._request("DELETE", f"/v1/webhooks/{webhook_id}")
71
- return None
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
- # Each item is a free-form ack record (additionalProperties: true).
163
- data: list[dict[str, object]]
175
+ data: list[BatchMessageAckEntry]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blueticks
3
- Version: 3.3.1
3
+ Version: 3.3.2
4
4
  Summary: Official Python client for the Blueticks API.
5
5
  Author-email: Blueticks <support@blueticks.co>
6
6
  License: MIT License
@@ -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(204)
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
- assert client.audiences.delete("aud_1") is None
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={"data": [{"key": "msg_a", "ack": 3}, {"key": "msg_b", "ack": 1}]},
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]["ack"] == 3
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 test_delete_scheduled_message_returns_none(mock_client) -> None:
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(204)
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
- assert client.scheduled_messages.delete("sched_1") is None
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 test_delete_webhook_returns_none():
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(204)
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
- assert client.webhooks.delete("wh_1") is None
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