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
15 changes: 15 additions & 0 deletions packages/gen/gen_ai_hub/_ssl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Shared SSL context factory for httpx2 clients.

httpx2 defaults to the OS trust store (truststore). This module preserves
the pre-migration behaviour of using certifi's CA bundle so existing
deployments are not affected. Switch callers to verify=True to adopt the
httpx2 default when ready.
"""
import ssl
import certifi


def default_ssl_context() -> ssl.SSLContext:
"""Return an SSL context backed by certifi's CA bundle."""
return ssl.create_default_context(cafile=certifi.where())
4 changes: 2 additions & 2 deletions packages/gen/gen_ai_hub/batch_service/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Exceptions for the batch service module.
"""

import httpx
import httpx2


class BatchServiceError(Exception):
Expand All @@ -17,7 +17,7 @@ def __init__(
request_id: str,
message: str,
status_code: int,
headers: httpx.Headers,
headers: httpx2.Headers,
):
self.request_id = request_id
self.message = message
Expand Down
71 changes: 36 additions & 35 deletions packages/gen/gen_ai_hub/batch_service/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

from typing import Optional, Union

import httpx
import httpx2
from gen_ai_hub._ssl import default_ssl_context

from gen_ai_hub import GenAIHubProxyClient
from gen_ai_hub.proxy import get_proxy_client
Expand All @@ -25,11 +26,11 @@
_BASE_PATH = "/llm-batch-service/v1/batches"


def _handle_http_error(response: httpx.Response) -> None:
def _handle_http_error(response: httpx2.Response) -> None:
"""Raises BatchServiceError from a non-2xx httpx response."""
try:
response.raise_for_status()
except httpx.HTTPStatusError as error:
except httpx2.HTTPStatusError as error:
try:
payload = response.json()
request_id = payload.get('request_id', '')
Expand Down Expand Up @@ -65,16 +66,16 @@ class BatchService:
:param resource_group: Value for the ``AI-Resource-Group`` header. Falls back
to the resource group on ``proxy_client`` when omitted.
:type resource_group: str, Optional
:param timeout: Default HTTP request timeout passed to httpx.
:type timeout: Union[int, float, httpx.Timeout], Optional
:param timeout: Default HTTP request timeout passed to httpx2.
:type timeout: Union[int, float, httpx2.Timeout], Optional
"""

def __init__(
self,
api_url: Optional[str] = None,
proxy_client: Optional[GenAIHubProxyClient] = None,
resource_group: Optional[str] = None,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
):
self.proxy_client = proxy_client or get_proxy_client(proxy_version="gen-ai-hub")
if api_url:
Expand All @@ -84,8 +85,8 @@ def __init__(
self.api_url = base
self.resource_group = resource_group
self.timeout = timeout
self.client = httpx.Client(timeout=self.timeout)
self.async_client = httpx.AsyncClient(timeout=self.timeout)
self.client = httpx2.Client(timeout=self.timeout, verify=default_ssl_context())
self.async_client = httpx2.AsyncClient(timeout=self.timeout, verify=default_ssl_context())

# ------------------------------------------------------------------
# Internal helpers
Expand All @@ -98,13 +99,13 @@ def _headers(self) -> dict:
return headers

def _determine_timeout(
self, timeout: Union[int, float, httpx.Timeout, None]
) -> Union[int, float, httpx.Timeout]:
self, timeout: Union[int, float, httpx2.Timeout, None]
) -> Union[int, float, httpx2.Timeout]:
if timeout is not None:
return timeout
if self.timeout is not None:
return self.timeout
return httpx.USE_CLIENT_DEFAULT
return httpx2.USE_CLIENT_DEFAULT

def _batches_url(self, *segments: str) -> str:
parts = [self.api_url + _BASE_PATH] + list(segments)
Expand All @@ -122,7 +123,7 @@ def create(
output_uri: str,
provider: str,
model: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchCreateResponse:
"""Create a new batch processing job.

Expand All @@ -137,7 +138,7 @@ def create(
:param model: Model name (e.g. ``"gpt-4.1-mini"``).
:type model: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchCreateResponse` with the job ID and initial status.
"""
body = BatchCreateRequest(
Expand All @@ -158,12 +159,12 @@ def create(

def list(
self,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchListResponse:
"""List all batch jobs for the current resource group.

:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchListResponse` containing the batch summaries.
"""
response = self.client.get(
Expand All @@ -178,14 +179,14 @@ def list(
def get(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchDetailResponse:
"""Retrieve details of a specific batch job.

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchDetailResponse` with full job details.
"""
response = self.client.get(
Expand All @@ -200,14 +201,14 @@ def get(
def get_status(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchStatusResponse:
"""Retrieve the current status of a batch job.

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchStatusResponse` with current and target status.
"""
response = self.client.get(
Expand All @@ -222,14 +223,14 @@ def get_status(
def cancel(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchCancelResponse:
"""Schedule a batch job for cancellation.

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchCancelResponse` confirming the cancellation request.
"""
response = self.client.patch(
Expand All @@ -244,14 +245,14 @@ def cancel(
def delete(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchDeleteResponse:
"""Delete a batch job (only allowed for terminal states: COMPLETED, FAILED, CANCELLED).

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchDeleteResponse` confirming the deletion.
"""
response = self.client.delete(
Expand All @@ -275,7 +276,7 @@ async def acreate(
output_uri: str,
provider: str,
model: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchCreateResponse:
"""Async variant of :meth:`create`.

Expand All @@ -290,7 +291,7 @@ async def acreate(
:param model: Model name (e.g. ``"gpt-4.1-mini"``).
:type model: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchCreateResponse` with the job ID and initial status.
"""
body = BatchCreateRequest(
Expand All @@ -311,12 +312,12 @@ async def acreate(

async def alist(
self,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchListResponse:
"""Async variant of :meth:`list`.

:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchListResponse` containing the batch summaries.
"""
response = await self.async_client.get(
Expand All @@ -331,14 +332,14 @@ async def alist(
async def aget(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchDetailResponse:
"""Async variant of :meth:`get`.

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchDetailResponse` with full job details.
"""
response = await self.async_client.get(
Expand All @@ -353,14 +354,14 @@ async def aget(
async def aget_status(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchStatusResponse:
"""Async variant of :meth:`get_status`.

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchStatusResponse` with current and target status.
"""
response = await self.async_client.get(
Expand All @@ -375,14 +376,14 @@ async def aget_status(
async def acancel(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchCancelResponse:
"""Async variant of :meth:`cancel`.

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchCancelResponse` confirming the cancellation request.
"""
response = await self.async_client.patch(
Expand All @@ -397,14 +398,14 @@ async def acancel(
async def adelete(
self,
batch_id: str,
timeout: Union[int, float, httpx.Timeout, None] = None,
timeout: Union[int, float, httpx2.Timeout, None] = None,
) -> BatchDeleteResponse:
"""Async variant of :meth:`delete`.

:param batch_id: UUID of the batch job.
:type batch_id: str
:param timeout: Per-request timeout override.
:type timeout: Union[int, float, httpx.Timeout], Optional
:type timeout: Union[int, float, httpx2.Timeout], Optional
:returns: :class:`BatchDeleteResponse` confirming the deletion.
"""
response = await self.async_client.delete(
Expand Down
6 changes: 3 additions & 3 deletions packages/gen/gen_ai_hub/orchestration/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import httpx
import httpx2
from typing import Dict, Any


Expand All @@ -12,7 +12,7 @@ class OrchestrationError(Exception):
def __init__(
self,
request_id: str,
http_headers: httpx.Headers,
http_headers: httpx2.Headers,
message: str,
code: int,
location: str,
Expand All @@ -24,7 +24,7 @@ def __init__(
:param request_id: unique identifier for the request
:type request_id: str
:param http_headers: the HTTP headers associated with the error, useful in case of e.g. rate limiting.
:type http_headers: httpx.Headers
:type http_headers: httpx2.Headers
:param message: Detailed error message describing the issue.
:type message: str
:param code: Error code associated with the specific type of failure
Expand Down
Loading
Loading