diff --git a/src/anthropic/__init__.py b/src/anthropic/__init__.py index d47dbb93..dd589f66 100644 --- a/src/anthropic/__init__.py +++ b/src/anthropic/__init__.py @@ -11,7 +11,6 @@ Transport, AsyncClient, AsyncStream, - ProxiesTypes, AsyncAnthropic, RequestOptions, ) diff --git a/src/anthropic/_base_client.py b/src/anthropic/_base_client.py index e8a42612..f7d910e4 100644 --- a/src/anthropic/_base_client.py +++ b/src/anthropic/_base_client.py @@ -304,6 +304,8 @@ class BaseClient: max_retries: int timeout: Union[float, Timeout, None] _limits: httpx.Limits + _proxies: ProxiesTypes | None + _transport: Transport | None _strict_response_validation: bool _idempotency_header: str | None @@ -315,6 +317,8 @@ def __init__( max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None = DEFAULT_TIMEOUT, limits: httpx.Limits, + transport: Transport | None, + proxies: ProxiesTypes | None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: @@ -322,6 +326,8 @@ def __init__( self.max_retries = max_retries self.timeout = timeout self._limits = limits + self._proxies = proxies + self._transport = transport self._custom_headers = custom_headers or {} self._custom_query = custom_query or {} self._strict_response_validation = _strict_response_validation @@ -590,6 +596,11 @@ def user_agent(self) -> str: def base_url(self) -> URL: return self._client.base_url + @base_url.setter + def base_url(self, url: URL | str) -> None: + # mypy doesn't use the type from the setter + self._client.base_url = url # type: ignore[assignment] + @lru_cache(maxsize=None) def platform_headers(self) -> Dict[str, str]: return { @@ -689,6 +700,8 @@ def __init__( version=version, limits=limits, timeout=timeout, + proxies=proxies, + transport=transport, max_retries=max_retries, custom_query=custom_query, custom_headers=custom_headers, @@ -1045,6 +1058,8 @@ def __init__( version=version, limits=limits, timeout=timeout, + proxies=proxies, + transport=transport, max_retries=max_retries, custom_query=custom_query, custom_headers=custom_headers, diff --git a/src/anthropic/_utils/__init__.py b/src/anthropic/_utils/__init__.py index b45dc1b1..679193bd 100644 --- a/src/anthropic/_utils/__init__.py +++ b/src/anthropic/_utils/__init__.py @@ -1,3 +1,4 @@ +from ._proxy import LazyProxy as LazyProxy from ._utils import flatten as flatten from ._utils import is_dict as is_dict from ._utils import is_list as is_list diff --git a/src/anthropic/_utils/_proxy.py b/src/anthropic/_utils/_proxy.py new file mode 100644 index 00000000..fd85ebd5 --- /dev/null +++ b/src/anthropic/_utils/_proxy.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Generic, TypeVar, Iterable, cast +from typing_extensions import ClassVar + +T = TypeVar("T") + + +class LazyProxy(Generic[T], ABC): + """Implements data methods to pretend that an instance is another instance. + + This includes forwarding attribute access and othe methods. + """ + + should_cache: ClassVar[bool] = False + + def __init__(self) -> None: + self.__proxied: T | None = None + + def __getattr__(self, attr: str) -> object: + return getattr(self.__get_proxied__(), attr) + + def __repr__(self) -> str: + return repr(self.__get_proxied__()) + + def __str__(self) -> str: + return str(self.__get_proxied__()) + + def __dir__(self) -> Iterable[str]: + return self.__get_proxied__().__dir__() + + @property # type: ignore + def __class__(self) -> type: + return self.__get_proxied__().__class__ + + def __get_proxied__(self) -> T: + if not self.should_cache: + return self.__load__() + + proxied = self.__proxied + if proxied is not None: + return proxied + + self.__proxied = proxied = self.__load__() + return proxied + + def __set_proxied__(self, value: T) -> None: + self.__proxied = value + + def __as_proxied__(self) -> T: + """Helper method that returns the current proxy, typed as the loaded object""" + return cast(T, self) + + @abstractmethod + def __load__(self) -> T: + ...