enthought / traitsui

TraitsUI: Traits-capable windowing framework
http://docs.enthought.com/traitsui
Other
297 stars 95 forks source link

Expanding tree nodes in qt tree editor causes attribute error #673

Closed notmatthancock closed 3 years ago

notmatthancock commented 5 years ago

When attempting to call expandAll on the Qt tree editor widget, the minimal example below fails with traceback:

Traceback (most recent call last):
  File ".../lib/python3.6/site-packages/traitsui/qt4/tree_editor.py", line 1974, in paint
    expanded, node, instance = self.editor._get_node_data(item)
  File ".../lib/python3.6/site-packages/traitsui/qt4/tree_editor.py", line 893, in _get_node_data
    return nid._py_data
AttributeError: 'QTreeWidgetItem' object has no attribute '_py_data'
from traits.api import *
from traitsui.api import *

class Cheese(HasTraits):
    name = Str

class Taco(HasTraits):
    name = Str
    cheeses = List(Cheese)

class Meal(HasTraits):
    tacos = List(Taco)

    def _tacos_default(self):
        return [
            Taco(name='crunchy',
                 cheeses=[Cheese(name='cheddar'), Cheese(name='cotija')]),
            Taco(name='greasy',
                 cheeses=[Cheese(name='parmesan'), Cheese(name='colby')]),
            Taco(name='grumpy',
                 cheeses=[Cheese(name='fresco')]),
        ]

class MenuHandler(Handler):
    def object_expand_all_changed(self, info):
        editor = info.ui.get_editors('meal')[0]
        editor._tree.expandAll()

class Menu(HasTraits):
    meal = Instance(Meal, ())
    expand_all = Button

    traits_view = View(
        UItem(
            'meal',
            editor=TreeEditor(
                editable=False,
                nodes=[
                    TreeNode(
                        node_for=[Meal],
                        label='=Meal',
                        children='tacos',
                        auto_open=False,
                    ),
                    TreeNode(
                        node_for=[Taco],
                        label='name',
                        children='cheeses',
                    ),
                    TreeNode(
                        node_for=[Cheese],
                        label='name',
                    ),
                ]
            ),
        ),
        UItem('expand_all'),
        handler=MenuHandler(),
    )

if __name__ == '__main__':
    Menu().configure_traits()
corranwebster commented 5 years ago

Qt4 or Qt5? There've been a few issues around the nid objects with Qt5, IIRC.

That said stepping down to the Qt level from TraitsUI always carries risks. The best solution to this may be to add an "expand all" API call to the TraitsUI editor - the use case is not entirely unreasonable (although dangerous if the tree is large...)

notmatthancock commented 5 years ago

Qt4 or Qt5? There've been a few issues around the nid objects with Qt5, IIRC.

Qt4 gives the traceback above. Qt5 apparently segfaults.

rahulporuri commented 3 years ago

so the original issue doesn't exist anymore but clicking on "Expand All" a second time raises the following issue, which promptly crashes the app -

Traceback (most recent call last):
  File "C:\Users\rporuri\work\github\ets\traitsui\traitsui\qt4\tree_editor.py", line 837, in _on_item_expanded
    self._expand_node(nid)
  File "C:\Users\rporuri\work\github\ets\traitsui\traitsui\qt4\tree_editor.py", line 480, in _expand_node
    for child in node.get_children(object):
TypeError: 'NoneType' object is not iterable
aaronayres35 commented 3 years ago

Potentially relevant from the Qt docs: "Note: This signal will not be emitted if an item changes its state when expandAll() is invoked." https://doc.qt.io/qt-5/qtreewidget.html#itemExpanded

Perhaps this is causing expanded to be False here: https://github.com/enthought/traitsui/blob/82f8ef426813255496798720f708065da1b955af/traitsui/qt4/tree_editor.py#L473

where expanded comes from: https://github.com/enthought/traitsui/blob/82f8ef426813255496798720f708065da1b955af/traitsui/qt4/tree_editor.py#L783-L785

This further supports this idea: https://github.com/enthought/traitsui/blob/82f8ef426813255496798720f708065da1b955af/traitsui/qt4/tree_editor.py#L1535

EDIT: So I tried updating the if not expanded: line above to be if not expanded and not nid.isExpanded(): as I noticed on the second time we clicked "expand all" expanded was still coming up as False, but nid.isExpanded() was True on individual nodes. Making this change, I now see the original traceback of

Traceback (most recent call last):
  File "/Users/aayres/Desktop/traitsui/traitsui/qt4/tree_editor.py", line 830, in _on_item_expanded
    expanded, node, object = self._get_node_data(nid)
  File "/Users/aayres/Desktop/traitsui/traitsui/qt4/tree_editor.py", line 791, in _get_node_data
    return nid._py_data
AttributeError: 'QTreeWidgetItem' object has no attribute '_py_data'
Abort trap: 6