diff options
author | Christoph Reiter <reiter.christoph@gmail.com> | 2018-04-20 10:09:31 +0200 |
---|---|---|
committer | Christoph Reiter <reiter.christoph@gmail.com> | 2018-04-21 04:06:42 +0000 |
commit | d0bfb29fe5b34c58a190e084614fe489771bf53b (patch) | |
tree | ced676b2d6861960cfa2405906e371074e2fa2fd | |
parent | 00779bbaa59bfac4ddf2daa043761a3954a0ded3 (diff) | |
download | pygobject-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.py | 2 | ||||
-rw-r--r-- | gi/gimodule.c | 27 | ||||
-rw-r--r-- | gi/overrides/Gio.py | 20 | ||||
-rw-r--r-- | 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 |