| | 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: ... |
| |
|