Skip to content

feat(client): implement raise_for_status for Client#583

Merged
0x676e67 merged 3 commits into
0x676e67:mainfrom
0x1997:main
May 4, 2026
Merged

feat(client): implement raise_for_status for Client#583
0x676e67 merged 3 commits into
0x676e67:mainfrom
0x1997:main

Conversation

@0x1997
Copy link
Copy Markdown
Contributor

@0x1997 0x1997 commented May 4, 2026

Fix #581

Summary by CodeRabbit

  • New Features
    • Added an optional client-level setting to control whether HTTP error status codes automatically raise exceptions.
    • Applies to both regular HTTP and WebSocket request flows; default behavior is unchanged when unset.
    • Setting is documented for client configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

Adds a client-level raise_for_status option: Python config exposes it, Rust Client stores it, request execution uses the stored flag to conditionally call error_for_status() on HTTP responses; request/websocket callers now pass the full Client into executors so the flag is available.

Changes

Error Status Control Feature

Layer / File(s) Summary
Python type hints
python/wreq/wreq.py
ClientConfig gains an optional raise_for_status: NotRequired[bool] field.
Builder / Config extraction
src/client.rs
Builder adds raise_for_status: Option<bool> and Builder::extract reads it from kwargs.
Client internal field & init
src/client.rs
Client gains raise_for_status: bool, set from config.raise_for_status.unwrap_or(false) in Client::new.
Execution wiring
src/client.rs
Client::request/websocket and blocking equivalents now pass self.clone() into execute_request/execute_websocket_request so the stored flag is available.
Request execution & response handling
src/client/req.rs
Executors build via client.inner.request(...) / client.inner.websocket(...), send the request, then conditionally call r.error_for_status() when client.raise_for_status is true before mapping into Response.
Manifest
Cargo.toml, pyproject.toml
Manifests touched (minor updates).

Sequence Diagram(s)

sequenceDiagram
    participant PyClient as Python Client
    participant RustClient as Rust Client
    participant Executor as execute_request
    participant HTTP as HTTP Backend

    PyClient->>RustClient: create Client (raise_for_status=?)
    PyClient->>RustClient: request(...)
    RustClient->>Executor: execute_request(request, client.clone())
    Executor->>HTTP: send HTTP request
    HTTP-->>Executor: HTTP response
    alt client.raise_for_status == true
        Executor->>Executor: response.error_for_status()  -- may raise
    else client.raise_for_status == false
        Executor-->>Executor: keep response as-is
    end
    Executor-->>RustClient: Response / Error
    RustClient-->>PyClient: Response / Error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit nibbles code with care,
A flag tucked in the client's lair,
When status turns from green to red,
The flag may shout — "Raise!" instead,
Hopping bugs away with flair 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: implementing raise_for_status feature for the Client.
Linked Issues check ✅ Passed The PR implements raise_for_status behavior across Client/BlockingClient and their request/websocket methods to conditionally raise StatusError for non-200 status codes, directly addressing issue #581.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing raise_for_status: configuration field added to ClientConfig, Client struct, and conditional error handling in request execution paths.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/client.rs (1)

459-466: ⚠️ Potential issue | 🔴 Critical

Fix compilation error: config is out of scope.

config only exists inside the if let Some(mut config) = kwds block (lines 263-457), but this code reads it at line 465 after that block has ended. Capture the flag while config is still in scope, or assign it to a local before building the Client.

🔧 Suggested fix
     fn new(py: Python, kwds: Option<Builder>) -> PyResult<Client> {
         py.detach(|| {
             // Create the client builder.
             let mut builder = wreq::Client::builder();
             let mut cookie_jar: Option<Jar> = None;
+            let mut raise_for_status = false;

             if let Some(mut config) = kwds {
                 // Emulation options.
                 apply_option!(set_if_some, builder, config.emulation, emulation);
@@
                 // Compression options.
                 apply_option!(set_if_some, builder, config.gzip, gzip);
                 apply_option!(set_if_some, builder, config.brotli, brotli);
                 apply_option!(set_if_some, builder, config.deflate, deflate);
                 apply_option!(set_if_some, builder, config.zstd, zstd);
+
+                raise_for_status = config.raise_for_status.unwrap_or(false);
             }

             builder
                 .build()
                 .map(|inner| Client {
                     inner,
                     cancel: CancellationToken::new(),
                     cookie_jar,
-                    raise_for_status: config.raise_for_status.unwrap_or(false),
+                    raise_for_status,
                 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client.rs` around lines 459 - 466, The build closure references `config`
out of scope when constructing the Client (raise_for_status:
config.raise_for_status.unwrap_or(false)); fix by capturing the flag while
`config` is still in scope—e.g., inside the `if let Some(mut config) = kwds`
block compute a local boolean like `let raise_for_status =
config.raise_for_status.unwrap_or(false)` (or otherwise store it in a local
variable) and then use that local (`raise_for_status`) in the
`builder.build().map(|inner| Client { ... raise_for_status, })` call so no
out-of-scope variable is accessed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/client.rs`:
- Around line 459-466: The build closure references `config` out of scope when
constructing the Client (raise_for_status:
config.raise_for_status.unwrap_or(false)); fix by capturing the flag while
`config` is still in scope—e.g., inside the `if let Some(mut config) = kwds`
block compute a local boolean like `let raise_for_status =
config.raise_for_status.unwrap_or(false)` (or otherwise store it in a local
variable) and then use that local (`raise_for_status`) in the
`builder.build().map(|inner| Client { ... raise_for_status, })` call so no
out-of-scope variable is accessed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 990f984a-b462-4a14-93c6-aea10504ef1b

📥 Commits

Reviewing files that changed from the base of the PR and between 0c262d1 and 72a32fb.

📒 Files selected for processing (3)
  • python/wreq/wreq.py
  • src/client.rs
  • src/client/req.rs

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/req.rs`:
- Around line 419-425: The closure currently only checks client.raise_for_status
and ignores the per-request override; change it to compute the effective flag by
reading Request.raise_for_status (from where it was extracted at Line 237) and
falling back to client.raise_for_status when the request value is not set, then
call r.error_for_status() only when that effective flag is true; update the
closure that currently references client.raise_for_status to use this computed
effective value instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3c2f2cc0-3b27-4028-8a1e-12507c1ab0c1

📥 Commits

Reviewing files that changed from the base of the PR and between 16a2ddc and 8da4039.

📒 Files selected for processing (2)
  • src/client.rs
  • src/client/req.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/client.rs

coderabbitai[bot]

This comment was marked as spam.

@0x676e67
Copy link
Copy Markdown
Owner

0x676e67 commented May 4, 2026

This commit only implements functionality similar to setting raise_for_status on aiohttp Client.It does not introduce messy request-level raise_for_status configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StatusError is not raised

2 participants