[pygobject/gio-liststore-sort: 9/9] Add overrides for Gio.ListStore.sort and Gio.ListStore.insert_sorted. Fixes #130



commit d0bfb29fe5b34c58a190e084614fe489771bf53b
Author: Christoph Reiter <reiter christoph gmail com>
Date:   Fri Apr 20 10:09:31 2018 +0200

    Add overrides for Gio.ListStore.sort and Gio.ListStore.insert_sorted. Fixes #130
    
    Those functions use CompareDataFunc which works with pointers and doesn't know
    anything about GObjects.
    
    Add overrides which wrap the passed in sort function and convert the pointers
    to proper Python wrappers.

 gi/_compat.py               |  2 ++
 gi/gimodule.c               | 27 ++++++++++++++++++++++++
 gi/overrides/Gio.py         | 20 ++++++++++++++++++
 tests/test_overrides_gio.py | 51 +++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 98 insertions(+), 2 deletions(-)
---
diff --git a/gi/_compat.py b/gi/_compat.py
index b4cc46d8..00f5fbb3 100644
--- a/gi/_compat.py
+++ b/gi/_compat.py
@@ -30,6 +30,7 @@ if sys.version_info[0] == 2:
 
     reload = eval("reload")
     xrange = eval("xrange")
+    cmp = eval("cmp")
 
     exec("def reraise(tp, value, tb):\n raise tp, value, tb")
 else:
@@ -49,6 +50,7 @@ else:
     from importlib import reload
     reload
     xrange = range
+    cmp = lambda a, b: (a > b) - (a < b)
 
     def reraise(tp, value, tb):
         raise tp(value).with_traceback(tb)
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 441831cc..a3984dad 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -2240,7 +2240,34 @@ _wrap_pyig_pyos_getsig (PyObject *self, PyObject *args)
     return PyLong_FromVoidPtr ((void *)(PyOS_getsig (sig_num)));
 }
 
+static PyObject *
+_wrap_pygobject_new_full (PyObject *self, PyObject *args)
+{
+    PyObject *ptr_value, *long_value;
+    PyObject *steal;
+    GObject *obj;
+
+    if (!PyArg_ParseTuple (args, "OO", &ptr_value, &steal))
+        return NULL;
+
+    long_value = PyNumber_Long (ptr_value);
+    if (!long_value) {
+        PyErr_SetString (PyExc_TypeError, "first argument must be an integer");
+        return NULL;
+    }
+    obj = PyLong_AsVoidPtr (long_value);
+    Py_DECREF (long_value);
+
+    if (!G_IS_OBJECT (obj)) {
+        PyErr_SetString (PyExc_TypeError, "pointer is not a GObject");
+        return NULL;
+    }
+
+    return pygobject_new_full (obj, PyObject_IsTrue (steal), NULL);
+}
+
 static PyMethodDef _gi_functions[] = {
+    { "pygobject_new_full", (PyCFunction) _wrap_pygobject_new_full, METH_VARARGS },
     { "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
     { "enum_register_new_gtype_and_add", (PyCFunction) _wrap_pyg_enum_register_new_gtype_and_add, 
METH_VARARGS | METH_KEYWORDS },
     { "flags_add", (PyCFunction) _wrap_pyg_flags_add, METH_VARARGS | METH_KEYWORDS },
diff --git a/gi/overrides/Gio.py b/gi/overrides/Gio.py
index 75a128e3..f3c26b8d 100644
--- a/gi/overrides/Gio.py
+++ b/gi/overrides/Gio.py
@@ -24,6 +24,7 @@ from .._ossighelper import wakeup_on_signal, register_sigint_fallback
 from ..overrides import override, deprecated_init
 from ..module import get_introspection_module
 from .._compat import xrange
+from gi._gi import pygobject_new_full
 from gi import PyGIWarning
 
 from gi.repository import GLib
@@ -324,8 +325,27 @@ ListModel = override(ListModel)
 __all__.append('ListModel')
 
 
+def _wrap_list_store_sort_func(func):
+
+    def wrap(a, b, *user_data):
+        a = pygobject_new_full(a, False)
+        b = pygobject_new_full(b, False)
+        return func(a, b, *user_data)
+
+    return wrap
+
+
 class ListStore(Gio.ListStore):
 
+    def sort(self, compare_func, *user_data):
+        compare_func = _wrap_list_store_sort_func(compare_func)
+        return super(ListStore, self).sort(compare_func, *user_data)
+
+    def insert_sorted(self, item, compare_func, *user_data):
+        compare_func = _wrap_list_store_sort_func(compare_func)
+        return super(ListStore, self).insert_sorted(
+            item, compare_func, *user_data)
+
     def __delitem__(self, key):
         if isinstance(key, slice):
             start, stop, step = key.indices(len(self))
diff --git a/tests/test_overrides_gio.py b/tests/test_overrides_gio.py
index 123653cd..8434c2b0 100644
--- a/tests/test_overrides_gio.py
+++ b/tests/test_overrides_gio.py
@@ -5,13 +5,14 @@ import random
 import pytest
 
 from gi.repository import Gio, GObject
+from gi._compat import cmp
 
 
 class Item(GObject.Object):
     _id = 0
 
-    def __init__(self):
-        super(Item, self).__init__()
+    def __init__(self, **kwargs):
+        super(Item, self).__init__(**kwargs)
         Item._id += 1
         self._id = self._id
 
@@ -19,6 +20,52 @@ class Item(GObject.Object):
         return str(self._id)
 
 
+class NamedItem(Item):
+
+    name = GObject.Property(type=str, default='')
+
+    def __repr__(self):
+        return self.props.name
+
+
+def test_list_store_sort():
+    store = Gio.ListStore()
+    items = [NamedItem(name=n) for n in "cabx"]
+    sorted_items = sorted(items, key=lambda i: i.props.name)
+
+    user_data = [object(), object()]
+
+    def sort_func(a, b, *args):
+        assert list(args) == user_data
+        assert isinstance(a, NamedItem)
+        assert isinstance(b, NamedItem)
+        return cmp(a.props.name, b.props.name)
+
+    store[:] = items
+    assert store[:] != sorted_items
+    store.sort(sort_func, *user_data)
+    assert store[:] == sorted_items
+
+
+def test_list_store_insert_sorted():
+    store = Gio.ListStore()
+    items = [NamedItem(name=n) for n in "cabx"]
+    sorted_items = sorted(items, key=lambda i: i.props.name)
+
+    user_data = [object(), object()]
+
+    def sort_func(a, b, *args):
+        assert list(args) == user_data
+        assert isinstance(a, NamedItem)
+        assert isinstance(b, NamedItem)
+        return cmp(a.props.name, b.props.name)
+
+    for item in items:
+        index = store.insert_sorted(item, sort_func, *user_data)
+        assert isinstance(index, int)
+    assert store[:] == sorted_items
+
+
 def test_list_model_len():
     model = Gio.ListStore.new(Item)
     assert len(model) == 0


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]