Recursion while using QTreeWidgetItem.__lt__
-
Hi,
I want to provide a custom sort order for QTreeWidgetItems withing the QTreeWidget.
According to documentation, I can use the lt method: https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QListWidgetItem.html#PySide2.QtWidgets.PySide2.QtWidgets.QListWidgetItem.lt
However, in practice, this gets a bit more complicated than this:
Here is my code :
class RepoBranchInfoTreeItem(QTreeWidgetItem): def __lt__(self, other: 'QTreeWidgetItem') -> bool: col = self.treeWidget().sortColumn() if col != 1: # regular sorting return bool( QTreeWidgetItem.__lt__(self, other) ) colTextSelf = self.text(col) colTextOther = other.text(col) if len(colTextSelf) and len(colTextOther) and colTextSelf[0].isdigit() and colTextOther[0].isdigit(): # natural number sorting if we can return extractInt(colTextSelf) < extractInt(colTextOther) # regular sort strategy will compare strings and place all number starting strings before others return bool( super().__lt__(other) )
It's pretty simple, the idea is to use a natural sort order on column 1, if column 1 content is only made of digits.
The issue I have is the following :
Traceback (most recent call last): File "C:\work\Multigit\Dev\src\mg_dialog_git_switch_delete_branch.py", line 111, in __lt__ def __lt__(self, other: 'QTreeWidgetItem') -> bool: RecursionError: maximum recursion depth exceeded while calling a Python object
It seems that eventhough I call super().lt(self, other) or QTreeWidgetitem.lt(self, other), instead of calling the lt of QTreeWidgetItem , I end up calling my own method.
So, virtual method override seems to be broken, I can no longer call the parent method. Or rather, i call it but it eventually calls my own implementation.
Does anybody knows a way around this ?
By the way, it works in PyQt5
-
@Bluebird75
I would use either one ofQTreeWidgetItem.__lt__(self, other)
orsuper().__lt__(other)
, not both mixed. Maybe to rule outsuper()
justQTreeWidgetItem.__lt__(self, other)
.If what you say is so, surely you can remove most of your code and try one or other of:
def __lt__(self, other: 'QTreeWidgetItem') -> bool: return bool( QTreeWidgetItem.__lt__(self, other) ) # or next line # return bool( super().__lt__(other) )
and reproduce the problem.
By the way, it works in PyQt5
If code works in PyQt5 but not in PySide2 you can report it as a bug.
-
I tried to use either
super().__lt__
orQTreeWidgetItem.__lt__
with equivalent results. I suppose it is something due to the virtual overloading machineray that always picks up the python method in every case.I got around it by simply not relying on the
QTreeWidgetItem.__lt__
at all. I just do a regular string comparison and it works fine.Final code looks like :
class RepoBranchInfoTreeItem(QTreeWidgetItem): def __lt__(self, other: 'QTreeWidgetItem') -> bool: col = self.treeWidget().sortColumn() if col != 1: # regular sorting return istrcmp(self.text(col), other.text(col)) colTextSelf = self.text(col) colTextOther = other.text(col) if len(colTextSelf) and len(colTextOther) and colTextSelf[0].isdigit() and colTextOther[0].isdigit(): # natural number sorting if we can return extractInt(colTextSelf) < extractInt(colTextOther) # regular sort strategy will compare strings and place all number starting strings before others return istrcmp(self.text(col), other.text(col)) def istrcmp(s1: str, s2: str) -> bool: '''Case-insensitive string compare''' return s1.lower() < s2.lower() ```
-
See PYSIDE-1951