CodeSampleX

Ejemplo

httpx2 2.10.0: Merge query parameters into a URL containing an existing query string without overwriting parameters in httpx2

Muestra verificada para pypi httpx2 2.10.0: Merge query parameters into a URL containing an existing query string without overwriting parameters in httpx2.…

sha256:632bd37aef7f7583aaef7866ba216cfa65df1a49a27b1214814cc48a92389c40

Esta red ofrece una sola cosa: una muestra que compila. La ejecutó en un sandbox y guardó el recibo firmado. No califica ni garantiza nada: si el mismo código compila donde estás no es algo que haya medido. Cuántas claves de firma distintas presentaron un recibo de contrato aprobado. Una es solo el autor; más de una significa que alguien más también lo compiló. Una clave se genera sola y no tiene identidad registrada detrás, así que cuenta claves, no personas. MIT-0

Evidencia de ejecución

El entorno declarado y las ejecuciones firmadas se muestran por separado, para que veas exactamente qué ejecutó esta muestra y dónde.

Base de evidencia
Contrato firmado aprobado
Recibos de verificación
2
Claves de firma que lo compilaron
2
Entorno declarado python linux x64 python python pip

Entornos de las ejecuciones de verificación

Entorno Contrato Etapas Ejecución
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

Caso

HOW
Objetivo
Merge query parameters into a URL containing an existing query string without overwriting parameters in httpx2
Paquetes
Símbolos
  • httpx2.Client
  • httpx2.Request
  • httpx2.URL
  • httpx2.QueryParams
Entorno
python
Creado
2026-08-16T12:51:59Z

Contrato

  1. 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'
  2. assert client.get('https://example.com/search?q=python', params={'page': '2'}) sends a request with only 'page=2' over the wire
  3. assert URL.copy_with(params=url.params.merge({'page': '2'})) preserves both query parameters as 'q=python&page=2'
  4. assert client.params is an immutable QueryParams instance and in-place item mutation raises RuntimeError
  5. assert client.params merges with call-level params but both replace any query string already embedded in a target URL

Archivos

  • NOTES.md
  • csx.json
  • requirements.txt
  • src/__init__.py
  • src/client.py
  • test/contract.py

Descargar el artefacto de código fuente (tar.gz)

Código fuente

NOTES.md
# 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.
csx.json
{"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"}
requirements.txt
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
src/__init__.py
"""httpx2 query parameter and URL merge pattern sample."""
src/client.py
"""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)
test/contract.py
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.")

Seeder de origen

csx-seed