[neon/forks/pyqt6/Neon/release] /: New upstream version 6.10.1

Dmitry Shachnev null at kde.org
Mon Jul 27 14:39:11 BST 2026


Git commit 0380835252971314da716d700e028abb8668c268 by Dmitry Shachnev.
Committed on 09/12/2025 at 12:44.
Pushed by carlosdem into branch 'Neon/release'.

New upstream version 6.10.1

M  +53   -0    ChangeLog
M  +7    -0    NEWS
M  +1    -1    PKG-INFO
A  +114  -0    examples/itemmodels/rangemodel.py
M  +0    -3    lupdate/python_source.py
M  +1    -1    pyproject.toml
M  +1    -0    qpy/QtCore/qpycore_post_init.cpp
M  +25   -0    qpy/QtCore/qpycore_pyqtpyobject.cpp
M  +1    -0    qpy/QtCore/qpycore_pyqtpyobject.h
A  +345  -0    qpy/QtCore/qpycore_qrangemodel.cpp     [License: GPL (v3)]
A  +128  -0    qpy/QtCore/qpycore_qrangemodel.h     [License: GPL (v3)]
M  +3    -2    sip/QtCore/QtCoremod.sip
M  +45   -25   sip/QtCore/qobject.sip
C  +47   -3    sip/QtCore/qpycore_qrangemodel.sip [from: sip/QtCore/qrangemodel.sip - 050% similarity]
M  +76   -0    sip/QtCore/qrangemodel.sip
M  +1    -1    sip/QtWidgets/qlineedit.sip
M  +3    -3    sip/QtWidgets/qplaintextedit.sip
M  +1    -1    sip/QtWidgets/qscrollbar.sip
M  +3    -3    sip/QtWidgets/qtextedit.sip

https://invent.kde.org/neon/forks/pyqt6/-/commit/0380835252971314da716d700e028abb8668c268

diff --git a/ChangeLog b/ChangeLog
index 13ecad9..c27ea16 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,56 @@
+commit d72db36074a3453ef6a5a5746082230b2afe4913
+Author: Phil Thompson <phil at riverbankcomputing.com>
+Date:   Fri Dec 5 14:37:07 2025 +0000
+
+    Release v6.10.1
+
+commit 48796838b960e1c9a7f2c66afa810034f2795a06
+Author: Phil Thompson <phil at riverbankcomputing.com>
+Date:   Thu Nov 27 21:58:59 2025 +0000
+
+    Bug fixes
+    
+    - Fixed ownership issues with the result of calls to
+      `createStandardContextMenu()` and `createMimeDataFromSelection()`.
+
+commit 6531d8a843928be180d317708ed759525e665082
+Author: Phil Thompson <phil at riverbankcomputing.com>
+Date:   Mon Nov 10 19:12:44 2025 +0000
+
+    Support for `QRangeModel`
+    
+    The support for `QRangeModel` was refactored to replace `QPyRange` with
+    `QPyAbstractRange`, `QPySequenceRange` and `QPyTableRange`.
+
+commit 3a6f12e54c4f85954cc727fee632b770915a5992
+Author: Phil Thompson <phil at riverbankcomputing.com>
+Date:   Mon Nov 10 10:50:42 2025 +0000
+
+    Development regressions
+    
+    - Fixed the support for QRangeModel for Python v3.9.
+
+commit 45477b08afa039072abf38b9e6832153bcd7e5d5
+Author: Phil Thompson <phil at riverbankcomputing.com>
+Date:   Sun Nov 9 15:39:50 2025 +0000
+
+    Support for `QRangeModel`
+    
+    Support was added for `QRangeModel` (added in Qt v6.10).  This allows a
+    range of Python objects to be edited in-situ using an appropriate Qt view.
+    Currently a range may be a sequence of Python objects or a table (ie. a
+    sequence of sequences).  Support for trees is planned to be added in a
+    later release.  Ranges are wrapped using the `QPyRange` class which is then
+    passed to `QRangeModel`.
+
+commit bcfacbbd491136b2a4a22c52646a36886d89f774
+Author: Phil Thompson <phil at riverbankcomputing.com>
+Date:   Sat Nov 1 12:15:08 2025 +0000
+
+    Bug fixes
+    
+    - Fixed a regression in `pylupdate6` when using Python v3.14.
+
 commit ecab96d9ca996c2496594c3a06d4cea1de93f395
 Author: Phil Thompson <phil at riverbankcomputing.com>
 Date:   Thu Oct 16 10:55:25 2025 +0100
diff --git a/NEWS b/NEWS
index b6df794..ea9d588 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+v6.10.1 5th December 2025
+  - Added support for `QRangeModel` (and related `QPyAbstractRange`,
+    `QPySequenceRange` and `QPyTableRange`).
+  - Fixed a regression in `pylupdate6` when using Python v3.14.
+  - Fixed ownership issues with the result of calls to
+    `createStandardContextMenu()` and `createMimeDataFromSelection()`.
+
 v6.10.0 16th October 2025
   - Added support for Qt v6.10 (excluding QRangeModel).
   - Added support for QGuiApplication.nativeInterface().
diff --git a/PKG-INFO b/PKG-INFO
index 2fb2568..f172b41 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: PyQt6
-Version: 6.10.0
+Version: 6.10.1
 Requires-Python: >=3.9
 Summary: Python bindings for the Qt cross platform application toolkit
 Description-Content-Type: text/markdown
diff --git a/examples/itemmodels/rangemodel.py b/examples/itemmodels/rangemodel.py
new file mode 100644
index 0000000..9d93e06
--- /dev/null
+++ b/examples/itemmodels/rangemodel.py
@@ -0,0 +1,114 @@
+import sys
+
+from PyQt6.QtCore import QPySequenceRange, QPyTableRange, QRangeModel, Qt
+from PyQt6.QtWidgets import (QApplication, QGridLayout, QLabel, QListView,
+        QTableView, QTreeView, QVBoxLayout, QWidget)
+
+
+class ViewContainer(QVBoxLayout):
+    """ A container for a view. """
+
+    def __init__(self, title, py_range, parent=None):
+        """ Initialise the view. """
+
+        super().__init__(parent)
+
+        self._py_range = py_range
+
+        if isinstance(py_range, QPySequenceRange):
+            py_range.dataChanged.connect(self._on_sequence_changed)
+            view = QListView()
+
+        if isinstance(py_range, QPyTableRange):
+            py_range.dataChanged.connect(self._on_table_changed)
+            view = QTableView()
+            view.horizontalHeader().setVisible(False)
+            view.verticalHeader().setVisible(False)
+
+        model = QRangeModel(py_range)
+        view.setModel(model)
+        view.selectionModel().currentChanged.connect(
+                self._on_selection_changed)
+
+        self._data_view = QLabel()
+
+        self.addWidget(
+                QLabel(f'<b>{title}</b>',
+                        alignment=Qt.AlignmentFlag.AlignHCenter))
+        self.addWidget(view)
+        self.addWidget(self._data_view)
+
+    def _on_selection_changed(self, current, _):
+        """ Handle the changed selection. """
+
+        self._set_data_view(current.row(), current.column())
+
+    def _on_sequence_changed(self, index):
+        """ Handle the changed Python sequence. """
+
+        self._set_data_view(index)
+
+    def _on_table_changed(self, row, column):
+        """ Handle the changed Python table. """
+
+        self._set_data_view(row, column)
+
+    def _set_data_view(self, row, column=-1):
+        """ Set the view of an element from the Python data. """
+
+        datum = self._py_range.data()[row]
+        if isinstance(self._py_range, QPyTableRange):
+            datum = datum[column]
+
+        self._data_view.setText(f"Selected data: {repr(datum)}")
+
+
+# Instances of this type are unknown to PyQt.
+class Data:
+    """ Wrap an arbitrary Python object. """
+
+    def __init__(self, data):
+        """ Initialise the object. """
+
+        self._data = data
+
+    def __str__(self):
+        """ Return a string representation of the data to be used in views. """
+
+        return str(self._data)
+
+
+if __name__ == '__main__':
+    app = QApplication(sys.argv)
+
+    gallery = QWidget()
+    layout = QGridLayout()
+
+    ro_seq_data = QPySequenceRange(
+            ("Foo", 1, True, 5.6, Data("A string"), Data(100)))
+    layout.addLayout(ViewContainer("Read-only Sequence", ro_seq_data), 0, 0)
+
+    fixed_seq_data = QPySequenceRange(["Cat", 9, False], editable=True)
+    layout.addLayout(ViewContainer("Fixed Size Sequence", fixed_seq_data), 0,
+            1)
+
+    ro_table_data = QPyTableRange(
+            (
+                ("Foo", 1, True, 5.6, Data("A string"), Data(100)),
+                ("Bar", 2, False, 6.6, Data("Another string"), Data(200)),
+            ))
+    layout.addLayout(ViewContainer("Read-only Table", ro_table_data), 1, 0)
+
+    fixed_table_data = QPyTableRange(
+            (
+                ["Cat", 9, False],
+                ["Dog", 1, True],
+            ),
+            editable=True)
+    layout.addLayout(ViewContainer("Fixed Size Table", fixed_table_data), 1, 1)
+
+    gallery.setLayout(layout)
+    gallery.resize(1400, 600)
+    gallery.show()
+
+    sys.exit(app.exec())
diff --git a/lupdate/python_source.py b/lupdate/python_source.py
index fe001e4..aa5f004 100644
--- a/lupdate/python_source.py
+++ b/lupdate/python_source.py
@@ -224,9 +224,6 @@ class Visitor(ast.NodeVisitor):
         node.
         """
 
-        if isinstance(node, ast.Str):
-            return node.s
-
         if isinstance(node, ast.Constant):
             if isinstance(node.value, str):
                 return node.value
diff --git a/pyproject.toml b/pyproject.toml
index 2b59362..20a11a1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "sipbuild.api"
 
 [project]
 name = "PyQt6"
-version = "6.10.0"
+version = "6.10.1"
 description = "Python bindings for the Qt cross platform application toolkit"
 readme = "README.md"
 urls.homepage = "https://www.riverbankcomputing.com/software/pyqt/"
diff --git a/qpy/QtCore/qpycore_post_init.cpp b/qpy/QtCore/qpycore_post_init.cpp
index ed2f409..fb6fe54 100644
--- a/qpy/QtCore/qpycore_post_init.cpp
+++ b/qpy/QtCore/qpycore_post_init.cpp
@@ -78,6 +78,7 @@ void qpycore_post_init(PyObject *module_dict)
 
     // Register the C++ type that wraps Python objects.
     qRegisterMetaType<PyQt_PyObject>("PyQt_PyObject");
+    QMetaType::registerConverter<PyQt_PyObject, QString>();
 
     // Register the lazy attribute getter.
     if (sipRegisterAttributeGetter(sipType_QObject, qpycore_get_lazy_attr) < 0)
diff --git a/qpy/QtCore/qpycore_pyqtpyobject.cpp b/qpy/QtCore/qpycore_pyqtpyobject.cpp
index 4cf89c1..487a9d0 100644
--- a/qpy/QtCore/qpycore_pyqtpyobject.cpp
+++ b/qpy/QtCore/qpycore_pyqtpyobject.cpp
@@ -90,6 +90,31 @@ PyQt_PyObject &PyQt_PyObject::operator=(const PyQt_PyObject &other)
 }
 
 
+// QString operator cast.
+PyQt_PyObject::operator QString() const
+{
+    QString qs;
+
+    SIP_BLOCK_THREADS
+
+    PyObject *py_s = PyObject_Str(pyobject);
+
+    if (py_s)
+    {
+        qs = qpycore_PyObject_AsQString(py_s);
+        Py_DECREF(py_s);
+    }
+    else
+    {
+        qs = QString("PyQt_PyObject string conversion failed");
+    }
+
+    SIP_UNBLOCK_THREADS
+
+    return qs;
+}
+
+
 // Comparison operator.  It must be global to be available to QMetaType.
 bool operator==(const PyQt_PyObject &self, const PyQt_PyObject &other)
 {
diff --git a/qpy/QtCore/qpycore_pyqtpyobject.h b/qpy/QtCore/qpycore_pyqtpyobject.h
index 9ba5cf7..18420ef 100644
--- a/qpy/QtCore/qpycore_pyqtpyobject.h
+++ b/qpy/QtCore/qpycore_pyqtpyobject.h
@@ -40,6 +40,7 @@ public:
     ~PyQt_PyObject();
 
     PyQt_PyObject &operator=(const PyQt_PyObject &other);
+    operator QString() const;
 
     // The Python object being wrapped.
     PyObject *pyobject;
diff --git a/qpy/QtCore/qpycore_qrangemodel.cpp b/qpy/QtCore/qpycore_qrangemodel.cpp
new file mode 100644
index 0000000..b9465ea
--- /dev/null
+++ b/qpy/QtCore/qpycore_qrangemodel.cpp
@@ -0,0 +1,345 @@
+// This is the support for QRangeModel.
+//
+// Copyright (c) 2025 Riverbank Computing Limited <info at riverbankcomputing.com>
+// 
+// This file is part of PyQt6.
+// 
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+// 
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+// 
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+#include <Python.h>
+
+#include <qglobal.h>
+
+#if QT_VERSION >= 0x060a00
+
+#include "qpycore_qrangemodel.h"
+
+#include "qpycore_api.h"
+
+#include "sipAPIQtCore.h"
+
+
+// Construct a range and take a strong reference to the Python object.
+QPyAbstractRange::QPyAbstractRange(PyObject *data, bool editable) :
+        m_data(data), m_editable(editable)
+{
+    SIP_BLOCK_THREADS
+    Py_INCREF(m_data);
+    SIP_UNBLOCK_THREADS
+}
+
+
+// Destroy the range.
+QPyAbstractRange::~QPyAbstractRange()
+{
+    SIP_BLOCK_THREADS
+    Py_DECREF(m_data);
+    SIP_UNBLOCK_THREADS
+}
+
+
+// Raise a Python exception regarding the structure of the data.
+void QPyAbstractRange::raiseBadStructure()
+{
+    PyErr_SetString(PyExc_ValueError,
+            "the range data does not have the correct structure");
+}
+
+
+// Populate a 1D range from a Python list.
+bool QPyAbstractRange::populate1DFromList(QVariantList &range, PyObject *data)
+{
+    if (!PyList_Check(data))
+    {
+        raiseBadStructure();
+        return false;
+    }
+
+    Py_ssize_t size = PyList_Size(data);
+    if (size < 0)
+        return false;
+
+    for (Py_ssize_t i = 0; i < size; ++i)
+    {
+        PyObject *val = PyList_GetItem(data, i);
+        if (!val)
+            return false;
+
+        int is_err = 0;
+
+        QVariant qv = qpycore_PyObject_AsQVariant(val, &is_err);
+        Py_DECREF(val);
+
+        if (is_err)
+            return false;
+
+        range.append(qv);
+    }
+
+    return true;
+}
+
+
+// Populate a 1D range from a Python sequence.
+bool QPyAbstractRange::populate1DFromSequence(QVariantList &range,
+        PyObject *data)
+{
+    if (!PySequence_Check(data))
+    {
+        raiseBadStructure();
+        return false;
+    }
+
+    Py_ssize_t size = PySequence_Size(data);
+    if (size < 0)
+        return false;
+
+    for (Py_ssize_t i = 0; i < size; ++i)
+    {
+        PyObject *val = PySequence_GetItem(data, i);
+        if (!val)
+            return false;
+
+        int is_err = 0;
+
+        QVariant qv = qpycore_PyObject_AsQVariant(val, &is_err);
+        Py_DECREF(val);
+
+        if (is_err)
+            return false;
+
+        range.append(qv);
+    }
+
+    return true;
+}
+
+
+// Construct a sequence range.
+QPySequenceRange::QPySequenceRange(PyObject *data, bool editable) :
+        QPyAbstractRange(data, editable)
+{
+}
+
+
+// Create an appropriately configured QRangeModel for a sequence range.  This
+// must be called with the GIL.
+sipQRangeModel *QPySequenceRange::create(QObject *parent)
+{
+    sipQRangeModel *model = nullptr;
+
+    if (editable())
+    {
+        if (populateFromList(m_seq_range, data()))
+        {
+            model = new sipQRangeModel(std::ref(m_seq_range), parent);
+            QObject::connect(model, &QRangeModel::dataChanged, this,
+                    &QPySequenceRange::handleDataChanged);
+        }
+    }
+    else
+    {
+        if (populateFromSequence(m_seq_range, data()))
+            model = new sipQRangeModel(std::cref(m_seq_range), parent);
+    }
+
+    if (model)
+        setParent(model);
+
+    return model;
+};
+
+
+// Handle the dataChanged() signal for a sequence range.
+void QPySequenceRange::handleDataChanged(const QModelIndex &tl,
+        const QModelIndex &br)
+{
+    Q_UNUSED(br);
+
+    bool do_emit = false;
+
+    SIP_BLOCK_THREADS
+
+    // Note that we don't report any errors.
+    PyObject *py_data = qpycore_PyObject_FromQVariant(tl.data());
+    if (py_data)
+        do_emit = (PyList_SetItem(data(), tl.row(), py_data) == 0);
+
+    SIP_UNBLOCK_THREADS
+
+    // The signal must be emited without the GIL.
+    if (do_emit)
+        emit dataChanged(tl.row());
+}
+
+
+// Populate a sequence range from a Python list.
+bool QPySequenceRange::populateFromList(QVariantList &range, PyObject *data)
+{
+    bool ok = true;
+
+    SIP_BLOCK_THREADS
+    ok = populate1DFromList(range, data);
+    SIP_UNBLOCK_THREADS
+
+    return ok;
+}
+
+
+// Populate a sequence range from a Python sequence.
+bool QPySequenceRange::populateFromSequence(QVariantList &range,
+        PyObject *data)
+{
+    bool ok;
+
+    SIP_BLOCK_THREADS
+    ok = populate1DFromSequence(range, data);
+    SIP_UNBLOCK_THREADS
+
+    return ok;
+}
+
+
+// Construct a table range.
+QPyTableRange::QPyTableRange(PyObject *data, bool editable) :
+        QPyAbstractRange(data, editable)
+{
+}
+
+
+// Create an appropriately configured QRangeModel for a table range.  This must
+// be called with the GIL.
+sipQRangeModel *QPyTableRange::create(QObject *parent)
+{
+    if (!populate(m_table_range, data()))
+        return nullptr;
+
+    sipQRangeModel *model;
+
+    if (editable())
+    {
+        model = new sipQRangeModel(std::ref(m_table_range), parent);
+        QObject::connect(model, &QRangeModel::dataChanged, this,
+                    &QPyTableRange::handleDataChanged);
+    }
+    else
+    {
+        model = new sipQRangeModel(std::cref(m_table_range), parent);
+    }
+
+    setParent(model);
+
+    return model;
+};
+
+
+// Handle the dataChanged() signal for a table range.
+void QPyTableRange::handleDataChanged(const QModelIndex &tl,
+        const QModelIndex &br)
+{
+    Q_UNUSED(br);
+
+    bool do_emit = false;
+
+    SIP_BLOCK_THREADS
+
+    // Note that we don't report any errors.
+    PyObject *py_data = qpycore_PyObject_FromQVariant(tl.data());
+    if (py_data)
+    {
+        PyObject *row_data = PySequence_GetItem(data(), tl.row());
+
+        if (row_data != NULL)
+        {
+            do_emit = (PyList_SetItem(row_data, tl.column(), py_data) == 0);
+            Py_DECREF(row_data);
+        }
+    }
+
+    SIP_UNBLOCK_THREADS
+
+    // The signal must be emited without the GIL.
+    if (do_emit)
+        emit dataChanged(tl.row(), tl.column());
+}
+
+
+// Populate a table range.
+bool QPyTableRange::populate(QList<QVariantList> &range, PyObject *data)
+{
+    bool ok = true;
+
+    SIP_BLOCK_THREADS
+
+    if (PySequence_Check(data))
+    {
+        Py_ssize_t size = PySequence_Size(data);
+        if (size >= 0)
+        {
+            Py_ssize_t nr_cols = -1;
+
+            for (Py_ssize_t i = 0; i < size; ++i)
+            {
+                PyObject *val = PySequence_GetItem(data, i);
+                if (!val)
+                {
+                    ok = false;
+                    break;
+                }
+
+                QVariantList qvl;
+
+                if (editable())
+                    ok = populate1DFromList(qvl, val);
+                else
+                    ok = populate1DFromSequence(qvl, val);
+
+                Py_DECREF(val);
+
+                if (!ok)
+                    break;
+
+                if (nr_cols < 0)
+                {
+                    nr_cols = qvl.size();
+                }
+                else if (nr_cols != qvl.size())
+                {
+                    PyErr_SetString(PyExc_ValueError,
+                            "the range data does not have the same number of columns in each row");
+                    ok = false;
+                    break;
+                }
+
+                range.append(qvl);
+            }
+        }
+        else
+        {
+            ok = false;
+        }
+    }
+    else
+    {
+        raiseBadStructure();
+        ok = false;
+    }
+
+    SIP_UNBLOCK_THREADS
+
+    return ok;
+}
+
+#endif
diff --git a/qpy/QtCore/qpycore_qrangemodel.h b/qpy/QtCore/qpycore_qrangemodel.h
new file mode 100644
index 0000000..aea4ee5
--- /dev/null
+++ b/qpy/QtCore/qpycore_qrangemodel.h
@@ -0,0 +1,128 @@
+// This is the interface support for QRangeModel.
+//
+// Copyright (c) 2025 Riverbank Computing Limited <info at riverbankcomputing.com>
+// 
+// This file is part of PyQt6.
+// 
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+// 
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+// 
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+#ifndef _QPYCORE_QRANGEMODEL_H
+#define _QPYCORE_QRANGEMODEL_H
+
+#include <Python.h>
+
+#include <qglobal.h>
+
+#if QT_VERSION >= 0x060a00
+
+#include <qlist.h>
+#include <qobject.h>
+#include <qrangemodel.h>
+#include <qvariant.h>
+
+
+class sipQRangeModel;
+
+
+// The abstract base for classes that wrap a Python object to be used as an
+// appropriately configured range for use by QRangeModel.
+class QPyAbstractRange : public QObject
+{
+    Q_OBJECT
+
+public:
+    QPyAbstractRange(PyObject *data, bool editable);
+    virtual ~QPyAbstractRange();
+
+    PyObject *data() const
+    {
+#if PY_VERSION_HEX >= 0x030a0000
+        return Py_NewRef(m_data);
+#else
+        Py_INCREF(m_data);
+        return m_data;
+#endif
+    }
+
+    bool editable() const {return m_editable;}
+
+    // This is internal.
+    virtual sipQRangeModel *create(QObject *parent) = 0;
+
+protected:
+    // These are internal.
+    static void raiseBadStructure();
+    static bool populate1DFromList(QVariantList &range, PyObject *data);
+    static bool populate1DFromSequence(QVariantList &range, PyObject *data);
+
+private:
+    PyObject *m_data;
+    bool m_editable;
+};
+
+
+// A class that wraps a Python object to be used as an appropriately configured
+// sequence range for use by QRangeModel.
+class QPySequenceRange : public QPyAbstractRange
+{
+    Q_OBJECT
+
+public:
+    QPySequenceRange(PyObject *data, bool editable = false);
+
+    // This is internal.
+    sipQRangeModel *create(QObject *parent);
+
+signals:
+    void dataChanged(int index);
+
+private slots:
+    void handleDataChanged(const QModelIndex &tl, const QModelIndex &br);
+
+private:
+    QVariantList m_seq_range;
+
+    static bool populateFromList(QVariantList &range, PyObject *data);
+    static bool populateFromSequence(QVariantList &range, PyObject *data);
+};
+
+
+// A class that wraps a Python object to be used as an appropriately configured
+// table range for use by QRangeModel.
+class QPyTableRange : public QPyAbstractRange
+{
+    Q_OBJECT
+
+public:
+    QPyTableRange(PyObject *data, bool editable = false);
+
+    // This is internal.
+    sipQRangeModel *create(QObject *parent);
+
+signals:
+    void dataChanged(int row, int column);
+
+private slots:
+    void handleDataChanged(const QModelIndex &tl, const QModelIndex &br);
+
+private:
+    QList<QVariantList> m_table_range;
+
+    bool populate(QList<QVariantList> &range, PyObject *data);
+};
+
+#endif
+
+#endif
diff --git a/sip/QtCore/QtCoremod.sip b/sip/QtCore/QtCoremod.sip
index 060316f..8e4d24c 100644
--- a/sip/QtCore/QtCoremod.sip
+++ b/sip/QtCore/QtCoremod.sip
@@ -78,8 +78,8 @@ int PYQT_VERSION;
 const char *PYQT_VERSION_STR;
 
 %ModuleCode
-static int PYQT_VERSION = 0x060a00;
-static const char *PYQT_VERSION_STR = "6.10.0";
+static int PYQT_VERSION = 0x060a01;
+static const char *PYQT_VERSION_STR = "6.10.1";
 %End
 
 %Include qglobal.sip
@@ -214,6 +214,7 @@ static const char *PYQT_VERSION_STR = "6.10.0";
 %Include qpycore_std_optional.sip
 %Include qpycore_qset.sip
 %Include qstringview.sip
+%Include qpycore_qrangemodel.sip
 %Include qpycore_qlist.sip
 %Include qwineventnotifier.sip
 %Include qstringlist.sip
diff --git a/sip/QtCore/qobject.sip b/sip/QtCore/qobject.sip
index b1ae154..3b99f6a 100644
--- a/sip/QtCore/qobject.sip
+++ b/sip/QtCore/qobject.sip
@@ -255,10 +255,10 @@ static PyObject *qtcore_FindChildren(const QObject *parent, PyObject *types, con
         sipTypeDef **type;
         int yes, no;
     } graph[] = {
-        {sipName_QAbstractAnimation, &sipType_QAbstractAnimation, 23, 1},
+        {sipName_QAbstractAnimation, &sipType_QAbstractAnimation, 24, 1},
         {sipName_QAbstractEventDispatcher, &sipType_QAbstractEventDispatcher, -1, 2},
-        {sipName_QAbstractItemModel, &sipType_QAbstractItemModel, 29, 3},
-        {sipName_QIODevice, &sipType_QIODevice, 37, 4},
+        {sipName_QAbstractItemModel, &sipType_QAbstractItemModel, 30, 3},
+        {sipName_QIODevice, &sipType_QIODevice, 39, 4},
         {sipName_QCoreApplication, &sipType_QCoreApplication, -1, 5},
         {sipName_QEventLoop, &sipType_QEventLoop, -1, 6},
         {sipName_QFileSelector, &sipType_QFileSelector, -1, 7},
@@ -268,44 +268,64 @@ static PyObject *qtcore_FindChildren(const QObject *parent, PyObject *types, con
         {sipName_QMimeData, &sipType_QMimeData, -1, 11},
         {sipName_QObjectCleanupHandler, &sipType_QObjectCleanupHandler, -1, 12},
         {sipName_QPluginLoader, &sipType_QPluginLoader, -1, 13},
-        {sipName_QSettings, &sipType_QSettings, -1, 14},
-        {sipName_QSharedMemory, &sipType_QSharedMemory, -1, 15},
-        {sipName_QSignalMapper, &sipType_QSignalMapper, -1, 16},
-        {sipName_QSocketNotifier, &sipType_QSocketNotifier, -1, 17},
-        {sipName_QThread, &sipType_QThread, -1, 18},
-        {sipName_QThreadPool, &sipType_QThreadPool, -1, 19},
-        {sipName_QTimeLine, &sipType_QTimeLine, -1, 20},
-        {sipName_QTimer, &sipType_QTimer, -1, 21},
-        {sipName_QTranslator, &sipType_QTranslator, -1, 22},
+    #if QT_VERSION >= 0x060a00
+        {sipName_QPyAbstractRange, &sipType_QPyAbstractRange, 45, 14},
+    #else
+        {0, 0, 45, 14},
+    #endif
+        {sipName_QSettings, &sipType_QSettings, -1, 15},
+        {sipName_QSharedMemory, &sipType_QSharedMemory, -1, 16},
+        {sipName_QSignalMapper, &sipType_QSignalMapper, -1, 17},
+        {sipName_QSocketNotifier, &sipType_QSocketNotifier, -1, 18},
+        {sipName_QThread, &sipType_QThread, -1, 19},
+        {sipName_QThreadPool, &sipType_QThreadPool, -1, 20},
+        {sipName_QTimeLine, &sipType_QTimeLine, -1, 21},
+        {sipName_QTimer, &sipType_QTimer, -1, 22},
+        {sipName_QTranslator, &sipType_QTranslator, -1, 23},
     #if defined(Q_OS_WIN)
         {sipName_QWinEventNotifier, &sipType_QWinEventNotifier, -1, -1},
     #else
         {0, 0, -1, -1},
     #endif
-        {sipName_QAnimationGroup, &sipType_QAnimationGroup, 26, 24},
-        {sipName_QPauseAnimation, &sipType_QPauseAnimation, -1, 25},
-        {sipName_QVariantAnimation, &sipType_QVariantAnimation, 28, -1},
-        {sipName_QParallelAnimationGroup, &sipType_QParallelAnimationGroup, -1, 27},
+        {sipName_QAnimationGroup, &sipType_QAnimationGroup, 27, 25},
+        {sipName_QPauseAnimation, &sipType_QPauseAnimation, -1, 26},
+        {sipName_QVariantAnimation, &sipType_QVariantAnimation, 29, -1},
+        {sipName_QParallelAnimationGroup, &sipType_QParallelAnimationGroup, -1, 28},
         {sipName_QSequentialAnimationGroup, &sipType_QSequentialAnimationGroup, -1, -1},
         {sipName_QPropertyAnimation, &sipType_QPropertyAnimation, -1, -1},
-        {sipName_QAbstractListModel, &sipType_QAbstractListModel, 33, 30},
-        {sipName_QAbstractProxyModel, &sipType_QAbstractProxyModel, 34, 31},
-        {sipName_QAbstractTableModel, &sipType_QAbstractTableModel, -1, 32},
-        {sipName_QConcatenateTablesProxyModel, &sipType_QConcatenateTablesProxyModel, -1, -1},
+        {sipName_QAbstractListModel, &sipType_QAbstractListModel, 35, 31},
+        {sipName_QAbstractProxyModel, &sipType_QAbstractProxyModel, 36, 32},
+        {sipName_QAbstractTableModel, &sipType_QAbstractTableModel, -1, 33},
+        {sipName_QConcatenateTablesProxyModel, &sipType_QConcatenateTablesProxyModel, -1, 34},
+    #if QT_VERSION >= 0x060a00
+        {sipName_QRangeModel, &sipType_QRangeModel, -1, -1},
+    #else
+        {0, 0, -1, -1},
+    #endif
         {sipName_QStringListModel, &sipType_QStringListModel, -1, -1},
-        {sipName_QIdentityProxyModel, &sipType_QIdentityProxyModel, -1, 35},
-        {sipName_QSortFilterProxyModel, &sipType_QSortFilterProxyModel, -1, 36},
+        {sipName_QIdentityProxyModel, &sipType_QIdentityProxyModel, -1, 37},
+        {sipName_QSortFilterProxyModel, &sipType_QSortFilterProxyModel, -1, 38},
         {sipName_QTransposeProxyModel, &sipType_QTransposeProxyModel, -1, -1},
-        {sipName_QBuffer, &sipType_QBuffer, -1, 38},
-        {sipName_QFileDevice, &sipType_QFileDevice, 40, 39},
+        {sipName_QBuffer, &sipType_QBuffer, -1, 40},
+        {sipName_QFileDevice, &sipType_QFileDevice, 42, 41},
     #if !defined(QT_NO_PROCESS)
         {sipName_QProcess, &sipType_QProcess, -1, -1},
     #else
         {0, 0, -1, -1},
     #endif
-        {sipName_QFile, &sipType_QFile, 42, 41},
+        {sipName_QFile, &sipType_QFile, 44, 43},
         {sipName_QSaveFile, &sipType_QSaveFile, -1, -1},
         {sipName_QTemporaryFile, &sipType_QTemporaryFile, -1, -1},
+    #if QT_VERSION >= 0x060a00
+        {sipName_QPySequenceRange, &sipType_QPySequenceRange, -1, 46},
+    #else
+        {0, 0, -1, 46},
+    #endif
+    #if QT_VERSION >= 0x060a00
+        {sipName_QPyTableRange, &sipType_QPyTableRange, -1, -1},
+    #else
+        {0, 0, -1, -1},
+    #endif
     };
     
     int i = 0;
diff --git a/sip/QtCore/qrangemodel.sip b/sip/QtCore/qpycore_qrangemodel.sip
similarity index 50%
copy from sip/QtCore/qrangemodel.sip
copy to sip/QtCore/qpycore_qrangemodel.sip
index 625b251..9ad84c4 100644
--- a/sip/QtCore/qrangemodel.sip
+++ b/sip/QtCore/qpycore_qrangemodel.sip
@@ -1,6 +1,4 @@
-// qrangemodel.sip generated by MetaSIP
-//
-// This file is part of the QtCore Python extension module.
+// This is the interface definition for the support for QRangeModel.
 //
 // Copyright (c) 2025 Riverbank Computing Limited <info at riverbankcomputing.com>
 // 
@@ -19,3 +17,49 @@
 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
+
+%If (Qt_6_10_0 -)
+
+class QPyAbstractRange : public QObject /Abstract/
+{
+%TypeHeaderCode
+#include "qpycore_qrangemodel.h"
+%End
+
+public:
+    QPyAbstractRange(SIP_PYOBJECT data, bool editable);
+    virtual ~QPyAbstractRange();
+
+    SIP_PYOBJECT data() const;
+    bool editable() const;
+};
+
+
+class QPySequenceRange : public QPyAbstractRange
+{
+%TypeHeaderCode
+#include "qpycore_qrangemodel.h"
+%End
+
+public:
+    QPySequenceRange(SIP_PYOBJECT data, bool editable = false);
+
+signals:
+    void dataChanged(int index);
+};
+
+
+class QPyTableRange : public QPyAbstractRange
+{
+%TypeHeaderCode
+#include "qpycore_qrangemodel.h"
+%End
+
+public:
+    QPyTableRange(SIP_PYOBJECT data, bool editable = false);
+
+signals:
+    void dataChanged(int row, int column);
+};
+
+%End
diff --git a/sip/QtCore/qrangemodel.sip b/sip/QtCore/qrangemodel.sip
index 625b251..090bc5a 100644
--- a/sip/QtCore/qrangemodel.sip
+++ b/sip/QtCore/qrangemodel.sip
@@ -19,3 +19,79 @@
 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
+
+%If (Qt_6_10_0 -)
+
+class QRangeModel : public QAbstractItemModel /ExportDerivedLocally/
+{
+%TypeHeaderCode
+#include <qrangemodel.h>
+#include "qpycore_qrangemodel.h"
+%End
+
+%TypeDerivedCode
+sipQRangeModel(const QVariantList &range, QObject *parent) : QRangeModel(range, parent) {}
+sipQRangeModel(QVariantList &range, QObject *parent) : QRangeModel(range, parent) {}
+sipQRangeModel(const QList<QVariantList> &range, QObject *parent) : QRangeModel(range, parent) {}
+sipQRangeModel(QList<QVariantList> &range, QObject *parent) : QRangeModel(range, parent) {}
+%End
+
+public:
+    QRangeModel(QPyAbstractRange *range /Transfer/, QObject *parent /TransferThis/ = 0) /HoldGIL, NoDerived/;
+%MethodCode
+        sipCpp = a0->create(a1);
+        
+        if (!sipCpp)
+            sipError = sipErrorFail;
+%End
+
+    virtual ~QRangeModel();
+    QModelIndex index(int row, int column, const QModelIndex &parent = {}) const final;
+    QModelIndex parent(const QModelIndex &child) const final;
+    QModelIndex sibling(int row, int column, const QModelIndex &index) const final;
+    int rowCount(const QModelIndex &parent = {}) const final;
+    int columnCount(const QModelIndex &parent = {}) const final;
+    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+    virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role = Qt::EditRole);
+    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+    virtual bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole);
+    virtual QMap<int, QVariant> itemData(const QModelIndex &index) const;
+    virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &data);
+    virtual bool clearItemData(const QModelIndex &index);
+    bool insertColumns(int column, int count, const QModelIndex &parent = {}) final;
+    bool removeColumns(int column, int count, const QModelIndex &parent = {}) final;
+    bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destParent, int destColumn) final;
+    bool insertRows(int row, int count, const QModelIndex &parent = {}) final;
+    bool removeRows(int row, int count, const QModelIndex &parent = {}) final;
+    bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow) final;
+    virtual QHash<int, QByteArray> roleNames() const;
+    void setRoleNames(const QHash<int, QByteArray> &names);
+    void resetRoleNames();
+    virtual bool canFetchMore(const QModelIndex &parent) const;
+    virtual void fetchMore(const QModelIndex &parent);
+    bool hasChildren(const QModelIndex &parent = QModelIndex()) const final;
+    virtual QModelIndex buddy(const QModelIndex &index) const;
+    virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const;
+    virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+    virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
+    virtual QStringList mimeTypes() const;
+    virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const;
+    virtual void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const;
+    virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+    virtual QSize span(const QModelIndex &index) const;
+    virtual Qt::DropActions supportedDragActions() const;
+    virtual Qt::DropActions supportedDropActions() const;
+
+signals:
+    void roleNamesChanged();
+
+protected slots:
+    virtual void resetInternalData();
+
+protected:
+    virtual bool event(QEvent *);
+    virtual bool eventFilter(QObject *, QEvent *);
+};
+
+%End
diff --git a/sip/QtWidgets/qlineedit.sip b/sip/QtWidgets/qlineedit.sip
index 881c561..0d464fb 100644
--- a/sip/QtWidgets/qlineedit.sip
+++ b/sip/QtWidgets/qlineedit.sip
@@ -89,7 +89,7 @@ public:
     void paste();
     void deselect();
     void insert(const QString &);
-    QMenu *createStandardContextMenu() /Factory/;
+    QMenu *createStandardContextMenu() /Transfer/;
 
 signals:
     void textChanged(const QString &);
diff --git a/sip/QtWidgets/qplaintextedit.sip b/sip/QtWidgets/qplaintextedit.sip
index 3b31e9c..5930b42 100644
--- a/sip/QtWidgets/qplaintextedit.sip
+++ b/sip/QtWidgets/qplaintextedit.sip
@@ -67,8 +67,8 @@ public:
     QString toPlainText() const;
     void ensureCursorVisible();
     virtual QVariant loadResource(int type, const QUrl &name);
-    QMenu *createStandardContextMenu() /Factory/;
-    QMenu *createStandardContextMenu(const QPoint &position) /Factory/;
+    QMenu *createStandardContextMenu() /Transfer/;
+    QMenu *createStandardContextMenu(const QPoint &position) /Transfer/;
     QTextCursor cursorForPosition(const QPoint &pos) const;
     QRect cursorRect(const QTextCursor &cursor) const;
     QRect cursorRect() const;
@@ -138,7 +138,7 @@ public:
     virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
 
 protected:
-    virtual QMimeData *createMimeDataFromSelection() const /Factory/;
+    virtual QMimeData *createMimeDataFromSelection() const /Transfer/;
     virtual bool canInsertFromMimeData(const QMimeData *source) const;
     virtual void insertFromMimeData(const QMimeData *source);
     virtual void scrollContentsBy(int dx, int dy);
diff --git a/sip/QtWidgets/qscrollbar.sip b/sip/QtWidgets/qscrollbar.sip
index 9e60018..62001e9 100644
--- a/sip/QtWidgets/qscrollbar.sip
+++ b/sip/QtWidgets/qscrollbar.sip
@@ -46,6 +46,6 @@ protected:
 
 public:
 %If (Qt_6_10_0 -)
-    QMenu *createStandardContextMenu(QPoint position) /Factory/;
+    QMenu *createStandardContextMenu(QPoint position) /Transfer/;
 %End
 };
diff --git a/sip/QtWidgets/qtextedit.sip b/sip/QtWidgets/qtextedit.sip
index 7919753..70dc9fd 100644
--- a/sip/QtWidgets/qtextedit.sip
+++ b/sip/QtWidgets/qtextedit.sip
@@ -93,8 +93,8 @@ public:
     void append(const QString &text);
     void ensureCursorVisible();
     virtual QVariant loadResource(int type, const QUrl &name);
-    QMenu *createStandardContextMenu() /Factory/;
-    QMenu *createStandardContextMenu(const QPoint &position) /Factory/;
+    QMenu *createStandardContextMenu() /Transfer/;
+    QMenu *createStandardContextMenu(const QPoint &position) /Transfer/;
     QTextCursor cursorForPosition(const QPoint &pos) const;
     QRect cursorRect(const QTextCursor &cursor) const;
     QRect cursorRect() const;
@@ -171,7 +171,7 @@ protected:
     virtual void showEvent(QShowEvent *);
     virtual void changeEvent(QEvent *e);
     virtual void wheelEvent(QWheelEvent *e);
-    virtual QMimeData *createMimeDataFromSelection() const /Factory/;
+    virtual QMimeData *createMimeDataFromSelection() const /Transfer/;
     virtual bool canInsertFromMimeData(const QMimeData *source) const;
     virtual void insertFromMimeData(const QMimeData *source);
     virtual void inputMethodEvent(QInputMethodEvent *);



More information about the Neon-commits mailing list