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

Unpredictable sorting of integers with QSortFilterProxyModel

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P3: Somewhat important
    • None
    • 6.2.0, 6.3.2
    • PySide
    • None
    • Linux
      Python 3.10
      PySide6 6.3.2
      PySide6 6.3.1
      PySide6 6.2.0
    • Linux/X11

    Description

      I've been using a table model with a sort/filter model in PySide6 and ran into a problem where integers are sorted incorrectly, and somewhat unpredictably.

      It looks like the sorting problem occurs on the C++ side, in the following function:

      ...
      bool QAbstractItemModelPrivate::isVariantLessThan(const QVariant &left, const QVariant &right,
      ...
          switch (left.userType()) {
          case QMetaType::Int:
              return left.toInt() < right.toInt();
          case QMetaType::UInt:
              return left.toUInt() < right.toUInt();
          case QMetaType::LongLong:
              return left.toLongLong() < right.toLongLong();
          case QMetaType::ULongLong:
              return left.toULongLong() < right.toULongLong();
      ...

      Adding some print debugging to the Python side, it first looked like an obvious case of everything being compared as signed 32-bit integers:

       left: 690636980    0x292a48b4   c_int(690636980)  c_long(690636980)
      right: 2885968800    0xac0463a0   c_int(-1408998496)  c_long(2885968800)
      l < r: False
      
      left: 15471165    0xec123d   c_int(15471165)  c_long(15471165)
      right: 2346638763    0x8bdeddab   c_int(-1948328533)  c_long(2346638763)
      l < r: False
      

      However, as I mentioned the sorting being unpredictable, other values seemed to be compared correctly:

       left: 2754875217    0xa4340f51   c_int(-1540092079)  c_long(2754875217)
      right: 1983291963    0x7636a23b   c_int(1983291963)  c_long(1983291963)
      l < r: False
      
      left: 2346638763    0x8bdeddab   c_int(-1948328533)  c_long(2346638763)
      right: 11220746    0xab370a   c_int(11220746)  c_long(11220746)
      l < r: False
      

      Looking back at the C++ code, I realized the switch only checks "left.userType()", so the issue seems to be that when the left value is small enough to fit into a signed 32-bit integer, the larger value accidentally gets converted to one as well.

      I haven't used Qt in C++ and don't know how QVariants behave there, but I'm guessing you'll be more aware of your integer types and there's no implicit conversion like this, so I'm reporting this as a PySide/Shiboken bug.

      I've attached a small example which should demonstrate the issue in a table view. I commented out the print statements (lines 44-53) since the output is somewhat verbose, but they're there just in case.

      I originally spotted the issue with PySide 6.3.1 and confirmed it with 6.3.2. I also downgraded to 6.2.0 and the same thing occurs, so it doesn't seem to be a recent regression.

      I realize there's an easy workaround by just doing your own sorting in lessThan() and avoiding the C++ calls altogether, but it feels like a "gotcha" for integers which aren't anywhere near breaking 64-bit limits.

       

      Attachments

        1. main.py
          2 kB
        2. pyside2066.py
          3 kB
        3. screenshot_cpp.png
          screenshot_cpp.png
          9 kB
        4. screenshot_pyside.png
          screenshot_pyside.png
          10 kB

        Issue Links

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

          Activity

            People

              crmaurei Cristian Maureira-Fredes
              gpw2323 Tony Korhonen
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes