Merge lp:~sinzui/bzr-gtk/precise-diff-0 into lp:bzr-gtk

Proposed by Curtis Hovey
Status: Merged
Merged at revision: 772
Proposed branch: lp:~sinzui/bzr-gtk/precise-diff-0
Merge into: lp:bzr-gtk
Diff against target: 187 lines (+65/-23)
4 files modified
diff.py (+13/-4)
tests/__init__.py (+19/-0)
tests/test_commit.py (+1/-19)
tests/test_diff.py (+32/-0)
To merge this branch: bzr merge lp:~sinzui/bzr-gtk/precise-diff-0
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) Approve
Review via email: mp+89759@code.launchpad.net

Commit message

Do not update the DiffWidget when it is being destroyed.

Description of the change

This is a fix for bug 914363, which is private so I cannot see it.
It may not even be reported against bzr-gtk. Everyone can see my
bug 920525 that Apport says is a duplicate.

This is a bzr-gtk gdiff issue. The diff works, but an error happens when
the window is closed. This may be the same kind of issue I fixed in
gcommit where the callback is called while the window is being
destroyed. In that case, The treeview still existed, but it's model and
state were None.

Traceback (most recent call last):
  File "/home/curtis/.bazaar/plugins/gtk/diff.py", line 391, in _treeview_cursor_cb
    specific_files = [ self.model[path][1] ]
  File "/usr/lib/python2.7/dist-packages/gi/overrides/Gtk.py", line 730, in __getitem__
    aiter = self.get_iter(key)
  File "/usr/lib/python2.7/dist-packages/gi/overrides/Gtk.py", line 744, in get_iter
    path = TreePath(path)
  File "/usr/lib/python2.7/dist-packages/gi/overrides/Gtk.py", line 1110, in __new__
    if len(path) == 0:
TypeError: object of type 'NoneType' has no len()

--------------------------------------------------------------------

RULES

    * Do not attempt to update the diff_view if the path is None.
    * Move the MockMethod helper to a common module so that it can be used
      by any test case
    * Update the DiffWidget to guard the calls to show(), subclasses the
      widget so that tests can run without rendering.

QA

    Using Precise:
    * Branch any project
    * bzr gdiff
    * See no changes
    * close the window
    * Verify there is no traceback in the console.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'diff.py'
--- diff.py 2011-09-05 03:44:26 +0000
+++ diff.py 2012-01-23 18:27:25 +0000
@@ -284,6 +284,9 @@
284 """Diff widget284 """Diff widget
285285
286 """286 """
287
288 SHOW_WIDGETS = True
289
287 def __init__(self):290 def __init__(self):
288 super(DiffWidget, self).__init__()291 super(DiffWidget, self).__init__()
289292
@@ -292,7 +295,8 @@
292 scrollwin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)295 scrollwin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
293 scrollwin.set_shadow_type(Gtk.ShadowType.IN)296 scrollwin.set_shadow_type(Gtk.ShadowType.IN)
294 self.pack1(scrollwin)297 self.pack1(scrollwin)
295 scrollwin.show()298 if self.SHOW_WIDGETS:
299 scrollwin.show()
296 300
297 self.model = Gtk.TreeStore(str, str)301 self.model = Gtk.TreeStore(str, str)
298 self.treeview = Gtk.TreeView(model=self.model)302 self.treeview = Gtk.TreeView(model=self.model)
@@ -300,7 +304,8 @@
300 self.treeview.set_search_column(1)304 self.treeview.set_search_column(1)
301 self.treeview.connect("cursor-changed", self._treeview_cursor_cb)305 self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
302 scrollwin.add(self.treeview)306 scrollwin.add(self.treeview)
303 self.treeview.show()307 if self.SHOW_WIDGETS:
308 self.treeview.show()
304309
305 cell = Gtk.CellRendererText()310 cell = Gtk.CellRendererText()
306 cell.set_property("width-chars", 20)311 cell.set_property("width-chars", 20)
@@ -321,7 +326,8 @@
321 if getattr(self, 'diff_view', None) is None:326 if getattr(self, 'diff_view', None) is None:
322 self.diff_view = DiffFileView()327 self.diff_view = DiffFileView()
323 self.pack2(self.diff_view)328 self.pack2(self.diff_view)
324 self.diff_view.show()329 if self.SHOW_WIDGETS:
330 self.diff_view.show()
325 for oldname, newname, patch in sections:331 for oldname, newname, patch in sections:
326 self.diff_view._diffs[newname] = str(patch)332 self.diff_view._diffs[newname] = str(patch)
327 if newname is None:333 if newname is None:
@@ -338,7 +344,8 @@
338 if getattr(self, 'diff_view', None) is None:344 if getattr(self, 'diff_view', None) is None:
339 self.diff_view = DiffView()345 self.diff_view = DiffView()
340 self.pack2(self.diff_view)346 self.pack2(self.diff_view)
341 self.diff_view.show()347 if self.SHOW_WIDGETS:
348 self.diff_view.show()
342 self.diff_view.set_trees(rev_tree, parent_tree)349 self.diff_view.set_trees(rev_tree, parent_tree)
343 self.rev_tree = rev_tree350 self.rev_tree = rev_tree
344 self.parent_tree = parent_tree351 self.parent_tree = parent_tree
@@ -388,6 +395,8 @@
388 def _treeview_cursor_cb(self, *args):395 def _treeview_cursor_cb(self, *args):
389 """Callback for when the treeview cursor changes."""396 """Callback for when the treeview cursor changes."""
390 (path, col) = self.treeview.get_cursor()397 (path, col) = self.treeview.get_cursor()
398 if path is None:
399 return
391 specific_files = [ self.model[path][1] ]400 specific_files = [ self.model[path][1] ]
392 if specific_files == [ None ]:401 if specific_files == [ None ]:
393 return402 return
394403
=== modified file 'tests/__init__.py'
--- tests/__init__.py 2011-09-04 20:04:03 +0000
+++ tests/__init__.py 2012-01-23 18:27:25 +0000
@@ -31,3 +31,22 @@
31 basic_tests.addTest(loader.loadTestsFromModuleNames(31 basic_tests.addTest(loader.loadTestsFromModuleNames(
32 ["%s.%s" % (__name__, tmn) for tmn in testmod_names]))32 ["%s.%s" % (__name__, tmn) for tmn in testmod_names]))
33 return basic_tests33 return basic_tests
34
35
36class MockMethod():
37
38 @classmethod
39 def bind(klass, test_instance, obj, method_name):
40 original_method = getattr(obj, method_name)
41 test_instance.addCleanup(setattr, obj, method_name, original_method)
42 setattr(obj, method_name, klass())
43
44 def __init__(self):
45 self.called = False
46 self.args = None
47 self.kwargs = None
48
49 def __call__(self, *args, **kwargs):
50 self.called = True
51 self.args = args
52 self.kwargs = kwargs
3453
=== modified file 'tests/test_commit.py'
--- tests/test_commit.py 2012-01-22 16:18:06 +0000
+++ tests/test_commit.py 2012-01-23 18:27:25 +0000
@@ -36,6 +36,7 @@
36 commitmsgs,36 commitmsgs,
37 )37 )
38from bzrlib.plugins.gtk.commitmsgs import SavedCommitMessagesManager38from bzrlib.plugins.gtk.commitmsgs import SavedCommitMessagesManager
39from bzrlib.plugins.gtk.tests import MockMethod
3940
4041
41# TODO: All we need is basic ancestry code to test this, we shouldn't need a42# TODO: All we need is basic ancestry code to test this, we shouldn't need a
@@ -143,25 +144,6 @@
143 pass # With no widgets, there are no widgets to fill out144 pass # With no widgets, there are no widgets to fill out
144145
145146
146class MockMethod():
147
148 @classmethod
149 def bind(klass, test_instance, obj, method_name):
150 original_method = getattr(obj, method_name)
151 test_instance.addCleanup(setattr, obj, method_name, original_method)
152 setattr(obj, method_name, klass())
153
154 def __init__(self):
155 self.called = False
156 self.args = None
157 self.kwargs = None
158
159 def __call__(self, *args, **kwargs):
160 self.called = True
161 self.args = args
162 self.kwargs = kwargs
163
164
165class TestCommitDialogSimple(tests.TestCaseWithTransport):147class TestCommitDialogSimple(tests.TestCaseWithTransport):
166148
167 def test_init(self):149 def test_init(self):
168150
=== modified file 'tests/test_diff.py'
--- tests/test_diff.py 2011-09-03 20:58:34 +0000
+++ tests/test_diff.py 2012-01-23 18:27:25 +0000
@@ -18,6 +18,8 @@
18from cStringIO import StringIO18from cStringIO import StringIO
19import os19import os
2020
21from gi.repository import Gtk
22
21from bzrlib import (23from bzrlib import (
22 conflicts,24 conflicts,
23 errors,25 errors,
@@ -32,9 +34,13 @@
32from bzrlib.plugins.gtk.diff import (34from bzrlib.plugins.gtk.diff import (
33 DiffController,35 DiffController,
34 DiffView,36 DiffView,
37 DiffWidget,
35 iter_changes_to_status,38 iter_changes_to_status,
36 MergeDirectiveController,39 MergeDirectiveController,
37 )40 )
41from bzrlib.plugins.gtk.tests import MockMethod
42
43
38eg_diff = """\44eg_diff = """\
39=== modified file 'tests/test_diff.py'45=== modified file 'tests/test_diff.py'
40--- tests/test_diff.py 2008-03-11 13:18:28 +000046--- tests/test_diff.py 2008-03-11 13:18:28 +0000
@@ -99,6 +105,32 @@
99 )105 )
100106
101107
108
109class FakeDiffWidget(DiffWidget):
110
111 SHOW_WIDGETS = False
112
113
114class TestDiffWidget(tests.TestCaseWithTransport):
115
116 def test_treeview_cursor_cb(self):
117 widget = FakeDiffWidget()
118 widget.set_diff_text_sections(
119 [('', None, 'patch1'), ('a', 'a', 'patch2')])
120 widget.treeview.set_cursor(Gtk.TreePath(path=1), None, False)
121 widget._treeview_cursor_cb(None)
122 self.assertTrue('patch2', widget.diff_view.buffer.props.text)
123
124 def test_treeview_cursor_cb_with_destroyed_treeview(self):
125 widget = FakeDiffWidget()
126 widget.set_diff_text_sections(
127 [('', None, 'patch1'), ('a', 'a', 'patch2')])
128 MockMethod.bind(self, widget.diff_view, 'show_diff')
129 widget.treeview.destroy()
130 widget._treeview_cursor_cb(None)
131 self.assertFalse(widget.diff_view.show_diff.called)
132
133
102class MockDiffWidget(object):134class MockDiffWidget(object):
103135
104 def set_diff_text_sections(self, sections):136 def set_diff_text_sections(self, sections):

Subscribers

People subscribed via source and target branches

to all changes: