Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-1695

QModelIndex.data() seems to copy data between invocation

    XMLWordPrintable

Details

    • Bug
    • Resolution: Invalid
    • Not Evaluated
    • None
    • 5.15.2, 6.2.0
    • PySide
    • None
    • Reproduced on:
      - Python 3.9.6 + PySide 5.15.2
      - Python 3.9.6 + PySide 6.2.0
    • Linux/X11

    Description

      I'm unsure if this is a bug, but here goes:

      I have a QtCore.QAbstractListModel subclass. In the data method, I return a QtGui.QIcon instance from a cache (to make things simpler in the example below, I use the global namespace as a cache). I expect that this instance should be returned on every call to data() made with the same index + role (again for this example I just always return it regardless of Index or role because KISS). As you can see from the result below, the icon inside the data method is the global icon but what's being returned from data() is a new Icon every time (I store the result in a list so the memory address of the previous result doesn't get gc'd and re-used, which python has a tendency to do, as this would mask the problem).

      from PySide6 import QtCore, QtGui
      
      
      icon = QtGui.QIcon.fromTheme('folder')
      print('global', icon)
      
      
      class MyModel(QtCore.QAbstractListModel):
          def rowCount(self, parent=QtCore.QModelIndex()) -> int:
              return 1
      
          def data(self, index, role=QtCore.Qt.DecorationRole):
              print('inside_data', icon)
              return icon
      
      
      if __name__ == '__main__':
          model = MyModel()
          idx = model.index(0, 0)
          icons = [idx.data(role=QtCore.Qt.DecorationRole) for _ in range(5)]
      
          for ico in icons:
              print('result of index.data()', ico)
      

      This outputs:

       global <PySide6.QtGui.QIcon(null) at 0x7f0c680710c0>
       inside_data <PySide6.QtGui.QIcon(null) at 0x7f0c680710c0>
       inside_data <PySide6.QtGui.QIcon(null) at 0x7f0c680710c0>
       inside_data <PySide6.QtGui.QIcon(null) at 0x7f0c680710c0>
       inside_data <PySide6.QtGui.QIcon(null) at 0x7f0c680710c0>
       inside_data <PySide6.QtGui.QIcon(null) at 0x7f0c680710c0>
       result of index.data() <PySide6.QtGui.QIcon(null) at 0x7f0c66355500>
       result of index.data() <PySide6.QtGui.QIcon(null) at 0x7f0c66355540>
       result of index.data() <PySide6.QtGui.QIcon(null) at 0x7f0c663555c0>
       result of index.data() <PySide6.QtGui.QIcon(null) at 0x7f0c66355640>
       result of index.data() <PySide6.QtGui.QIcon(null) at 0x7f0c663556c0>
      

      As you can see each returned value from index.data() occupies a different address in memory. I would expect it to be the same object as the one logged inside data() and at the module level.

      This actually led to a memory leak that caused my machine to crash as my delegate was doing some caching using the functools.cache decorator (which doesn't let you choose a cache_key, it automatically uses object._hash_ which default to a unique id per object). One of the element used for caching was the icon returned by data. That means I was filling a cache but never using it (and since the icon was cached, its memory space was also never re-used so: crash)

       

      Is this normal behavior?

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            crmaurei Cristian Maureira-Fredes
            thomas701 Thomas Mc Kay
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes