nikkie-ftnextの日記

イベントレポートや読書メモを発信

HTTPXは、HTTPリクエストを発行するコード(.request())と、レスポンスのステータスコードをチェックするコード(response.raise_for_status())とで、それぞれ例外が送出されうる

はじめに

七尾百合子さん、お誕生日 94日目 おめでとうございます! nikkieです。

先日のリリース報告エントリで「HTTPXで例外が送出される箇所の理解が深まりました」と予告した1のを回収します。

目次

まとめ:通信とステータスコードチェックの2箇所

私が理解した内容は、改めてドキュメントを確認すると、QuickstartのExceptionsに書かれていました。
確認不足でやらかしてます... orz

The most important exception classes in HTTPX are RequestError and HTTPStatusError.

try:
    response = httpx.get("https://www.example.com/")
    response.raise_for_status()
except httpx.RequestError as exc:
    print(f"An error occurred while requesting {exc.request.url!r}.")
except httpx.HTTPStatusError as exc:
    print(f"Error response {exc.response.status_code} while requesting {exc.request.url!r}.")
  • httpx.get()httpx.post()httpx.RequestErrorを送出する
  • response.raise_for_status()httpx.HTTPStatusErrorを送出する

tryを狭くしようとしてやらかした

前提としてtry節は最小にしたいです。

結論を繰り返すと、以下の2行は両方try節に入れる必要があるのですが、

response = httpx.get("https://www.example.com/")
response.raise_for_status()

私は狭いtry節を作ろうとして誤解していました。

response = httpx.get("https://www.example.com/")
try:
    response.raise_for_status()
except httpx.HTTPStatusError:
    ...

これだとhttpx.get()で例外が発生し得ますし、try節の外なのでプログラムが終了してしまいます。

HTTPXの例外のドキュメントより

https://www.python-httpx.org/exceptions/#exception-classes

httpx.RequestError

Base class for all exceptions that may occur when issuing a .request().

httpx.get()httpx.post()は、内部で.request()を呼び出していますね。
このHTTPリクエス(いわばHTTP通信の過程)で問題が起こった場合です。
その1つがTimeoutです2

httpx.HTTPStatusError

May be raised when calling response.raise_for_status()

HTTP通信に問題はなかったけれど、サーバから4xxや5xxが帰ってきた場合ですね。

httpx.HTTPError

Base class for RequestError and HTTPStatusError.

例外の基底クラスを使って、except節を1つにまとめられます。

Useful for try...except blocks when issuing a request, and then calling .raise_for_status().

try:
    response = httpx.get("https://www.example.com/")
    response.raise_for_status()
except httpx.HTTPError as exc:
    # RequestError でも HTTPStatusError でも共通の処理

終わりに

llm-devinllm-openhandsでWeb APIに繰り返しHTTPXでリクエストするときに、書いたようにやらかしたためにRequestErrorで処理が落ちていて、今回の内容を学びました。

  • httpx.request()ではhttpx.RequestErrorが送出されうる
  • response.raise_for_status()ではhttpx.HTTPStatusErrorが送出されうる
  • ゆえに、try節には両方を含める必要がある
  • 基底のhttpx.HTTPErrorで両種の例外をまとめて処理できる

ここまで理解すると、例外の名前が送出箇所と対応するのが見えてきますね。

おまけ:HTTPクライアントを知るのは重要です!