From b869dbd58925b1847591c4bc9b50080f9d19d9ae Mon Sep 17 00:00:00 2001 From: xic Date: Fri, 4 Sep 2026 14:17:20 +0800 Subject: [PATCH] refactor: migrate httpx to httpx2 with dual import Use the actively maintained httpx2 fork (Pydantic Services) when available, falling back to httpx. 11 source files updated; the public API surface (httpx.Client, httpx.AsyncClient, httpx.Response, httpx.HTTPStatusError) behaves identically in both libraries. Tests: 431 passed, 1 failed (test_prompt - pre-existing on stock, reproduced on clean checkout before changes), 18 errors in tests requiring optional deps (langchain) not installed in the dev env. Refs: #1856 --- langfuse/_client/client.py | 5 ++++- langfuse/_client/resource_manager.py | 5 ++++- langfuse/_task_manager/media_manager.py | 5 ++++- langfuse/_utils/request.py | 5 ++++- langfuse/api/client.py | 5 ++++- langfuse/api/core/client_wrapper.py | 5 ++++- langfuse/api/core/http_client.py | 5 ++++- langfuse/api/core/http_response.py | 5 ++++- langfuse/api/core/http_sse/_api.py | 5 ++++- langfuse/api/core/http_sse/_exceptions.py | 5 ++++- langfuse/media.py | 5 ++++- pyproject.toml | 1 + 12 files changed, 45 insertions(+), 11 deletions(-) diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index f8267ea45..7d0ae2908 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -28,7 +28,10 @@ ) import backoff -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from opentelemetry import context as otel_context_api from opentelemetry import trace as otel_trace_api from opentelemetry.sdk.trace import ReadableSpan, TracerProvider diff --git a/langfuse/_client/resource_manager.py b/langfuse/_client/resource_manager.py index a61101fe3..a41ea38f7 100644 --- a/langfuse/_client/resource_manager.py +++ b/langfuse/_client/resource_manager.py @@ -23,7 +23,10 @@ from queue import Full, Queue from typing import Any, Callable, Dict, List, Optional, cast -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from opentelemetry import trace as otel_trace_api from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import ReadableSpan, TracerProvider diff --git a/langfuse/_task_manager/media_manager.py b/langfuse/_task_manager/media_manager.py index 9a66ecd63..340793ed6 100644 --- a/langfuse/_task_manager/media_manager.py +++ b/langfuse/_task_manager/media_manager.py @@ -4,7 +4,10 @@ from typing import Any, Callable, Optional, TypeVar, cast import backoff -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from typing_extensions import ParamSpec from langfuse._client.environment_variables import LANGFUSE_MEDIA_UPLOAD_ENABLED diff --git a/langfuse/_utils/request.py b/langfuse/_utils/request.py index 402d0b5a7..23237cc41 100644 --- a/langfuse/_utils/request.py +++ b/langfuse/_utils/request.py @@ -4,7 +4,10 @@ from base64 import b64encode from typing import Any, List, Union -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from langfuse._utils.serializer import EventSerializer from langfuse.logger import langfuse_logger as logger diff --git a/langfuse/api/client.py b/langfuse/api/client.py index 3781b4fcc..44c793c93 100644 --- a/langfuse/api/client.py +++ b/langfuse/api/client.py @@ -4,7 +4,10 @@ import typing -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper if typing.TYPE_CHECKING: diff --git a/langfuse/api/core/client_wrapper.py b/langfuse/api/core/client_wrapper.py index 22bb6a70b..f99a44a16 100644 --- a/langfuse/api/core/client_wrapper.py +++ b/langfuse/api/core/client_wrapper.py @@ -2,7 +2,10 @@ import typing -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from .http_client import AsyncHttpClient, HttpClient diff --git a/langfuse/api/core/http_client.py b/langfuse/api/core/http_client.py index 3025a49ba..aae8d45f9 100644 --- a/langfuse/api/core/http_client.py +++ b/langfuse/api/core/http_client.py @@ -9,7 +9,10 @@ from contextlib import asynccontextmanager, contextmanager from random import random -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from .file import File, convert_file_dict_to_httpx_tuples from .force_multipart import FORCE_MULTIPART from .jsonable_encoder import jsonable_encoder diff --git a/langfuse/api/core/http_response.py b/langfuse/api/core/http_response.py index 2479747e8..5025dfcf0 100644 --- a/langfuse/api/core/http_response.py +++ b/langfuse/api/core/http_response.py @@ -2,7 +2,10 @@ from typing import Dict, Generic, TypeVar -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx # Generic to represent the underlying type of the data wrapped by the HTTP response. T = TypeVar("T") diff --git a/langfuse/api/core/http_sse/_api.py b/langfuse/api/core/http_sse/_api.py index eb739a22b..9e6605386 100644 --- a/langfuse/api/core/http_sse/_api.py +++ b/langfuse/api/core/http_sse/_api.py @@ -4,7 +4,10 @@ from contextlib import asynccontextmanager, contextmanager from typing import Any, AsyncGenerator, AsyncIterator, Iterator, cast -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from ._decoders import SSEDecoder from ._exceptions import SSEError from ._models import ServerSentEvent diff --git a/langfuse/api/core/http_sse/_exceptions.py b/langfuse/api/core/http_sse/_exceptions.py index 81605a8a6..2b3b052f4 100644 --- a/langfuse/api/core/http_sse/_exceptions.py +++ b/langfuse/api/core/http_sse/_exceptions.py @@ -1,6 +1,9 @@ # This file was auto-generated by Fern from our API Definition. -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx class SSEError(httpx.TransportError): diff --git a/langfuse/media.py b/langfuse/media.py index 6410079ab..b1a16e049 100644 --- a/langfuse/media.py +++ b/langfuse/media.py @@ -8,7 +8,10 @@ from datetime import datetime, timezone from typing import TYPE_CHECKING, Any, Literal, Optional, Tuple, TypeVar, cast -import httpx +try: + import httpx2 as httpx +except ImportError: + import httpx from langfuse.api import MediaContentType from langfuse.logger import langfuse_logger as logger diff --git a/pyproject.toml b/pyproject.toml index 7defd3079..33f569c47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ license-files = ["LICENSE"] requires-python = ">=3.10,<4.0" dependencies = [ "httpx>=0.15.4,<1.0", + "httpx2>=2.12.0; python_version >= \"3.10\"", "pydantic>=2,<3", "backoff>=1.10.0", "wrapt>=1.14,<3",