| 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. |
| """ |
|
|
| |
| |
|
|
| def __getattr__(self, attr: str) -> object: |
| proxied = self.__get_proxied__() |
| if isinstance(proxied, LazyProxy): |
| return proxied |
| 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 |
| @override |
| def __class__(self) -> type: |
| 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: ... |
|
|