| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- from __future__ import annotations
- from abc import ABC, abstractmethod
- from typing import Generic, TypeVar, Iterable, cast
- from typing_extensions import override
- 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 other methods.
- """
- # 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:
- 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:
- proxied = self.__get_proxied__()
- if isinstance(proxied, LazyProxy):
- return proxied.__class__.__name__
- return str(proxied)
- @override
- def __dir__(self) -> Iterable[str]:
- proxied = self.__get_proxied__()
- if isinstance(proxied, LazyProxy):
- return []
- return proxied.__dir__()
- @property # type: ignore
- @override
- def __class__(self) -> type: # pyright: ignore
- try:
- proxied = self.__get_proxied__()
- except Exception:
- return type(self)
- if issubclass(type(proxied), LazyProxy):
- return type(proxied)
- return proxied.__class__
- def __get_proxied__(self) -> T:
- return self.__load__()
- 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: ...
|