GNOME Bugzilla – Bug 656891
Add support for __setitem__ to TreeModel and support for slices to TreeModelRow
Last modified: 2011-08-24 16:15:11 UTC
Assigning rows like the following worked in pygtk as well: model = Gtk.ListStore(int, str) ... model[0] = (132, "something") Setting and retrieving slices from a row was not possible with pygtk, though. With this feature you can do things like print model[0][3:] model[0][3:] = (1, 2, 3) or even use extended slices: print model[0][2:10:2] model[0][2:10:2] = (2, 4, 6, 8)
Created attachment 194209 [details] [review] Adds overrides and test cases
Comment on attachment 194209 [details] [review] Adds overrides and test cases >From 2319b16fe9fd773c70dedf50f764a3b8e6042240 Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Sebastian=20P=C3=B6lsterl?= <sebp@k-d-w.org> >Date: Fri, 19 Aug 2011 12:27:04 +0200 >Subject: [PATCH] Added support for __setitem__ to TreeModel and support for > slices to TreeModelRow > >--- > gi/overrides/Gtk.py | 26 +++++++++++++++++++- > tests/test_overrides.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 81 insertions(+), 2 deletions(-) > >diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py >index 2aea6ad..3d82276 100644 >--- a/gi/overrides/Gtk.py >+++ b/gi/overrides/Gtk.py >@@ -734,6 +734,10 @@ class TreeModel(Gtk.TreeModel): > raise IndexError("could not find tree path '%s'" % key) > return TreeModelRow(self, aiter) > >+ def __setitem__(self, key, value): >+ row = self[key] >+ self.set_row(row.iter, value) >+ > def __iter__(self): > return TreeModelRowIter(self, self.get_iter_first()) > >@@ -781,6 +785,8 @@ class TreeModel(Gtk.TreeModel): > def set_row(self, treeiter, row): > # TODO: Accept a dictionary for row > # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name}) What is this for? Is this because str are iterable also? >+ if isinstance(row, str): >+ raise TypeError('Expected a list or tuple, but got str') > n_columns = self.get_n_columns() > if len(row) != n_columns: >@@ -1033,6 +1039,12 @@ class TreeModelRow(object): > elif key < 0: > key = self._convert_negative_index(key) > return self.model.get_value(self.iter, key) >+ elif isinstance(key, slice): >+ start, stop, step = key.indices(self.model.get_n_columns()) >+ alist = [] xrange is not supported in python 3. Essentially range is a generator in python 3. Just use range, don't try to use fancy logic. If it is really a performance issue file another bug and we will look at it then. >+ for i in xrange(start, stop, step): >+ alist.append(self.model.get_value(self.iter, i)) >+ return alist > else: > raise TypeError("indices must be integers, not %s" % type(key).__name__) > >@@ -1042,9 +1054,19 @@ class TreeModelRow(object): > raise IndexError("column index is out of bounds: %d" % key) > elif key < 0: > key = self._convert_negative_index(key) >- return self.model.set_value(self.iter, key, value) >+ self.model.set_value(self.iter, key, value) >+ elif isinstance(key, slice): >+ start, stop, step = key.indices(self.model.get_n_columns()) >+ indexList = range(start, stop, step) >+ if len(indexList) != len(value): >+ raise ValueError( >+ "attempt to assign sequence of size %d to slice of size %d" >+ % (len(value), len(indexList))) >+ >+ for i,v in enumerate(indexList): >+ self.model.set_value(self.iter, v, value[i]) > else: >- raise TypeError("indices must be integers, not %s" % type(key).__name__) >+ raise TypeError("index must be an integer or slice, not %s" % type(key).__name__) > > def _convert_negative_index(self, index): > new_index = self.model.get_n_columns() + index >diff --git a/tests/test_overrides.py b/tests/test_overrides.py >index 427f4d1..2f25121 100644 >--- a/tests/test_overrides.py >+++ b/tests/test_overrides.py >@@ -1246,6 +1246,63 @@ class TestGtk(unittest.TestCase): > self.assertRaises(ValueError, tree_store.get, aiter, 1, 100) > self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10')) > >+ def test_tree_model_edit(self): >+ model = Gtk.ListStore(int, str, float) >+ model.append([1, "one", -0.1]) >+ model.append([2, "two", -0.2]) >+ >+ def set_row(value): >+ model[1] = value >+ >+ self.assertRaises(TypeError, set_row, 3) >+ self.assertRaises(TypeError, set_row, "three") >+ self.assertRaises(ValueError, set_row, []) >+ self.assertRaises(ValueError, set_row, [3, "three"]) >+ >+ model[0] = (3, "three", -0.3) >+ >+ def test_tree_row_slice(self): >+ model = Gtk.ListStore(int, str, float) >+ model.append([1, "one", -0.1]) >+ >+ self.assertEqual([1, "one", -0.1], model[0][:]) >+ self.assertEqual([1, "one"], model[0][:2]) >+ self.assertEqual(["one", -0.1], model[0][1:]) >+ self.assertEqual(["one"], model[0][1:-1]) >+ self.assertEqual([1], model[0][:-2]) >+ self.assertEqual([], model[0][5:]) >+ self.assertEqual([1, -0.1], model[0][0:3:2]) >+ >+ model[0][:] = (2, "two", -0.2) >+ self.assertEqual([2, "two", -0.2], model[0][:]) >+ >+ model[0][:2] = (3, "three") >+ self.assertEqual([3, "three", -0.2], model[0][:]) >+ >+ model[0][1:] = ("four", -0.4) >+ self.assertEqual([3, "four", -0.4], model[0][:]) >+ >+ model[0][1:-1] = ("five",) >+ self.assertEqual([3, "five", -0.4], model[0][:]) >+ >+ model[0][0:3:2] = (6, -0.6) >+ self.assertEqual([6, "five", -0.6], model[0][:]) >+ >+ def set_row1(): >+ model[0][5:] = ("doesn't", "matter",) >+ >+ self.assertRaises(ValueError, set_row1) >+ >+ def set_row2(): >+ model[0][:1] = (0, "zero", 0) >+ >+ self.assertRaises(ValueError, set_row2) >+ >+ def set_row3(): >+ model[0][:2] = ("0", 0) >+ >+ self.assertRaises(ValueError, set_row3) >+ > def test_tree_view_column(self): > cell = Gtk.CellRendererText() > column = Gtk.TreeViewColumn(title='This is just a test', >-- >1.7.6 >
Feel free to commit after fixing the xrange issue.
(In reply to comment #2) > > What is this for? Is this because str are iterable also? > > >+ if isinstance(row, str): > >+ raise TypeError('Expected a list or tuple, but got str') I added this to error out on calls such as model[aiter] = "something" which should be model[aiter] = ["something",]
Replaced xrange with range and committed as commit 01142060ae7d71a8a1f7d3e9bbc6f52e65f01c8d