← pod_r4_v1

fastapi_15589

failed WRONG_FIX UNSUBMITTED wrong_fix_unsubmitted(timeout) · 30 tool calls · 0 s · fastapi/fastapi

Task input

♻️ Do not accept underscore headers when using `convert_underscores=True` (the default)

## Pull Request

<!--
Please start with a GitHub Discussion.

Once a team member asks you to open a PR, create it and link the discussion here.

Obvious typo fixes can be made in a PR without starting a discussion.
-->

Discussion: <!-- Link to the GitHub Discussion -->

## Description

♻️ Do not accept underscore headers when using `convert_underscores=True` (the default)

This means it would only accept header names separated with hyphens by default, and to accept header names separated with underscores, an app would need to explicitly set `convert_underscores=False`.

<!-- Write the description of your PR here -->

## AI Disclaimer

<!-- If using AI, write here the prompt and model used -->

<details>
<summary>AI transcript</summary>

<!-- Paste here the entire AI transcript -->

</details>

## Checklist

- [ ] This PR is an obvious typo fix, or it links to a GitHub Discussion for the proposed code change.
- [ ] I added tests for the change.
- [ ] The new or updated tests fail on the main branch and pass on this PR.
- [ ] Coverage stays at 100%.
- [ ] The documentation explains the change if needed.

Tool calls (0)

#ToolArgumentsResult
No trace captured.

Patch

diff --git a/repro.py b/repro.py
new file mode 100644
index 000000000..861af14a3
--- /dev/null
+++ b/repro.py
@@ -0,0 +1,40 @@
+
+from fastapi import FastAPI, Header
+from fastapi.testclient import TestClient
+import pytest
+
+app = FastAPI()
+
+@app.get("/items")
+async def read_items(user_agent: str = Header(default="testclient")):
+    return {"User-Agent": user_agent}
+
+@app.get("/items_underscore")
+async def read_items_underscore(user_agent_name: str = Header(default="testclient")):
+    return {"User-Agent": user_agent_name}
+
+client = TestClient(app)
+
+def test_header_hyphen():
+    # Should work: user-agent-name -> user_agent_name
+    response = client.get("/items_underscore", headers={"user-agent-name": "fastapi-test"})
+    assert response.status_code == 200
+    assert response.json() == {"User-Agent": "fastapi-test"}
+
+def test_header_underscore_default():
+    # Should NOT work by default: user_agent_name -> user_agent_name
+    response = client.get("/items_underscore", headers={"user_agent_name": "fastapi-test"})
+    # If the change is implemented, this should return the default value
+    assert response.json() == {"User-Agent": "testclient"}
+
+def test_header_underscore_disabled():
+    # Now test with convert_underscores=False
+    app_disabled = FastAPI()
+    @app_disabled.get("/items")
+    async def read_items_disabled(user_agent_name: str = Header(default="testclient", convert_underscores=False)):
+        return {"User-Agent": user_agent_name}
+    
+    client_disabled = TestClient(app_disabled)
+    response = client_disabled.get("/items", headers={"user_agent_name": "fastapi-test"})
+    assert response.status_code == 200
+    assert response.json() == {"User-Agent": "fastapi-test"}

Test output

show
....F
=================================== FAILURES ===================================
_____ test_header_model_prefers_hyphenated_header_with_convert_underscores _____

    def test_header_model_prefers_hyphenated_header_with_convert_underscores():
        client = TestClient(app)
    
        resp = client.get(
            "/header-requires-hyphen",
            headers=[
                ("x-user-id", "hyphenated-value"),
                ("x_user_id", "underscore-value"),
            ],
        )
    
        assert resp.status_code == 200
>       assert resp.json() == {"x_user_id": "hyphenated-value"}
E       AssertionError: assert {'x_user_id':...rscore-value'} == {'x_user_id':...enated-value'}
E         
E         Differing items:
E         {'x_user_id': 'underscore-value'} != {'x_user_id': 'hyphenated-value'}
E         Use -v to get more diff

tests/test_query_cookie_header_model_extra_params.py:115: AssertionError
=============================== warnings summary ===============================
../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-1.6.0-py3-none-any/starlette/testclient.py:53
  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-1.6.0-py3-none-any/starlette/testclient.py:53: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
    _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 4 passed, 1 warning in 0.57s