[PyQt] PyQt5.6 with Python 3.5 Crash

Hans-Peter Jansen hpj at urpla.net
Mon May 22 10:59:04 BST 2017


Hi Rathinam,

On Freitag, 19. Mai 2017 17:21:28 Rathinam Signup wrote:
> 
> class TreeItem(object):
>     def __init__(self, resource_id, name, parent_id, root_id,
> parent=None, type="Folder"):
>         self.resource_id = resource_id
>         self.parent_id = parent_id
>         self.root_id = root_id
>         self.parentItem = parent
>         self.name= name
>         self.nodeType=type
>         self.childItems = []
> 
>         self.populated = None
>         self.hasChildren = True
> 
>         self.checkState = Qt.Checked
> 
>     def insertChild(self, pos, item):
>         self.childItems.insert(pos, item)
> 
>     def appendChild(self, item):
>         self.childItems.append(item)
> 
>     def removeChild(self, item):
>         self.childItems.pop(0)
> 
>     def child(self, row):
>         return self.childItems[row]

This doesn't catch invalid rows..

>     def childCount(self):
>         return len(self.childItems)
> 
>     def data(self, column):
>         try:
>             return self.name
>         except IndexError:
>             return None

while you will never harvest an IndexError here.

Guess, the two methods bodies are mixed up...

>     def parent(self):
>         return self.parentItem
> 
>     def row(self):
>         if self.parentItem:
>             return self.parentItem.childItems.index(self)
>         return 0
> 
> class TreeModel(QAbstractItemModel):
>     inProgress = pyqtSignal(str,str)
>     def __init__(self, parentDialog):
>         super().__init__(parent=None)
>         self.checks = {}
> 
>         self.widget=QWidget()
>         self.parentCls = parentDialog
>         self.rootItem = parentDialog.rootItem
>         self.dbHandle = parentDialog.dbhandle
> 
>     def hasChildren(self,index):
>         return True

Either implement this in a sane way, or not at all.

>     def columnCount(self, parent):
>         return 1
> 
>     def data(self, index, role):
>         try:
>             if not index.isValid():
>                 return None
> 
>             if role == Qt.CheckStateRole:
>                 if index.column() == 0:
>                     if index.internalPointer().resource_id==LOADING_IN_PROGRESS:
>                         return None
>                     else:
>                         return self.getCheckState(index)
> 
>             elif role == Qt.DecorationRole:
>                 if index.internalPointer().resource_id==LOADING_IN_PROGRESS:
>                     return None
>                 else:
>                     return self.widget.style().standardIcon(QStyle.SP_DirIcon)
> 
>             elif role == Qt.DisplayRole:
>                 item = index.internalPointer()
>                 return item.data(index.column())
> 
>             elif role == Qt.UserRole:
>                 uniqueId =
> index.internalPointer().resource_id+index.internalPointer().root_id
>                 return uniqueId
> 
>             else:
>                 return None
>         except Exception as err:
>             traceback.print_exc()

By ignoring the exception, you're making things worse...

>     def getCheckState(self, index):
>         if index.isValid():
>             return index.internalPointer().checkState
> 
>     def setData(self, index, value, role):
>         try:
>             if not index.isValid():
>                 return None

setData return booleans

>             if index.internalPointer().resource_id!=LOADING_IN_PROGRESS
> and (role == Qt.CheckStateRole and index.column() == 0):
>                 #self.checks[index] = value
> 
>                 if (value ==  Qt.Unchecked and not
>                     self.db.can_uncheck(index.internalPointer().resource_id)):
>                     if index.internalPointer().checkState:
> 
> self.inProgress.emit(index.internalPointer().resource_id,index.internalPointer().root_id)
>                     return True
> 
>                 index.internalPointer().checkState = value
> 
>                 if value== Qt.PartiallyChecked:
>                     self.dataChanged.emit(index,index)
>                     return True
> 
>                 for i in range(self.rowCount(index)):
>                     child=self.index(i, 0, index)
>                     if child.internalPointer().resource_id!=LOADING_IN_PROGRESS:
>                         self.setData(child, value, Qt.CheckStateRole)
> 
>                 if value ==  Qt.Unchecked:
>                     parent  =   self.parent(index)
> 
>                     while parent.isValid() and self.data(parent,
> Qt.CheckStateRole) == Qt.Checked:
>                         self.setData(parent, Qt.PartiallyChecked,
> Qt.CheckStateRole)
>                         #parent.setCheckState(column,
> QtCore.Qt.PartiallyChecked)
>                         parent  =   parent.parent()
> 
>                 else:
>                     parent  =   self.parent(index)
>                     while parent.isValid():
> #                        ispartial = not all(self.data(parent,
> QtCore.Qt.CheckStateRole)==value for i in range(self.rowCount(parent))
> if parent.isValid())
>                         ispartial=False
>                         for i in range(self.rowCount(parent)):
>                             child=self.index(i, 0, parent)
>                             if
> child.internalPointer().resource_id!=LOADING_IN_PROGRESS:
>                                 if self.data(child, Qt.CheckStateRole)!=value:
>                                     ispartial=True
>                                     break
> 
>                         newstate =   [value, Qt.PartiallyChecked][ispartial]
>                         #parent.setCheckState(value, newstate)
>                         if self.data(parent, Qt.CheckStateRole)!=newstate:
>                             self.setData(parent, newstate, Qt.CheckStateRole)
>                         parent  =   parent.parent()
> 
>                 self.dataChanged.emit(index,index)
>                 return True
> 
>             return super().setData(index, value, role)
>         except Exception as err:
>             traceback.print_exc()

Hmm, failed to follow your logic here, but the comment from data() applies, 
but why would you want to call the super class here?

>     def flags(self, index):
>         try:
>             flags=super().flags(index) #|QtCore.Qt.ItemIsEnabled |
> QtCore.Qt.ItemIsSelectable
>             if not index.isValid():
>                 return Qt.NoItemFlags
>             if index.internalPointer().resource_id == LOADING_IN_PROGRESS:
>                 return flags & ~Qt.ItemIsUserCheckable & ~Qt.ItemIsEnabled
>             return flags|Qt.ItemIsUserCheckable
>         except Exception as err:
>             traceback.print_exc()

isValid check _after_ calling the super class?

>     def headerData(self, section, orientation, role):
>         return None
> 
>     def index(self, row, column, parent):
>         try:
>             if not self.hasIndex(row, column, parent):
>                 return QModelIndex()
> 
>             if not parent.isValid():
>                 parentItem = self.rootItem
>             else:
>                 parentItem = parent.internalPointer()
> 
>             childItem = parentItem.child(row)
>             if childItem:
>                 return self.createIndex(row, column, childItem)
>             else:
>                 return QModelIndex()
>         except Exception as err:
>             traceback.print_exc()
> 
>     def parent(self, index):
>         try:
>             if not index.isValid():
>                 return QModelIndex()
> 
>             childItem = index.internalPointer()
>             parentItem = childItem.parent()
> 
>             if parentItem == self.rootItem:
>                 return QModelIndex()
> 
>             return self.createIndex(parentItem.row(), 0, parentItem)
>         except Exception as err:
>             traceback.print_exc()
> 
>     def rowCount(self, parent):
>         try:
>             if parent.column() > 0:
>                 return 0
>             if not parent.isValid():
>                 parentItem = self.rootItem
>             else:
>                 parentItem = parent.internalPointer()
>             return parentItem.childCount()
>         except Exception as err:
>             traceback.print_exc()

Apart, from what Florian already said, you contribute to your issues by 
catching and ignoring any exceptions. Given, that you feed your model 
from another thread, you get exactly, what you asked for: disaster..
Better feed your model by emitting data from threads and consuming it 
in the main thread.

The usual strategy applies: extract/reduce the code to the minimum possible.
You will get something, that's testable and shareable, and chances are big,
that you're able to solve your issue in that course.

Good luck,
Pete


More information about the PyQt mailing list