summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Reiter <reiter.christoph@gmail.com>2018-04-20 10:09:31 +0200
committerChristoph Reiter <reiter.christoph@gmail.com>2018-04-21 04:06:42 +0000
commitd0bfb29fe5b34c58a190e084614fe489771bf53b (patch)
treeced676b2d6861960cfa2405906e371074e2fa2fd
parent00779bbaa59bfac4ddf2daa043761a3954a0ded3 (diff)
downloadpygobject-gio-liststore-sort.tar.gz
Add overrides for Gio.ListStore.sort and Gio.ListStore.insert_sorted. Fixes #130gio-liststore-sort
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.
-rw-r--r--gi/_compat.py2
-rw-r--r--gi/gimodule.c27
-rw-r--r--gi/overrides/Gio.py20
-rw-r--r--tests/test_overrides_gio.py51
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