mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
refactor
This commit is contained in:
@@ -111,6 +111,24 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
"""
|
"""
|
||||||
return cls(default, layout=False, repaint=False, init=True)
|
return cls(default, layout=False, repaint=False, init=True)
|
||||||
|
|
||||||
|
def _initialize_reactive(self, obj: Reactable, name: str) -> None:
|
||||||
|
internal_name = f"_reactive_{name}"
|
||||||
|
if hasattr(obj, internal_name):
|
||||||
|
# Attribute already has a value
|
||||||
|
return
|
||||||
|
if self._is_compute:
|
||||||
|
default = getattr(obj, f"compute_{name}")()
|
||||||
|
else:
|
||||||
|
default_or_callable = self._default
|
||||||
|
default = (
|
||||||
|
default_or_callable()
|
||||||
|
if callable(default_or_callable)
|
||||||
|
else default_or_callable
|
||||||
|
)
|
||||||
|
setattr(obj, internal_name, default)
|
||||||
|
if self._init:
|
||||||
|
self._check_watchers(obj, name, default)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _initialize_object(cls, obj: Reactable) -> None:
|
def _initialize_object(cls, obj: Reactable) -> None:
|
||||||
"""Set defaults and call any watchers / computes for the first time.
|
"""Set defaults and call any watchers / computes for the first time.
|
||||||
@@ -118,24 +136,31 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
Args:
|
Args:
|
||||||
obj (Reactable): An object with Reactive descriptors
|
obj (Reactable): An object with Reactive descriptors
|
||||||
"""
|
"""
|
||||||
return
|
reactives = getattr(obj, "__reactives", {})
|
||||||
if not getattr(obj, "__reactive_initialized", False):
|
for name, reactive in reactives.items():
|
||||||
startswith = str.startswith
|
reactive._initialize_reactive(obj, name)
|
||||||
watchers = []
|
|
||||||
for key in obj.__class__.__dict__:
|
|
||||||
if startswith(key, "_default_"):
|
|
||||||
name = key[9:]
|
|
||||||
internal_name = f"_reactive_{name}"
|
|
||||||
# Check defaults
|
|
||||||
if internal_name not in obj.__dict__:
|
|
||||||
# Attribute has no value yet
|
|
||||||
default = getattr(obj, key)
|
|
||||||
default_value = default() if callable(default) else default
|
|
||||||
# Set the default vale (calls `__set__`)
|
|
||||||
obj.__dict__[internal_name] = default_value
|
|
||||||
watchers.append((name, default_value))
|
|
||||||
|
|
||||||
setattr(obj, "__reactive_initialized", True)
|
# startswith = str.startswith
|
||||||
|
# watchers = []
|
||||||
|
# reactives = getattr(obj, "__reactives", [])
|
||||||
|
|
||||||
|
# print(reactives)
|
||||||
|
# for name in reactives.keys():
|
||||||
|
# internal_name = f"_reactive_{name}"
|
||||||
|
# # Check defaults
|
||||||
|
# if internal_name not in obj.__dict__:
|
||||||
|
# # Attribute has no value yet
|
||||||
|
|
||||||
|
# for k in obj.__dict__:
|
||||||
|
# if k.startswith("_default"):
|
||||||
|
# print(k)
|
||||||
|
|
||||||
|
# default = getattr(obj, f"_default_{name}")
|
||||||
|
# default_value = default() if callable(default) else default
|
||||||
|
# # Set the default vale (calls `__set__`)
|
||||||
|
# obj.__dict__[internal_name] = None
|
||||||
|
# setattr(obj, name, default_value)
|
||||||
|
# # watchers.append((name, default_value))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _reset_object(cls, obj: object) -> None:
|
def _reset_object(cls, obj: object) -> None:
|
||||||
@@ -148,6 +173,9 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
getattr(obj, "__computes", []).clear()
|
getattr(obj, "__computes", []).clear()
|
||||||
|
|
||||||
def __set_name__(self, owner: Type[MessageTarget], name: str) -> None:
|
def __set_name__(self, owner: Type[MessageTarget], name: str) -> None:
|
||||||
|
reactives = getattr(owner, "__reactives", {})
|
||||||
|
reactives[name] = self
|
||||||
|
setattr(owner, "__reactives", reactives)
|
||||||
|
|
||||||
# Check for compute method
|
# Check for compute method
|
||||||
if hasattr(owner, f"compute_{name}"):
|
if hasattr(owner, f"compute_{name}"):
|
||||||
@@ -170,32 +198,38 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
def __get__(self, obj: Reactable, obj_type: type[object]) -> ReactiveType:
|
def __get__(self, obj: Reactable, obj_type: type[object]) -> ReactiveType:
|
||||||
_rich_traceback_omit = True
|
_rich_traceback_omit = True
|
||||||
|
|
||||||
|
self._initialize_reactive(obj, self.name)
|
||||||
|
|
||||||
value: _NotSet | ReactiveType
|
value: _NotSet | ReactiveType
|
||||||
if self._is_compute:
|
if self._is_compute:
|
||||||
value = getattr(obj, f"compute_{self.name}")()
|
value = getattr(obj, f"compute_{self.name}")()
|
||||||
else:
|
else:
|
||||||
value = getattr(obj, self.internal_name, _NOT_SET)
|
value = getattr(obj, self.internal_name, _NOT_SET)
|
||||||
|
|
||||||
if isinstance(value, _NotSet):
|
|
||||||
# No value present, we need to set the default
|
|
||||||
init_name = f"_default_{self.name}"
|
|
||||||
default = getattr(obj, init_name)
|
|
||||||
default_value = default() if callable(default) else default
|
|
||||||
# Set and return the value
|
|
||||||
setattr(obj, self.internal_name, default_value)
|
|
||||||
|
|
||||||
if self._init:
|
|
||||||
print("CHECK WATCHERS")
|
|
||||||
self._check_watchers(obj, self.name, default_value)
|
|
||||||
|
|
||||||
if not self._no_compute:
|
if not self._no_compute:
|
||||||
self._compute(obj)
|
self._compute(obj)
|
||||||
value = getattr(obj, self.internal_name)
|
|
||||||
|
# if isinstance(value, _NotSet):
|
||||||
|
# # No value present, we need to set the default
|
||||||
|
# init_name = f"_default_{self.name}"
|
||||||
|
# default = getattr(obj, init_name)
|
||||||
|
# default_value = default() if callable(default) else default
|
||||||
|
# # Set and return the value
|
||||||
|
# setattr(obj, self.internal_name, default_value)
|
||||||
|
|
||||||
|
# if self._init:
|
||||||
|
# self._check_watchers(obj, self.name, default_value)
|
||||||
|
|
||||||
|
# if not self._no_compute:
|
||||||
|
# self._compute(obj)
|
||||||
|
# value = getattr(obj, self.internal_name)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def __set__(self, obj: Reactable, value: ReactiveType) -> None:
|
def __set__(self, obj: Reactable, value: ReactiveType) -> None:
|
||||||
_rich_traceback_omit = True
|
_rich_traceback_omit = True
|
||||||
# Reactive._initialize_object(obj)
|
# Reactive._initialize_object(obj)
|
||||||
|
|
||||||
|
self._initialize_reactive(obj, self.name)
|
||||||
name = self.name
|
name = self.name
|
||||||
current_value = getattr(obj, name)
|
current_value = getattr(obj, name)
|
||||||
# Check for validate function
|
# Check for validate function
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ async def test_reactive_with_callable_default():
|
|||||||
Textual will call it in order to retrieve the default value."""
|
Textual will call it in order to retrieve the default value."""
|
||||||
called_with_app = None
|
called_with_app = None
|
||||||
|
|
||||||
def set_called(app: App) -> int:
|
def set_called() -> int:
|
||||||
nonlocal called_with_app
|
nonlocal called_with_app
|
||||||
called_with_app = app
|
called_with_app = app
|
||||||
return OLD_VALUE
|
return OLD_VALUE
|
||||||
|
|||||||
Reference in New Issue
Block a user