Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions tools/gmail/oauth-draft/src/oauth_draft/create_draft.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ def api_get(access_token: str, path: str) -> dict:
f"{GMAIL_API}{path}",
headers={"Authorization": f"Bearer {access_token}"},
)
with urllib.request.urlopen(req, timeout=15) as r:
return json.loads(r.read())
try:
with urllib.request.urlopen(req, timeout=15) as r:
return json.loads(r.read())
except urllib.error.HTTPError as e:
raise SystemExit(f"Gmail API {path} failed ({e.code}): {e.read().decode(errors='replace')}") from e


def api_post(access_token: str, path: str, payload: dict) -> dict:
Expand Down
23 changes: 23 additions & 0 deletions tools/gmail/oauth-draft/tests/test_create_draft.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,29 @@ def test_api_post_parses_json_response():
assert json.loads(request.data) == {"message": {"raw": "X"}}


def test_api_get_raises_on_http_error():
"""``api_get`` must surface HTTP errors as a clean ``SystemExit``.

Regression: ``api_get`` was the only ``urlopen`` call in the
package without a ``try/except HTTPError``, so a 401/403/404 from
``threads.get`` (the path exercised on every ``oauth-draft-create
--thread-id <X>`` invocation) produced a raw Python traceback
instead of a one-line error matching the rest of the tool.
"""
err = urllib.error.HTTPError(
url="https://x",
code=404,
msg="Not Found",
hdrs=None, # type: ignore[arg-type]
fp=io.BytesIO(b'{"error": "thread missing"}'),
)
with patch("oauth_draft.create_draft.urllib.request.urlopen", side_effect=err):
with pytest.raises(SystemExit) as excinfo:
api_get("token", "/threads/missing-thread")
assert "failed (404)" in str(excinfo.value)
assert "thread missing" in str(excinfo.value)


def test_api_post_raises_on_http_error():
err = urllib.error.HTTPError(
url="https://x",
Expand Down
Loading