You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi, I have some problem with reactivity. I want to have a reactive data container like dict, dataclass, etc..
But then I can't instantiate it in right time, because it is already forced to be instantiated in the reactive() call.
Which means that all the properties in my dataclass must have default values.
But I don't want that. Because in code which uses these properties in some scenarios I need to have a unnecessary
if/else statement to check if the actual data is already there or not.
This is more or less how it looks in the code:
import random
from dataclasses import dataclass
from textual.app import App, ComposeResult
from textual.reactive import var
from textual.widgets import RichLog
@dataclass(frozen=True)
class DataHolder:
value: int | None = None
values: list[int] | None = None # in a real case could be an empty list, so I can't use that as default value
class FirstApp(App[None]):
content: DataHolder = reactive(DataHolder(), init=False)
@property
def rich_log(self) -> RichLog:
return self.query_one(RichLog)
def on_mount(self) -> None:
self.set_interval(1, self.update_content)
self.watch(self, "content", self.content_has_been_changed, init=False)
def compose(self) -> ComposeResult:
yield RichLog()
def update_content(self):
def randomize() -> int:
return random.randint(1, 100)
self.rich_log.write("Updating content...")
self.content = DataHolder(
value=randomize(),
values=[randomize() for _ in range(3)],
)
def content_has_been_changed(self):
if self.content.value is not None: # But we re sure that it is always not None
self.rich_log.write(f"a: {self.content.value=}")
if self.content.values is not None: # But we re sure that it is not None
self.rich_log.write(f"b: {self.content.values=}")
# So we should be able to use it like this, but typing doesn't know that as it is `| None`
self.rich_log.write(f"c: {self.content.value=}")
self.rich_log.write(f"d: {self.content.values=}")
FirstApp().run()
I hope the example above is clear enough. It is a simple example in which also removing | None should do the job:
value: int = -1
values: list[int] = field(default_factory=list)
but in a more complex case it is not possible and...
I wanted to ask is there a way to have that reactive later evaluated? I mean I don't want to instantiate
the DataHolder class right in the reactive(), but I want to set it later, when my data arrives. Is that possible?
Maybe should be with some syntax that is common in python (e.g. in Typer) I mean ... to mark it like that:
content: DataHolder = reactive(..., init=False)
What I actually tried is a workaround like:
content: DataHolder = reactive(None, init=False)
but this is not a good solution, because it won't throw an error if someone try to access content by accident before
it is set. Neither a good solution is to use | None in the dataclass, because then I need to have a if/else
statement in every place where I use it:
A good analogy is the way how to handle it via @Property:
@dataclass
class SomeDataClass:
_content: DataHolder | None = None
@property
def content(self) -> DataHolder:
if self._content is None:
raise ValueError("Content is not set yet")
return self._content
def is_content_set(self) -> bool:
return self._content is not None
I think same thing should be possible with reactive() as well but we cannot have one reactive depend on another one.
I hope I was clear enough. Thanks in advance for any help.
The text was updated successfully, but these errors were encountered:
Hi, I have some problem with reactivity. I want to have a reactive data container like dict, dataclass, etc..
But then I can't instantiate it in right time, because it is already forced to be instantiated in the reactive() call.
Which means that all the properties in my dataclass must have default values.
But I don't want that. Because in code which uses these properties in some scenarios I need to have a unnecessary
if/else statement to check if the actual data is already there or not.
This is more or less how it looks in the code:
I hope the example above is clear enough. It is a simple example in which also removing | None should do the job:
but in a more complex case it is not possible and...
I wanted to ask is there a way to have that reactive later evaluated? I mean I don't want to instantiate
the DataHolder class right in the reactive(), but I want to set it later, when my data arrives. Is that possible?
Maybe should be with some syntax that is common in python (e.g. in Typer) I mean ... to mark it like that:
content: DataHolder = reactive(..., init=False)
What I actually tried is a workaround like:
content: DataHolder = reactive(None, init=False)
but this is not a good solution, because it won't throw an error if someone try to access content by accident before
it is set. Neither a good solution is to use | None in the dataclass, because then I need to have a if/else
statement in every place where I use it:
content: DataHolder | None = reactive(None, init=False)
A good analogy is the way how to handle it via @Property:
I think same thing should be possible with reactive() as well but we cannot have one reactive depend on another one.
I hope I was clear enough. Thanks in advance for any help.
The text was updated successfully, but these errors were encountered: