Skip to content

Commit dc0e792

Browse files
committed
feat: add status() method for delivery report lookup (v0.7.21)
1 parent aca8629 commit dc0e792

5 files changed

Lines changed: 78 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
1111

1212
---
1313

14+
## [0.7.21] - 2026-03-05
15+
16+
### Added
17+
- `status()` method on `KwtSMS`: looks up delivery status for a sent message via `/report/` endpoint
18+
- `tests/test_status.py`: three tests covering OK response, error enrichment, and network error handling
19+
20+
---
21+
1422
## [0.7.20] - 2026-03-05
1523

1624
### Added

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "kwtsms"
3-
version = "0.7.20"
3+
version = "0.7.21"
44
description = "Python client for kwtSMS, the Kuwait SMS gateway trusted by top businesses to deliver messages worldwide, with private Sender ID, free API testing, and non-expiring credits."
55
readme = "README.md"
66
requires-python = ">=3.8"

src/kwtsms/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
result = sms.send("96598765432", "Hello", sender="MY-APP") # override sender
1111
report = sms.validate(["96598765432", "+96512345678"])
1212
balance = sms.balance()
13+
delivery = sms.status(result["msg-id"]) # delivery report
1314
1415
Utility functions:
1516
from kwtsms import normalize_phone, clean_message, validate_phone_input
@@ -18,4 +19,4 @@
1819
from kwtsms._core import KwtSMS, clean_message, normalize_phone, validate_phone_input
1920

2021
__all__ = ["KwtSMS", "normalize_phone", "clean_message", "validate_phone_input"]
21-
__version__ = "0.7.20"
22+
__version__ = "0.7.21"

src/kwtsms/_core.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,32 @@ def balance(self) -> Optional[float]:
466466
ok, bal, _ = self.verify()
467467
return bal if ok else self._cached_balance
468468

469+
# ── status ────────────────────────────────────────────────────────────────
470+
471+
def status(self, msg_id: str) -> dict:
472+
"""
473+
Get delivery status for a sent message via /report/.
474+
475+
Args:
476+
msg_id: The message ID returned by send() in result["msg-id"].
477+
478+
Returns:
479+
OK: {"result": "OK", "msg-id": "...", "status": "DELIVERED", ...}
480+
ERROR: {"result": "ERROR", "code": "ERR020", "description": "...", "action": "..."}
481+
482+
Common error codes:
483+
ERR019: No delivery reports found
484+
ERR020: Message ID does not exist
485+
ERR021: Report not ready yet
486+
ERR022: Try again after 24 hours
487+
"""
488+
try:
489+
data = _request("report", {**self._creds(), "msgid": msg_id}, self.log_file)
490+
except RuntimeError as e:
491+
return {"result": "ERROR", "code": "NETWORK", "description": str(e),
492+
"action": "Check your internet connection and try again."}
493+
return _enrich_error(data)
494+
469495
# ── senderids ─────────────────────────────────────────────────────────────
470496

471497
def senderids(self) -> dict:

tests/test_status.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from unittest.mock import patch
2+
from kwtsms import KwtSMS
3+
4+
def _client(**kwargs) -> KwtSMS:
5+
defaults = dict(username="python_username", password="python_password",
6+
sender_id="TEST", log_file="")
7+
defaults.update(kwargs)
8+
return KwtSMS(**defaults)
9+
10+
OK_RESPONSE = {
11+
"result": "OK",
12+
"msg-id": "abc123",
13+
"status": "DELIVERED",
14+
"delivered-at": 1700000000,
15+
}
16+
17+
ERR020_RESPONSE = {
18+
"result": "ERROR",
19+
"code": "ERR020",
20+
"description": "Message ID does not exist.",
21+
}
22+
23+
class TestStatus:
24+
def test_status_ok_returns_dict_with_result_ok(self):
25+
with patch("kwtsms._core._request", return_value=OK_RESPONSE):
26+
result = _client().status("abc123")
27+
assert result["result"] == "OK"
28+
assert result["msg-id"] == "abc123"
29+
assert result["status"] == "DELIVERED"
30+
31+
def test_status_error_has_action(self):
32+
with patch("kwtsms._core._request", return_value=ERR020_RESPONSE):
33+
result = _client().status("bad-id")
34+
assert result["result"] == "ERROR"
35+
assert "action" in result
36+
37+
def test_status_network_error_returns_dict(self):
38+
with patch("kwtsms._core._request", side_effect=RuntimeError("Timeout")):
39+
result = _client().status("abc123")
40+
assert result["result"] == "ERROR"
41+
assert result["code"] == "NETWORK"

0 commit comments

Comments
 (0)