Merge lp:~pitti/software-center/deprecated-ctors into lp:software-center

Proposed by Martin Pitt
Status: Merged
Approved by: dobey
Approved revision: 3322
Merged at revision: 3321
Proposed branch: lp:~pitti/software-center/deprecated-ctors
Merge into: lp:software-center
Diff against target: 297 lines (+34/-34)
12 files modified
softwarecenter/ui/gtk3/dialogs/dialog_tos.py (+1/-1)
softwarecenter/ui/gtk3/panes/historypane.py (+4/-4)
softwarecenter/ui/gtk3/views/appdetailsview.py (+3/-3)
softwarecenter/ui/gtk3/widgets/actionbar.py (+6/-6)
softwarecenter/ui/gtk3/widgets/menubutton.py (+3/-3)
softwarecenter/ui/gtk3/widgets/recommendations.py (+2/-2)
softwarecenter/ui/gtk3/widgets/reviews.py (+1/-1)
softwarecenter/ui/gtk3/widgets/spinner.py (+3/-3)
softwarecenter/ui/gtk3/widgets/videoplayer.py (+1/-1)
tests/gtk3/test_lp1048912.py (+1/-1)
tests/gtk3/test_spinner.py (+1/-1)
tests/gtk3/windows.py (+8/-8)
To merge this branch: bzr merge lp:~pitti/software-center/deprecated-ctors
Reviewer Review Type Date Requested Status
Michael Vogt Approve
Review via email: mp+201158@code.launchpad.net

Commit message

Stop using deprecated GObject constructors with positional arguments.

Description of the change

Stop using deprecated GObject constructors with positional arguments

See commit message and https://wiki.gnome.org/PyGObject/InitializerDeprecations
for details.

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote :

Hi Martin,

thanks a bunch for your branch. It looks great.

However, one question. The "InitializerDeprecations" reads:
  "Additionally, positional arguments and non-standard keyword argument names will also show deprecation warnings."
But I do still see positional arguments sometimes. Am I just not fully understanding the wiki page?

E.g. gtk_label_new() does not need a keyword argument:
- self.label = Gtk.Label(_(u"One moment, please\u2026"))
+ self.label = Gtk.Label.new(_(u"One moment, please\u2026"))

But:
- self.button_apply = Gtk.Button(_("Apply Changes"))
+ self.button_apply = Gtk.Button(label=_("Apply Changes"))
does? Just to understand the change, is the above prefered over "Gtk.Button.new_with_label(_("Apply Changes"))" ?

And if its preferable, why is this so? It seems inconsitent to use:
  label = Gtk.Label.new("foo")
but
  button = Gtk.Button(label="foo")

Wouldn't: "label = Gtk.Label(label="foo")" be more consistent (assumging that gtk_label_new("foo") is equivalent to gtk_object_newv with setting the label property). Or alternatively using Gtk.Button.new_with_label("foo") ? I.e. either using new() and new_with_() or using keyword based constructors that map to g_object_newv().

I hope the above make sense and I'm curious about whats considered best-practise here :)

Thanks!
 Michael

Revision history for this message
Martin Pitt (pitti) wrote :

Hey Michael,

Michael Vogt [2014-01-10 19:19 -0000]:
> E.g. gtk_label_new() does not need a keyword argument:

That's correct. gtk_label_new() is one specific constructor for
GtkLabel:
> + self.label = Gtk.Label.new(_(u"One moment, please\u2026"))

while the old one is the generic GObject constructor:

> - self.label = Gtk.Label(_(u"One moment, please\u2026"))

I. e. equivalent to g_object_new(GtkLabel, prop1=val1, ...)

>
> But:
> - self.button_apply = Gtk.Button(_("Apply Changes"))
> + self.button_apply = Gtk.Button(label=_("Apply Changes"))
> does?

Right, that's the GObject constructor in both cases. With the
appropriate GtkButton constructor this would bt

  Gtk.Button.new_with_label("Apply Changes")

corresponding to gtk_button_new_with_label().

> Just to understand the change, is the above prefered over
> "Gtk.Button.new_with_label(_("Apply Changes"))" ?

There is no strict preference. Sometimes one is a tad more convenient
than the other. Personally I usually prefer the real class
constructors, as they avoid bugs when the class' _new constructor does
more things than just allocate the object and set properties (doing
other things is a bug, but they do happen with some classes).

So we can certainly use one style consistently, but I didn't try too
hard as the existing code already uses both styles. If you have a
preference there I can change the code to always use one style, that
would touch a lot more code, though.

Thanks,

Martin
--
Martin Pitt | http://www.piware.de
Ubuntu Developer (www.ubuntu.com) | Debian Developer (www.debian.org)

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks for this explanation, I have a better understanding about the change now :) I agree that it makes more sense to keep the branch small for now. So +1 for the branch from me.

review: Approve
Revision history for this message
Kiwinote (kiwinote) wrote :

Hi Martin - any chance you might be able to help clarify a few of these things?

In the merge proposal I see a few lines in the form of the below, this gives an error:
>>> Gtk.Label.new(label='text')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: new() got an unexpected keyword argument 'label'

A few more general queries:

From reading the rational on the wiki page it sounds like it is beneficial/advisable to use
>>> Gtk.Label.new() # ie without arguments, will later call set_markup or so
<Label object at 0x7fcf8faa5fa0 (GtkLabel at 0x1761420)>
instead of
>>> Gtk.Label()
<Label object at 0x7fcf8faa5a50 (GtkLabel at 0x17612c0)>
due to performance (sounds like good reasoning, but just checking)?

If so, this then means that where I used to use
>>> Gtk.VBox()
<VBox object at 0x7f85e5968a50 (GtkVBox at 0x274a0f0)>
I now get
>>> Gtk.VBox.new()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: new() takes exactly 2 arguments (0 given)
so it is preferable to be more explicit and use the below?
>>> Gtk.VBox.new(False, 0)
<VBox object at 0x7f85d80c3cd0 (GtkVBox at 0x274a210)>

When subclassing I used to use something like this
class SomethingBox(Gtk.Box):
    def __init__(self):
        Gtk.Box.__init__(self, Gtk.Orientation.HORIZONTAL, 0)
SomethingBox()
which now gives the deprecation warning
__main__:3: PyGTKDeprecationWarning: Using positional arguments with the GObject constructor has been deprecated. Please specify keywords for homogeneous, spacing or use a class specific constructor. See: https://wiki.gnome.org/PyGObject/InitializerDeprecations
I see that I can solve this by using
class SomethingBox(Gtk.Box):
    def __init__(self):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
SomethingBox()
but this leads to very long lines - is there a way I can use the much shorter Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) in some way instead, or is the above the preferred way?

Thanks!

3322. By Martin Pitt

fix constructors harder

Revision history for this message
Martin Pitt (pitti) wrote :

Hey Kiwinote,

Kiwinote [2014-01-13 10:24 -0000]:
> In the merge proposal I see a few lines in the form of the below, this gives an error:
> >>> Gtk.Label.new(label='text')

Oops, thanks for spotting. Fixed.

> From reading the rational on the wiki page it sounds like it is beneficial/advisable to use
> >>> Gtk.Label.new() # ie without arguments, will later call set_markup or so
> <Label object at 0x7fcf8faa5fa0 (GtkLabel at 0x1761420)>
> instead of
> >>> Gtk.Label()
> <Label object at 0x7fcf8faa5a50 (GtkLabel at 0x17612c0)>
> due to performance (sounds like good reasoning, but just checking)?

In theory the GObject ctor (Gtk.Label()) should be a tad faster as it
skips gtk_label_new(). But the latter is rather trivial, so with the
overhead of pygobject/GI/python I doubt that there is a
meaningful/measurable difference between those.

> >>> Gtk.VBox.new()
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> TypeError: new() takes exactly 2 arguments (0 given)

Right, that's gtk_vbox_new() which has two positional arguments.

> so it is preferable to be more explicit and use the below?
> >>> Gtk.VBox.new(False, 0)
> <VBox object at 0x7f85d80c3cd0 (GtkVBox at 0x274a210)>

That or explicitly setting the homogeneous and spacing properties.
Again, matter of taste, there are no obvious pros/cons for those (I
slightly prefer the explicit constructors like the above).

> When subclassing I used to use something like this
> class SomethingBox(Gtk.Box):
> def __init__(self):
> Gtk.Box.__init__(self, Gtk.Orientation.HORIZONTAL, 0)
> SomethingBox()
> which now gives the deprecation warning
> __main__:3: PyGTKDeprecationWarning: Using positional arguments with the GObject constructor has been deprecated. Please specify keywords for homogeneous, spacing or use a class specific constructor. See: https://wiki.gnome.org/PyGObject/InitializerDeprecations

Indeed that's a bit confusing. You can't really call a C constructor
in __init__(), as at that point the C object is already allocated.

> I see that I can solve this by using
> class SomethingBox(Gtk.Box):
> def __init__(self):
> Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
> SomethingBox()
> but this leads to very long lines - is there a way I can use the much shorter Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) in some way instead, or is the above the preferred way?

If you want to use the real constructors, it's necessary to override
__new__() instead:

  class SomethingBox(Gtk.Box):
      def __new__(cls, arg1, ...):
         return Gtk.Box.new(arg, ...)

Revision history for this message
Kiwinote (kiwinote) wrote :

cool, thanks for the info!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'softwarecenter/ui/gtk3/dialogs/dialog_tos.py'
2--- softwarecenter/ui/gtk3/dialogs/dialog_tos.py 2012-12-14 16:44:25 +0000
3+++ softwarecenter/ui/gtk3/dialogs/dialog_tos.py 2014-01-13 10:52:04 +0000
4@@ -40,7 +40,7 @@
5 self.add_button(_("Decline"), Gtk.ResponseType.NO)
6 self.add_button(_("Accept"), Gtk.ResponseType.YES)
7 # label
8- self.label = Gtk.Label(_(u"One moment, please\u2026"))
9+ self.label = Gtk.Label.new(_(u"One moment, please\u2026"))
10 self.label.show()
11 # add the label
12 box = self.get_action_area()
13
14=== modified file 'softwarecenter/ui/gtk3/panes/historypane.py'
15--- softwarecenter/ui/gtk3/panes/historypane.py 2012-11-28 17:36:38 +0000
16+++ softwarecenter/ui/gtk3/panes/historypane.py 2014-01-13 10:52:04 +0000
17@@ -86,25 +86,25 @@
18 self.toolbar.set_style(Gtk.ToolbarStyle.TEXT)
19 self.pack_start(self.toolbar, False, True, 0)
20
21- all_action = Gtk.RadioAction('filter_all', _('All Changes'), None,
22+ all_action = Gtk.RadioAction.new('filter_all', _('All Changes'), None,
23 None, self.ALL)
24 all_action.connect('changed', self.change_filter)
25 all_button = all_action.create_tool_item()
26 self.toolbar.insert(all_button, 0)
27
28- installs_action = Gtk.RadioAction('filter_installs',
29+ installs_action = Gtk.RadioAction.new('filter_installs',
30 _('Installations'), None, None, self.INSTALLED)
31 installs_action.join_group(all_action)
32 installs_button = installs_action.create_tool_item()
33 self.toolbar.insert(installs_button, 1)
34
35- upgrades_action = Gtk.RadioAction(
36+ upgrades_action = Gtk.RadioAction.new(
37 'filter_upgrads', _('Updates'), None, None, self.UPGRADED)
38 upgrades_action.join_group(all_action)
39 upgrades_button = upgrades_action.create_tool_item()
40 self.toolbar.insert(upgrades_button, 2)
41
42- removals_action = Gtk.RadioAction(
43+ removals_action = Gtk.RadioAction.new(
44 'filter_removals', _('Removals'), None, None, self.REMOVED)
45 removals_action.join_group(all_action)
46 removals_button = removals_action.create_tool_item()
47
48=== modified file 'softwarecenter/ui/gtk3/views/appdetailsview.py'
49--- softwarecenter/ui/gtk3/views/appdetailsview.py 2013-10-08 15:13:59 +0000
50+++ softwarecenter/ui/gtk3/views/appdetailsview.py 2014-01-13 10:52:04 +0000
51@@ -699,14 +699,14 @@
52 self.applying = False
53
54 # TRANSLATORS: Free here means Gratis
55- self.label_price = Gtk.Label(_("Free"))
56+ self.label_price = Gtk.Label.new(_("Free"))
57 self.hbox.pack_start(self.label_price, False, False, 0)
58
59 self.hbuttonbox = Gtk.HButtonBox()
60 self.hbuttonbox.set_layout(Gtk.ButtonBoxStyle.END)
61- self.button_apply = Gtk.Button(_("Apply Changes"))
62+ self.button_apply = Gtk.Button(label=_("Apply Changes"))
63 self.button_apply.connect("clicked", self._on_button_apply_clicked)
64- self.button_cancel = Gtk.Button(_("Cancel"))
65+ self.button_cancel = Gtk.Button(label=_("Cancel"))
66 self.button_cancel.connect("clicked", self.addons_manager.restore)
67 self.hbox.pack_end(self.button_apply, False, False, 0)
68 self.hbox.pack_end(self.button_cancel, False, False, 0)
69
70=== modified file 'softwarecenter/ui/gtk3/widgets/actionbar.py'
71--- softwarecenter/ui/gtk3/widgets/actionbar.py 2012-12-14 16:44:25 +0000
72+++ softwarecenter/ui/gtk3/widgets/actionbar.py 2014-01-13 10:52:04 +0000
73@@ -87,7 +87,7 @@
74 overwrite = self.get_button(id)
75 if overwrite:
76 self._btns.remove(overwrite)
77- btn = Gtk.Button(label)
78+ btn = Gtk.Button(label=label)
79 btn.connect("clicked", self._callback(result, result_args))
80 btn.id = id
81 btn.show()
82@@ -129,7 +129,7 @@
83 self._label_text = text
84
85 for i, text_for_label in enumerate(sections):
86- action_bar_item = Gtk.Label(text_for_label)
87+ action_bar_item = Gtk.Label.new(text_for_label)
88 # every second item in the bar is a clickable link,
89 # this is because the text.split("_") earlier (all links
90 # are put into "_foo_"
91@@ -363,10 +363,10 @@
92 def unset_func(*args):
93 bar.unset_label()
94
95- addbtn = Gtk.Button("Add Button")
96- rmvbtn = Gtk.Button("Remove Button")
97- setbtn = Gtk.Button("Set Label")
98- unsetbtn = Gtk.Button("Unset Label")
99+ addbtn = Gtk.Button(label="Add Button")
100+ rmvbtn = Gtk.Button(label="Remove Button")
101+ setbtn = Gtk.Button(label="Set Label")
102+ unsetbtn = Gtk.Button(label="Unset Label")
103 addbtn.connect("clicked", add_func)
104 rmvbtn.connect("clicked", rmv_func)
105 setbtn.connect("clicked", set_func)
106
107=== modified file 'softwarecenter/ui/gtk3/widgets/menubutton.py'
108--- softwarecenter/ui/gtk3/widgets/menubutton.py 2012-12-14 16:44:25 +0000
109+++ softwarecenter/ui/gtk3/widgets/menubutton.py 2014-01-13 10:52:04 +0000
110@@ -30,7 +30,7 @@
111 if icon:
112 box.pack_start(icon, False, True, 1)
113 if label:
114- box.pack_start(Gtk.Label(label), True, True, 0)
115+ box.pack_start(Gtk.Label.new(label), True, True, 0)
116
117 arrow = Gtk.Arrow.new(Gtk.ArrowType.DOWN, Gtk.ShadowType.OUT)
118 box.pack_start(arrow, False, False, 1)
119@@ -102,14 +102,14 @@
120 menuitem2.show()
121
122 box1 = Gtk.Box()
123- box1.pack_start(Gtk.Label("something before to show we don't cheat"),
124+ box1.pack_start(Gtk.Label.new("something before to show we don't cheat"),
125 True, True, 0)
126 win.add(box1)
127
128 box2 = Gtk.Box()
129 box2.set_orientation(Gtk.Orientation.VERTICAL)
130 box1.pack_start(box2, True, True, 0)
131- box2.pack_start(Gtk.Label("first label with multiple line"), True, True, 0)
132+ box2.pack_start(Gtk.Label.new("first label with multiple line"), True, True, 0)
133
134 image = Gtk.Image.new_from_stock(Gtk.STOCK_PROPERTIES, Gtk.IconSize.BUTTON)
135 label = "fooo"
136
137=== modified file 'softwarecenter/ui/gtk3/widgets/recommendations.py'
138--- softwarecenter/ui/gtk3/widgets/recommendations.py 2012-12-14 16:44:25 +0000
139+++ softwarecenter/ui/gtk3/widgets/recommendations.py 2014-01-13 10:52:04 +0000
140@@ -243,9 +243,9 @@
141 self.add(self.recommended_for_you_content)
142
143 # opt in button
144- self.opt_in_button = Gtk.Button(_(self.TURN_ON_RECOMMENDATIONS_TEXT))
145+ self.opt_in_button = Gtk.Button(label=_(self.TURN_ON_RECOMMENDATIONS_TEXT))
146 self.opt_in_button.connect("clicked", self._on_opt_in_button_clicked)
147- hbox = Gtk.Box(Gtk.Orientation.HORIZONTAL)
148+ hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
149 hbox.pack_start(self.opt_in_button, False, False, 0)
150 self.recommended_for_you_content.pack_start(hbox, False, False, 0)
151
152
153=== modified file 'softwarecenter/ui/gtk3/widgets/reviews.py'
154--- softwarecenter/ui/gtk3/widgets/reviews.py 2012-12-14 16:44:25 +0000
155+++ softwarecenter/ui/gtk3/widgets/reviews.py 2014-01-13 10:52:04 +0000
156@@ -303,7 +303,7 @@
157 # check and make it unreliable
158 # if self.reviews and len(self.reviews) % REVIEWS_BATCH_PAGE_SIZE == 0:
159 if self.reviews:
160- button = Gtk.Button(_("Check for more reviews"))
161+ button = Gtk.Button(label=_("Check for more reviews"))
162 button.connect("clicked", self._on_more_reviews_clicked)
163 button.show()
164 self.vbox.pack_start(button, False, False, 0)
165
166=== modified file 'softwarecenter/ui/gtk3/widgets/spinner.py'
167--- softwarecenter/ui/gtk3/widgets/spinner.py 2012-11-28 15:54:20 +0000
168+++ softwarecenter/ui/gtk3/widgets/spinner.py 2014-01-13 10:52:04 +0000
169@@ -49,7 +49,7 @@
170 self.spinner.set_size_request(24, 24)
171
172 # use a table for the spinner (otherwise the spinner is massive!)
173- spinner_table = Gtk.Table(3, 3, False)
174+ spinner_table = Gtk.Table.new(3, 3, False)
175 self.spinner_label = Gtk.Label()
176 self.spinner_label.set_markup('<big>%s</big>' % label_text)
177 spinner_vbox = Gtk.VBox()
178@@ -98,8 +98,8 @@
179 if not SOFTWARE_CENTER_DEBUG_TABS:
180 self.set_show_tabs(False)
181 self.set_show_border(False)
182- self.append_page(content, Gtk.Label("content"))
183- self.append_page(self.spinner_view, Gtk.Label("spinner"))
184+ self.append_page(content, Gtk.Label.new("content"))
185+ self.append_page(self.spinner_view, Gtk.Label.new("spinner"))
186
187 def _unmask_view_spinner(self):
188 # start is actually start_and_show()
189
190=== modified file 'softwarecenter/ui/gtk3/widgets/videoplayer.py'
191--- softwarecenter/ui/gtk3/widgets/videoplayer.py 2012-08-20 09:09:45 +0000
192+++ softwarecenter/ui/gtk3/widgets/videoplayer.py 2014-01-13 10:52:04 +0000
193@@ -103,7 +103,7 @@
194 # gtk ui
195 self.movie_window = Gtk.DrawingArea()
196 self.pack_start(self.movie_window, True, True, 0)
197- self.button = Gtk.Button(_("Play"))
198+ self.button = Gtk.Button(label=_("Play"))
199 self.pack_start(self.button, False, True, 0)
200 self.button.connect("clicked", self.on_play_clicked)
201 # player
202
203=== modified file 'tests/gtk3/test_lp1048912.py'
204--- tests/gtk3/test_lp1048912.py 2012-11-28 15:52:31 +0000
205+++ tests/gtk3/test_lp1048912.py 2014-01-13 10:52:04 +0000
206@@ -19,7 +19,7 @@
207 def add_tiles(tile_grid):
208 print "add_tiles"
209 for i in range(10):
210- b = Gtk.Button("tile %i" % i)
211+ b = Gtk.Button(label="tile %i" % i)
212 b.show()
213 tile_grid.pack_start(b, False, False, 0)
214 print "/add_tiles"
215
216=== modified file 'tests/gtk3/test_spinner.py'
217--- tests/gtk3/test_spinner.py 2012-11-28 16:31:53 +0000
218+++ tests/gtk3/test_spinner.py 2014-01-13 10:52:04 +0000
219@@ -20,7 +20,7 @@
220 self._interval = None
221 self._callback = None
222
223- self.content = Gtk.Label('My test')
224+ self.content = Gtk.Label.new('My test')
225 self.content.show()
226 self.addCleanup(self.content.hide)
227 self.addCleanup(self.content.destroy)
228
229=== modified file 'tests/gtk3/windows.py'
230--- tests/gtk3/windows.py 2013-09-06 17:01:24 +0000
231+++ tests/gtk3/windows.py 2014-01-13 10:52:04 +0000
232@@ -261,9 +261,9 @@
233 # create global AppManager instance
234 manager = appmanager.ApplicationManager(db, backend, icons)
235
236- navhistory_back_action = Gtk.Action("navhistory_back_action", "Back",
237+ navhistory_back_action = Gtk.Action.new("navhistory_back_action", "Back",
238 "Back", None)
239- navhistory_forward_action = Gtk.Action("navhistory_forward_action",
240+ navhistory_forward_action = Gtk.Action.new("navhistory_forward_action",
241 "Forward", "Forward", None)
242
243 zl = "softwarecenter.backend.zeitgeist_logger.ZeitgeistLogger";
244@@ -422,7 +422,7 @@
245
246 scroll = Gtk.ScrolledWindow()
247 scroll.add(lobby_view)
248- notebook.append_page(scroll, Gtk.Label(label="Lobby"))
249+ notebook.append_page(scroll, Gtk.Label.new("Lobby"))
250
251 subcat_cat = None
252 for cat in lobby_view.categories:
253@@ -440,7 +440,7 @@
254
255 scroll = Gtk.ScrolledWindow()
256 scroll.add(subcat_view)
257- notebook.append_page(scroll, Gtk.Label(label="Subcats"))
258+ notebook.append_page(scroll, Gtk.Label.new("Subcats"))
259
260 win = get_test_window(child=notebook, width=800, height=800)
261 win.set_data("subcat", subcat_view)
262@@ -842,7 +842,7 @@
263 (EXAMPLE4, ''))
264
265 vb = Gtk.VBox()
266- b = Gtk.Button('Next test description >>')
267+ b = Gtk.Button(label='Next test description >>')
268 b.position = 0
269 vb.pack_start(b, False, False, 0)
270 scroll = Gtk.ScrolledWindow()
271@@ -971,7 +971,7 @@
272
273
274 def get_test_spinner_window():
275- label = Gtk.Label("foo")
276+ label = Gtk.Label.new("foo")
277 spinner_notebook = spinner.SpinnerNotebook(label, "random msg")
278
279 win = get_test_window(child=spinner_notebook)
280@@ -987,7 +987,7 @@
281 win = get_test_window(child=vb)
282
283 vb.add(Gtk.Button())
284- vb.add(Gtk.Label(label="BLAHHHHHH"))
285+ vb.add(Gtk.Label.new("BLAHHHHHH"))
286
287 star = stars.Star()
288 star.set_n_stars(5)
289@@ -1079,7 +1079,7 @@
290
291 win.set_data("screenshot_thumbnail_widget", t)
292
293- b = Gtk.Button('A button for cycle testing')
294+ b = Gtk.Button(label='A button for cycle testing')
295 vb.pack_start(b, False, False, 8)
296 win.set_data("screenshot_button_widget", b)
297 vb.pack_start(frame, True, True, 0)