Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 20 additions & 40 deletions backend/python/app/sources/client/http/http_client.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,29 @@
from typing import Optional

import httpx # type: ignore

import httpx
from app.sources.client.http.http_request import HTTPRequest
from app.sources.client.http.http_response import HTTPResponse
from app.sources.client.iclient import IClient
from codeflash.verification.codeflash_capture import codeflash_capture


class HTTPClient(IClient):
def __init__(
self,
token: str,
token_type: str = "Bearer",
timeout: float = 30.0,
follow_redirects: bool = True
) -> None:
self.headers = {
"Authorization": f"{token_type} {token}",
}

@codeflash_capture(function_name='HTTPClient.__init__', tmp_dir_path='/tmp/codeflash_1j5ekrv2/test_return_values', tests_root='/home/ubuntu/work/repo/backend/python/tests', is_fto=False)
def __init__(self, token: str, token_type: str='Bearer', timeout: float=30.0, follow_redirects: bool=True) -> None:
self.headers = {'Authorization': f'{token_type} {token}'}
self.timeout = timeout
self.follow_redirects = follow_redirects
self.client: Optional[httpx.AsyncClient] = None

def get_client(self) -> "HTTPClient":
def get_client(self) -> 'HTTPClient':
"""Get the client"""
return self

async def _ensure_client(self) -> httpx.AsyncClient:
"""Ensure client is created and available"""
if self.client is None:
self.client = httpx.AsyncClient(
timeout=self.timeout,
follow_redirects=self.follow_redirects
)
self.client = httpx.AsyncClient(timeout=self.timeout, follow_redirects=self.follow_redirects)
return self.client

async def execute(self, request: HTTPRequest, **kwargs) -> HTTPResponse:
Expand All @@ -43,30 +34,19 @@ async def execute(self, request: HTTPRequest, **kwargs) -> HTTPResponse:
Returns:
A HTTPResponse object containing the response from the server
"""
url = f"{request.url.format(**request.path_params)}"
client = await self._ensure_client()

# Merge client headers with request headers (request headers take precedence)
merged_headers = {**self.headers, **request.headers}
request_kwargs = {
"params": request.query_params,
"headers": merged_headers,
**kwargs
}

if isinstance(request.body, dict):
# Check if Content-Type indicates form data
content_type = request.headers.get("Content-Type", "").lower()
if "application/x-www-form-urlencoded" in content_type:
# Send as form data
request_kwargs["data"] = request.body
merged_headers = {**self.headers, **request.headers} if request.headers else self.headers
request_kwargs = {'params': request.query_params, 'headers': merged_headers, **kwargs}
body = request.body
content_type = request.headers.get('Content-Type', '').lower() if request.headers else ''
if isinstance(body, dict):
if 'application/x-www-form-urlencoded' in content_type:
request_kwargs['data'] = body
else:
# Send as JSON (default behavior)
request_kwargs["json"] = request.body
elif isinstance(request.body, bytes):
request_kwargs["content"] = request.body

response = await client.request(request.method, url, **request_kwargs)
request_kwargs['json'] = body
elif isinstance(body, bytes):
request_kwargs['content'] = body
response = await client.request(request.method, f'{request.url.format(**request.path_params)}', **request_kwargs)
return HTTPResponse(response)

async def close(self) -> None:
Expand All @@ -75,7 +55,7 @@ async def close(self) -> None:
await self.client.aclose()
self.client = None

async def __aenter__(self) -> "HTTPClient":
async def __aenter__(self) -> 'HTTPClient':
"""Async context manager entry"""
await self._ensure_client()
return self
Expand Down
12 changes: 9 additions & 3 deletions backend/python/app/sources/external/confluence/confluence.py
Original file line number Diff line number Diff line change
Expand Up @@ -1640,10 +1640,15 @@ async def get_custom_content_content_properties_by_id(
property_id: int,
headers: Optional[Dict[str, Any]] = None
) -> HTTPResponse:
"""Auto-generated from OpenAPI: Get content property for custom content by id\n\nHTTP GET /custom-content/{custom-content-id}/properties/{property-id}\nPath params:\n - custom-content-id (int)\n - property-id (int)"""
"""Auto-generated from OpenAPI: Get content property for custom content by id

HTTP GET /custom-content/{custom-content-id}/properties/{property-id}
Path params:
- custom-content-id (int)
- property-id (int)"""
if self._client is None:
raise ValueError('HTTP client is not initialized')
_headers: Dict[str, Any] = dict(headers or {})
_headers: Dict[str, Any] = dict(headers) if headers else {}
_path: Dict[str, Any] = {
'custom-content-id': custom_content_id,
'property-id': property_id,
Expand Down Expand Up @@ -7124,4 +7129,5 @@ def _serialize_value(v: Union[bool, str, int, float, list, tuple, set, None]) ->
return _to_bool_str(v)

def _as_str_dict(d: Dict[str, Any]) -> Dict[str, str]:
return {str(k): _serialize_value(v) for k, v in (d or {}).items()}
# Avoid unnecessary copy if d is already a dict
return {str(k): _serialize_value(v) for k, v in (d.items() if d else [])}