Summary
Client.__init__ and the README both document a default request timeout of 30 seconds, but no timeout is ever applied. A default httpr.Client() will block indefinitely on a server that accepts the connection and never responds.
Cause
httpr/__init__.py:203 declares timeout: float | None = 30, but the body of Client.__init__ is just super().__init__() — it forwards nothing. The real constructor is PyO3's #[new] on RClient (src/lib.rs:118), whose signature defaults to timeout=None. With None, src/lib.rs:183 never calls client_builder.timeout(...), so reqwest applies no timeout at all.
Reproduction
import httpr
print(httpr.Client().timeout) # -> None, not 30.0
Against a local server that accepts the request and then sleeps for 120s:
httpr.Client() [docs say default timeout=30] raised RequestError after 120.0s
httpx.Client() [default timeout=5] raised ReadTimeout after 5.1s
httpr did not time out — it returned only when the server finally closed the socket at 120s.
Expected
httpr.Client().timeout == 30.0, and a request against an unresponsive server raises a timeout exception after ~30s.
Proposed fix
Change the default in the Rust #[new] signature (src/lib.rs:118) from timeout=None to timeout=30.0, so the documented default is the one that actually applies.
I audited all 16 constructor parameters — timeout is the only one where the Python-documented default disagrees with the Rust default. cookie_store, referer, follow_redirects, max_redirects, verify, https_only and http2_only all agree.
While here, it's worth making Client.__init__'s signature non-misleading (it currently lists every parameter and forwards none of them; the values reach Rust via __new__).
Suggested tests
assert httpr.Client().timeout == 30.0
assert httpr.Client(timeout=5).timeout == 5.0
- A test against a deliberately slow endpoint asserting a timeout is raised.
Size
~30 minutes.
Summary
Client.__init__and the README both document a default request timeout of 30 seconds, but no timeout is ever applied. A defaulthttpr.Client()will block indefinitely on a server that accepts the connection and never responds.Cause
httpr/__init__.py:203declarestimeout: float | None = 30, but the body ofClient.__init__is justsuper().__init__()— it forwards nothing. The real constructor is PyO3's#[new]onRClient(src/lib.rs:118), whose signature defaults totimeout=None. WithNone,src/lib.rs:183never callsclient_builder.timeout(...), so reqwest applies no timeout at all.Reproduction
Against a local server that accepts the request and then sleeps for 120s:
httpr did not time out — it returned only when the server finally closed the socket at 120s.
Expected
httpr.Client().timeout == 30.0, and a request against an unresponsive server raises a timeout exception after ~30s.Proposed fix
Change the default in the Rust
#[new]signature (src/lib.rs:118) fromtimeout=Nonetotimeout=30.0, so the documented default is the one that actually applies.I audited all 16 constructor parameters —
timeoutis the only one where the Python-documented default disagrees with the Rust default.cookie_store,referer,follow_redirects,max_redirects,verify,https_onlyandhttp2_onlyall agree.While here, it's worth making
Client.__init__'s signature non-misleading (it currently lists every parameter and forwards none of them; the values reach Rust via__new__).Suggested tests
assert httpr.Client().timeout == 30.0assert httpr.Client(timeout=5).timeout == 5.0Size
~30 minutes.