<div dir="ltr"><div>After updating to PyQt5 version 5.5.1 from PyQt5 version 5.4.1 I have strange memory leaks, there are no any leaks on 5.4.1 version. I have custom QAbstractTableModel and custom QTableView in my project with delegates for data types. Here is example code, which has memory leaks in lines 98 and 117 (it can be found using tracemalloc). Memory leak occur when you select cells in table.</div><div>Also there is memory leak in PyQt5 version 5.6.</div><div><br></div><div>#!/usr/bin/python3 </div><div>import tracemalloc </div><div><br></div><div>tracemalloc.start() </div><div><br></div><div>import sys </div><div>from PyQt5.QtCore import * </div><div>from PyQt5.QtGui import * </div><div>from PyQt5.QtWidgets import * </div><div><br></div><div>RW = (Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled) </div><div><br></div><div>my_array = [['00','01','02'], </div><div>            ['10','11','12'], </div><div>            ['20','21','22']] </div><div><br></div><div>class MyWindow(QWidget): </div><div>    def __init__(self, *args): </div><div>        QWidget.__init__(self, *args) </div><div><br></div><div>        tablemodel = MyTableModel(my_array, self) </div><div>        tableview = QTableView() </div><div>        tableview.setModel(tablemodel) </div><div><br></div><div>        self.cdelegates = [] </div><div>        for i in range(3): </div><div>            d = RSpinDelegate(self) </div><div>            self.cdelegates.append(d) </div><div>            tableview.setItemDelegateForColumn(i, d) </div><div><br></div><div>        layout = QVBoxLayout(self) </div><div>        layout.addWidget(tableview) </div><div>        self.setLayout(layout) </div><div>        self.startTimer(5000) </div><div><br></div><div>    def timerEvent(self, e): </div><div>        snapshot = tracemalloc.take_snapshot() </div><div>        top_stats = snapshot.statistics('lineno') </div><div><br></div><div>        print("[ Top 10 ]") </div><div>        for stat in top_stats[:10]: </div><div>            print(stat) </div><div><br></div><div>class RSpinDelegate(QItemDelegate): </div><div>    def __init__(self, parent=None, decimals=0, step=1, range_=(0, 1e9), edit=RW, suffix='', colorfill=None, stepFilter=None): </div><div>        super(RSpinDelegate, self).__init__(parent) </div><div>        self.decimals = decimals </div><div>        self.step = step </div><div>        self.range_ = range_ </div><div>        self.edit = edit </div><div>        self.suffix = suffix </div><div>        self.colorfill = colorfill </div><div>        self.stepFilter = stepFilter </div><div><br></div><div>    def setDecimals(self, decimals): </div><div>        self.decimals = decimals </div><div><br></div><div>    def createEditor(self, parent, option, index): </div><div>        if self.edit == RW: </div><div>            if self.decimals: </div><div>                decimals = self.decimals </div><div>                dec = int(index.model().data(index, RBaseTableModel.DECIMALS_ROLE)) </div><div>                decimals = dec </div><div>                d = 10 ** (-decimals) </div><div>                editor = RDoubleSpinBox(parent) </div><div>                if self.stepFilter != None: </div><div>                    editor.installEventFilter(self.stepFilter) </div><div>                editor.setSingleStep(d) </div><div>                editor.setDecimals(decimals) </div><div>                editor.setRange(self.range_[0], self.range_[1]) </div><div>                editor.setSuffix(self.suffix) </div><div>                self._editor = editor </div><div>                return editor </div><div>            else: </div><div>                editor = RSpinBox(parent) </div><div>                if self.stepFilter != None: </div><div>                    editor.installEventFilter(self.stepFilter) </div><div>                editor.setSingleStep(self.step) </div><div>                editor.setRange(self.range_[0], self.range_[1]) </div><div>                editor.setSuffix(self.suffix) </div><div>                self._editor = editor </div><div>                return editor </div><div>            return None </div><div>        return None </div><div><br></div><div>    def setEditorData(self, editor, index): </div><div>        val = index.model().data(index, Qt.EditRole) </div><div>        try: </div><div>            editor.setValue(float(val.replace(' ', '')) if self.decimals != 0 else int(val.replace(' ', '')))</div><div>        except: </div><div>            editor.setValue(editor.minimum()) </div><div><br></div><div>    def setModelData(self, editor, model, index): </div><div>        model.setData(index, editor.value(), Qt.EditRole) </div><div><br></div><div>    def getBrush(self, option): </div><div>        brush = option.palette.base() </div><div>        if option.state & QStyle.State_Selected:# memory leak is here!</div><div>            if option.state & QStyle.State_Active: </div><div>                brush = option.palette.highlight() </div><div>            else: </div><div>                brush = option.palette.light() </div><div>        return brush </div><div><br></div><div>    def updateEditorGeometry(self, editor, option, index): </div><div>        editor.setGeometry(option.rect) </div><div><br></div><div>    def paint(self, painter, option, index): </div><div>        opt = QStyleOptionViewItem(option) </div><div>        if self.colorfill: </div><div>            brush = self.colorfill(index.model().data(index, RBaseTableModel.INDEX_ROLE), option) </div><div>            if not(option.state & QStyle.State_Selected): </div><div>                painter.fillRect(option.rect, brush) </div><div>            opt.palette.setBrush(QPalette.Highlight, brush) </div><div>        else: </div><div>            brush = self.getBrush(option) </div><div>            painter.fillRect(option.rect, brush)# memory leak is here!</div><div>        super(RSpinDelegate, self).paint(painter, opt, index) </div><div><br></div><div># création du modèle </div><div>class MyTableModel(QAbstractTableModel): </div><div>    refreshTable = pyqtSignal() </div><div><br></div><div>    def __init__(self, datain, parent = None, *args): </div><div>        QAbstractTableModel.__init__(self, parent, *args) </div><div>        self.arraydata = datain </div><div>        self.timer = self.startTimer(300) </div><div><br></div><div>    def timerEvent(self, e): </div><div>        if self.timer == e.timerId(): </div><div>            self.refreshTable.emit() </div><div>        else: </div><div>            super(RBaseTableView, self).timerEvent(e) </div><div><br></div><div>    def refreshTableSlot(self): </div><div>        self.layoutAboutToBeChanged.emit() </div><div>        self.layoutChanged.emit() </div><div><br></div><div>    def rowCount(self, parent): </div><div>        return len(self.arraydata) </div><div><br></div><div>    def columnCount(self, parent): </div><div>        return len(self.arraydata[0]) </div><div><br></div><div>    def data(self, index, role): </div><div>        if not index.isValid(): </div><div>            return None </div><div>        elif role != Qt.DisplayRole: </div><div>            return None </div><div>        return (self.arraydata[index.row()][index.column()]) </div><div><br></div><div>if __name__ == "__main__": </div><div>    app = QApplication(sys.argv) </div><div>    w = MyWindow() </div><div>    w.show() </div><div>    sys.exit(app.exec_())</div><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div>Faithfully yours, Roman I. Liverovskiy</div></div></div>
</div>