From b5e0618c01224947215cbb99a3b3b013993db1b0 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Jan 2026 00:32:22 +0000 Subject: [PATCH 1/4] Update requestx adapter for v1.0.2 API (httpx-like interface) - Changed from Session() to Client() for sync and AsyncClient() for async - Added proper aclose() for async client cleanup - Switched from 'data' to 'content' parameter for request body - Added native streaming support using stream() method with iter_bytes/aiter_bytes - Added verify_ssl attribute initialization - Updated pyproject.toml to require requestx>=1.0.2 https://claude.ai/code/session_018m5XH5sVYS25zAr6258ygf --- http_benchmark/clients/requestx_adapter.py | 139 ++++++++++----------- pyproject.toml | 2 +- 2 files changed, 66 insertions(+), 75 deletions(-) diff --git a/http_benchmark/clients/requestx_adapter.py b/http_benchmark/clients/requestx_adapter.py index 88ab752..41619a1 100644 --- a/http_benchmark/clients/requestx_adapter.py +++ b/http_benchmark/clients/requestx_adapter.py @@ -1,6 +1,8 @@ -"""RequestX HTTP client adapter for the HTTP benchmark framework.""" +"""RequestX HTTP client adapter for the HTTP benchmark framework. + +Updated for requestx 1.0.2 which has an API similar to httpx. +""" -import time import asyncio from typing import Any, Dict @@ -11,32 +13,37 @@ class RequestXAdapter(BaseHTTPAdapter): - """HTTP adapter for the requestx library.""" + """HTTP adapter for the requestx library (v1.0.2+). + + RequestX 1.0.2 uses an httpx-like API with Client for sync + and AsyncClient for async operations. + """ def __init__(self): super().__init__("requestx") - self.session = None - self.async_session = None + self.client = None + self.async_client = None + self.verify_ssl = True def __enter__(self): - """Initialize session when entering sync context.""" - self.session = requestx.Session() + """Initialize sync client when entering sync context.""" + self.client = requestx.Client(verify=self.verify_ssl) return self def __exit__(self, exc_type, exc_val, exc_tb): - """Close session when exiting sync context.""" - if self.session: - self.session.close() + """Close sync client when exiting sync context.""" + if self.client: + self.client.close() async def __aenter__(self): - """Initialize session when entering async context.""" - self.async_session = requestx.Session() + """Initialize async client when entering async context.""" + self.async_client = requestx.AsyncClient(verify=self.verify_ssl) return self async def __aexit__(self, exc_type, exc_val, exc_tb): - """Close session when exiting async context.""" - if self.async_session: - self.async_session.close() + """Close async client when exiting async context.""" + if self.async_client: + await self.async_client.aclose() def make_request(self, request: HTTPRequest) -> Dict[str, Any]: """Make an HTTP request using the requestx library.""" @@ -45,27 +52,22 @@ def make_request(self, request: HTTPRequest) -> Dict[str, Any]: url = request.url headers = request.headers timeout = request.timeout - verify_ssl = request.verify_ssl data = request.body if request.body else None - kwargs = {"headers": headers, "timeout": timeout, "verify": verify_ssl} - if data is not None: - kwargs["data"] = data - - start_time = time.time() - response = self.session.request(method, url, **kwargs) - end_time = time.time() - - response_time = end_time - start_time - if hasattr(response, "elapsed"): - response_time = response.elapsed.total_seconds() + response = self.client.request( + method=method, + url=url, + headers=headers, + content=data, + timeout=timeout + ) return { "status_code": response.status_code, "headers": dict(response.headers), "content": response.text, - "response_time": response_time, + "response_time": response.elapsed.total_seconds(), "url": str(response.url), "success": True, "error": None, @@ -88,27 +90,24 @@ async def make_request_async(self, request: HTTPRequest) -> Dict[str, Any]: url = request.url headers = request.headers timeout = request.timeout - verify_ssl = request.verify_ssl data = request.body if request.body else None - kwargs = {"headers": headers, "timeout": timeout, "verify": verify_ssl} - if data is not None: - kwargs["data"] = data - start_time = asyncio.get_event_loop().time() - response = await self.async_session.request(method, url, **kwargs) + response = await self.async_client.request( + method=method, + url=url, + headers=headers, + content=data, + timeout=timeout + ) end_time = asyncio.get_event_loop().time() - response_time = end_time - start_time - if hasattr(response, "elapsed"): - response_time = response.elapsed.total_seconds() - return { "status_code": response.status_code, "headers": dict(response.headers), "content": response.text, - "response_time": response_time, + "response_time": end_time - start_time, "url": str(response.url), "success": True, "error": None, @@ -131,40 +130,37 @@ def make_request_stream(self, request: HTTPRequest) -> Dict[str, Any]: url = request.url headers = request.headers timeout = request.timeout - verify_ssl = request.verify_ssl data = request.body if request.body else None - kwargs = {"headers": headers, "timeout": timeout, "verify": verify_ssl} - if data is not None: - kwargs["data"] = data + import time start_time = time.time() - # RequestX doesn't have native streaming like requests - # Fall back to regular request and simulate streaming behavior - response = self.session.request(method, url, **kwargs) - - # Simulate chunked reading - content = response.content - chunk_count = 1 if content else 0 + with self.client.stream( + method=method, + url=url, + headers=headers, + content=data, + timeout=timeout + ) as response: + content = b"" + for chunk in response.iter_bytes(chunk_size=8192): + if chunk: + content += chunk end_time = time.time() - response_time = end_time - start_time - if hasattr(response, "elapsed"): - response_time = response.elapsed.total_seconds() - return { "status_code": response.status_code, "headers": dict(response.headers), "content": content.decode("utf-8") if content else "", - "response_time": response_time, + "response_time": end_time - start_time, "url": str(response.url), "success": True, "error": None, "streamed": True, - "chunk_count": chunk_count, + "chunk_count": len(content) // 8192 + (1 if len(content) % 8192 > 0 else 0), } except Exception as e: return { @@ -185,40 +181,35 @@ async def make_request_stream_async(self, request: HTTPRequest) -> Dict[str, Any url = request.url headers = request.headers timeout = request.timeout - verify_ssl = request.verify_ssl data = request.body if request.body else None - kwargs = {"headers": headers, "timeout": timeout, "verify": verify_ssl} - if data is not None: - kwargs["data"] = data - start_time = asyncio.get_event_loop().time() - # RequestX doesn't have native streaming like requests - # Fall back to regular request and simulate streaming behavior - response = await self.async_session.request(method, url, **kwargs) - - # Simulate chunked reading - content = response.content - chunk_count = 1 if content else 0 + async with self.async_client.stream( + method=method, + url=url, + headers=headers, + content=data, + timeout=timeout + ) as response: + content = b"" + async for chunk in response.aiter_bytes(chunk_size=8192): + if chunk: + content += chunk end_time = asyncio.get_event_loop().time() - response_time = end_time - start_time - if hasattr(response, "elapsed"): - response_time = response.elapsed.total_seconds() - return { "status_code": response.status_code, "headers": dict(response.headers), "content": content.decode("utf-8") if content else "", - "response_time": response_time, + "response_time": end_time - start_time, "url": str(response.url), "success": True, "error": None, "streamed": True, - "chunk_count": chunk_count, + "chunk_count": len(content) // 8192 + (1 if len(content) % 8192 > 0 else 0), } except Exception as e: return { diff --git a/pyproject.toml b/pyproject.toml index 0e39abf..bb6251e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ classifiers = [ ] dependencies = [ "requests>=2.31.0", - "requestx>=0.1.0", + "requestx>=1.0.2", "httpx>=0.27.0", "aiohttp>=3.9.0", "urllib3>=2.0.0", From a80ede8f374e31504df185442ea243c9fcd56c60 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Jan 2026 00:33:12 +0000 Subject: [PATCH 2/4] Bump requestx version requirement to 1.0.3 https://claude.ai/code/session_018m5XH5sVYS25zAr6258ygf --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bb6251e..6d591f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ classifiers = [ ] dependencies = [ "requests>=2.31.0", - "requestx>=1.0.2", + "requestx>=1.0.3", "httpx>=0.27.0", "aiohttp>=3.9.0", "urllib3>=2.0.0", From bbcc21b793a6e8205abc067bead63cad670818c3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Jan 2026 00:38:44 +0000 Subject: [PATCH 3/4] Align requestx adapter formatting with httpx adapter Reformatted to match httpx adapter style exactly: - Single line docstrings - Inline method call parameters - Consistent code structure https://claude.ai/code/session_018m5XH5sVYS25zAr6258ygf --- http_benchmark/clients/requestx_adapter.py | 43 +++------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/http_benchmark/clients/requestx_adapter.py b/http_benchmark/clients/requestx_adapter.py index 41619a1..50b82df 100644 --- a/http_benchmark/clients/requestx_adapter.py +++ b/http_benchmark/clients/requestx_adapter.py @@ -1,7 +1,4 @@ -"""RequestX HTTP client adapter for the HTTP benchmark framework. - -Updated for requestx 1.0.2 which has an API similar to httpx. -""" +"""RequestX HTTP client adapter for the HTTP benchmark framework.""" import asyncio from typing import Any, Dict @@ -13,11 +10,7 @@ class RequestXAdapter(BaseHTTPAdapter): - """HTTP adapter for the requestx library (v1.0.2+). - - RequestX 1.0.2 uses an httpx-like API with Client for sync - and AsyncClient for async operations. - """ + """HTTP adapter for the requestx library.""" def __init__(self): super().__init__("requestx") @@ -55,13 +48,7 @@ def make_request(self, request: HTTPRequest) -> Dict[str, Any]: data = request.body if request.body else None - response = self.client.request( - method=method, - url=url, - headers=headers, - content=data, - timeout=timeout - ) + response = self.client.request(method=method, url=url, headers=headers, content=data, timeout=timeout) return { "status_code": response.status_code, @@ -94,13 +81,7 @@ async def make_request_async(self, request: HTTPRequest) -> Dict[str, Any]: data = request.body if request.body else None start_time = asyncio.get_event_loop().time() - response = await self.async_client.request( - method=method, - url=url, - headers=headers, - content=data, - timeout=timeout - ) + response = await self.async_client.request(method=method, url=url, headers=headers, content=data, timeout=timeout) end_time = asyncio.get_event_loop().time() return { @@ -137,13 +118,7 @@ def make_request_stream(self, request: HTTPRequest) -> Dict[str, Any]: start_time = time.time() - with self.client.stream( - method=method, - url=url, - headers=headers, - content=data, - timeout=timeout - ) as response: + with self.client.stream(method=method, url=url, headers=headers, content=data, timeout=timeout) as response: content = b"" for chunk in response.iter_bytes(chunk_size=8192): if chunk: @@ -186,13 +161,7 @@ async def make_request_stream_async(self, request: HTTPRequest) -> Dict[str, Any start_time = asyncio.get_event_loop().time() - async with self.async_client.stream( - method=method, - url=url, - headers=headers, - content=data, - timeout=timeout - ) as response: + async with self.async_client.stream(method=method, url=url, headers=headers, content=data, timeout=timeout) as response: content = b"" async for chunk in response.aiter_bytes(chunk_size=8192): if chunk: From 3b81937141eb29be932860454842d5a9dffae0d1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Jan 2026 00:42:42 +0000 Subject: [PATCH 4/4] Bump version to 5.1.1 - Updated requestx adapter for v1.0.3 API (httpx-like interface) https://claude.ai/code/session_018m5XH5sVYS25zAr6258ygf --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6d591f3..02d9a3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "http-client-benchmarker" -version = "5.1.0" +version = "5.1.1" description = "A Python HTTP Client Performance Benchmark Framework" readme = "README.md" authors = [{name = "Qunfei Wu", email = "wu.qunfei@gmail.com"}]