Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty children at instantiation #4015

Closed
PabloLec opened this issue Jan 13, 2024 · 5 comments
Closed

Empty children at instantiation #4015

PabloLec opened this issue Jan 13, 2024 · 5 comments
Labels
question Further information is requested

Comments

@PabloLec
Copy link

PabloLec commented Jan 13, 2024

Hello, I am encountering a problem with version 47.0.
Specifically, in my case, my tests fail because my ListItem has an empty list of children. My ListItem is instantiated as follows:

self.list_item = ListItem(
                Label(str(self.line), markup=False),
                classes=self.css_class,
                id=f"grep-result-{self.inode}",
            )

I think this new behavior was introduced with the changes to LazyMount:
b8fccd4#diff-517d10c1480e3774a450b0a8095a4ac3a214de831f7ec457ab648f487fc46308L359

If I understand correctly, the children of a widget are no longer directly added to the _nodes of the DOMNode at instantiation but are stored in a temporary object. The children are really added on compose, during the call to self.mount_composed_widgets() in widget.py.
In my specific case, this poses a problem for me, as I want to manipulate a child (Label) of my list to truncate its content dynamically before it is displayed.

I can always find another solution to retrieve my Label without going through the children of the parent ListItem, by creating a custom ListItem, for example.
But I wonder if this behavior is intended. I think that in principle, children is a public property, and in my example, one could consider that the Label is a child of its parent from the moment of instantiation. (This is subjective, I admit).
And by the way, I'm wondering if there is another solution other than the children property to retrieve my object that I might not have noticed."

@rodrigogiraoserrao
Copy link
Contributor

Hey Pablo, thanks for opening this issue.
Would you mind providing a minimal reproducible example that mimics the issue you're describing in your context as closely as possible?

You are probably right in all of the conclusions you made but without having some concrete code to look at and run we may end up spending a bunch of time going back and forth without even knowing if we're talking about the same thing.

@rodrigogiraoserrao rodrigogiraoserrao added the question Further information is requested label Jan 18, 2024
@PabloLec
Copy link
Author

@rodrigogiraoserrao Yes, no problem, will do asap 👍

@PabloLec
Copy link
Author

@rodrigogiraoserrao Here is the MRE: https://github.com/PabloLec/textual_4015_mre/blob/main/textual_4015_mre/__init__.py

With test runs showing the behavior difference between versions: https://github.com/PabloLec/textual_4015_mre/actions

So, since version 0.47.0, you can't access an element's children before compose. The children parameter turns up empty.

This is just a basic example, so its practicality might not be obvious at first.
In my situation, for instance, I've got this asynchronous component that's responsible for creating ListItems with a Label, which can be pretty lengthy, without any restrictions during creation. Then, there's another component that adds these ListItems to a list and chops down the Label text depending on the screen size. And all this happens before compose, before the user can see the result.
I'm focusing on the ListItem example because it's what I'm dealing with, but this is actually a behavior that's common to all components with children.

@willmcgugan
Copy link
Collaborator

There are two ways of adding children.

You can do this...

yield ListItem(item)

Or this...

with ListItem():
    yield item

Both should work in the same way, but the second will have children added after compose. Which is why its not a good idea to rely on the children being available in the constructor.

Widgets that haven't been mounted aren't that useful, and may break if you use their methods, so we want to discourage using them until everything is mounted.

It shouldn't be much of an issue in practice. But you will need to write your tests diffrently. I assume you have seen our guide on testing Textual apps ?

Copy link

Don't forget to star the repository!

Follow @textualizeio for Textual updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants