Created
January 4, 2025 09:29
-
-
Save FFY00/77e0275793d8445528955924b7771d42 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Transform[T, SetterT=None]: | |
def __init__(self, fn: Callable[[SetterT], T] | None = None, *, default: T = typing.NoDefault) -> None: | |
self._fn = fn | |
self._default = default | |
self._values: dict[object, T] = {} | |
@functools.cached_property | |
def _type(self): | |
if not hasattr(self, '__orig_class__'): | |
raise TypeError('Use Transform[...](...) instead of Transform(...).') | |
return typing.get_args(self.__orig_class__)[0] | |
@functools.cached_property | |
def _optional(self): | |
if typing.get_origin(self._type) == types.UnionType: | |
for typ in typing.get_args(self._type): | |
if typ is types.NoneType: | |
return True | |
return False | |
def __get__[ObjT](self, obj: ObjT, owner: type[ObjT] | None = None) -> T: | |
if self._default is typing.NoDefault: | |
return self._values[obj] | |
else: | |
return self._values.get(obj, self._default) | |
def __set__[ObjT](self, obj: ObjT, value: T | SetterT) -> None: | |
if isinstance(value, self._type): | |
value = typing.cast(T, value) | |
self._values[obj] = value | |
elif self._fn is not None: | |
value = typing.cast(SetterT, value) | |
self._values[obj] = self._fn(value) | |
else: | |
raise TypeError(f'Unable to convert {value!r} to {self._type}') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment