# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
import contextlib
import unittest
import sys
import gc
import warnings
import timeit
import pytest
from .helper import ignore_gi_deprecation_warnings, capture_glib_warnings
import gi.overrides
import gi.types
from gi.repository import Gio, GLib, GObject
try:
from gi.repository import Gtk, GdkPixbuf, Gdk
PyGTKDeprecationWarning = Gtk.PyGTKDeprecationWarning
Gtk_version = Gtk._version
except ImportError:
Gtk = None
Gtk_version = None
PyGTKDeprecationWarning = None
GdkPixbuf = None
Gdk = None
def gtkver():
if Gtk is None:
return (0, 0, 0)
return (Gtk.get_major_version(),
Gtk.get_minor_version(),
Gtk.get_micro_version())
GTK4 = (Gtk._version == "4.0")
@contextlib.contextmanager
def realized(widget):
"""Makes sure the widget is realized.
view = Gtk.TreeView()
with realized(view):
do_something(view)
"""
if isinstance(widget, Gtk.Window):
toplevel = widget
else:
if Gtk._version == "4.0":
toplevel = widget.get_parent()
else:
toplevel = widget.get_parent_window()
if toplevel is None:
window = Gtk.Window()
if Gtk._version == "4.0":
window.set_child(widget)
else:
window.add(widget)
window.show()
widget.realize()
if Gtk._version == "4.0":
context = GLib.MainContext()
while context.pending():
context.iteration(False)
else:
while Gtk.events_pending():
Gtk.main_iteration()
assert widget.get_realized()
yield widget
if toplevel is None:
if Gtk._version == "4.0":
window.set_child(None)
else:
window.remove(widget)
window.destroy()
if Gtk._version == "4.0":
context = GLib.MainContext()
while context.pending():
context.iteration(False)
else:
while Gtk.events_pending():
Gtk.main_iteration()
@unittest.skipUnless(Gtk, 'Gtk not available')
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_freeze_child_notif():
events = []
def on_notify(widget, spec):
events.append(spec.name)
b = Gtk.Box()
c = Gtk.Button()
c.connect("child-notify", on_notify)
c.freeze_child_notify()
b.pack_start(c, True, True, 0)
b.child_set_property(c, "pack-type", Gtk.PackType.END)
b.child_set_property(c, "pack-type", Gtk.PackType.START)
c.thaw_child_notify()
assert events.count("pack-type") == 1
del events[:]
with c.freeze_child_notify():
b.child_set_property(c, "pack-type", Gtk.PackType.END)
b.child_set_property(c, "pack-type", Gtk.PackType.START)
assert events.count("pack-type") == 1
@unittest.skipUnless(Gtk, 'Gtk not available')
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_menu_popup():
m = Gtk.Menu()
with capture_glib_warnings():
m.popup(None, None, None, None, 0, 0)
m.popdown()
@unittest.skipUnless(Gtk, 'Gtk not available')
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_button_stock():
with capture_glib_warnings():
button = Gtk.Button(stock=Gtk.STOCK_OK)
assert button.props.label == Gtk.STOCK_OK
assert button.props.use_stock
@unittest.skipUnless(Gtk, 'Gtk not available')
def test_wrapper_toggle_refs():
if not GTK4:
BASE = Gtk.Button
else:
BASE = Gtk.Widget
class MyWidget(BASE):
def __init__(self, height):
BASE.__init__(self)
self._height = height
def do_measure(self, orientation, for_size):
if orientation == Gtk.Orientation.VERTICAL:
return (self._height, self._height, -1, -1)
else:
return (0, 0, -1, -1)
def do_get_preferred_height(self):
return (self._height, self._height)
height = 142
w = Gtk.Window()
b = MyWidget(height)
if not GTK4:
w.add(b)
b.show_all()
else:
w.set_child(b)
del b
gc.collect()
gc.collect()
assert w.get_preferred_size().minimum_size.height >= height
@unittest.skipUnless(Gtk, 'Gtk not available')
@ignore_gi_deprecation_warnings
class TestGtk(unittest.TestCase):
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_container(self):
box = Gtk.Box()
self.assertTrue(isinstance(box, Gtk.Box))
self.assertTrue(isinstance(box, Gtk.Container))
self.assertTrue(isinstance(box, Gtk.Widget))
self.assertTrue(box)
label = Gtk.Label()
label2 = Gtk.Label()
box.add(label)
box.add(label2)
self.assertTrue(label in box)
self.assertTrue(label2 in box)
self.assertEqual(len(box), 2)
self.assertTrue(box)
labels = [x for x in box]
self.assertEqual(labels, [label, label2])
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_actions(self):
self.assertEqual(Gtk.Action, gi.overrides.Gtk.Action)
action = Gtk.Action(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY)
self.assertEqual(action.get_name(), "test")
self.assertEqual(action.get_label(), "Test")
self.assertEqual(action.get_tooltip(), "Test Action")
self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
self.assertEqual(Gtk.RadioAction, gi.overrides.Gtk.RadioAction)
action = Gtk.RadioAction(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY, value=1)
self.assertEqual(action.get_name(), "test")
self.assertEqual(action.get_label(), "Test")
self.assertEqual(action.get_tooltip(), "Test Action")
self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
self.assertEqual(action.get_current_value(), 1)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_actiongroup(self):
self.assertEqual(Gtk.ActionGroup, gi.overrides.Gtk.ActionGroup)
action_group = Gtk.ActionGroup(name='TestActionGroup')
callback_data = "callback data"
def test_action_callback_data(action, user_data):
self.assertEqual(user_data, callback_data)
def test_radio_action_callback_data(action, current, user_data):
self.assertEqual(user_data, callback_data)
action_group.add_actions([
('test-action1', None, 'Test Action 1',
None, None, test_action_callback_data),
('test-action2', Gtk.STOCK_COPY, 'Test Action 2',
None, None, test_action_callback_data)], callback_data)
action_group.add_toggle_actions([
('test-toggle-action1', None, 'Test Toggle Action 1',
None, None, test_action_callback_data, False),
('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2',
None, None, test_action_callback_data, True)], callback_data)
action_group.add_radio_actions([
('test-radio-action1', None, 'Test Radio Action 1'),
('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1,
test_radio_action_callback_data,
callback_data)
expected_results = [('test-action1', Gtk.Action),
('test-action2', Gtk.Action),
('test-toggle-action1', Gtk.ToggleAction),
('test-toggle-action2', Gtk.ToggleAction),
('test-radio-action1', Gtk.RadioAction),
('test-radio-action2', Gtk.RadioAction)]
for action in action_group.list_actions():
a = (action.get_name(), type(action))
self.assertTrue(a in expected_results)
expected_results.remove(a)
action.activate()
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_action_group_error_handling(self):
action_group = Gtk.ActionGroup(name='TestActionGroup')
with pytest.raises(TypeError):
action_group.add_actions(42)
with pytest.raises(TypeError):
action_group.add_toggle_actions(42)
with pytest.raises(TypeError):
action_group.add_radio_actions(42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_action_group_no_user_data(self):
action_group = Gtk.ActionGroup(name='TestActionGroup')
called = []
def test_action_callback_no_data(action):
called.append(action)
action_group.add_actions([
('test-action1', None, 'Test Action 1',
None, None, test_action_callback_no_data)])
action_group.add_actions([('test2-action1',)])
action_group.get_action('test-action1').activate()
action_group.add_toggle_actions([
('test-action2', None, 'Test Action 2',
None, None, test_action_callback_no_data)])
action_group.add_toggle_actions([('test2-action2',)])
action_group.get_action('test-action2').activate()
def test_action_callback_no_data_radio(action, current):
called.append(action)
action_group.add_radio_actions([
('test-action3', None, 'Test Action 3', None, None, 0),
('test-action4', None, 'Test Action 4', None, None, 1)],
1, test_action_callback_no_data_radio)
action_group.add_radio_actions([('test2-action3',)])
action = action_group.get_action('test-action3')
assert action.get_current_value() == 1
action.activate()
assert len(called) == 3
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_uimanager(self):
self.assertEqual(Gtk.UIManager, gi.overrides.Gtk.UIManager)
ui = Gtk.UIManager()
ui.add_ui_from_string("""
""")
menubar = ui.get_widget("/menubar1")
self.assertEqual(type(menubar), Gtk.MenuBar)
ag = Gtk.ActionGroup(name="ag1")
ui.insert_action_group(ag)
ag2 = Gtk.ActionGroup(name="ag2")
ui.insert_action_group(ag2)
groups = ui.get_action_groups()
self.assertEqual(ag, groups[-2])
self.assertEqual(ag2, groups[-1])
with pytest.raises(TypeError):
ui.add_ui_from_string(42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_uimanager_nonascii(self):
ui = Gtk.UIManager()
ui.add_ui_from_string(b''.decode('UTF-8'))
mi = ui.get_widget("/menubær1")
self.assertEqual(type(mi), Gtk.MenuBar)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_window_gtk3(self):
# standard Window
w = Gtk.Window()
self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL)
# type works as keyword argument
w = Gtk.Window(type=Gtk.WindowType.POPUP)
self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
class TestWindow(Gtk.Window):
__gtype_name__ = "TestWindow"
# works from builder
builder = Gtk.Builder()
builder.add_from_string('''
''')
self.assertEqual(builder.get_object('win').get_property('type'),
Gtk.WindowType.POPUP)
self.assertEqual(builder.get_object('testwin').get_property('type'),
Gtk.WindowType.TOPLEVEL)
self.assertEqual(builder.get_object('testpop').get_property('type'),
Gtk.WindowType.POPUP)
@unittest.skipUnless(Gtk_version == "4.0", "no GtkWindowType in gtk4")
def test_window_gtk4(self):
w = Gtk.Window()
# check that setting default size works
w.set_default_size(300, 300)
self.assertEqual(w.get_default_size(), (300, 300))
class TestWindow(Gtk.Window):
__gtype_name__ = "TestWindow"
# works from builder
builder = Gtk.Builder()
builder.add_from_string('''
''')
self.assertEqual(builder.get_object("win").get_property("css-name"),
"amazing")
self.assertEqual(builder.get_object("testwin").get_property("css-name"),
"amazing-test")
def test_dialog_classes(self):
self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
if not GTK4:
self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog)
self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog)
self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog)
self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog)
def test_dialog_base(self):
dialog = Gtk.Dialog(title='Foo', modal=True)
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('Foo', dialog.get_title())
self.assertTrue(dialog.get_modal())
@unittest.skipIf(GTK4, "flags not in gtk4")
def test_dialog_deprecations(self):
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.MODAL)
self.assertTrue(dialog.get_modal())
self.assertEqual(len(warn), 1)
self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
self.assertRegex(str(warn[0].message),
'.*flags.*modal.*')
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.DESTROY_WITH_PARENT)
self.assertTrue(dialog.get_destroy_with_parent())
self.assertEqual(len(warn), 1)
self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
self.assertRegex(str(warn[0].message),
'.*flags.*destroy_with_parent.*')
@unittest.skipIf(GTK4, "flags not in gtk4")
def test_dialog_deprecation_stacklevels(self):
# Test warning levels are setup to give the correct filename for
# deprecations in different classes in the inheritance hierarchy.
# Base class
self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
Gtk.Dialog(flags=Gtk.DialogFlags.MODAL)
self.assertEqual(len(warn), 1)
self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*')
# Validate overridden base with overridden sub-class.
self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog)
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL)
self.assertEqual(len(warn), 1)
self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*')
# Validate overridden base with non-overridden sub-class.
self.assertEqual(Gtk.AboutDialog, gi.repository.Gtk.AboutDialog)
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
Gtk.AboutDialog(flags=Gtk.DialogFlags.MODAL)
self.assertEqual(len(warn), 1)
self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*')
def test_dialog_add_buttons(self):
if not GTK4:
# The overloaded "buttons" keyword gives a warning when attempting
# to use it for adding buttons as was available in PyGTK.
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
dialog = Gtk.Dialog(title='Foo', modal=True,
buttons=('test-button1', 1))
self.assertEqual(len(warn), 1)
self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
self.assertRegex(str(warn[0].message),
'.*ButtonsType.*add_buttons.*')
else:
dialog = Gtk.Dialog()
dialog.add_buttons('test-button1', 1)
dialog.add_buttons('test-button2', 2, 'gtk-close', Gtk.ResponseType.CLOSE)
button = dialog.get_widget_for_response(1)
self.assertEqual('test-button1', button.get_label())
button = dialog.get_widget_for_response(2)
self.assertEqual('test-button2', button.get_label())
button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
self.assertEqual('gtk-close', button.get_label())
with pytest.raises(ValueError, match="even number"):
dialog.add_buttons('test-button2', 2, 'gtk-close')
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_dialog_deprecated_attributes(self):
dialog = Gtk.Dialog()
assert dialog.action_area == dialog.get_action_area()
assert dialog.vbox == dialog.get_content_area()
def test_about_dialog(self):
dialog = Gtk.AboutDialog()
self.assertTrue(isinstance(dialog, Gtk.Window))
if not GTK4:
self.assertTrue(isinstance(dialog, Gtk.Dialog))
# AboutDialog is not sub-classed in overrides, make sure
# the mro still injects the base class "add_buttons" override.
self.assertTrue(hasattr(dialog, 'add_buttons'))
def test_message_dialog(self):
dialog = Gtk.MessageDialog(title='message dialog test',
modal=True,
buttons=Gtk.ButtonsType.OK,
text='dude!')
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('message dialog test', dialog.get_title())
self.assertTrue(dialog.get_modal())
text = dialog.get_property('text')
self.assertEqual('dude!', text)
if not GTK4:
dialog.format_secondary_text('2nd text')
self.assertEqual(dialog.get_property('secondary-text'), '2nd text')
self.assertFalse(dialog.get_property('secondary-use-markup'))
dialog.format_secondary_markup('2nd markup')
self.assertEqual(dialog.get_property('secondary-text'), '2nd markup')
self.assertTrue(dialog.get_property('secondary-use-markup'))
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_color_selection_dialog(self):
dialog = Gtk.ColorSelectionDialog(title="color selection dialog test")
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('color selection dialog test', dialog.get_title())
def test_file_chooser_dialog(self):
# might cause a GVFS warning, do not break on this
with capture_glib_warnings(allow_warnings=True):
dialog = Gtk.FileChooserDialog(title='file chooser dialog test',
action=Gtk.FileChooserAction.SAVE)
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('file chooser dialog test', dialog.get_title())
action = dialog.get_property('action')
self.assertEqual(Gtk.FileChooserAction.SAVE, action)
def test_file_chooser_dialog_default_action(self):
# might cause a GVFS warning, do not break on this
with capture_glib_warnings(allow_warnings=True):
dialog = Gtk.FileChooserDialog(title='file chooser dialog test')
action = dialog.get_property('action')
self.assertEqual(Gtk.FileChooserAction.OPEN, action)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_font_selection_dialog(self):
dialog = Gtk.FontSelectionDialog(title="font selection dialog test")
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('font selection dialog test', dialog.get_title())
@unittest.skipIf(GTK4, "not in gtk4")
def test_recent_chooser_dialog(self):
test_manager = Gtk.RecentManager()
dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test',
recent_manager=test_manager)
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('recent chooser dialog test', dialog.get_title())
class TestClass(GObject.GObject):
__gtype_name__ = "GIOverrideTreeAPITest"
def __init__(self, tester, int_value, string_value):
super(TestGtk.TestClass, self).__init__()
self.tester = tester
self.int_value = int_value
self.string_value = string_value
def check(self, int_value, string_value):
self.tester.assertEqual(int_value, self.int_value)
self.tester.assertEqual(string_value, self.string_value)
def test_buttons(self):
if not GTK4:
self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button)
# test Gtk.Button
button = Gtk.Button()
self.assertTrue(isinstance(button, Gtk.Button))
if Gtk._version != "4.0":
self.assertTrue(isinstance(button, Gtk.Container))
self.assertTrue(isinstance(button, Gtk.Widget))
if Gtk_version != "4.0":
# Using stock items causes hard warning in devel versions of GTK.
with capture_glib_warnings(allow_warnings=True):
button = Gtk.Button.new_from_stock(Gtk.STOCK_CLOSE)
self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
self.assertTrue(button.get_use_stock())
self.assertTrue(button.get_use_underline())
# test Gtk.Button use_stock
button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True,
use_underline=True)
self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
self.assertTrue(button.get_use_stock())
self.assertTrue(button.get_use_underline())
# test Gtk.LinkButton
button = Gtk.LinkButton(uri='http://www.Gtk.org', label='Gtk')
self.assertTrue(isinstance(button, Gtk.Button))
if Gtk._version != "4.0":
self.assertTrue(isinstance(button, Gtk.Container))
self.assertTrue(isinstance(button, Gtk.Widget))
self.assertEqual('http://www.Gtk.org', button.get_uri())
self.assertEqual('Gtk', button.get_label())
def test_inheritance(self):
for name in gi.overrides.Gtk.__all__:
over = getattr(gi.overrides.Gtk, name)
for element in dir(Gtk):
try:
klass = getattr(Gtk, element)
info = klass.__info__
except (NotImplementedError, AttributeError):
continue
# Get all parent classes and interfaces klass inherits from
if isinstance(info, gi.types.ObjectInfo):
classes = list(info.get_interfaces())
parent = info.get_parent()
while parent is not None and parent.get_name() != "Object":
classes.append(parent)
parent = parent.get_parent()
classes = [kl for kl in classes if kl.get_namespace() == "Gtk"]
else:
continue
for kl in classes:
if kl.get_name() == name:
self.assertTrue(issubclass(klass, over,),
"%r does not inherit from override %r" % (klass, over,))
def test_editable(self):
self.assertEqual(Gtk.Editable, gi.overrides.Gtk.Editable)
# need to use Gtk.Entry because Editable is an interface
entry = Gtk.Entry()
pos = entry.insert_text('HeWorld', 0)
self.assertEqual(pos, 7)
pos = entry.insert_text('llo ', 2)
self.assertEqual(pos, 6)
text = entry.get_chars(0, 11)
self.assertEqual('Hello World', text)
def test_label(self):
label = Gtk.Label(label='Hello')
self.assertTrue(isinstance(label, Gtk.Widget))
self.assertEqual(label.get_text(), 'Hello')
def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0,
step_increment=0.0, page_increment=0.0, page_size=0.0):
self.assertEqual(adjustment.get_value(), value)
self.assertEqual(adjustment.get_lower(), lower)
self.assertEqual(adjustment.get_upper(), upper)
self.assertEqual(adjustment.get_step_increment(), step_increment)
self.assertEqual(adjustment.get_page_increment(), page_increment)
self.assertEqual(adjustment.get_page_size(), page_size)
def test_adjustment(self):
adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5)
self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5)
adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4)
self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4)
adjustment = Gtk.Adjustment(value=1, lower=0, upper=6)
self.adjustment_check(adjustment, value=1, lower=0, upper=6)
adjustment = Gtk.Adjustment()
self.adjustment_check(adjustment)
if not GTK4:
adjustment = Gtk.Adjustment(1, -1, 3, 0, 0, 0)
self.adjustment_check(adjustment, value=1, lower=-1, upper=3)
adjustment = Gtk.Adjustment(1, -1, 3, 0, 0, 0, value=2)
self.adjustment_check(adjustment, value=2, lower=-1, upper=3)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_table(self):
table = Gtk.Table()
self.assertTrue(isinstance(table, Gtk.Table))
if Gtk._version != "4.0":
self.assertTrue(isinstance(table, Gtk.Container))
self.assertTrue(isinstance(table, Gtk.Widget))
self.assertEqual(table.get_size(), (1, 1))
self.assertEqual(table.get_homogeneous(), False)
table = Gtk.Table(n_rows=2, n_columns=3)
self.assertEqual(table.get_size(), (2, 3))
self.assertEqual(table.get_homogeneous(), False)
table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True)
self.assertEqual(table.get_size(), (2, 3))
self.assertEqual(table.get_homogeneous(), True)
label = Gtk.Label(label='Hello')
self.assertTrue(isinstance(label, Gtk.Widget))
table.attach(label, 0, 1, 0, 1)
self.assertEqual(label, table.get_children()[0])
def test_scrolledwindow(self):
sw = Gtk.ScrolledWindow()
self.assertTrue(isinstance(sw, Gtk.ScrolledWindow))
if Gtk._version != "4.0":
self.assertTrue(isinstance(sw, Gtk.Container))
self.assertTrue(isinstance(sw, Gtk.Widget))
sb = sw.get_hscrollbar()
self.assertEqual(sw.get_hadjustment(), sb.get_adjustment())
sb = sw.get_vscrollbar()
self.assertEqual(sw.get_vadjustment(), sb.get_adjustment())
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_widget_drag_methods(self):
widget = Gtk.Button()
# here we are not checking functionality, only that the methods exist
# and except the right number of arguments
widget.drag_check_threshold(0, 0, 0, 0)
# drag_dest_ methods
widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
widget.drag_dest_add_image_targets()
widget.drag_dest_add_text_targets()
widget.drag_dest_add_uri_targets()
widget.drag_dest_get_track_motion()
widget.drag_dest_set_track_motion(True)
widget.drag_dest_get_target_list()
widget.drag_dest_set_target_list(None)
widget.drag_dest_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
widget.drag_dest_unset()
widget.drag_highlight()
widget.drag_unhighlight()
# drag_source_ methods
widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
widget.drag_source_add_image_targets()
widget.drag_source_add_text_targets()
widget.drag_source_add_uri_targets()
widget.drag_source_set_icon_name("_About")
widget.drag_source_set_icon_pixbuf(GdkPixbuf.Pixbuf())
widget.drag_source_set_icon_stock(Gtk.STOCK_ABOUT)
widget.drag_source_get_target_list()
widget.drag_source_set_target_list(None)
widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
widget.drag_source_unset()
# these methods cannot be called because they require a valid drag on
# a real GdkWindow. So we only check that they exist and are callable.
self.assertTrue(hasattr(widget, 'drag_dest_set_proxy'))
self.assertTrue(hasattr(widget, 'drag_get_data'))
@unittest.skipIf(Gtk_version != "4.0", "gtk4 only")
def test_widget_drag_methods_gtk4(self):
widget = Gtk.Button()
widget.drag_check_threshold(0, 0, 0, 0)
# drag source
drag_source = Gtk.DragSource()
content = Gdk.ContentProvider.new_for_value("data")
drag_source.set_content(content)
drag_source.set_actions(Gdk.DragAction.COPY)
image = Gtk.Image.new_from_icon_name("dialog-warning")
drag_source.set_icon(image.get_paintable(), 0, 0)
widget.add_controller(drag_source)
# drop target
drop_target = Gtk.DropTarget.new(Gdk.ContentFormats.new([]), Gdk.DragAction.COPY)
widget.add_controller(drop_target)
widget.remove_controller(drag_source)
widget.remove_controller(drop_target)
@unittest.skipIf(sys.platform == "darwin", "crashes")
@unittest.skipIf(GTK4, "uses lots of gtk3 only api")
def test_tree_view_drag_target_list_gtk3(self):
mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0),
('test1', 1, 1),
Gtk.TargetEntry.new('test2', 2, 2),
('test3', 3, 3)]
def _test_target_list(targets):
for i, target in enumerate(targets):
self.assertTrue(isinstance(target, Gtk.TargetEntry))
self.assertEqual(target.target, 'test' + str(i))
self.assertEqual(target.flags, i)
self.assertEqual(target.info, i)
_test_target_list(Gtk._construct_target_list(mixed_target_list))
widget = Gtk.Button()
widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
widget.drag_dest_set_target_list(mixed_target_list)
widget.drag_dest_get_target_list()
widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
widget.drag_source_set_target_list(mixed_target_list)
widget.drag_source_get_target_list()
treeview = Gtk.TreeView()
treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
mixed_target_list,
Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
treeview.enable_model_drag_dest(mixed_target_list,
Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
@unittest.skipUnless(GTK4, "gtk4 only")
def test_tree_view_drag_content_formats_gtk4(self):
content_formats = Gdk.ContentFormats.new(
["application/json", "GTK_TREE_MODEL_ROW"]
)
treeview = Gtk.TreeView()
treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
content_formats,
Gdk.DragAction.MOVE)
treeview.enable_model_drag_dest(content_formats,
Gdk.DragAction.MOVE)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_scrollbar(self):
adjustment = Gtk.Adjustment()
hscrollbar = Gtk.HScrollbar()
vscrollbar = Gtk.VScrollbar()
self.assertNotEqual(hscrollbar.props.adjustment, adjustment)
self.assertNotEqual(vscrollbar.props.adjustment, adjustment)
hscrollbar = Gtk.HScrollbar(adjustment=adjustment)
vscrollbar = Gtk.VScrollbar(adjustment=adjustment)
self.assertEqual(hscrollbar.props.adjustment, adjustment)
self.assertEqual(vscrollbar.props.adjustment, adjustment)
def test_iconview(self):
# PyGTK compat
iconview = Gtk.IconView()
self.assertEqual(iconview.props.model, None)
model = Gtk.ListStore(str)
iconview = Gtk.IconView(model=model)
self.assertEqual(iconview.props.model, model)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_toolbutton(self):
# PyGTK compat
# Using stock items causes hard warning in devel versions of GTK.
with capture_glib_warnings(allow_warnings=True):
button = Gtk.ToolButton()
self.assertEqual(button.props.stock_id, None)
button = Gtk.ToolButton(stock_id='gtk-new')
self.assertEqual(button.props.stock_id, 'gtk-new')
icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR)
button = Gtk.ToolButton(label='mylabel', icon_widget=icon)
self.assertEqual(button.props.label, 'mylabel')
self.assertEqual(button.props.icon_widget, icon)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_iconset(self):
Gtk.IconSet()
pixbuf = GdkPixbuf.Pixbuf()
Gtk.IconSet.new_from_pixbuf(pixbuf)
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
Gtk.IconSet(pixbuf)
assert issubclass(warn[0].category, PyGTKDeprecationWarning)
def test_viewport(self):
vadjustment = Gtk.Adjustment()
hadjustment = Gtk.Adjustment()
viewport = Gtk.Viewport(hadjustment=hadjustment,
vadjustment=vadjustment)
self.assertEqual(viewport.props.vadjustment, vadjustment)
self.assertEqual(viewport.props.hadjustment, hadjustment)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_stock_lookup(self):
stock_item = Gtk.stock_lookup('gtk-ok')
self.assertEqual(type(stock_item), Gtk.StockItem)
self.assertEqual(stock_item.stock_id, 'gtk-ok')
self.assertEqual(Gtk.stock_lookup('nosuchthing'), None)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_gtk_main(self):
# with no arguments
GLib.idle_add(Gtk.main_quit)
Gtk.main()
# overridden function ignores its arguments
GLib.idle_add(Gtk.main_quit, 'hello')
Gtk.main()
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_widget_render_icon(self):
button = Gtk.Button(label='OK')
pixbuf = button.render_icon(Gtk.STOCK_OK, Gtk.IconSize.BUTTON)
self.assertTrue(pixbuf is not None)
@unittest.skipUnless(
Gtk_version == "4.0", "GtkWidget prior to gtk4 is not iterable")
def test_widget_iterable(self):
widget = Gtk.Box()
children = [child for child in widget]
self.assertEqual(len(children), 0)
nr_children = 7
for i in range(nr_children):
widget.append(Gtk.Label())
children = [child for child in widget]
self.assertEqual(len(children), nr_children)
first_child = children[0]
last_child = children[-1]
self.assertEqual(first_child, widget.get_first_child())
self.assertEqual(last_child, widget.get_last_child())
self.assertTrue(first_child in widget)
self.assertTrue(last_child in widget)
widget.remove(first_child)
self.assertTrue(first_child not in widget)
self.assertTrue(last_child in widget)
widget.remove(last_child)
self.assertTrue(first_child not in widget)
self.assertTrue(last_child not in widget)
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestWidget(unittest.TestCase):
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_style_get_property_gvalue(self):
button = Gtk.Button()
value = GObject.Value(int, -42)
button.style_get_property('focus-padding', value)
# Test only that the style property changed since we can't actuall
# set it.
self.assertNotEqual(value.get_int(), -42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_style_get_property_return_with_explicit_gvalue(self):
button = Gtk.Button()
value = GObject.Value(int, -42)
result = button.style_get_property('focus-padding', value)
self.assertIsInstance(result, int)
self.assertNotEqual(result, -42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_style_get_property_return_with_implicit_gvalue(self):
button = Gtk.Button()
result = button.style_get_property('focus-padding')
self.assertIsInstance(result, int)
self.assertNotEqual(result, -42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_style_get_property_error(self):
button = Gtk.Button()
with self.assertRaises(ValueError):
button.style_get_property('not-a-valid-style-property')
@unittest.skipIf(Gtk_version != "4.0", "only in gtk4")
def test_translate_coordinates(self):
box = Gtk.Box()
child = Gtk.Button()
box.append(child)
with realized(box):
assert box.translate_coordinates(child, 42, 24) == (42.0, 24.0)
assert box.translate_coordinates(Gtk.Button(), 0, 0) is None
@unittest.skipIf(sys.platform == "darwin", "hangs")
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestSignals(unittest.TestCase):
def test_class_closure_override_with_aliased_type(self):
class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
if not GTK4:
__gsignals__ = {'size-allocate': 'override'}
def __init__(self):
Gtk.ScrolledWindow.__init__(self)
self._alloc_called = False
self._alloc_value = None
self._alloc_error = None
def do_size_allocate(self, *args):
self._alloc_called = True
self._alloc_value = args[0]
try:
Gtk.ScrolledWindow.do_size_allocate(self, *args)
except Exception as e:
self._alloc_error = e
win = WindowWithSizeAllocOverride()
rect = Gdk.Rectangle()
rect.width = 100
rect.height = 100
with realized(win):
win.show()
win.get_preferred_size()
if GTK4:
win.size_allocate(rect, 0)
else:
win.size_allocate(rect)
self.assertTrue(win._alloc_called)
if GTK4:
self.assertIsInstance(win._alloc_value, int)
else:
self.assertIsInstance(win._alloc_value, Gdk.Rectangle)
self.assertTrue(win._alloc_error is None, win._alloc_error)
@unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=735693
def test_overlay_child_position(self):
def get_child_position(overlay, widget, rect, user_data=None):
rect.x = 1
rect.y = 2
rect.width = 3
rect.height = 4
return True
overlay = Gtk.Overlay()
overlay.connect('get-child-position', get_child_position)
rect = Gdk.Rectangle()
rect.x = -1
rect.y = -1
rect.width = -1
rect.height = -1
overlay.emit('get-child-position', None, rect)
self.assertEqual(rect.x, 1)
self.assertEqual(rect.y, 2)
self.assertEqual(rect.width, 3)
self.assertEqual(rect.height, 4)
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestBuilder(unittest.TestCase):
class SignalTest(GObject.GObject):
__gtype_name__ = "GIOverrideSignalTest"
__gsignals__ = {
"test-signal": (GObject.SignalFlags.RUN_FIRST,
None,
[]),
}
class SignalTestObject(GObject.GObject):
__gtype_name__ = "GIOverrideSignalTestObject"
def test_add_from_string(self):
builder = Gtk.Builder()
with pytest.raises(TypeError):
builder.add_from_string(object())
builder.add_from_string(u"")
builder.add_from_string("")
def get_example(string):
return u"""\
""" % string
builder.add_from_string(get_example(u"ä" * 1000))
builder = Gtk.Builder()
builder.add_objects_from_string(u"", [''])
builder.add_objects_from_string("", [''])
builder.add_objects_from_string(get_example(u"ä" * 1000), [''])
with pytest.raises(TypeError):
builder.add_objects_from_string(object(), [])
def test_extract_handler_and_args_object(self):
class Obj():
pass
obj = Obj()
obj.foo = lambda: None
handler, args = Gtk._extract_handler_and_args(obj, 'foo')
self.assertEqual(handler, obj.foo)
self.assertEqual(len(args), 0)
def test_extract_handler_and_args_dict(self):
obj = {'foo': lambda: None}
handler, args = Gtk._extract_handler_and_args(obj, 'foo')
self.assertEqual(handler, obj['foo'])
self.assertEqual(len(args), 0)
def test_extract_handler_and_args_with_seq(self):
obj = {'foo': (lambda: None, 1, 2)}
handler, args = Gtk._extract_handler_and_args(obj, 'foo')
self.assertEqual(handler, obj['foo'][0])
self.assertSequenceEqual(args, [1, 2])
def test_extract_handler_and_args_no_handler_error(self):
obj = dict(foo=lambda: None)
self.assertRaises(AttributeError,
Gtk._extract_handler_and_args,
obj, 'not_a_handler')
def test_extract_handler_and_args_type_mismatch(self):
with pytest.raises(TypeError):
Gtk._extract_handler_and_args({"foo": object()}, "foo")
with pytest.raises(TypeError):
Gtk._extract_handler_and_args({"foo": []}, "foo")
def test_builder_with_handler_and_args(self):
args_collector = []
def on_signal(*args):
args_collector.append(args)
signals_dict = {'on_signal1': (on_signal, 1, 2),
'on_signal2': on_signal}
if GTK4:
builder = Gtk.Builder(signals_dict)
else:
builder = Gtk.Builder()
builder.add_from_string("""
""")
if not GTK4:
builder.connect_signals(signals_dict)
objects = builder.get_objects()
self.assertEqual(len(objects), 1)
obj, = objects
obj.emit('test-signal')
self.assertEqual(len(args_collector), 2)
self.assertSequenceEqual(args_collector[0], (obj, 1, 2))
self.assertSequenceEqual(args_collector[1], (obj, ))
def test_builder_with_handler_object(self):
args_collector = []
def on_signal(*args):
args_collector.append(args)
signals_dict = {'on_signal1': (on_signal, 1, 2),
'on_signal2': on_signal}
if GTK4:
builder = Gtk.Builder(signals_dict)
else:
builder = Gtk.Builder()
builder.add_from_string("""
""")
if not GTK4:
builder.connect_signals(signals_dict)
obj = builder.get_object("foo")
emitter = builder.get_object("object_sig_test")
emitter.emit("test-signal")
assert len(args_collector) == 2
assert args_collector[0] == (obj, 1, 2)
assert args_collector[1] == (obj, )
def test_builder(self):
self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder)
class SignalCheck:
def __init__(self):
self.sentinel = 0
self.after_sentinel = 0
def on_signal_1(self, *args):
self.sentinel += 1
self.after_sentinel += 1
def on_signal_3(self, *args):
self.sentinel += 3
def on_signal_after(self, *args):
if self.after_sentinel == 1:
self.after_sentinel += 1
signal_checker = SignalCheck()
signal_checker = SignalCheck()
if GTK4:
builder = Gtk.Builder(signal_checker)
else:
builder = Gtk.Builder()
# add object1 to the builder
builder.add_from_string("""
""")
# only add object3 to the builder
builder.add_objects_from_string("""
""", ['object3'])
# hook up signals for Gtk3
if not GTK4:
builder.connect_signals(signal_checker)
# call their notify signals and check sentinel
objects = builder.get_objects()
self.assertEqual(len(objects), 2)
for obj in objects:
obj.emit('test-signal')
self.assertEqual(signal_checker.sentinel, 4)
self.assertEqual(signal_checker.after_sentinel, 2)
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTreeModelRow(unittest.TestCase):
def test_tree_model_row(self):
model = Gtk.TreeStore(int)
iter_ = model.append(None, [42])
path = model.get_path(iter_)
Gtk.TreeModelRow(model, iter_)
row = Gtk.TreeModelRow(model, path)
with pytest.raises(TypeError):
row["foo"]
with pytest.raises(TypeError):
Gtk.TreeModelRow(model, 42)
with pytest.raises(TypeError):
Gtk.TreeModelRow(42, path)
iter_ = model.append(None, [24])
row = Gtk.TreeModelRow(model, iter_)
assert row.previous[0] == 42
assert row.get_previous()[0] == 42
assert row.previous.previous is None
@unittest.skipUnless(Gtk, "Gtk not available")
class TestCustomSorter():
class Person(GObject.GObject):
name = GObject.Property(type=str, default="")
def __init__(self, name):
super().__init__()
self.props.name = name
user_data = "user_data"
def names_sort(self, name_a, name_b, user_data):
assert user_data is None
if name_a.props.name < name_b.props.name:
return Gtk.Ordering.SMALLER
elif name_a.props.name > name_b.props.name:
return Gtk.Ordering.LARGER
else:
return Gtk.Ordering.EQUAL
def names_invert_sort(self, name_a, name_b, user_data):
assert user_data == self.user_data
if name_a.props.name < name_b.props.name:
return Gtk.Ordering.LARGER
elif name_a.props.name > name_b.props.name:
return Gtk.Ordering.SMALLER
else:
return Gtk.Ordering.EQUAL
@unittest.skipIf(Gtk_version != "4.0", "gtk4 only")
def test_custom_sorter_init(self):
custom_sorter_empty = Gtk.CustomSorter()
assert isinstance(custom_sorter_empty, Gtk.CustomSorter)
custom_sorter_empty.set_sort_func(self.names_sort)
assert isinstance(custom_sorter_empty, Gtk.CustomSorter)
custom_sorter_empty.set_sort_func(
self.names_invert_sort, self.user_data)
assert isinstance(custom_sorter_empty, Gtk.CustomSorter)
custom_sorter_empty_sort = Gtk.CustomSorter.new(None)
assert isinstance(custom_sorter_empty_sort, Gtk.CustomSorter)
custom_sorter_with_sort = Gtk.CustomSorter.new(self.names_sort, None)
assert isinstance(custom_sorter_with_sort, Gtk.CustomSorter)
custom_sorter_with_sort_ud = Gtk.CustomSorter.new(
self.names_invert_sort, self.user_data)
assert isinstance(custom_sorter_with_sort_ud, Gtk.CustomSorter)
@unittest.skipIf(Gtk_version != "4.0", "gtk4 only")
def test_custom_sorter_with_model(self):
model = Gio.ListStore.new(self.Person)
sort_model = Gtk.SortListModel.new(model)
assert sort_model.props.sorter is None
empty_sorter = Gtk.CustomSorter()
empty_sorter.set_sort_func(self.names_sort, None)
sort_model.set_sorter(empty_sorter)
assert sort_model.props.sorter is empty_sorter
john = self.Person("john")
bob = self.Person("bob")
model.append(john)
model.append(bob)
assert sort_model[0] == bob
assert sort_model[1] == john
alice = self.Person("alice")
model.append(alice)
assert sort_model[0] == alice
assert sort_model[2] == john
new_model = Gio.ListStore.new(self.Person)
new_sort_model = Gtk.SortListModel.new(new_model)
assert new_sort_model.props.sorter is None
invert_sorter = Gtk.CustomSorter.new(
self.names_invert_sort, self.user_data)
new_sort_model.set_sorter(invert_sorter)
assert new_sort_model.props.sorter is invert_sorter
beatles = ["john", "paul", "george", "ringo"]
for member in beatles:
new_model.append(self.Person(member))
expected_result = ["ringo", "paul", "john", "george"]
for result, member in zip(new_sort_model, expected_result):
assert result.props.name == member
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestListStore(unittest.TestCase):
def test_insert_with_values(self):
model = Gtk.ListStore(int)
assert hasattr(model, 'insert_with_values')
iter_ = model.insert_with_values(0, (0,), [42])
assert isinstance(iter_, Gtk.TreeIter)
assert hasattr(model, 'insert_with_valuesv')
iter_ = model.insert_with_valuesv(0, (0,), [43])
assert isinstance(iter_, Gtk.TreeIter)
assert len(model) == 2
@ignore_gi_deprecation_warnings
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTreeModel(unittest.TestCase):
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_tree_model_sort_new_with_model_old(self):
# https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1134
model = Gtk.TreeStore(int)
sort_model = model.sort_new_with_model()
assert isinstance(sort_model, Gtk.TreeModelSort)
assert sort_model.get_model() == model
def test_tree_model_sort_new_with_model_new(self):
# https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1134
model = Gtk.TreeStore(int)
sort_model = Gtk.TreeModelSort.new_with_model(child_model=model)
assert isinstance(sort_model, Gtk.TreeModelSort)
assert sort_model.get_model() == model
def test_tree_model_sort(self):
if not GTK4:
self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort)
model = Gtk.TreeStore(int, bool)
model_sort = Gtk.TreeModelSort(model=model)
self.assertEqual(model_sort.get_model(), model)
def test_tree_store(self):
self.assertEqual(Gtk.TreeStore, gi.overrides.Gtk.TreeStore)
self.assertEqual(Gtk.ListStore, gi.overrides.Gtk.ListStore)
self.assertEqual(Gtk.TreeModel, gi.overrides.Gtk.TreeModel)
self.assertEqual(Gtk.TreeViewColumn, gi.overrides.Gtk.TreeViewColumn)
class TestPyObject(object):
pass
test_pyobj = TestPyObject()
test_pydict = {1: 1, "2": 2, "3": "3"}
test_pylist = [1, "2", "3"]
tree_store = Gtk.TreeStore(int,
'gchararray',
TestGtk.TestClass,
GObject.TYPE_PYOBJECT,
object,
object,
object,
bool,
bool,
GObject.TYPE_UINT,
GObject.TYPE_ULONG,
GObject.TYPE_INT64,
GObject.TYPE_UINT64,
GObject.TYPE_UCHAR,
GObject.TYPE_CHAR)
parent = None
for i in range(97):
label = 'this is child #%d' % i
testobj = TestGtk.TestClass(self, i, label)
parent = tree_store.append(parent, (i,
label,
testobj,
testobj,
test_pyobj,
test_pydict,
test_pylist,
i % 2,
bool(i % 2),
i,
GLib.MAXULONG,
GLib.MININT64,
0xffffffffffffffff,
254,
b'a'
))
# test set
parent = tree_store.append(parent)
i = 97
label = 'this is child #%d' % i
testobj = TestGtk.TestClass(self, i, label)
tree_store.set(parent,
0, i,
2, testobj,
1, label,
3, testobj,
4, test_pyobj,
5, test_pydict,
6, test_pylist,
7, i % 2,
8, bool(i % 2),
9, i,
10, GLib.MAXULONG,
11, GLib.MININT64,
12, 0xffffffffffffffff,
13, 254,
14, b'a')
parent = tree_store.append(parent)
i = 98
label = 'this is child #%d' % i
testobj = TestGtk.TestClass(self, i, label)
tree_store.set(parent, {0: i,
2: testobj,
1: label,
3: testobj,
4: test_pyobj,
5: test_pydict,
6: test_pylist,
7: i % 2,
8: bool(i % 2),
9: i,
10: GLib.MAXULONG,
11: GLib.MININT64,
12: 0xffffffffffffffff,
13: 254,
14: b'a'})
parent = tree_store.append(parent)
i = 99
label = 'this is child #%d' % i
testobj = TestGtk.TestClass(self, i, label)
tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
(i,
testobj,
label,
testobj,
test_pyobj,
test_pydict,
test_pylist,
i % 2,
bool(i % 2),
i,
GLib.MAXULONG,
GLib.MININT64,
0xffffffffffffffff,
254,
b'a'))
# len gets the number of children in the root node
# since we kept appending to the previous node
# there should only be one child of the root
self.assertEqual(len(tree_store), 1)
# walk the tree to see if the values were stored correctly
parent = None
i = 0
treeiter = tree_store.iter_children(parent)
while treeiter:
i = tree_store.get_value(treeiter, 0)
s = tree_store.get_value(treeiter, 1)
obj = tree_store.get_value(treeiter, 2)
obj.check(i, s)
obj2 = tree_store.get_value(treeiter, 3)
self.assertEqual(obj, obj2)
pyobj = tree_store.get_value(treeiter, 4)
self.assertEqual(pyobj, test_pyobj)
pydict = tree_store.get_value(treeiter, 5)
self.assertEqual(pydict, test_pydict)
pylist = tree_store.get_value(treeiter, 6)
self.assertEqual(pylist, test_pylist)
bool_1 = tree_store.get_value(treeiter, 7)
bool_2 = tree_store.get_value(treeiter, 8)
self.assertEqual(bool_1, bool_2)
self.assertTrue(isinstance(bool_1, bool))
self.assertTrue(isinstance(bool_2, bool))
uint_ = tree_store.get_value(treeiter, 9)
self.assertEqual(uint_, i)
ulong_ = tree_store.get_value(treeiter, 10)
self.assertEqual(ulong_, GLib.MAXULONG)
int64_ = tree_store.get_value(treeiter, 11)
self.assertEqual(int64_, GLib.MININT64)
uint64_ = tree_store.get_value(treeiter, 12)
self.assertEqual(uint64_, 0xffffffffffffffff)
uchar_ = tree_store.get_value(treeiter, 13)
self.assertEqual(ord(uchar_), 254)
char_ = tree_store.get_value(treeiter, 14)
self.assertEqual(char_, 'a')
parent = treeiter
treeiter = tree_store.iter_children(parent)
self.assertEqual(i, 99)
def test_tree_store_signals(self):
tree_store = Gtk.TreeStore(int, bool)
def on_row_inserted(tree_store, tree_path, tree_iter, signal_list):
signal_list.append('row-inserted')
def on_row_changed(tree_store, tree_path, tree_iter, signal_list):
signal_list.append('row-changed')
signals = []
tree_store.connect('row-inserted', on_row_inserted, signals)
tree_store.connect('row-changed', on_row_changed, signals)
# adding rows with and without data should only call one signal
tree_store.append(None, (0, False))
self.assertEqual(signals, ['row-inserted'])
signals.pop()
tree_store.append(None)
self.assertEqual(signals, ['row-inserted'])
signals.pop()
tree_store.prepend(None, (0, False))
self.assertEqual(signals, ['row-inserted'])
signals.pop()
tree_store.prepend(None)
self.assertEqual(signals, ['row-inserted'])
signals.pop()
tree_store.insert(None, 1, (0, False))
self.assertEqual(signals, ['row-inserted'])
signals.pop()
tree_store.insert(None, 1)
self.assertEqual(signals, ['row-inserted'])
# One set one signal
signals.pop()
tree_iter = tree_store.append(None, (10, False))
tree_store.set(tree_iter, (0, 1), (20, True))
self.assertEqual(signals, ['row-inserted', 'row-changed'])
def test_list_store(self):
class TestPyObject(object):
pass
test_pyobj = TestPyObject()
test_pydict = {1: 1, "2": 2, "3": "3"}
test_pylist = [1, "2", "3"]
list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool)
for i in range(1, 93):
label = 'this is row #%d' % i
testobj = TestGtk.TestClass(self, i, label)
list_store.append((i,
label,
testobj,
test_pyobj,
test_pydict,
test_pylist,
i % 2,
bool(i % 2)))
i = 93
label = u'this is row #93'
treeiter = list_store.append()
list_store.set_value(treeiter, 0, i)
list_store.set_value(treeiter, 1, label)
list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
list_store.set_value(treeiter, 3, test_pyobj)
list_store.set_value(treeiter, 4, test_pydict)
list_store.set_value(treeiter, 5, test_pylist)
list_store.set_value(treeiter, 6, 1)
list_store.set_value(treeiter, 7, True)
# test prepend
label = 'this is row #0'
list_store.prepend((0,
label,
TestGtk.TestClass(self, 0, label),
test_pyobj,
test_pydict,
test_pylist,
0,
False))
# test automatic unicode->str conversion
i = 94
label = u'this is row #94'
treeiter = list_store.append((i,
label,
TestGtk.TestClass(self, i, label),
test_pyobj,
test_pydict,
test_pylist,
0,
False))
# add sorted items out of order to test insert* apis
# also test sending in None to not set a column
i = 97
label = 'this is row #97'
treeiter = list_store.append((None,
None,
None,
test_pyobj,
None,
test_pylist,
1,
None))
list_store.set_value(treeiter, 0, i)
list_store.set_value(treeiter, 1, label)
list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
list_store.set_value(treeiter, 4, test_pydict)
list_store.set_value(treeiter, 7, True)
# this should append
i = 99
label = 'this is row #99'
list_store.insert(9999, (i,
label,
TestGtk.TestClass(self, i, label),
test_pyobj,
test_pydict,
test_pylist,
1,
True))
i = 96
label = 'this is row #96'
list_store.insert_before(treeiter, (i,
label,
TestGtk.TestClass(self, i, label),
test_pyobj,
test_pydict,
test_pylist,
0,
False))
i = 98
label = 'this is row #98'
list_store.insert_after(treeiter, (i,
label,
TestGtk.TestClass(self, i, label),
test_pyobj,
test_pydict,
test_pylist,
0,
False))
i = 95
label = 'this is row #95'
list_store.insert(95, (i,
label,
TestGtk.TestClass(self, i, label),
test_pyobj,
test_pydict,
test_pylist,
1,
True))
i = 100
label = 'this is row #100'
treeiter = list_store.append()
list_store.set(treeiter,
1, label,
0, i,
2, TestGtk.TestClass(self, i, label),
3, test_pyobj,
4, test_pydict,
5, test_pylist,
6, 0,
7, False)
i = 101
label = 'this is row #101'
treeiter = list_store.append()
list_store.set(treeiter, {1: label,
0: i,
2: TestGtk.TestClass(self, i, label),
3: test_pyobj,
4: test_pydict,
5: test_pylist,
6: 1,
7: True})
i = 102
label = 'this is row #102'
treeiter = list_store.append()
list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7),
(label,
i,
TestGtk.TestClass(self, i, label),
test_pyobj,
test_pydict,
test_pylist,
0,
False))
self.assertEqual(len(list_store), 103)
# walk the list to see if the values were stored correctly
i = 0
treeiter = list_store.get_iter_first()
counter = 0
while treeiter:
i = list_store.get_value(treeiter, 0)
self.assertEqual(i, counter)
s = list_store.get_value(treeiter, 1)
obj = list_store.get_value(treeiter, 2)
obj.check(i, s)
pyobj = list_store.get_value(treeiter, 3)
self.assertEqual(pyobj, test_pyobj)
pydict = list_store.get_value(treeiter, 4)
self.assertEqual(pydict, test_pydict)
pylist = list_store.get_value(treeiter, 5)
self.assertEqual(pylist, test_pylist)
bool_1 = list_store.get_value(treeiter, 6)
bool_2 = list_store.get_value(treeiter, 7)
self.assertEqual(bool_1, bool_2)
self.assertTrue(isinstance(bool_1, bool))
self.assertTrue(isinstance(bool_2, bool))
treeiter = list_store.iter_next(treeiter)
counter += 1
self.assertEqual(i, 102)
def test_list_store_sort(self):
def comp1(model, row1, row2, user_data):
v1 = model[row1][1]
v2 = model[row2][1]
# make "m" smaller than anything else
if v1.startswith('m') and not v2.startswith('m'):
return -1
if v2.startswith('m') and not v1.startswith('m'):
return 1
return (v1 > v2) - (v1 < v2)
list_store = Gtk.ListStore(int, str)
list_store.set_sort_func(2, comp1, None)
list_store.append((1, 'apples'))
list_store.append((3, 'oranges'))
list_store.append((2, 'mango'))
# not sorted yet, should be original order
self.assertEqual([list(i) for i in list_store],
[[1, 'apples'], [3, 'oranges'], [2, 'mango']])
# sort with our custom function
list_store.set_sort_column_id(2, Gtk.SortType.ASCENDING)
self.assertEqual([list(i) for i in list_store],
[[2, 'mango'], [1, 'apples'], [3, 'oranges']])
list_store.set_sort_column_id(2, Gtk.SortType.DESCENDING)
self.assertEqual([list(i) for i in list_store],
[[3, 'oranges'], [1, 'apples'], [2, 'mango']])
def test_list_store_signals(self):
list_store = Gtk.ListStore(int, bool)
def on_row_inserted(list_store, tree_path, tree_iter, signal_list):
signal_list.append('row-inserted')
def on_row_changed(list_store, tree_path, tree_iter, signal_list):
signal_list.append('row-changed')
signals = []
list_store.connect('row-inserted', on_row_inserted, signals)
list_store.connect('row-changed', on_row_changed, signals)
# adding rows with and without data should only call one signal
list_store.append((0, False))
self.assertEqual(signals, ['row-inserted'])
signals.pop()
list_store.append()
self.assertEqual(signals, ['row-inserted'])
signals.pop()
list_store.prepend((0, False))
self.assertEqual(signals, ['row-inserted'])
signals.pop()
list_store.prepend()
self.assertEqual(signals, ['row-inserted'])
signals.pop()
list_store.insert(1, (0, False))
self.assertEqual(signals, ['row-inserted'])
signals.pop()
list_store.insert(1)
self.assertEqual(signals, ['row-inserted'])
# One set one signal
signals.pop()
tree_iter = list_store.append((10, False))
list_store.set(tree_iter, (0, 1), (20, True))
self.assertEqual(signals, ['row-inserted', 'row-changed'])
def test_list_store_insert_before(self):
store = Gtk.ListStore(object)
signals = []
def on_row_inserted(store, tree_path, tree_iter, signal_list):
signal_list.append('row-inserted')
def on_row_changed(store, tree_path, tree_iter, signal_list):
signal_list.append('row-changed')
store.connect('row-inserted', on_row_inserted, signals)
store.connect('row-changed', on_row_changed, signals)
iter_ = store.append([0])
assert store.get_value(iter_, 0) == 0
assert signals == ['row-inserted']
del signals[:]
# append empty
iter_ = store.insert_before(None)
assert store.get_path(iter_).get_indices() == [1]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# insert empty
iter_ = store.insert_before(iter_)
assert store.get_path(iter_).get_indices() == [1]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# append non-empty
iter_ = store.insert_before(None, [1234])
assert store.get_path(iter_).get_indices() == [3]
assert store.get_value(iter_, 0) == 1234
assert signals == ['row-inserted']
del signals[:]
# insert non-empty
iter_ = store.insert_before(iter_, [4321])
assert store.get_path(iter_).get_indices() == [3]
assert store.get_value(iter_, 0) == 4321
assert signals == ['row-inserted']
del signals[:]
assert [r[0] for r in store] == [0, None, None, 4321, 1234]
def test_list_store_insert_after(self):
store = Gtk.ListStore(object)
signals = []
def on_row_inserted(store, tree_path, tree_iter, signal_list):
signal_list.append('row-inserted')
def on_row_changed(store, tree_path, tree_iter, signal_list):
signal_list.append('row-changed')
store.connect('row-inserted', on_row_inserted, signals)
store.connect('row-changed', on_row_changed, signals)
iter_ = store.append([0])
assert store.get_value(iter_, 0) == 0
assert signals == ['row-inserted']
del signals[:]
# prepend empty
iter_ = store.insert_after(None)
assert store.get_path(iter_).get_indices() == [0]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# insert empty
iter_ = store.insert_after(iter_)
assert store.get_path(iter_).get_indices() == [1]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# prepend non-empty
iter_ = store.insert_after(None, [1234])
assert store.get_path(iter_).get_indices() == [0]
assert store.get_value(iter_, 0) == 1234
assert signals == ['row-inserted']
del signals[:]
# insert non-empty
iter_ = store.insert_after(iter_, [4321])
assert store.get_path(iter_).get_indices() == [1]
assert store.get_value(iter_, 0) == 4321
assert signals == ['row-inserted']
del signals[:]
assert [r[0] for r in store] == [1234, 4321, None, None, 0]
def test_tree_store_insert_before(self):
store = Gtk.TreeStore(object)
signals = []
def on_row_inserted(store, tree_path, tree_iter, signal_list):
signal_list.append('row-inserted')
def on_row_changed(store, tree_path, tree_iter, signal_list):
signal_list.append('row-changed')
store.connect('row-inserted', on_row_inserted, signals)
store.connect('row-changed', on_row_changed, signals)
parent = store.append(None, [-1])
assert signals == ['row-inserted']
del signals[:]
iter_ = store.append(parent, [0])
assert store.get_path(iter_).get_indices() == [0, 0]
assert store.get_value(iter_, 0) == 0
assert signals == ['row-inserted']
del signals[:]
# append empty
iter_ = store.insert_before(parent, None)
assert store.get_path(iter_).get_indices() == [0, 1]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# insert empty
iter_ = store.insert_before(parent, iter_)
assert store.get_path(iter_).get_indices() == [0, 1]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# append non-empty
iter_ = store.insert_before(parent, None, [1234])
assert store.get_path(iter_).get_indices() == [0, 3]
assert store.get_value(iter_, 0) == 1234
assert signals == ['row-inserted']
del signals[:]
# insert non-empty
iter_ = store.insert_before(parent, iter_, [4321])
assert store.get_path(iter_).get_indices() == [0, 3]
assert store.get_value(iter_, 0) == 4321
assert signals == ['row-inserted']
del signals[:]
def func(model, path, iter_, rows):
rows.append((path.get_indices(), model[iter_][:]))
rows = []
store.foreach(func, rows)
assert rows == [
([0], [-1]), ([0, 0], [0]), ([0, 1], [None]), ([0, 2], [None]),
([0, 3], [4321]), ([0, 4], [1234])]
def test_tree_store_insert_before_none(self):
store = Gtk.TreeStore(object)
root = store.append(None)
sub = store.append(root)
iter_ = store.insert_before(None, None, [1])
assert store.get_path(iter_).get_indices() == [1]
iter_ = store.insert_before(root, None, [1])
assert store.get_path(iter_).get_indices() == [0, 1]
iter_ = store.insert_before(sub, None, [1])
assert store.get_path(iter_).get_indices() == [0, 0, 0]
iter_ = store.insert_before(None, root, [1])
assert store.get_path(iter_).get_indices() == [0]
iter_ = store.insert_before(None, sub, [1])
assert store.get_path(iter_).get_indices() == [1, 0]
def test_tree_store_insert_after(self):
store = Gtk.TreeStore(object)
signals = []
def on_row_inserted(store, tree_path, tree_iter, signal_list):
signal_list.append('row-inserted')
def on_row_changed(store, tree_path, tree_iter, signal_list):
signal_list.append('row-changed')
store.connect('row-inserted', on_row_inserted, signals)
store.connect('row-changed', on_row_changed, signals)
parent = store.append(None, [-1])
assert signals == ['row-inserted']
del signals[:]
iter_ = store.append(parent, [0])
assert store.get_path(iter_).get_indices() == [0, 0]
assert store.get_value(iter_, 0) == 0
assert signals == ['row-inserted']
del signals[:]
# append empty
iter_ = store.insert_after(parent, None)
assert store.get_path(iter_).get_indices() == [0, 0]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# insert empty
iter_ = store.insert_after(parent, iter_)
assert store.get_path(iter_).get_indices() == [0, 1]
assert store.get_value(iter_, 0) is None
assert signals == ['row-inserted']
del signals[:]
# append non-empty
iter_ = store.insert_after(parent, None, [1234])
assert store.get_path(iter_).get_indices() == [0, 0]
assert store.get_value(iter_, 0) == 1234
assert signals == ['row-inserted']
del signals[:]
# insert non-empty
iter_ = store.insert_after(parent, iter_, [4321])
assert store.get_path(iter_).get_indices() == [0, 1]
assert store.get_value(iter_, 0) == 4321
assert signals == ['row-inserted']
del signals[:]
def func(model, path, iter_, rows):
rows.append((path.get_indices(), model[iter_][:]))
rows = []
store.foreach(func, rows)
assert rows == [
([0], [-1]), ([0, 0], [1234]), ([0, 1], [4321]),
([0, 2], [None]), ([0, 3], [None]), ([0, 4], [0])]
def test_tree_store_insert_after_none(self):
store = Gtk.TreeStore(object)
root = store.append(None)
sub = store.append(root)
iter_ = store.insert_after(None, None, [1])
assert store.get_path(iter_).get_indices() == [0]
iter_ = store.insert_after(root, None, [1])
assert store.get_path(iter_).get_indices() == [1, 0]
iter_ = store.insert_after(sub, None, [1])
assert store.get_path(iter_).get_indices() == [1, 1, 0]
iter_ = store.insert_after(None, root, [1])
assert store.get_path(iter_).get_indices() == [2]
iter_ = store.insert_after(None, sub, [1])
assert store.get_path(iter_).get_indices() == [1, 2]
def test_tree_path(self):
p1 = Gtk.TreePath()
p2 = Gtk.TreePath.new_first()
self.assertEqual(p1, p2)
self.assertEqual(str(p1), '0')
self.assertEqual(len(p1), 1)
p1 = Gtk.TreePath(2)
p2 = Gtk.TreePath.new_from_string('2')
self.assertEqual(p1, p2)
self.assertEqual(str(p1), '2')
self.assertEqual(len(p1), 1)
p1 = Gtk.TreePath('1:2:3')
p2 = Gtk.TreePath.new_from_string('1:2:3')
self.assertEqual(p1, p2)
self.assertEqual(str(p1), '1:2:3')
self.assertEqual(len(p1), 3)
p1 = Gtk.TreePath((1, 2, 3))
p2 = Gtk.TreePath.new_from_string('1:2:3')
self.assertEqual(p1, p2)
self.assertEqual(str(p1), '1:2:3')
self.assertEqual(len(p1), 3)
self.assertNotEqual(p1, None)
self.assertTrue(p1 > None)
self.assertTrue(p1 >= None)
self.assertFalse(p1 < None)
self.assertFalse(p1 <= None)
self.assertEqual(tuple(p1), (1, 2, 3))
self.assertEqual(p1[0], 1)
self.assertEqual(p1[1], 2)
self.assertEqual(p1[2], 3)
self.assertRaises(IndexError, p1.__getitem__, 3)
def test_tree_path_empty(self):
p1 = Gtk.TreePath.new()
assert str(p1) == ""
def test_tree_model(self):
tree_store = Gtk.TreeStore(int, str)
self.assertTrue(tree_store)
self.assertEqual(len(tree_store), 0)
self.assertEqual(tree_store.get_iter_first(), None)
def get_by_index(row, col=None):
if col:
return tree_store[row][col]
else:
return tree_store[row]
self.assertRaises(TypeError, get_by_index, None)
self.assertRaises(TypeError, get_by_index, "")
self.assertRaises(TypeError, get_by_index, ())
self.assertRaises(IndexError, get_by_index, "0")
self.assertRaises(IndexError, get_by_index, 0)
self.assertRaises(IndexError, get_by_index, (0,))
self.assertRaises(ValueError, tree_store.get_iter, "0")
self.assertRaises(ValueError, tree_store.get_iter, 0)
self.assertRaises(ValueError, tree_store.get_iter, (0,))
self.assertRaises(ValueError, tree_store.get_iter_from_string, "0")
for row in tree_store:
self.fail("Should not be reached")
class DerivedIntType(int):
pass
class DerivedStrType(str):
pass
for i in range(100):
label = 'this is row #%d' % i
parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),))
self.assertNotEqual(parent, None)
for j in range(20):
label = 'this is child #%d of node #%d' % (j, i)
child = tree_store.append(parent, (j, label,))
self.assertNotEqual(child, None)
self.assertTrue(tree_store)
self.assertEqual(len(tree_store), 100)
self.assertEqual(tree_store.iter_previous(tree_store.get_iter(0)), None)
for i, row in enumerate(tree_store):
self.assertEqual(row.model, tree_store)
self.assertEqual(row.parent, None)
self.assertEqual(tree_store[i].path, row.path)
self.assertEqual(tree_store[str(i)].path, row.path)
self.assertEqual(tree_store[(i,)].path, row.path)
self.assertEqual(tree_store[i][0], i)
self.assertEqual(tree_store[i][1], "this is row #%d" % i)
aiter = tree_store.get_iter(i)
self.assertEqual(tree_store.get_path(aiter), row.path)
aiter = tree_store.get_iter(str(i))
self.assertEqual(tree_store.get_path(aiter), row.path)
aiter = tree_store.get_iter((i,))
self.assertEqual(tree_store.get_path(aiter), row.path)
self.assertEqual(tree_store.iter_parent(aiter), row.parent)
next = tree_store.iter_next(aiter)
if i < len(tree_store) - 1:
self.assertEqual(tree_store.get_path(next), row.next.path)
self.assertEqual(tree_store.get_path(tree_store.iter_previous(next)),
tree_store.get_path(aiter))
else:
self.assertEqual(next, None)
self.assertEqual(tree_store.iter_n_children(row.iter), 20)
child = tree_store.iter_children(row.iter)
for j, childrow in enumerate(row.iterchildren()):
child_path = tree_store.get_path(child)
self.assertEqual(childrow.path, child_path)
self.assertEqual(childrow.parent.path, row.path)
self.assertEqual(childrow.path, tree_store[child].path)
self.assertEqual(childrow.path, tree_store[child_path].path)
self.assertEqual(childrow[0], tree_store[child][0])
self.assertEqual(childrow[0], j)
self.assertEqual(childrow[1], tree_store[child][1])
self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i))
self.assertRaises(IndexError, get_by_index, child, 2)
tree_store[child][1] = 'this was child #%d of node #%d' % (j, i)
self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i))
nth_child = tree_store.iter_nth_child(row.iter, j)
self.assertEqual(childrow.path, tree_store.get_path(nth_child))
childrow2 = tree_store["%d:%d" % (i, j)]
self.assertEqual(childrow.path, childrow2.path)
childrow2 = tree_store[(i, j,)]
self.assertEqual(childrow.path, childrow2.path)
child = tree_store.iter_next(child)
if j < 19:
self.assertEqual(childrow.next.path, tree_store.get_path(child))
else:
self.assertEqual(child, childrow.next)
self.assertEqual(child, None)
self.assertEqual(j, 19)
self.assertEqual(i, 99)
# negative indices
for i in range(-1, -100, -1):
i_real = i + 100
self.assertEqual(tree_store[i][0], i_real)
row = tree_store[i]
for j in range(-1, -20, -1):
j_real = j + 20
path = (i_real, j_real,)
self.assertEqual(tree_store[path][-2], j_real)
label = 'this was child #%d of node #%d' % (j_real, i_real)
self.assertEqual(tree_store[path][-1], label)
new_label = 'this still is child #%d of node #%d' % (j_real, i_real)
tree_store[path][-1] = new_label
self.assertEqual(tree_store[path][-1], new_label)
self.assertRaises(IndexError, get_by_index, path, -3)
self.assertRaises(IndexError, get_by_index, -101)
last_row = tree_store[99]
self.assertNotEqual(last_row, None)
for i, childrow in enumerate(last_row.iterchildren()):
if i < 19:
self.assertTrue(tree_store.remove(childrow.iter))
else:
self.assertFalse(tree_store.remove(childrow.iter))
self.assertEqual(i, 19)
self.assertEqual(tree_store.iter_n_children(last_row.iter), 0)
for childrow in last_row.iterchildren():
self.fail("Should not be reached")
aiter = tree_store.get_iter(10)
self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a')
self.assertRaises(ValueError, tree_store.get, aiter, 1, -1)
self.assertRaises(ValueError, tree_store.get, aiter, 1, 100)
self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10'))
# check __delitem__
self.assertEqual(len(tree_store), 100)
aiter = tree_store.get_iter(10)
del tree_store[aiter]
self.assertEqual(len(tree_store), 99)
self.assertRaises(TypeError, tree_store.__delitem__, None)
self.assertRaises(IndexError, tree_store.__delitem__, -101)
self.assertRaises(IndexError, tree_store.__delitem__, 101)
def test_tree_model_get_iter_fail(self):
# TreeModel class with a failing get_iter()
class MyTreeModel(GObject.GObject, Gtk.TreeModel):
def do_get_iter(self, iter):
return (False, None)
tm = MyTreeModel()
self.assertEqual(tm.get_iter_first(), None)
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(TypeError, set_row3)
def test_tree_row_sequence(self):
model = Gtk.ListStore(int, str, float)
model.append([1, "one", -0.1])
self.assertEqual([1, "one", -0.1], model[0][0, 1, 2])
self.assertEqual([1, "one"], model[0][0, 1])
self.assertEqual(["one", -0.1], model[0][1, 2])
self.assertEqual("one", model[0][1])
self.assertEqual([1, -0.1], model[0][0, 2])
self.assertEqual([-0.1, 1], model[0][2, 0])
model[0][0, 1, 2] = (2, "two", -0.2)
self.assertEqual([2, "two", -0.2], model[0][0, 1, 2])
model[0][0, 1] = (3, "three")
self.assertEqual([3, "three"], model[0][0, 1])
model[0][1, 2] = ("four", -0.4)
self.assertEqual(["four", -0.4], model[0][1, 2])
model[0][0, 2] = (5, -0.5)
self.assertEqual([5, -0.5], model[0][0, 2])
model[0][0, 1, 2] = (6, "six", -0.6)
self.assertEqual([-0.6, 6, "six"], model[0][2, 0, 1])
def set_row1():
model[0][4, 5] = ("shouldn't", "work",)
self.assertRaises(IndexError, set_row1)
def set_row2():
model[0][0, 1] = (0, "zero", 0)
self.assertRaises(ValueError, set_row2)
def set_row3():
model[0][0, 1] = ("shouldn't", 0)
self.assertRaises(TypeError, set_row3)
def set_row4():
model[0][0, "two"] = (0, "zero")
self.assertRaises(TypeError, set_row4)
def test_tree_model_set_value_to_none(self):
# Tests allowing the usage of None to set an empty value on a model.
store = Gtk.ListStore(str)
row = store.append(['test'])
self.assertSequenceEqual(store[0][:], ['test'])
store.set_value(row, 0, None)
self.assertSequenceEqual(store[0][:], [None])
def test_signal_emission_tree_path_coerce(self):
class Model(GObject.Object, Gtk.TreeModel):
pass
model = Model()
tree_paths = []
def on_any_signal(model, path, *args):
tree_paths.append(path.to_string())
model.connect('row-changed', on_any_signal)
model.connect('row-deleted', on_any_signal)
model.connect('row-has-child-toggled', on_any_signal)
model.connect('row-inserted', on_any_signal)
model.row_changed('0', Gtk.TreeIter())
self.assertEqual(tree_paths[-1], '0')
model.row_deleted('1')
self.assertEqual(tree_paths[-1], '1')
model.row_has_child_toggled('2', Gtk.TreeIter())
self.assertEqual(tree_paths[-1], '2')
model.row_inserted('3', Gtk.TreeIter())
self.assertEqual(tree_paths[-1], '3')
def test_tree_model_filter(self):
model = Gtk.ListStore(int, str, float)
model.append([1, "one", -0.1])
model.append([2, "two", -0.2])
filtered = Gtk.TreeModelFilter(child_model=model)
self.assertEqual(filtered[0][1], 'one')
filtered[0][1] = 'ONE'
self.assertEqual(filtered[0][1], 'ONE')
def foo(store, iter_, data):
assert data is None
return False
filtered.set_visible_func(foo)
filtered.refilter()
assert len(filtered) == 0
def test_list_store_performance(self):
model = Gtk.ListStore(int, str)
iterations = 2000
start = timeit.default_timer()
i = iterations
while i > 0:
model.append([1, 'hello'])
i -= 1
end = timeit.default_timer()
sys.stderr.write('[%.0f µs/append] ' % ((end - start) * 1000000 / iterations))
def test_filter_new_default(self):
# Test filter_new accepts implicit default of None
model = Gtk.ListStore(int)
filt = model.filter_new()
self.assertTrue(filt is not None)
def test_tree_store_set(self):
tree_store = Gtk.TreeStore(int, int)
iter_ = tree_store.append(None)
tree_store.set(iter_)
assert tree_store.get_value(iter_, 0) == 0
tree_store.set(iter_, 0, 42)
assert tree_store.get_value(iter_, 0) == 42
assert tree_store.get_value(iter_, 1) == 0
tree_store.set(iter_, 0, 42, 1, 24)
assert tree_store.get_value(iter_, 1) == 24
tree_store.set(iter_, 1, 124)
assert tree_store.get_value(iter_, 1) == 124
with pytest.raises(TypeError):
tree_store.set(iter_, 0, 42, "foo", 24)
with pytest.raises(TypeError):
tree_store.set(iter_, "foo")
with pytest.raises(TypeError):
tree_store.set(iter_, [1, 2, 3])
with pytest.raises(TypeError):
tree_store.set(iter_, 0, 42, 24)
def test_list_store_set(self):
list_store = Gtk.ListStore(int, int)
iter_ = list_store.append()
list_store.set(iter_)
assert list_store.get_value(iter_, 0) == 0
list_store.set(iter_, 0, 42)
assert list_store.get_value(iter_, 0) == 42
assert list_store.get_value(iter_, 1) == 0
list_store.set(iter_, 0, 42, 1, 24)
assert list_store.get_value(iter_, 1) == 24
list_store.set(iter_, 1, 124)
assert list_store.get_value(iter_, 1) == 124
with pytest.raises(TypeError):
list_store.set(iter_, 0, 42, "foo", 24)
with pytest.raises(TypeError):
list_store.set(iter_, "foo")
with pytest.raises(TypeError):
list_store.set(iter_, [1, 2, 3])
with pytest.raises(TypeError):
list_store.set(iter_, 0, 42, 24)
def test_set_default_sort_func(self):
list_store = Gtk.ListStore(int)
list_store.append([2])
list_store.append([1])
def sort_func(store, iter1, iter2, data):
assert data is None
cmp = lambda a, b: (a > b) - (a < b)
return cmp(store[iter1][0], store[iter2][0])
list_store.set_default_sort_func(sort_func)
list_store.set_sort_column_id(
Gtk.TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, Gtk.SortType.ASCENDING)
assert [v[0] for v in list_store] == [1, 2]
def test_model_rows_reordered(self):
list_store = Gtk.ListStore(int)
list_store.append([2])
list_store.append([1])
list_store.rows_reordered(Gtk.TreePath.new_first(), None, [0, 1])
list_store.rows_reordered(0, None, [0, 1])
def test_model_set_row(self):
list_store = Gtk.ListStore(int, int)
list_store.append([1, 2])
iter_ = list_store.get_iter_first()
list_store.set_row(iter_, [3, 4])
assert list_store[0][:] == [3, 4]
list_store.set_row(iter_, [None, 7])
assert list_store[0][:] == [3, 7]
list_store.set_row(iter_, [None, GObject.Value(int, 9)])
assert list_store[0][:] == [3, 9]
def test_model_set_row_skip_on_none(self):
list_store = Gtk.ListStore(int, int, int, int)
list_store.append([1, 2, 3, 4])
iter_ = list_store.get_iter_first()
list_store.set_row(iter_, [None, 7, None, 9])
assert list_store[0][:] == [1, 7, 3, 9]
@unittest.skipIf(sys.platform == "darwin", "hangs")
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTreeView(unittest.TestCase):
def test_tree_view(self):
store = Gtk.ListStore(int, str)
store.append((0, "foo"))
store.append((1, "bar"))
view = Gtk.TreeView()
with realized(view):
view.set_cursor(store[1].path)
view.set_cursor(str(store[1].path))
view.get_cell_area(store[1].path)
view.get_cell_area(str(store[1].path))
def test_tree_view_column(self):
cell = Gtk.CellRendererText()
col = Gtk.TreeViewColumn(title='This is just a test',
cell_renderer=cell,
text=0,
style=2)
# Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=711173
col.set_cell_data_func(cell, None, None)
def test_tree_view_add_column_with_attributes(self):
model = Gtk.ListStore(str, str, str)
# deliberately use out-of-order sorting here; we assign column 0 to
# model index 2, etc.
model.append(['cell13', 'cell11', 'cell12'])
model.append(['cell23', 'cell21', 'cell22'])
tree = Gtk.TreeView(model=model)
cell1 = Gtk.CellRendererText()
cell2 = Gtk.CellRendererText()
cell3 = Gtk.CellRendererText()
cell4 = Gtk.CellRendererText()
tree.insert_column_with_attributes(0, 'Head2', cell2, text=2)
tree.insert_column_with_attributes(0, 'Head1', cell1, text=1)
tree.insert_column_with_attributes(-1, 'Head3', cell3, text=0)
# unconnected
tree.insert_column_with_attributes(-1, 'Head4', cell4)
with realized(tree):
tree.set_cursor(model[0].path)
if Gtk._version == "4.0":
context = GLib.MainContext()
while context.pending():
context.iteration(False)
else:
while Gtk.events_pending():
Gtk.main_iteration()
self.assertEqual(tree.get_column(0).get_title(), 'Head1')
self.assertEqual(tree.get_column(1).get_title(), 'Head2')
self.assertEqual(tree.get_column(2).get_title(), 'Head3')
self.assertEqual(tree.get_column(3).get_title(), 'Head4')
# cursor should be at the first row
if not GTK4:
# not sure why this doesn't work with gtk4
self.assertEqual(cell1.props.text, 'cell11')
self.assertEqual(cell2.props.text, 'cell12')
self.assertEqual(cell3.props.text, 'cell13')
self.assertEqual(cell4.props.text, None)
def test_tree_view_column_set_attributes(self):
store = Gtk.ListStore(int, str)
directors = ['Fellini', 'Tarantino', 'Tarkovskiy']
for i, director in enumerate(directors):
store.append([i, director])
treeview = Gtk.TreeView()
treeview.set_model(store)
column = Gtk.TreeViewColumn()
treeview.append_column(column)
cell = Gtk.CellRendererText()
column.pack_start(cell, expand=True)
column.set_attributes(cell, text=1)
with realized(treeview):
if not GTK4:
# not sure why this doesn't work with gtk4
self.assertTrue(cell.props.text in directors)
def test_tree_selection(self):
store = Gtk.ListStore(int, str)
for i in range(10):
store.append((i, "foo"))
view = Gtk.TreeView()
view.set_model(store)
firstpath = store.get_path(store.get_iter_first())
sel = view.get_selection()
sel.select_path(firstpath)
(m, s) = sel.get_selected()
self.assertEqual(m, store)
self.assertEqual(store.get_path(s), firstpath)
sel.select_path(0)
(m, s) = sel.get_selected()
self.assertEqual(m, store)
self.assertEqual(store.get_path(s), firstpath)
sel.select_path("0:0")
(m, s) = sel.get_selected()
self.assertEqual(m, store)
self.assertEqual(store.get_path(s), firstpath)
sel.select_path((0, 0))
(m, s) = sel.get_selected()
self.assertEqual(m, store)
self.assertEqual(store.get_path(s), firstpath)
sel.unselect_all()
(m, s) = sel.get_selected()
assert s is None
sel.select_path(0)
m, r = sel.get_selected_rows()
assert m == store
assert len(r) == 1
assert r[0] == store[0].path
def test_scroll_to_cell(self):
store = Gtk.ListStore(int, str)
store.append((0, "foo"))
view = Gtk.TreeView()
view.set_model(store)
view.scroll_to_cell(store[0].path)
view.scroll_to_cell(0)
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTextBuffer(unittest.TestCase):
def test_text_buffer(self):
self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer)
buffer = Gtk.TextBuffer()
assert buffer.get_tag_table() is not None
tag = buffer.create_tag('title', font='Sans 18')
self.assertEqual(tag.props.name, 'title')
self.assertEqual(tag.props.font, 'Sans 18')
(start, end) = buffer.get_bounds()
mark = buffer.create_mark(None, start)
self.assertFalse(mark.get_left_gravity())
buffer.set_text('Hello Jane Hello Bob')
(start, end) = buffer.get_bounds()
text = buffer.get_text(start, end, False)
self.assertEqual(text, 'Hello Jane Hello Bob')
buffer.set_text('')
(start, end) = buffer.get_bounds()
text = buffer.get_text(start, end, False)
self.assertEqual(text, '')
buffer.insert(end, 'HelloHello')
buffer.insert(end, ' Bob')
cursor_iter = end.copy()
cursor_iter.backward_chars(9)
buffer.place_cursor(cursor_iter)
buffer.insert_at_cursor(' Jane ')
(start, end) = buffer.get_bounds()
text = buffer.get_text(start, end, False)
self.assertEqual(text, 'Hello Jane Hello Bob')
sel = buffer.get_selection_bounds()
self.assertEqual(sel, ())
buffer.select_range(start, end)
sel = buffer.get_selection_bounds()
self.assertTrue(sel[0].equal(start))
self.assertTrue(sel[1].equal(end))
buffer.set_text('')
buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello')
start, end = buffer.get_bounds()
text = buffer.get_text(start, end, False)
self.assertEqual(text, 'HelloHello')
buffer.set_text('')
buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello')
start, end = buffer.get_bounds()
text = buffer.get_text(start, end, False)
self.assertEqual(text, 'HelloHello')
try:
starts_tag = Gtk.TextIter.starts_tag
except AttributeError:
starts_tag = Gtk.TextIter.begins_tag
buffer.set_text('')
buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello', tag)
(start, end) = buffer.get_bounds()
self.assertTrue(starts_tag(start, tag))
self.assertTrue(start.has_tag(tag))
buffer.set_text('')
buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello', 'title')
(start, end) = buffer.get_bounds()
self.assertTrue(starts_tag(start, tag))
self.assertTrue(start.has_tag(tag))
self.assertRaises(ValueError, buffer.insert_with_tags_by_name,
buffer.get_start_iter(), 'HelloHello', 'unknowntag')
def test_insert(self):
buffer = Gtk.TextBuffer()
start = buffer.get_bounds()[0]
with pytest.raises(TypeError):
buffer.insert(start, 42)
with pytest.raises(TypeError):
buffer.insert_at_cursor(42)
def test_text_iter(self):
try:
starts_tag = Gtk.TextIter.starts_tag
except AttributeError:
starts_tag = Gtk.TextIter.begins_tag
self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter)
buffer = Gtk.TextBuffer()
buffer.set_text('Hello Jane Hello Bob')
tag = buffer.create_tag('title', font='Sans 18')
(start, end) = buffer.get_bounds()
start.forward_chars(10)
buffer.apply_tag(tag, start, end)
self.assertTrue(starts_tag(start))
self.assertTrue(end.ends_tag())
self.assertTrue(start.toggles_tag())
self.assertTrue(end.toggles_tag())
start.backward_chars(1)
self.assertFalse(starts_tag(start))
self.assertFalse(start.ends_tag())
self.assertFalse(start.toggles_tag())
def test_text_buffer_search(self):
buffer = Gtk.TextBuffer()
buffer.set_text('Hello World Hello GNOME')
i = buffer.get_iter_at_offset(0)
self.assertTrue(isinstance(i, Gtk.TextIter))
self.assertEqual(i.forward_search('world', 0, None), None)
(start, end) = i.forward_search('World', 0, None)
self.assertEqual(start.get_offset(), 6)
self.assertEqual(end.get_offset(), 11)
(start, end) = i.forward_search('world',
Gtk.TextSearchFlags.CASE_INSENSITIVE,
None)
self.assertEqual(start.get_offset(), 6)
self.assertEqual(end.get_offset(), 11)
def test_insert_text_signal_location_modification(self):
# Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=736175
def callback(buffer, location, text, length):
location.assign(buffer.get_end_iter())
buffer = Gtk.TextBuffer()
buffer.set_text('first line\n')
buffer.connect('insert-text', callback)
# attempt insertion at the beginning of the buffer, the callback will
# modify the insert location to the end.
buffer.place_cursor(buffer.get_start_iter())
buffer.insert_at_cursor('second line\n')
self.assertEqual(buffer.get_property('text'),
'first line\nsecond line\n')
@unittest.skipIf(gtkver() < (3, 20, 0), "broken with older gtk")
def test_backward_find_char(self):
buffer = Gtk.TextBuffer()
buffer.set_text('abc')
res = buffer.get_iter_at_line(99)
if GTK4:
end = res.iter
else:
end = res
values = []
def pred_func(ch, user_data):
values.append(ch)
return ch == u"a"
self.assertTrue(end.backward_find_char(pred_func))
self.assertEqual(values, [u"c", u"b", u"a"])
@unittest.skipUnless(Gtk, 'Gtk not available')
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
class TestPaned(unittest.TestCase):
def test_pack_defaults(self):
p = Gtk.Paned()
l1 = Gtk.Label()
l2 = Gtk.Label()
p.pack1(l1)
p.pack2(l2)
assert p.get_children() == [l1, l2]
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestContainer(unittest.TestCase):
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_child_set_property(self):
box = Gtk.Box()
child = Gtk.Button()
box.pack_start(child, expand=False, fill=True, padding=0)
box.child_set_property(child, 'padding', 42)
value = GObject.Value(int)
box.child_get_property(child, 'padding', value)
self.assertEqual(value.get_int(), 42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_child_get_property_gvalue(self):
box = Gtk.Box()
child = Gtk.Button()
box.pack_start(child, expand=False, fill=True, padding=42)
value = GObject.Value(int)
box.child_get_property(child, 'padding', value)
self.assertEqual(value.get_int(), 42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_child_get_property_return_with_explicit_gvalue(self):
box = Gtk.Box()
child = Gtk.Button()
box.pack_start(child, expand=False, fill=True, padding=42)
value = GObject.Value(int)
result = box.child_get_property(child, 'padding', value)
self.assertEqual(result, 42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_child_get_property_return_with_implicit_gvalue(self):
box = Gtk.Box()
child = Gtk.Button()
box.pack_start(child, expand=False, fill=True, padding=42)
result = box.child_get_property(child, 'padding')
self.assertEqual(result, 42)
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_child_get_property_error(self):
box = Gtk.Box()
child = Gtk.Button()
if Gtk_version == "4.0":
box.add(child)
else:
box.pack_start(child, expand=False, fill=True, padding=42)
with self.assertRaises(ValueError):
box.child_get_property(child, 'not-a-valid-child-property')
@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_child_get_and_set(self):
box = Gtk.Box()
child = Gtk.Button()
box.pack_start(child, expand=True, fill=True, padding=42)
expand, fill, padding = box.child_get(child, 'expand', 'fill', 'padding')
self.assertEqual(expand, True)
self.assertEqual(fill, True)
self.assertEqual(padding, 42)
box.child_set(child, expand=False, fill=False, padding=21, pack_type=1)
expand, fill, padding, pack_type = box.child_get(child, 'expand', 'fill', 'padding', 'pack-type')
self.assertEqual(expand, False)
self.assertEqual(fill, False)
self.assertEqual(padding, 21)
def test_button_focus_on_click():
b = Gtk.Button()
b.set_focus_on_click(True)
assert b.get_focus_on_click()
b.set_focus_on_click(False)
assert not b.get_focus_on_click()
@pytest.mark.parametrize(
"data",
[
"* { background: white; }",
"* { background: white; }".encode()
]
)
def test_css_provider_load_from_data(data):
provider = Gtk.CssProvider.new()
provider.load_from_data(data)