TUI freezes when calling pop_screen right after a reactive attribute update has occurred
              
              #3215
            
            
          -
| 
         VERSION:  When checking again with version  Our application relies heavily on storing state in reactive stored class/dataclass attributes, where we keep certain data, because we have a lot of things to track (like 20 fields per account where you could have many accounts to observe), which we get from the external API. I just wanted to check if #3194 works for me, and it works, but in the different part of the application, I noticed that when calling pop_screen right after when reactive update happens - the whole app freezes. Unfortunately, I'm unable to provide minimal working example but here are some parts of the code which cause this to happen: We've got: Binding("f2", "add_to_cart", "Add to cart"),and     def action_add_to_cart(self) -> None:
        if self.__add_to_cart():
            self.app.pop_screen()inside the  self.app.world.update_reactive("profile_data")(which when is commented - causes pop screen to succeed, unless we accidentally trigger pop_screen in such a way that it will happen soon after the reactive update of the background worker) 
 class ManualReactive(DOMNode):
    def update_reactive(self, attribute_name: str) -> None:
        """
        Updates the given reactive attribute.
        Reactive attributes of Textual are unable to detect changes to their own attributes
        (if we are dealing with a non-primitive type like a class).
        In order to notify watchers of a reactive attribute, it would have to be re-instantiated with the modified
        attributes. (See https://github.com/Textualize/textual/discussions/1099#discussioncomment-4047932)
        This is where this method comes in handy.
        """
        try:
            attribute = getattr(self, attribute_name)
        except AttributeError as error:
            raise AttributeError(f"{error}. Available ones are: {list(self._reactives)}") from error
        descriptor = self.__class__.__dict__[attribute_name]
        
        # now we trigger the descriptor.__set__ method like the `self.attribute_name = value` would do
        if not descriptor._always_update:
            # that means, watchers won't be notified unless __ne__ returns False, we could bypass with `always_update`
            descriptor._always_update = True
            setattr(self, attribute_name, attribute)
            descriptor._always_update = False
        else:
            # we just need to trigger descriptor.__set__
            setattr(self, attribute_name, attribute)
        logger.debug(f"Manually updated reactive attribute {attribute_name} of {self.__class__.__name__}")In our logs we can observe, that the freeze happens when  What's intresting, the background worker keeps harvesting and processing the data though we got a TUI freezed (we use  In the textual console (  | 
  
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
| 
         Thank you for your issue. Give us a little time to review it. PS. You might want to check the FAQ if you haven't done so already. This is an automated reply, generated by FAQtory  | 
  
Beta Was this translation helpful? Give feedback.
-
| 
         You are doing unconventional things by directly accessing descriptors and private variables. I'd need to know if you can repeat the issue using reactives in the documented way. Regardless, the warnings indicate that callbacks have not completed after 3 seconds. It suggests a watcher or some other deferred callable is still running, or deadlocked waiting for something. Obviously I can't give any concrete suggestions without seeing code.  | 
  
Beta Was this translation helpful? Give feedback.
-
        
 I removed the  
 Instead, used the documented way of  But still, this issue persists. (0.35.1 was fine, observable on 0.36.0)  | 
  
Beta Was this translation helpful? Give feedback.
You are doing unconventional things by directly accessing descriptors and private variables. I'd need to know if you can repeat the issue using reactives in the documented way.
Regardless, the warnings indicate that callbacks have not completed after 3 seconds. It suggests a watcher or some other deferred callable is still running, or deadlocked waiting for something. Obviously I can't give any concrete suggestions without seeing code.