Open kitchoi opened 5 years ago
Does it go away when you apply the temporary fixes suggested in #680 and #403?
It does not go away unfortunately.
I tried the workaround in #677 (which works around #403) and I also tried to use auto_set=False
(which works around #680).
auto_set=False
doesn't remove the issue of recreating the UI components, it just makes it so you don't notice it as much. Try the fix of patching Traits trait_notifier.py
to give it a _type_changed
handler as described here https://github.com/enthought/traits/issues/537
auto_set=False doesn't remove the issue of recreating the UI components, it just makes it so you don't notice it as much.
Yep, agreed.
Try the fix of patching Traits trait_notifier.py to give it a _type_changed handler as described here enthought/traits#537
Yes I can try that.
Try the fix of patching Traits trait_notifier.py to give it a _type_changed handler as described here enthought/traits#537 Yes I can try that.
I tried to add the block of code to traits.traits_listener.ListenerItem._type_changed
as described in enthought/traits#537
I have not yet seen an abnormal exit.
Unfortunately because the behaviour is somewhat random, it is difficult to be 100% certain.
The hypothesis, particularly given that crash is associated with a QLineEdit
is that there is some sort of race between a keystroke being processed and the re-building of the UI panel caused by #680 so that Qt is trying to deliver to a widget that has been disposed of.
However there is perhaps a deeper issue at work here. Looking at the way that editors are cleaned up, it seems like the dispose
method of an editor should attempt to ensure that any Qt signals/slots that are connected should be disconnected during the dispose
of the Editor
class. In the particular case of the TextEditor
which uses the QLineEdit
I am guessing that we can get into a state where:
dispose
d and so we can no longer access self.ui
and other important traits for the editor's operation, but the editor instance still exists.update_object
would be the prime candidate here, particularly given https://github.com/enthought/traitsui/blob/master/traitsui/qt4/text_editor.py#L76-L85)dispose
is called, deleteLater
is also called on the QLineEdit
, but deleteLater
schedules deletion via the event queue.QLineEvent
is still happily alive at that point, even though the editor instance is in a non-functional state) and the method bound the the signal/slot gets called.To completely fix, we need to:
dispose
disconnects signals and slots (Do Not Call Up That Which You Cannot Put Down!)update_object
) so that they don't try to do anything if called in a non-functional state (ie. something like if self.ui is None: return
at the start of these functions)I expect that we have this sort of stuff all through the codebase. :(
I tried the following patch:
Unfortunately this does not fix the issue (unassigning myself for now).
Using the same example in #680:
Code to reproduce
``` from traits.api import HasTraits, Float, List, Instance from traitsui.api import ModelView, View, Item class Child(HasTraits): play_list = List(Float(), [1, 2, 3, 4]) class Model(HasTraits): child = Instance(Child, ()) class ListEditorDemo(ModelView): # The Trait to be displayed in the editor model = Instance(Model) def default_traits_view(self): return View( Item('model.child.play_list', label='Simple'), title='ListEditor', height=400, width=400, ) popup = ListEditorDemo(model=Model()) if __name__ == '__main__': popup.configure_traits() ```If the user enters some invalid values, and then corrects them, Python exits abnormally. This has been observed on Windows and OSX, using PyQt 5.7.1 (with Qt 5.6.2).
Just before Python exits, one gets the following traceback:
I saw this traceback for both PyQt4 and PyQt5. However the difference is that with PyQt4, Python does NOT exit abnormally. With PyQt5, it does.
The behaviour is somewhat random and difficult to reproduce. Sometimes Python exits abnormally when the state switches from invalid to valid the first time, sometimes it exits only after a few attempts going between invalid and valid states.
Here is the dump from Python:
``` Process: Python [13254] Path: /Users/USER/*/Python.app/Contents/MacOS/Python Identifier: org.python.python Version: 3.6.5 (3.6.5) Code Type: X86-64 (Native) Parent Process: edm [13247] Responsible: Python [13254] User ID: 501 Date/Time: 2019-11-07 14:48:39.976 +0000 OS Version: Mac OS X 10.14.6 (18G103) Report Version: 12 Anonymous UUID: 967113EC-05FF-86C3-F919-0E445A5F87B9 Sleep/Wake UUID: 2D1FCE4B-420E-4B5A-A316-1BA65AEDB17F Time Awake Since Boot: 17000 seconds Time Since Wake: 5800 seconds System Integrity Protection: enabled Crashed Thread: 0 Dispatch queue: com.apple.main-thread Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Application Specific Information: abort() called Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 libsystem_kernel.dylib 0x00007fff57b1b2c6 __pthread_kill + 10 1 libsystem_pthread.dylib 0x00007fff57bd6bf1 pthread_kill + 284 2 libsystem_c.dylib 0x00007fff57a856a6 abort + 127 3 org.qt-project.QtCore 0x00000001214afb79 qt_message_fatal(QtMsgType, QMessageLogContext const&, QString const&) + 9 4 org.qt-project.QtCore 0x00000001214b1589 QMessageLogger::fatal(char const*, ...) const + 233 5 QtCore.so 0x00000001211d8409 pyqt5_err_print() + 1593 (qpycore_public_api.cpp:200) 6 QtCore.so 0x00000001211e17ad PyQtSlotProxy::unislot(void**) + 189 (qpycore_pyqtslotproxy.cpp:204) 7 QtCore.so 0x00000001211e16c9 PyQtSlotProxy::qt_metacall(QMetaObject::Call, int, void**) + 137 (qpycore_pyqtslotproxy.cpp:163) 8 org.qt-project.QtCore 0x00000001216b7682 QMetaObject::activate(QObject*, int, int, void**) + 2450 9 org.qt-project.QtWidgets 0x0000000127954d28 QLineEdit::textEdited(QString const&) + 56 10 org.qt-project.QtWidgets 0x000000012794be12 QLineEditPrivate::_q_textEdited(QString const&) + 18 11 org.qt-project.QtCore 0x00000001216b78a0 QMetaObject::activate(QObject*, int, int, void**) + 2992 12 org.qt-project.QtWidgets 0x00000001279e737c QWidgetLineControl::finishChange(int, bool, bool) + 572 13 org.qt-project.QtWidgets 0x00000001279ecb75 QWidgetLineControl::processKeyEvent(QKeyEvent*) + 4549 14 org.qt-project.QtWidgets 0x00000001279513e2 QLineEdit::keyPressEvent(QKeyEvent*) + 34 15 QtWidgets.so 0x0000000127131646 sipQLineEdit::keyPressEvent(QKeyEvent*) + 134 (sipQtWidgetsQLineEdit.cpp:681) 16 org.qt-project.QtWidgets 0x000000012784a8b6 QWidget::event(QEvent*) + 4854 17 org.qt-project.QtWidgets 0x0000000127950783 QLineEdit::event(QEvent*) + 611 18 QtWidgets.so 0x0000000127130c16 sipQLineEdit::event(QEvent*) + 134 (sipQtWidgetsQLineEdit.cpp:466) 19 org.qt-project.QtWidgets 0x0000000127808496 QApplicationPrivate::notify_helper(QObject*, QEvent*) + 294 20 org.qt-project.QtWidgets 0x0000000127809afd QApplication::notify(QObject*, QEvent*) + 749 21 QtWidgets.so 0x0000000126fcd15b sipQApplication::notify(QObject*, QEvent*) + 139 (sipQtWidgetsQApplication.cpp:224) 22 org.qt-project.QtCore 0x0000000121683324 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 164 23 org.qt-project.QtWidgets 0x000000012786a581 QWidgetWindow::event(QEvent*) + 321 24 org.qt-project.QtWidgets 0x0000000127808496 QApplicationPrivate::notify_helper(QObject*, QEvent*) + 294 25 org.qt-project.QtWidgets 0x00000001278099c9 QApplication::notify(QObject*, QEvent*) + 441 26 QtWidgets.so 0x0000000126fcd15b sipQApplication::notify(QObject*, QEvent*) + 139 (sipQtWidgetsQApplication.cpp:224) 27 org.qt-project.QtCore 0x0000000121683324 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 164 28 org.qt-project.QtGui 0x000000012380c05e QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyEvent*) + 174 29 org.qt-project.QtGui 0x00000001237f41db QWindowSystemInterface::sendWindowSystemEvents(QFlagsMaybe related to #680 and/or #403