blueticks 3.2.0__tar.gz → 3.3.0__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 (59) hide show
  1. {blueticks-3.2.0/src/blueticks.egg-info → blueticks-3.3.0}/PKG-INFO +1 -1
  2. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/_client.py +2 -0
  3. blueticks-3.3.0/src/blueticks/_version.py +1 -0
  4. blueticks-3.3.0/src/blueticks/resources/__init__.py +27 -0
  5. blueticks-3.3.0/src/blueticks/resources/scheduled_messages.py +70 -0
  6. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/__init__.py +5 -0
  7. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/chats.py +19 -1
  8. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/groups.py +11 -0
  9. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/messages.py +1 -1
  10. blueticks-3.3.0/src/blueticks/types/scheduled_messages.py +26 -0
  11. {blueticks-3.2.0 → blueticks-3.3.0/src/blueticks.egg-info}/PKG-INFO +1 -1
  12. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks.egg-info/SOURCES.txt +3 -0
  13. blueticks-3.3.0/tests/test_scheduled_messages.py +155 -0
  14. blueticks-3.2.0/src/blueticks/_version.py +0 -1
  15. blueticks-3.2.0/src/blueticks/resources/__init__.py +0 -4
  16. {blueticks-3.2.0 → blueticks-3.3.0}/LICENSE +0 -0
  17. {blueticks-3.2.0 → blueticks-3.3.0}/README.md +0 -0
  18. {blueticks-3.2.0 → blueticks-3.3.0}/pyproject.toml +0 -0
  19. {blueticks-3.2.0 → blueticks-3.3.0}/setup.cfg +0 -0
  20. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/__init__.py +0 -0
  21. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/_base_resource.py +0 -0
  22. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/_errors.py +0 -0
  23. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/_transport.py +0 -0
  24. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/py.typed +0 -0
  25. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/account.py +0 -0
  26. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/audiences.py +0 -0
  27. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/campaigns.py +0 -0
  28. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/chats.py +0 -0
  29. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/contacts.py +0 -0
  30. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/engines.py +0 -0
  31. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/groups.py +0 -0
  32. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/messages.py +0 -0
  33. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/ping.py +0 -0
  34. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/utils.py +0 -0
  35. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/resources/webhooks.py +0 -0
  36. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/account.py +0 -0
  37. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/audiences.py +0 -0
  38. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/campaigns.py +0 -0
  39. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/contacts.py +0 -0
  40. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/engines.py +0 -0
  41. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/page.py +0 -0
  42. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/ping.py +0 -0
  43. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/utils.py +0 -0
  44. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/types/webhooks.py +0 -0
  45. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks/webhooks.py +0 -0
  46. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks.egg-info/dependency_links.txt +0 -0
  47. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks.egg-info/requires.txt +0 -0
  48. {blueticks-3.2.0 → blueticks-3.3.0}/src/blueticks.egg-info/top_level.txt +0 -0
  49. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_account.py +0 -0
  50. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_audiences.py +0 -0
  51. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_campaigns.py +0 -0
  52. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_client.py +0 -0
  53. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_errors.py +0 -0
  54. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_messages.py +0 -0
  55. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_ping.py +0 -0
  56. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_transport.py +0 -0
  57. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_types.py +0 -0
  58. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_webhook_verify.py +0 -0
  59. {blueticks-3.2.0 → blueticks-3.3.0}/tests/test_webhooks_resource.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blueticks
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: Official Python client for the Blueticks API.
5
5
  Author-email: Blueticks <support@blueticks.co>
6
6
  License: MIT License
@@ -69,6 +69,7 @@ class Blueticks:
69
69
  from blueticks.resources.engines import EnginesResource
70
70
  from blueticks.resources.groups import GroupsResource
71
71
  from blueticks.resources.messages import MessagesResource
72
+ from blueticks.resources.scheduled_messages import ScheduledMessagesResource
72
73
  from blueticks.resources.utils import UtilsResource
73
74
  from blueticks.resources.webhooks import WebhooksResource
74
75
 
@@ -80,6 +81,7 @@ class Blueticks:
80
81
  self.engines = EnginesResource(self)
81
82
  self.groups = GroupsResource(self)
82
83
  self.messages = MessagesResource(self)
84
+ self.scheduled_messages = ScheduledMessagesResource(self)
83
85
  self.utils = UtilsResource(self)
84
86
  self.webhooks = WebhooksResource(self)
85
87
 
@@ -0,0 +1 @@
1
+ __version__ = "3.3.0"
@@ -0,0 +1,27 @@
1
+ from blueticks.resources.account import AccountResource
2
+ from blueticks.resources.audiences import AudiencesResource
3
+ from blueticks.resources.campaigns import CampaignsResource
4
+ from blueticks.resources.chats import ChatsResource
5
+ from blueticks.resources.contacts import ContactsResource
6
+ from blueticks.resources.engines import EnginesResource
7
+ from blueticks.resources.groups import GroupsResource
8
+ from blueticks.resources.messages import MessagesResource
9
+ from blueticks.resources.ping import PingResource
10
+ from blueticks.resources.scheduled_messages import ScheduledMessagesResource
11
+ from blueticks.resources.utils import UtilsResource
12
+ from blueticks.resources.webhooks import WebhooksResource
13
+
14
+ __all__ = [
15
+ "AccountResource",
16
+ "AudiencesResource",
17
+ "CampaignsResource",
18
+ "ChatsResource",
19
+ "ContactsResource",
20
+ "EnginesResource",
21
+ "GroupsResource",
22
+ "MessagesResource",
23
+ "PingResource",
24
+ "ScheduledMessagesResource",
25
+ "UtilsResource",
26
+ "WebhooksResource",
27
+ ]
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from blueticks._base_resource import BaseResource
6
+ from blueticks.types.page import Page
7
+ from blueticks.types.scheduled_messages import ScheduledMessage
8
+
9
+
10
+ class ScheduledMessagesResource(BaseResource):
11
+ def list(
12
+ self,
13
+ *,
14
+ limit: int | None = None,
15
+ cursor: str | None = None,
16
+ ) -> Page[ScheduledMessage]:
17
+ """List scheduled messages.
18
+
19
+ Retrieves a list of all resources from the service.
20
+ """
21
+ params: dict[str, Any] = {}
22
+ if limit is not None:
23
+ params["limit"] = limit
24
+ if cursor is not None:
25
+ params["cursor"] = cursor
26
+ data = self._client._request("GET", "/v1/scheduled-messages", params=params or None)
27
+ return Page[ScheduledMessage].model_validate(data)
28
+
29
+ def retrieve(self, scheduled_message_id: str) -> ScheduledMessage:
30
+ """Get scheduled message.
31
+
32
+ Retrieves a single resource with the given id from the service.
33
+ """
34
+ data = self._client._request("GET", f"/v1/scheduled-messages/{scheduled_message_id}")
35
+ return ScheduledMessage.model_validate(data)
36
+
37
+ def update(
38
+ self,
39
+ scheduled_message_id: str,
40
+ *,
41
+ text: str | None = None,
42
+ media_url: str | None = None,
43
+ media_caption: str | None = None,
44
+ send_at: str | None = None,
45
+ ) -> ScheduledMessage:
46
+ """Update scheduled message.
47
+
48
+ Updates the resource identified by id using data.
49
+ """
50
+ body: dict[str, Any] = {}
51
+ if text is not None:
52
+ body["text"] = text
53
+ if media_url is not None:
54
+ body["media_url"] = media_url
55
+ if media_caption is not None:
56
+ body["media_caption"] = media_caption
57
+ if send_at is not None:
58
+ body["send_at"] = send_at
59
+ data = self._client._request(
60
+ "PATCH", f"/v1/scheduled-messages/{scheduled_message_id}", body=body
61
+ )
62
+ return ScheduledMessage.model_validate(data)
63
+
64
+ def delete(self, scheduled_message_id: str) -> None:
65
+ """Cancel scheduled message.
66
+
67
+ Removes the resource with id.
68
+ """
69
+ self._client._request("DELETE", f"/v1/scheduled-messages/{scheduled_message_id}")
70
+ return None
@@ -1,9 +1,11 @@
1
1
  from blueticks.types.account import Account
2
2
  from blueticks.types.audiences import AppendContactsResult, Audience, Contact
3
3
  from blueticks.types.campaigns import Campaign
4
+ from blueticks.types.groups import Group, GroupParticipant
4
5
  from blueticks.types.messages import Message
5
6
  from blueticks.types.page import Page
6
7
  from blueticks.types.ping import Ping
8
+ from blueticks.types.scheduled_messages import ScheduledMessage
7
9
  from blueticks.types.webhooks import Webhook, WebhookCreateResult, WebhookEvent
8
10
 
9
11
  __all__ = [
@@ -12,9 +14,12 @@ __all__ = [
12
14
  "Audience",
13
15
  "Campaign",
14
16
  "Contact",
17
+ "Group",
18
+ "GroupParticipant",
15
19
  "Message",
16
20
  "Page",
17
21
  "Ping",
22
+ "ScheduledMessage",
18
23
  "Webhook",
19
24
  "WebhookCreateResult",
20
25
  "WebhookEvent",
@@ -70,6 +70,7 @@ class ChatMessage(BaseModel):
70
70
  MediaUnavailableReason = Literal[
71
71
  "expired",
72
72
  "fetching",
73
+ "awaiting_sender",
73
74
  "error",
74
75
  "no_media",
75
76
  ]
@@ -87,4 +88,21 @@ class ChatMedia(BaseModel):
87
88
  # genuine original from the sender.
88
89
  original_quality: Optional[bool] = None # noqa: UP045
89
90
  # Reason the bytes couldn't be retrieved. None/absent on success.
90
- media_unavailable: Optional[MediaUnavailableReason] = None # noqa: UP045
91
+ # "expired" = WA aged the file out of CDN retention. "fetching" = WA is
92
+ # mid-download from its CDN — transient, retry in a few seconds.
93
+ # "awaiting_sender" = WA's CDN doesn't have the file but has asked the
94
+ # sender's device to reupload it; only completes when the sender's
95
+ # WhatsApp client is open and online. "error" = unexpected failure.
96
+ # "no_media" = the message is text-only/revoked/location/vcard.
97
+ media_unavailable: Optional[MediaUnavailableReason] = Field( # noqa: UP045
98
+ default=None,
99
+ description=(
100
+ "Set when the bytes could not be downloaded or never existed. "
101
+ '"expired" = WA aged the file out of CDN retention. '
102
+ '"fetching" = WA is mid-download from its CDN — transient, retry in a few seconds. '
103
+ "\"awaiting_sender\" = WA's CDN does not have the file but has asked the sender's "
104
+ "device to reupload it; only completes when the sender's WhatsApp client is open and "
105
+ 'online. "error" = unexpected failure. "no_media" = the message is text-only / revoked '
106
+ "/ location / vcard."
107
+ ),
108
+ )
@@ -6,6 +6,15 @@ from typing import Optional # noqa: UP045
6
6
  from pydantic import BaseModel, ConfigDict
7
7
 
8
8
 
9
+ class GroupParticipant(BaseModel):
10
+ model_config = ConfigDict(extra="ignore")
11
+
12
+ chat_id: str
13
+ is_admin: bool
14
+ is_super_admin: bool
15
+ name: Optional[str] = None # noqa: UP045
16
+
17
+
9
18
  class Group(BaseModel):
10
19
  model_config = ConfigDict(extra="ignore")
11
20
 
@@ -14,6 +23,8 @@ class Group(BaseModel):
14
23
  description: Optional[str] = None # noqa: UP045
15
24
  owner: Optional[str] = None # noqa: UP045
16
25
  created_at: Optional[str] = None # noqa: UP045
26
+ last_message_at: Optional[str] = None # noqa: UP045
17
27
  participant_count: Optional[int] = None # noqa: UP045
18
28
  announce: Optional[bool] = None # noqa: UP045
19
29
  restrict: Optional[bool] = None # noqa: UP045
30
+ participants: Optional[list[GroupParticipant]] = None # noqa: UP045
@@ -5,7 +5,7 @@ from typing import Literal, Optional
5
5
 
6
6
  from pydantic import BaseModel, ConfigDict, Field
7
7
 
8
- MessageStatus = Literal["scheduled", "queued", "sending", "delivered", "failed"]
8
+ MessageStatus = Literal["scheduled", "queued", "sending", "delivered", "read", "failed"]
9
9
 
10
10
 
11
11
  class Message(BaseModel):
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ # ruff: noqa: UP045 # Pydantic field annotations need Optional[T] for Python 3.9 (see CLAUDE.md)
4
+ from typing import Optional # noqa: UP045
5
+
6
+ from pydantic import BaseModel, ConfigDict
7
+
8
+
9
+ class ScheduledMessage(BaseModel):
10
+ """A message queued for future delivery via /v1/scheduled-messages."""
11
+
12
+ model_config = ConfigDict(extra="ignore")
13
+
14
+ id: str
15
+ to: Optional[str] = None # noqa: UP045
16
+ text: Optional[str] = None # noqa: UP045
17
+ media_url: Optional[str] = None # noqa: UP045
18
+ media_caption: Optional[str] = None # noqa: UP045
19
+ media_filename: Optional[str] = None # noqa: UP045
20
+ media_mime_type: Optional[str] = None # noqa: UP045
21
+ send_at: Optional[str] = None # noqa: UP045
22
+ status: Optional[str] = None # noqa: UP045
23
+ is_recurring: bool
24
+ recurrence_rule: Optional[str] = None # noqa: UP045
25
+ created_at: Optional[str] = None # noqa: UP045
26
+ updated_at: Optional[str] = None # noqa: UP045
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blueticks
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: Official Python client for the Blueticks API.
5
5
  Author-email: Blueticks <support@blueticks.co>
6
6
  License: MIT License
@@ -24,6 +24,7 @@ src/blueticks/resources/engines.py
24
24
  src/blueticks/resources/groups.py
25
25
  src/blueticks/resources/messages.py
26
26
  src/blueticks/resources/ping.py
27
+ src/blueticks/resources/scheduled_messages.py
27
28
  src/blueticks/resources/utils.py
28
29
  src/blueticks/resources/webhooks.py
29
30
  src/blueticks/types/__init__.py
@@ -37,6 +38,7 @@ src/blueticks/types/groups.py
37
38
  src/blueticks/types/messages.py
38
39
  src/blueticks/types/page.py
39
40
  src/blueticks/types/ping.py
41
+ src/blueticks/types/scheduled_messages.py
40
42
  src/blueticks/types/utils.py
41
43
  src/blueticks/types/webhooks.py
42
44
  tests/test_account.py
@@ -46,6 +48,7 @@ tests/test_client.py
46
48
  tests/test_errors.py
47
49
  tests/test_messages.py
48
50
  tests/test_ping.py
51
+ tests/test_scheduled_messages.py
49
52
  tests/test_transport.py
50
53
  tests/test_types.py
51
54
  tests/test_webhook_verify.py
@@ -0,0 +1,155 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ import httpx
6
+ import pytest
7
+ from pydantic import ValidationError
8
+
9
+ from blueticks import AuthenticationError
10
+ from blueticks.types.page import Page
11
+ from blueticks.types.scheduled_messages import ScheduledMessage
12
+
13
+
14
+ def _scheduled(sid: str = "sched_1", **overrides) -> dict:
15
+ data = {
16
+ "id": sid,
17
+ "to": "+12025550100",
18
+ "text": "hello future",
19
+ "media_url": None,
20
+ "media_caption": None,
21
+ "media_filename": None,
22
+ "media_mime_type": None,
23
+ "send_at": "2026-06-01T09:00:00Z",
24
+ "status": "pending",
25
+ "is_recurring": False,
26
+ "recurrence_rule": None,
27
+ "created_at": "2026-04-23T00:00:00Z",
28
+ "updated_at": "2026-04-23T00:00:00Z",
29
+ }
30
+ data.update(overrides)
31
+ return data
32
+
33
+
34
+ def test_list_scheduled_messages(mock_client) -> None:
35
+ def handler(req: httpx.Request) -> httpx.Response:
36
+ assert req.method == "GET"
37
+ assert req.url.path == "/v1/scheduled-messages"
38
+ return httpx.Response(
39
+ 200,
40
+ content=json.dumps(
41
+ {
42
+ "data": [_scheduled("sched_1"), _scheduled("sched_2", is_recurring=True)],
43
+ "has_more": False,
44
+ "next_cursor": None,
45
+ }
46
+ ).encode(),
47
+ headers={"content-type": "application/json"},
48
+ )
49
+
50
+ with mock_client(handler) as client:
51
+ page = client.scheduled_messages.list()
52
+ assert isinstance(page, Page)
53
+ assert len(page.data) == 2
54
+ assert page.data[0].id == "sched_1"
55
+ assert page.data[1].is_recurring is True
56
+ assert page.has_more is False
57
+
58
+
59
+ def test_list_scheduled_messages_passes_pagination_params(mock_client) -> None:
60
+ seen_params: dict = {}
61
+
62
+ def handler(req: httpx.Request) -> httpx.Response:
63
+ seen_params.update(dict(req.url.params))
64
+ return httpx.Response(
65
+ 200,
66
+ content=json.dumps({"data": [], "has_more": True, "next_cursor": "cur_next"}).encode(),
67
+ headers={"content-type": "application/json"},
68
+ )
69
+
70
+ with mock_client(handler) as client:
71
+ page = client.scheduled_messages.list(limit=25, cursor="cur_abc")
72
+ assert seen_params == {"limit": "25", "cursor": "cur_abc"}
73
+ assert page.next_cursor == "cur_next"
74
+
75
+
76
+ def test_retrieve_scheduled_message(mock_client) -> None:
77
+ def handler(req: httpx.Request) -> httpx.Response:
78
+ assert req.method == "GET"
79
+ assert req.url.path == "/v1/scheduled-messages/sched_1"
80
+ return httpx.Response(
81
+ 200,
82
+ content=json.dumps(_scheduled("sched_1", text="reminder")).encode(),
83
+ headers={"content-type": "application/json"},
84
+ )
85
+
86
+ with mock_client(handler) as client:
87
+ result = client.scheduled_messages.retrieve("sched_1")
88
+ assert isinstance(result, ScheduledMessage)
89
+ assert result.id == "sched_1"
90
+ assert result.text == "reminder"
91
+
92
+
93
+ def test_update_scheduled_message(mock_client) -> None:
94
+ body_seen: dict = {}
95
+
96
+ def handler(req: httpx.Request) -> httpx.Response:
97
+ body_seen.update(json.loads(req.content))
98
+ assert req.method == "PATCH"
99
+ assert req.url.path == "/v1/scheduled-messages/sched_1"
100
+ return httpx.Response(
101
+ 200,
102
+ content=json.dumps(_scheduled("sched_1", text="updated")).encode(),
103
+ headers={"content-type": "application/json"},
104
+ )
105
+
106
+ with mock_client(handler) as client:
107
+ result = client.scheduled_messages.update(
108
+ "sched_1",
109
+ text="updated",
110
+ send_at="2026-07-01T09:00:00Z",
111
+ )
112
+ assert result.text == "updated"
113
+ assert body_seen == {"text": "updated", "send_at": "2026-07-01T09:00:00Z"}
114
+
115
+
116
+ def test_delete_scheduled_message_returns_none(mock_client) -> None:
117
+ def handler(req: httpx.Request) -> httpx.Response:
118
+ assert req.method == "DELETE"
119
+ assert req.url.path == "/v1/scheduled-messages/sched_1"
120
+ return httpx.Response(204)
121
+
122
+ with mock_client(handler) as client:
123
+ assert client.scheduled_messages.delete("sched_1") is None
124
+
125
+
126
+ def test_scheduled_messages_propagates_authentication_error(mock_client) -> None:
127
+ def handler(_req: httpx.Request) -> httpx.Response:
128
+ body = {
129
+ "error": {
130
+ "code": "authentication_required",
131
+ "message": "bad key",
132
+ "request_id": "req_z",
133
+ }
134
+ }
135
+ return httpx.Response(
136
+ 401,
137
+ content=json.dumps(body).encode(),
138
+ headers={"content-type": "application/json"},
139
+ )
140
+
141
+ with mock_client(handler) as client:
142
+ with pytest.raises(AuthenticationError) as info:
143
+ client.scheduled_messages.retrieve("sched_1")
144
+ assert info.value.code == "authentication_required"
145
+ assert info.value.message == "bad key"
146
+ assert info.value.request_id == "req_z"
147
+
148
+
149
+ def test_scheduled_messages_missing_required_field_raises_validation_error(mock_client) -> None:
150
+ def handler(_req: httpx.Request) -> httpx.Response:
151
+ return httpx.Response(200, content=b"{}", headers={"content-type": "application/json"})
152
+
153
+ with mock_client(handler) as client:
154
+ with pytest.raises(ValidationError):
155
+ client.scheduled_messages.retrieve("sched_1")
@@ -1 +0,0 @@
1
- __version__ = "3.2.0"
@@ -1,4 +0,0 @@
1
- from blueticks.resources.account import AccountResource
2
- from blueticks.resources.ping import PingResource
3
-
4
- __all__ = ["AccountResource", "PingResource"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes