샘플
httpx2 2.10.0: Merge query parameters into a URL containing an existing query string without overwriting parameters in httpx2
검증된 샘플 — pypi httpx2 2.10.0: Merge query parameters into a URL containing an existing query string without overwriting parameters in httpx2. python 3.12 …
sha256:632bd37aef7f7583aaef7866ba216cfa65df1a49a27b1214814cc48a92389c40
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 2
- 빌드한 서명 키
- 2
선언된 환경
python linux x64 python python pip
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-16 |
| python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-18 |
케이스
HOW- 목표
- Merge query parameters into a URL containing an existing query string without overwriting parameters in httpx2
- 패키지
- 심벌
-
- httpx2.Client
- httpx2.Request
- httpx2.URL
- httpx2.QueryParams
- 환경
- python
- 생성일
- 2026-08-16T12:51:59Z
컨트랙트
- assert passing params to Request('GET', 'https://example.com/search?q=python', params={'page': '2'}) overwrites the URL query to 'page=2', discarding 'q=python'
- assert client.get('https://example.com/search?q=python', params={'page': '2'}) sends a request with only 'page=2' over the wire
- assert URL.copy_with(params=url.params.merge({'page': '2'})) preserves both query parameters as 'q=python&page=2'
- assert client.params is an immutable QueryParams instance and in-place item mutation raises RuntimeError
- assert client.params merges with call-level params but both replace any query string already embedded in a target URL
파일
- NOTES.md
- csx.json
- requirements.txt
- src/__init__.py
- src/client.py
- test/contract.py
소스
# Query Parameter Handling and URL Mutation in httpx2
## 1. What `search_known_solution` Answered
- `search_known_solution` returned three general compatible samples (`sha256:fc03836e42df24fc9ebcc02153f8212390e8abec2d04d133be4cc5598abd71d4` covering FastAPI proxy `root_path`, `sha256:e32f5508a8ae9e5ee4ceff480b4d4ce78a2a9080072498c9a96762cd8bb95456` covering redirect headers, and `sha256:a40d7f23a7553db846896ca28ec8f7c6c6b132e22d61c01c48414c25a4c841ca` covering Undici interceptors).
- None of the existing samples addressed `httpx2` URL query parameter replacement or `QueryParams` immutability semantics.
## 2. What a Naive Model Would Have Written Instead
- When asked to add pagination or filter parameters to an existing endpoint URL (`https://example.com/search?q=python`), models ported from `requests` write `httpx2.get(url, params={"page": "2"})` expecting the request URL to become `https://example.com/search?q=python&page=2`.
- Models also attempt direct in-place mutation of `client.params` (`client.params["sort"] = "asc"` or `client.params.update(...)`), expecting `client.params` to behave like a standard mutable Python dictionary.
## 3. How the Wrong Version Fails
- Silently with a green build: the HTTP request succeeds over the wire but the original query parameters embedded in the URL are omitted, causing API backends to return un-filtered or default responses without raising any client-side error.
{"case":{"believed":"Passing query parameters via the params argument merges them with query parameters already present in the target URL.","caseId":"case:sha256:12460d8794b1ab56830eb5790c3f01f761cd46a54d682b93f4f75157e4de41d7","contract":["assert passing params to Request('GET', 'https://example.com/search?q=python', params={'page': '2'}) overwrites the URL query to 'page=2', discarding 'q=python'","assert client.get('https://example.com/search?q=python', params={'page': '2'}) sends a request with only 'page=2' over the wire","assert URL.copy_with(params=url.params.merge({'page': '2'})) preserves both query parameters as 'q=python\u0026page=2'","assert client.params is an immutable QueryParams instance and in-place item mutation raises RuntimeError","assert client.params merges with call-level params but both replace any query string already embedded in a target URL"],"goal":"Merge query parameters into a URL containing an existing query string without overwriting parameters in httpx2","kind":"HOW","packages":["pkg:pypi/httpx2@2.10.0"],"schemaVersion":1,"symbols":["httpx2.Client","httpx2.Request","httpx2.URL","httpx2.QueryParams"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/httpx2@2.10.0"],"schemaVersion":1,"symbols":["httpx2.Client","httpx2.Request","httpx2.URL","httpx2.QueryParams"],"verifierAdapter":"python@1"}
httpx2==2.10.0
httpcore2==2.10.0
idna==3.18
truststore==0.10.4
anyio==4.13.0
h11==0.16.0
typing-extensions==4.15.0
"""httpx2 query parameter and URL merge pattern sample."""
"""Reference implementations demonstrating URL query merging patterns in httpx2."""
from __future__ import annotations
import httpx2
def naive_request_with_params(url: str, params: dict[str, str]) -> httpx2.Request:
"""Naive request construction.
In httpx2, passing `params` replaces the query string embedded in `url`
instead of merging with it.
"""
return httpx2.Request("GET", url, params=params)
def safe_merge_url_params(url: str, extra_params: dict[str, str]) -> httpx2.URL:
"""Safe URL construction that preserves existing query parameters.
Parses the target URL and merges extra query parameters via URL.params.merge().
"""
parsed = httpx2.URL(url)
return parsed.copy_with(params=parsed.params.merge(extra_params))
def update_client_params(client: httpx2.Client, extra_params: dict[str, str]) -> None:
"""Update client query parameters safely.
httpx2.QueryParams is immutable; item assignment raises RuntimeError.
The client.params property must be replaced with the merged QueryParams.
"""
client.params = client.params.merge(extra_params)
import sys
from pathlib import Path
# Ensure src is importable
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import httpx2
from src.client import (
naive_request_with_params,
safe_merge_url_params,
update_client_params,
)
# ---------------------------------------------------------------------------
# 1. Naive Request with params replaces existing URL query string
# ---------------------------------------------------------------------------
# When a target URL already contains query parameters, passing the `params` argument
# does NOT append or merge them. Instead, httpx2 replaces the URL query string
# with the supplied parameters, silently discarding the query string in the URL.
url_with_query = "https://example.com/search?q=python"
naive_req = naive_request_with_params(url_with_query, {"page": "2"})
assert naive_req.url.query == b"page=2"
assert "q" not in naive_req.url.params
assert naive_req.url.params.get("page") == "2"
assert str(naive_req.url) == "https://example.com/search?page=2"
# ---------------------------------------------------------------------------
# 2. Wire verification with MockTransport
# ---------------------------------------------------------------------------
# Dispatching via Client.get confirms the exact HTTP request URL transmitted.
dispatched_urls = []
def mock_handler(request: httpx2.Request) -> httpx2.Response:
dispatched_urls.append(str(request.url))
return httpx2.Response(200, json={"status": "ok"})
transport = httpx2.MockTransport(mock_handler)
client = httpx2.Client(transport=transport)
# Naive call: q=python is lost on dispatch
client.get(url_with_query, params={"page": "2"})
assert dispatched_urls[0] == "https://example.com/search?page=2"
# ---------------------------------------------------------------------------
# 3. Correct Pattern: URL.params.merge() preserves existing parameters
# ---------------------------------------------------------------------------
# To preserve parameters in the URL while adding new ones, the caller must
# parse the URL and merge the parameters explicitly.
safe_url = safe_merge_url_params(url_with_query, {"page": "2"})
assert str(safe_url) == "https://example.com/search?q=python&page=2"
assert safe_url.params.get("q") == "python"
assert safe_url.params.get("page") == "2"
client.get(safe_url)
assert dispatched_urls[1] == "https://example.com/search?q=python&page=2"
# ---------------------------------------------------------------------------
# 4. Immutability of QueryParams on Client
# ---------------------------------------------------------------------------
# Unlike requests.Session where session.params is a mutable dict, httpx2.QueryParams
# is immutable. Mutating it in-place raises RuntimeError.
try:
client.params["sort"] = "asc"
raise AssertionError("Expected RuntimeError on QueryParams mutation")
except RuntimeError as exc:
assert "QueryParams are immutable" in str(exc)
# Safe update replaces the client.params property with merged parameters
update_client_params(client, {"sort": "asc"})
assert str(client.params) == "sort=asc"
assert client.params.get("sort") == "asc"
# ---------------------------------------------------------------------------
# 5. Client params vs URL query interaction
# ---------------------------------------------------------------------------
# Client-level params combine with request-level params, but both replace
# any query string embedded in the target URL.
client.get(url_with_query, params={"page": "2"})
assert dispatched_urls[2] == "https://example.com/search?sort=asc&page=2"
print("All httpx2 query parameter contracts verified successfully.")