diff --git a/src/openai/_utils/_proxy.py b/src/openai/_utils/_proxy.py index aa934a3fbc..3c9e790a25 100644 --- a/src/openai/_utils/_proxy.py +++ b/src/openai/_utils/_proxy.py @@ -18,25 +18,43 @@ class LazyProxy(Generic[T], ABC): def __init__(self) -> None: self.__proxied: T | None = None + # Note: we have to special case proxies that themselves return proxies + # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` + def __getattr__(self, attr: str) -> object: - return getattr(self.__get_proxied__(), attr) + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied # pyright: ignore + return getattr(proxied, attr) @override def __repr__(self) -> str: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ return repr(self.__get_proxied__()) @override def __str__(self) -> str: - return str(self.__get_proxied__()) + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ + return str(proxied) @override def __dir__(self) -> Iterable[str]: - return self.__get_proxied__().__dir__() + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return [] + return proxied.__dir__() @property # type: ignore @override def __class__(self) -> type: - return self.__get_proxied__().__class__ + proxied = self.__get_proxied__() + if issubclass(type(proxied), LazyProxy): + return type(proxied) + return proxied.__class__ def __get_proxied__(self) -> T: if not self.should_cache: diff --git a/src/openai/lib/_old_api.py b/src/openai/lib/_old_api.py index c4038fcfaf..929c87e80b 100644 --- a/src/openai/lib/_old_api.py +++ b/src/openai/lib/_old_api.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from typing_extensions import override from .._utils import LazyProxy @@ -23,13 +23,19 @@ def __init__(self, *, symbol: str) -> None: super().__init__(INSTRUCTIONS.format(symbol=symbol)) -class APIRemovedInV1Proxy(LazyProxy[None]): +class APIRemovedInV1Proxy(LazyProxy[Any]): def __init__(self, *, symbol: str) -> None: super().__init__() self._symbol = symbol @override - def __load__(self) -> None: + def __load__(self) -> Any: + # return the proxy until it is eventually called so that + # we don't break people that are just checking the attributes + # of a module + return self + + def __call__(self, *_args: Any, **_kwargs: Any) -> Any: raise APIRemovedInV1(symbol=self._symbol)