fix: seven.io-Statuscode als nacktes int/float robust parsen (0.1.1)

Der SMS-Endpunkt liefert standardmäßig nur den nackten Statuscode (z. B. 100),
der als JSON zu einem int decodiert — _parse rief darauf data.get() auf und
crashte mit AttributeError. Jetzt wird ein Nicht-Objekt-JSON als Statuscode
behandelt (ok = code == "100").

- client.py: _parse behandelt dict / int-Code / Text einheitlich
- Tests: nackter int-Code 100 (ok) und 900 (Fehler)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-25 12:51:11 +02:00
commit fad93e194f
4 changed files with 31 additions and 5 deletions

View file

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "seven-send"
version = "0.1.0"
version = "0.1.1"
description = "Kleine Library + CLI zum Verschicken von SMS und TTS-Sprachanrufen über seven.io"
readme = "README.md"
requires-python = ">=3.10"

View file

@ -3,4 +3,4 @@
from seven_send.client import Result, SevenClient, SevenError
__all__ = ["SevenClient", "Result", "SevenError"]
__version__ = "0.1.0"
__version__ = "0.1.1"

View file

@ -107,9 +107,20 @@ class SevenClient:
)
try:
data = resp.json()
except Exception: # Legacy: nackter Statuscode als Text
first = body.splitlines()[0] if body else ""
return Result(ok=(first == "100"), channel=channel, to=to, code=first or None, raw=body)
except Exception:
data = None
# seven.io liefert je nach Endpunkt/Format entweder ein JSON-Objekt ODER nur
# den nackten Statuscode (z. B. "100") — der decodiert als JSON zu int/float.
# Beides hier robust behandeln.
if not isinstance(data, dict):
code = str(data).strip() if data is not None else (body.splitlines()[0] if body else "")
code = code or None
return Result(
ok=(code == "100"), channel=channel, to=to, code=code, raw=body,
error=None if code == "100" else f"seven status={code}",
)
code = str(data.get("success", "")).strip() or None
msgs = data.get("messages") or []
ok = code in (None, "100") and all(m.get("success", True) for m in msgs)

View file

@ -61,6 +61,21 @@ def test_failure_code(monkeypatch):
assert not r.ok and r.code == "401"
def test_sms_bare_int_code_ok(monkeypatch):
# SMS-Endpunkt liefert oft nur den nackten Code -> resp.json() == int 100
cap = []
_patch_post(monkeypatch, cap, FakeResp(payload=100, text="100"))
r = SevenClient("key").send_sms("+49", "x")
assert r.ok and r.code == "100"
def test_sms_bare_int_code_error(monkeypatch):
cap = []
_patch_post(monkeypatch, cap, FakeResp(payload=900, text="900"))
r = SevenClient("key").send_sms("+49", "x")
assert not r.ok and r.code == "900" and "900" in r.error
def test_http_error(monkeypatch):
cap = []
_patch_post(monkeypatch, cap, FakeResp(status_code=500, text="boom"))