From c7cd08b7e064b1c06b1754e343c671c17875634e Mon Sep 17 00:00:00 2001 From: rus07tam Date: Sun, 23 Nov 2025 10:47:37 +0000 Subject: [PATCH] feat: more safety in BaseBindable, AsyncBindable, Bindable --- src/snakia/core/rx/async_bindable.py | 29 +++++++++++++++++++++++----- src/snakia/core/rx/base_bindable.py | 21 +++++++++++++++++++- src/snakia/core/rx/bindable.py | 3 +++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/snakia/core/rx/async_bindable.py b/src/snakia/core/rx/async_bindable.py index 81d4698..e684e3d 100644 --- a/src/snakia/core/rx/async_bindable.py +++ b/src/snakia/core/rx/async_bindable.py @@ -1,4 +1,12 @@ -from typing import Any, Awaitable, Callable, Generic, Literal, TypeVar, overload +from typing import ( + Any, + Awaitable, + Callable, + Generic, + Literal, + TypeVar, + overload, +) from .base_bindable import BaseBindable, BindableSubscriber, ValueChanged @@ -23,6 +31,9 @@ class AsyncBindable(BaseBindable[T], Generic[T]): async def set(self, value: T) -> None: """Set the value.""" + if not (self.has_default_value or self.has_value): + self.set_silent(value) + return e = ValueChanged(self.value, value) self.set_silent(value) for subscriber in self.__subscribers: @@ -55,19 +66,25 @@ class AsyncBindable(BaseBindable[T], Generic[T]): if run_now: async def _run() -> None: - await subscriber(ValueChanged(self.__default_value, self.value)) + await subscriber( + ValueChanged(self.__default_value, self.value) + ) return _run() return None - def unsubscribe(self, subscriber: BindableSubscriber[T, Awaitable[Any]]) -> None: + def unsubscribe( + self, subscriber: BindableSubscriber[T, Awaitable[Any]] + ) -> None: """Unsubscribe from an value.""" self.__subscribers.remove(subscriber) @overload def on( self, run_now: Literal[True] - ) -> Callable[[BindableSubscriber[T, Awaitable[Any]]], Awaitable[None]]: ... + ) -> Callable[ + [BindableSubscriber[T, Awaitable[Any]]], Awaitable[None] + ]: ... @overload def on( @@ -87,7 +104,9 @@ class AsyncBindable(BaseBindable[T], Generic[T]): if run_now: async def _run() -> None: - await subscriber(ValueChanged(self.__default_value, self.value)) + await subscriber( + ValueChanged(self.__default_value, self.value) + ) return _run() return None diff --git a/src/snakia/core/rx/base_bindable.py b/src/snakia/core/rx/base_bindable.py index 35b3415..b229821 100644 --- a/src/snakia/core/rx/base_bindable.py +++ b/src/snakia/core/rx/base_bindable.py @@ -27,7 +27,26 @@ class BaseBindable(Generic[T]): @property def value(self) -> T: - return self.__value + if self.has_value: + return self.__value + else: + return self.default_value + + @property + def has_value(self) -> bool: + try: + _ = self.__value + return True + except AttributeError: + return False + + @property + def has_default_value(self) -> bool: + try: + _ = self.__default_value + return True + except AttributeError: + return False def set_silent(self, value: T) -> None: self.__value = value diff --git a/src/snakia/core/rx/bindable.py b/src/snakia/core/rx/bindable.py index 161632c..7896463 100644 --- a/src/snakia/core/rx/bindable.py +++ b/src/snakia/core/rx/bindable.py @@ -21,6 +21,9 @@ class Bindable(BaseBindable[T], Generic[T]): def set(self, value: T) -> None: """Set the value.""" + if not (self.has_default_value or self.has_value): + self.set_silent(value) + return e = ValueChanged(self.value, value) self.set_silent(value) for subscriber in self.__subscribers: