12 from gi.repository import GObject, GLib, Gio
13 from gi import PyGIDeprecationWarning
14 from gi.module import get_introspection_module
18 from .helper import capture_glib_deprecation_warnings
21 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="crashes")
22 def test_gobject_weak_ref():
29 # object gets finalized
30 obj = GObject.Object()
31 obj.weak_ref(callback, 1)
38 # wrapper gets finalized first
39 obj = GObject.Object()
40 pyref = weakref.ref(obj, lambda x: callback(-2))
41 value = GObject.Value(GObject.Object, obj)
42 ref = obj.weak_ref(callback, 2)
49 assert called == [-2, 2]
52 # weakref gets unregistered first
53 obj = GObject.Object()
54 ref = obj.weak_ref(callback, 3)
61 obj = GObject.Object()
62 obj.weak_ref(callback, 4)
68 class TestGObjectAPI(unittest.TestCase):
70 def test_run_dispose(self):
71 class TestObject(GObject.GObject):
72 int_prop = GObject.Property(default=0, type=int)
80 obj.connect('notify::int-prop', on_notify)
81 obj.notify("int-prop")
82 obj.notify("int-prop")
83 # after this everything should be disconnected
85 obj.notify("int-prop")
86 obj.notify("int-prop")
87 assert len(called) == 2
89 def test_call_method_uninitialized_instance(self):
90 obj = GObject.Object.__new__(GObject.Object)
91 with self.assertRaisesRegex(RuntimeError, '.*is not initialized'):
94 def test_gobject_inheritance(self):
95 # GObject.Object is a class hierarchy as follows:
96 # overrides.Object -> introspection.Object -> static.GObject
97 GIObjectModule = get_introspection_module('GObject')
98 self.assertTrue(issubclass(GObject.Object, GIObjectModule.Object))
99 self.assertTrue(issubclass(GIObjectModule.Object, _gi.GObject))
101 self.assertEqual(_gi.GObject.__gtype__, GObject.TYPE_OBJECT)
102 self.assertEqual(GIObjectModule.Object.__gtype__, GObject.TYPE_OBJECT)
103 self.assertEqual(GObject.Object.__gtype__, GObject.TYPE_OBJECT)
105 # The pytype wrapper should hold the outer most Object class from overrides.
106 self.assertEqual(GObject.TYPE_OBJECT.pytype, GObject.Object)
108 def test_gobject_unsupported_overrides(self):
109 obj = GObject.Object()
111 with self.assertRaisesRegex(RuntimeError, 'Data access methods are unsupported.*'):
114 with self.assertRaisesRegex(RuntimeError, 'This method is currently unsupported.*'):
117 def test_compat_api(self):
118 with warnings.catch_warnings(record=True) as w:
119 warnings.simplefilter('always')
120 # GObject formerly exposed a lot of GLib's functions
121 self.assertEqual(GObject.markup_escape_text('foo'), 'foo')
123 ml = GObject.MainLoop()
124 self.assertFalse(ml.is_running())
126 context = GObject.main_context_default()
127 self.assertTrue(context.pending() in [False, True])
129 context = GObject.MainContext()
130 self.assertFalse(context.pending())
132 self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning))
133 self.assertTrue('GLib.markup_escape_text' in str(w[0]), str(w[0]))
135 self.assertLess(GObject.PRIORITY_HIGH, GObject.PRIORITY_DEFAULT)
137 def test_min_max_int(self):
138 with warnings.catch_warnings():
139 warnings.simplefilter('ignore', PyGIDeprecationWarning)
141 self.assertEqual(GObject.G_MAXINT16, 2 ** 15 - 1)
142 self.assertEqual(GObject.G_MININT16, -2 ** 15)
143 self.assertEqual(GObject.G_MAXUINT16, 2 ** 16 - 1)
145 self.assertEqual(GObject.G_MAXINT32, 2 ** 31 - 1)
146 self.assertEqual(GObject.G_MININT32, -2 ** 31)
147 self.assertEqual(GObject.G_MAXUINT32, 2 ** 32 - 1)
149 self.assertEqual(GObject.G_MAXINT64, 2 ** 63 - 1)
150 self.assertEqual(GObject.G_MININT64, -2 ** 63)
151 self.assertEqual(GObject.G_MAXUINT64, 2 ** 64 - 1)
154 class TestReferenceCounting(unittest.TestCase):
155 def test_regular_object(self):
156 obj = GObject.GObject()
157 self.assertEqual(obj.__grefcount__, 1)
159 obj = GObject.new(GObject.GObject)
160 self.assertEqual(obj.__grefcount__, 1)
162 def test_floating(self):
163 obj = testhelper.Floating()
164 self.assertEqual(obj.__grefcount__, 1)
166 obj = GObject.new(testhelper.Floating)
167 self.assertEqual(obj.__grefcount__, 1)
169 def test_owned_by_library(self):
170 # Upon creation, the refcount of the object should be 2:
171 # - someone already has a reference on the new object.
172 # - the python wrapper should hold its own reference.
173 obj = testhelper.OwnedByLibrary()
174 self.assertEqual(obj.__grefcount__, 2)
176 # We ask the library to release its reference, so the only
177 # remaining ref should be our wrapper's. Once the wrapper
178 # will run out of scope, the object will get finalized.
180 self.assertEqual(obj.__grefcount__, 1)
182 def test_owned_by_library_out_of_scope(self):
183 obj = testhelper.OwnedByLibrary()
184 self.assertEqual(obj.__grefcount__, 2)
186 # We are manually taking the object out of scope. This means
187 # that our wrapper has been freed, and its reference dropped. We
188 # cannot check it but the refcount should now be 1 (the ref held
189 # by the library is still there, we didn't call release()
192 # When we get the object back from the lib, the wrapper is
193 # re-created, so our refcount will be 2 once again.
194 obj = testhelper.owned_by_library_get_instance_list()[0]
195 self.assertEqual(obj.__grefcount__, 2)
198 self.assertEqual(obj.__grefcount__, 1)
200 def test_owned_by_library_using_gobject_new(self):
201 # Upon creation, the refcount of the object should be 2:
202 # - someone already has a reference on the new object.
203 # - the python wrapper should hold its own reference.
204 obj = GObject.new(testhelper.OwnedByLibrary)
205 self.assertEqual(obj.__grefcount__, 2)
207 # We ask the library to release its reference, so the only
208 # remaining ref should be our wrapper's. Once the wrapper
209 # will run out of scope, the object will get finalized.
211 self.assertEqual(obj.__grefcount__, 1)
213 def test_owned_by_library_out_of_scope_using_gobject_new(self):
214 obj = GObject.new(testhelper.OwnedByLibrary)
215 self.assertEqual(obj.__grefcount__, 2)
217 # We are manually taking the object out of scope. This means
218 # that our wrapper has been freed, and its reference dropped. We
219 # cannot check it but the refcount should now be 1 (the ref held
220 # by the library is still there, we didn't call release()
223 # When we get the object back from the lib, the wrapper is
224 # re-created, so our refcount will be 2 once again.
225 obj = testhelper.owned_by_library_get_instance_list()[0]
226 self.assertEqual(obj.__grefcount__, 2)
229 self.assertEqual(obj.__grefcount__, 1)
231 def test_floating_and_sunk(self):
232 # Upon creation, the refcount of the object should be 2:
233 # - someone already has a reference on the new object.
234 # - the python wrapper should hold its own reference.
235 obj = testhelper.FloatingAndSunk()
236 self.assertEqual(obj.__grefcount__, 2)
238 # We ask the library to release its reference, so the only
239 # remaining ref should be our wrapper's. Once the wrapper
240 # will run out of scope, the object will get finalized.
242 self.assertEqual(obj.__grefcount__, 1)
244 def test_floating_and_sunk_out_of_scope(self):
245 obj = testhelper.FloatingAndSunk()
246 self.assertEqual(obj.__grefcount__, 2)
248 # We are manually taking the object out of scope. This means
249 # that our wrapper has been freed, and its reference dropped. We
250 # cannot check it but the refcount should now be 1 (the ref held
251 # by the library is still there, we didn't call release()
254 # When we get the object back from the lib, the wrapper is
255 # re-created, so our refcount will be 2 once again.
256 obj = testhelper.floating_and_sunk_get_instance_list()[0]
257 self.assertEqual(obj.__grefcount__, 2)
260 self.assertEqual(obj.__grefcount__, 1)
262 def test_floating_and_sunk_using_gobject_new(self):
263 # Upon creation, the refcount of the object should be 2:
264 # - someone already has a reference on the new object.
265 # - the python wrapper should hold its own reference.
266 obj = GObject.new(testhelper.FloatingAndSunk)
267 self.assertEqual(obj.__grefcount__, 2)
269 # We ask the library to release its reference, so the only
270 # remaining ref should be our wrapper's. Once the wrapper
271 # will run out of scope, the object will get finalized.
273 self.assertEqual(obj.__grefcount__, 1)
275 def test_floating_and_sunk_out_of_scope_using_gobject_new(self):
276 obj = GObject.new(testhelper.FloatingAndSunk)
277 self.assertEqual(obj.__grefcount__, 2)
279 # We are manually taking the object out of scope. This means
280 # that our wrapper has been freed, and its reference dropped. We
281 # cannot check it but the refcount should now be 1 (the ref held
282 # by the library is still there, we didn't call release()
285 # When we get the object back from the lib, the wrapper is
286 # re-created, so our refcount will be 2 once again.
287 obj = testhelper.floating_and_sunk_get_instance_list()[0]
288 self.assertEqual(obj.__grefcount__, 2)
291 self.assertEqual(obj.__grefcount__, 1)
293 def test_uninitialized_object(self):
294 class Obj(GObject.GObject):
296 x = self.__grefcount__
297 super(Obj, self).__init__()
298 assert x >= 0 # quiesce pyflakes
300 # Accessing __grefcount__ before the object is initialized is wrong.
301 # Ensure we get a proper exception instead of a crash.
302 self.assertRaises(TypeError, Obj)
305 class A(GObject.GObject):
307 super(A, self).__init__()
310 class TestPythonReferenceCounting(unittest.TestCase):
311 # Newly created instances should alwayshave two references: one for
312 # the GC, and one for the bound variable in the local scope.
314 def test_new_instance_has_two_refs(self):
315 obj = GObject.GObject()
316 if hasattr(sys, "getrefcount"):
317 self.assertEqual(sys.getrefcount(obj), 2)
319 def test_new_instance_has_two_refs_using_gobject_new(self):
320 obj = GObject.new(GObject.GObject)
321 if hasattr(sys, "getrefcount"):
322 self.assertEqual(sys.getrefcount(obj), 2)
324 def test_new_subclass_instance_has_two_refs(self):
326 if hasattr(sys, "getrefcount"):
327 self.assertEqual(sys.getrefcount(obj), 2)
329 def test_new_subclass_instance_has_two_refs_using_gobject_new(self):
331 if hasattr(sys, "getrefcount"):
332 self.assertEqual(sys.getrefcount(obj), 2)
335 class TestContextManagers(unittest.TestCase):
336 class ContextTestObject(GObject.GObject):
337 prop = GObject.Property(default=0, type=int)
339 def on_prop_set(self, obj, prop):
340 # Handler which tracks property changed notifications.
341 self.tracking.append(obj.get_property(prop.name))
345 self.obj = self.ContextTestObject()
346 self.handler = self.obj.connect('notify::prop', self.on_prop_set)
348 def test_freeze_notify_context(self):
349 # Verify prop tracking list
350 self.assertEqual(self.tracking, [])
351 self.obj.props.prop = 1
352 self.assertEqual(self.tracking, [1])
353 self.obj.props.prop = 2
354 self.assertEqual(self.tracking, [1, 2])
355 self.assertEqual(self.obj.__grefcount__, 1)
357 if hasattr(sys, "getrefcount"):
358 pyref_count = sys.getrefcount(self.obj)
360 # Using the context manager the tracking list should not be affected.
361 # The GObject reference count should stay the same and the python
362 # object ref-count should go up.
363 with self.obj.freeze_notify():
364 self.assertEqual(self.obj.__grefcount__, 1)
365 if hasattr(sys, "getrefcount"):
366 self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1)
367 self.obj.props.prop = 3
368 self.assertEqual(self.obj.props.prop, 3)
369 self.assertEqual(self.tracking, [1, 2])
371 # After the context manager, the prop should have been modified,
372 # the tracking list will be modified, and the python object ref
373 # count goes back down.
375 self.assertEqual(self.obj.props.prop, 3)
376 self.assertEqual(self.tracking, [1, 2, 3])
377 self.assertEqual(self.obj.__grefcount__, 1)
378 if hasattr(sys, "getrefcount"):
379 self.assertEqual(sys.getrefcount(self.obj), pyref_count)
381 def test_handler_block_context(self):
382 # Verify prop tracking list
383 self.assertEqual(self.tracking, [])
384 self.obj.props.prop = 1
385 self.assertEqual(self.tracking, [1])
386 self.obj.props.prop = 2
387 self.assertEqual(self.tracking, [1, 2])
388 self.assertEqual(self.obj.__grefcount__, 1)
390 if hasattr(sys, "getrefcount"):
391 pyref_count = sys.getrefcount(self.obj)
393 # Using the context manager the tracking list should not be affected.
394 # The GObject reference count should stay the same and the python
395 # object ref-count should go up.
396 with self.obj.handler_block(self.handler):
397 self.assertEqual(self.obj.__grefcount__, 1)
398 if hasattr(sys, "getrefcount"):
399 self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1)
400 self.obj.props.prop = 3
401 self.assertEqual(self.obj.props.prop, 3)
402 self.assertEqual(self.tracking, [1, 2])
404 # After the context manager, the prop should have been modified
405 # the tracking list should have stayed the same and the GObject ref
406 # count goes back down.
408 self.assertEqual(self.obj.props.prop, 3)
409 self.assertEqual(self.tracking, [1, 2])
410 self.assertEqual(self.obj.__grefcount__, 1)
411 if hasattr(sys, "getrefcount"):
412 self.assertEqual(sys.getrefcount(self.obj), pyref_count)
414 def test_freeze_notify_context_nested(self):
415 self.assertEqual(self.tracking, [])
416 with self.obj.freeze_notify():
417 self.obj.props.prop = 1
418 self.assertEqual(self.tracking, [])
420 with self.obj.freeze_notify():
421 self.obj.props.prop = 2
422 self.assertEqual(self.tracking, [])
424 with self.obj.freeze_notify():
425 self.obj.props.prop = 3
426 self.assertEqual(self.tracking, [])
427 self.assertEqual(self.tracking, [])
428 self.assertEqual(self.tracking, [])
430 # Finally after last context, the notifications should have collapsed
431 # and the last one sent.
432 self.assertEqual(self.tracking, [3])
434 def test_handler_block_context_nested(self):
435 self.assertEqual(self.tracking, [])
436 with self.obj.handler_block(self.handler):
437 self.obj.props.prop = 1
438 self.assertEqual(self.tracking, [])
440 with self.obj.handler_block(self.handler):
441 self.obj.props.prop = 2
442 self.assertEqual(self.tracking, [])
444 with self.obj.handler_block(self.handler):
445 self.obj.props.prop = 3
446 self.assertEqual(self.tracking, [])
447 self.assertEqual(self.tracking, [])
448 self.assertEqual(self.tracking, [])
450 # Finally after last context, the notifications should have collapsed
451 # and the last one sent.
452 self.assertEqual(self.obj.props.prop, 3)
453 self.assertEqual(self.tracking, [])
455 def test_freeze_notify_normal_usage_ref_counts(self):
456 # Ensure ref counts without using methods as context managers
457 # maintain the same count.
458 self.assertEqual(self.obj.__grefcount__, 1)
459 self.obj.freeze_notify()
460 self.assertEqual(self.obj.__grefcount__, 1)
461 self.obj.thaw_notify()
462 self.assertEqual(self.obj.__grefcount__, 1)
464 def test_handler_block_normal_usage_ref_counts(self):
465 self.assertEqual(self.obj.__grefcount__, 1)
466 self.obj.handler_block(self.handler)
467 self.assertEqual(self.obj.__grefcount__, 1)
468 self.obj.handler_unblock(self.handler)
469 self.assertEqual(self.obj.__grefcount__, 1)
471 def test_freeze_notify_context_error(self):
472 # Test an exception occurring within a freeze context exits the context
474 with self.obj.freeze_notify():
475 self.obj.props.prop = 1
476 self.assertEqual(self.tracking, [])
477 raise ValueError('Simulation')
481 # Verify the property set within the context called notify.
482 self.assertEqual(self.obj.props.prop, 1)
483 self.assertEqual(self.tracking, [1])
485 # Verify we are still not in a frozen context.
486 self.obj.props.prop = 2
487 self.assertEqual(self.tracking, [1, 2])
489 def test_handler_block_context_error(self):
490 # Test an exception occurring within a handler block exits the context
492 with self.obj.handler_block(self.handler):
493 self.obj.props.prop = 1
494 self.assertEqual(self.tracking, [])
495 raise ValueError('Simulation')
499 # Verify the property set within the context didn't call notify.
500 self.assertEqual(self.obj.props.prop, 1)
501 self.assertEqual(self.tracking, [])
503 # Verify we are still not in a handler block context.
504 self.obj.props.prop = 2
505 self.assertEqual(self.tracking, [2])
508 @unittest.skipUnless(hasattr(GObject.Binding, 'unbind'),
509 'Requires newer GLib which has g_binding_unbind')
510 class TestPropertyBindings(unittest.TestCase):
511 class TestObject(GObject.GObject):
512 int_prop = GObject.Property(default=0, type=int)
515 self.source = self.TestObject()
516 self.target = self.TestObject()
518 def test_default_binding(self):
519 binding = self.source.bind_property('int_prop', self.target, 'int_prop',
520 GObject.BindingFlags.DEFAULT)
521 binding = binding # PyFlakes
523 # Test setting value on source gets pushed to target
524 self.source.int_prop = 1
525 self.assertEqual(self.source.int_prop, 1)
526 self.assertEqual(self.target.int_prop, 1)
528 # Test setting value on target does not change source
529 self.target.props.int_prop = 2
530 self.assertEqual(self.source.int_prop, 1)
531 self.assertEqual(self.target.int_prop, 2)
533 def test_call_binding(self):
534 binding = self.source.bind_property('int_prop', self.target, 'int_prop',
535 GObject.BindingFlags.DEFAULT)
536 with capture_glib_deprecation_warnings() as warn:
539 assert result is binding
541 def test_bidirectional_binding(self):
542 binding = self.source.bind_property('int_prop', self.target, 'int_prop',
543 GObject.BindingFlags.BIDIRECTIONAL)
544 binding = binding # PyFlakes
546 # Test setting value on source gets pushed to target
547 self.source.int_prop = 1
548 self.assertEqual(self.source.int_prop, 1)
549 self.assertEqual(self.target.int_prop, 1)
551 # Test setting value on target also changes source
552 self.target.props.int_prop = 2
553 self.assertEqual(self.source.int_prop, 2)
554 self.assertEqual(self.target.int_prop, 2)
556 def test_transform_to_only(self):
557 def transform_to(binding, value, user_data=None):
558 self.assertEqual(user_data, 'test-data')
561 binding = self.source.bind_property('int_prop', self.target, 'int_prop',
562 GObject.BindingFlags.DEFAULT,
563 transform_to, None, 'test-data')
564 binding = binding # PyFlakes
566 self.source.int_prop = 1
567 self.assertEqual(self.source.int_prop, 1)
568 self.assertEqual(self.target.int_prop, 2)
570 self.target.props.int_prop = 1
571 self.assertEqual(self.source.int_prop, 1)
572 self.assertEqual(self.target.int_prop, 1)
574 def test_transform_from_only(self):
575 def transform_from(binding, value, user_data=None):
576 self.assertEqual(user_data, None)
579 binding = self.source.bind_property('int_prop', self.target, 'int_prop',
580 GObject.BindingFlags.BIDIRECTIONAL,
581 None, transform_from)
582 binding = binding # PyFlakes
584 self.source.int_prop = 1
585 self.assertEqual(self.source.int_prop, 1)
586 self.assertEqual(self.target.int_prop, 1)
588 self.target.props.int_prop = 1
589 self.assertEqual(self.source.int_prop, 2)
590 self.assertEqual(self.target.int_prop, 1)
592 def test_transform_bidirectional(self):
595 def transform_to(binding, value, user_data=None):
596 self.assertEqual(user_data, test_data)
599 def transform_from(binding, value, user_data=None):
600 self.assertEqual(user_data, test_data)
603 if hasattr(sys, "getrefcount"):
604 test_data_ref_count = sys.getrefcount(test_data)
605 transform_to_ref_count = sys.getrefcount(transform_to)
606 transform_from_ref_count = sys.getrefcount(transform_from)
608 # bidirectional bindings
609 binding = self.source.bind_property('int_prop', self.target, 'int_prop',
610 GObject.BindingFlags.BIDIRECTIONAL,
611 transform_to, transform_from, test_data)
612 binding = binding # PyFlakes
613 if hasattr(sys, "getrefcount"):
614 binding_ref_count = sys.getrefcount(binding)
615 binding_gref_count = binding.__grefcount__
617 self.source.int_prop = 1
618 self.assertEqual(self.source.int_prop, 1)
619 self.assertEqual(self.target.int_prop, 2)
621 self.target.props.int_prop = 4
622 self.assertEqual(self.source.int_prop, 2)
623 self.assertEqual(self.target.int_prop, 4)
625 if hasattr(sys, "getrefcount"):
626 self.assertEqual(sys.getrefcount(binding), binding_ref_count)
627 self.assertEqual(binding.__grefcount__, binding_gref_count)
629 # test_data ref count increases by 2, once for each callback.
630 if hasattr(sys, "getrefcount"):
631 self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2)
632 self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count + 1)
633 self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count + 1)
635 # Unbind should clear out the binding and its transforms
638 # Setting source or target should not change the other.
639 self.target.int_prop = 3
640 self.source.int_prop = 5
641 self.assertEqual(self.target.int_prop, 3)
642 self.assertEqual(self.source.int_prop, 5)
644 if hasattr(sys, "getrefcount"):
645 self.assertEqual(sys.getrefcount(test_data), test_data_ref_count)
646 self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count)
647 self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count)
649 def test_explicit_unbind_clears_connection(self):
650 self.assertEqual(self.source.int_prop, 0)
651 self.assertEqual(self.target.int_prop, 0)
653 # Test deleting binding reference removes binding.
654 binding = self.source.bind_property('int_prop', self.target, 'int_prop')
655 self.source.int_prop = 1
656 self.assertEqual(self.source.int_prop, 1)
657 self.assertEqual(self.target.int_prop, 1)
659 # unbind should clear out the bindings self reference
661 self.assertEqual(binding.__grefcount__, 1)
663 self.source.int_prop = 10
664 self.assertEqual(self.source.int_prop, 10)
665 self.assertEqual(self.target.int_prop, 1)
667 glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)
669 # calling unbind() on an already unbound binding
670 if glib_version >= (2, 57, 3):
671 # Fixed in newer glib:
672 # https://gitlab.gnome.org/GNOME/glib/merge_requests/244
676 self.assertRaises(ValueError, binding.unbind)
678 def test_reference_counts(self):
679 self.assertEqual(self.source.__grefcount__, 1)
680 self.assertEqual(self.target.__grefcount__, 1)
682 # Binding ref count will be 2 do to the initial ref implicitly held by
683 # the act of binding and the ref incurred by using __call__ to generate
684 # a wrapper from the weak binding ref within python.
685 binding = self.source.bind_property('int_prop', self.target, 'int_prop')
686 self.assertEqual(binding.__grefcount__, 2)
688 # Creating a binding does not inc refs on source and target (they are weak
689 # on the binding object itself)
690 self.assertEqual(self.source.__grefcount__, 1)
691 self.assertEqual(self.target.__grefcount__, 1)
693 # Use GObject.get_property because the "props" accessor leaks.
694 # Note property names are canonicalized.
695 self.assertEqual(binding.get_property('source'), self.source)
696 self.assertEqual(binding.get_property('source_property'), 'int-prop')
697 self.assertEqual(binding.get_property('target'), self.target)
698 self.assertEqual(binding.get_property('target_property'), 'int-prop')
699 self.assertEqual(binding.get_property('flags'), GObject.BindingFlags.DEFAULT)
701 # Delete reference to source or target and the binding will remove its own
703 ref = self.source.weak_ref()
706 self.assertEqual(ref(), None)
707 self.assertEqual(binding.__grefcount__, 1)
709 # Finally clear out the last ref held by the python wrapper
710 ref = binding.weak_ref()
713 self.assertEqual(ref(), None)
716 class TestGValue(unittest.TestCase):
717 def test_type_constant(self):
718 self.assertEqual(GObject.TYPE_VALUE, GObject.Value.__gtype__)
719 self.assertEqual(GObject.type_name(GObject.TYPE_VALUE), 'GValue')
721 def test_no_type(self):
722 value = GObject.Value()
723 self.assertEqual(value.g_type, GObject.TYPE_INVALID)
724 self.assertRaises(TypeError, value.set_value, 23)
725 self.assertEqual(value.get_value(), None)
728 value = GObject.Value(GObject.TYPE_UINT)
729 self.assertEqual(value.g_type, GObject.TYPE_UINT)
731 self.assertEqual(value.get_value(), 23)
732 value.set_value(42.0)
733 self.assertEqual(value.get_value(), 42)
735 def test_string(self):
736 value = GObject.Value(str, 'foo_bar')
737 self.assertEqual(value.g_type, GObject.TYPE_STRING)
738 self.assertEqual(value.get_value(), 'foo_bar')
740 def test_float(self):
741 # python float is G_TYPE_DOUBLE
742 value = GObject.Value(float, 23.4)
743 self.assertEqual(value.g_type, GObject.TYPE_DOUBLE)
744 value.set_value(1e50)
745 self.assertAlmostEqual(value.get_value(), 1e50)
747 value = GObject.Value(GObject.TYPE_FLOAT, 23.4)
748 self.assertEqual(value.g_type, GObject.TYPE_FLOAT)
749 self.assertRaises(TypeError, value.set_value, 'string')
750 self.assertRaises(OverflowError, value.set_value, 1e50)
752 def test_float_inf_nan(self):
754 for type_ in [GObject.TYPE_FLOAT, GObject.TYPE_DOUBLE]:
755 for x in [float('inf'), float('-inf'), nan]:
756 value = GObject.Value(type_, x)
757 # assertEqual() is False for (nan, nan)
759 self.assertEqual(str(value.get_value()), 'nan')
761 self.assertEqual(value.get_value(), x)
764 value = GObject.Value(GLib.FileError, GLib.FileError.FAILED)
765 self.assertEqual(value.get_value(), GLib.FileError.FAILED)
767 def test_flags(self):
768 value = GObject.Value(GLib.IOFlags, GLib.IOFlags.IS_READABLE)
769 self.assertEqual(value.get_value(), GLib.IOFlags.IS_READABLE)
771 def test_object(self):
772 class TestObject(GObject.Object):
775 value = GObject.Value(GObject.TYPE_OBJECT, obj)
776 self.assertEqual(value.get_value(), obj)
778 def test_value_array(self):
779 value = GObject.Value(GObject.ValueArray)
780 self.assertEqual(value.g_type, GObject.type_from_name('GValueArray'))
781 value.set_value([32, 'foo_bar', 0.3])
782 self.assertEqual(value.get_value(), [32, 'foo_bar', 0.3])
784 def test_value_array_from_gvalue_list(self):
785 value = GObject.Value(GObject.ValueArray, [
786 GObject.Value(GObject.TYPE_UINT, 0xffffffff),
787 GObject.Value(GObject.TYPE_STRING, 'foo_bar')])
788 self.assertEqual(value.g_type, GObject.type_from_name('GValueArray'))
789 self.assertEqual(value.get_value(), [0xffffffff, 'foo_bar'])
790 self.assertEqual(testhelper.value_array_get_nth_type(value, 0), GObject.TYPE_UINT)
791 self.assertEqual(testhelper.value_array_get_nth_type(value, 1), GObject.TYPE_STRING)
793 def test_value_array_append_gvalue(self):
794 with warnings.catch_warnings():
795 warnings.simplefilter('ignore', DeprecationWarning)
797 arr = GObject.ValueArray.new(0)
798 arr.append(GObject.Value(GObject.TYPE_UINT, 0xffffffff))
799 arr.append(GObject.Value(GObject.TYPE_STRING, 'foo_bar'))
800 self.assertEqual(arr.get_nth(0), 0xffffffff)
801 self.assertEqual(arr.get_nth(1), 'foo_bar')
802 self.assertEqual(testhelper.value_array_get_nth_type(arr, 0), GObject.TYPE_UINT)
803 self.assertEqual(testhelper.value_array_get_nth_type(arr, 1), GObject.TYPE_STRING)
805 def test_gerror_boxing(self):
806 error = GLib.Error('test message', domain='mydomain', code=42)
807 value = GObject.Value(GLib.Error, error)
808 self.assertEqual(value.g_type, GObject.type_from_name('GError'))
810 unboxed = value.get_value()
811 self.assertEqual(unboxed.message, error.message)
812 self.assertEqual(unboxed.domain, error.domain)
813 self.assertEqual(unboxed.code, error.code)
815 def test_gerror_novalue(self):
816 GLib.Error('test message', domain='mydomain', code=42)
817 value = GObject.Value(GLib.Error)
818 self.assertEqual(value.g_type, GObject.type_from_name('GError'))
819 self.assertEqual(value.get_value(), None)
822 def test_list_properties():
824 def find_param(props, name):
826 if param.name == name:
830 list_props = GObject.list_properties
832 props = list_props(Gio.Action)
833 param = find_param(props, "enabled")
835 assert param.value_type == GObject.TYPE_BOOLEAN
836 assert list_props("GAction") == list_props(Gio.Action)
837 assert list_props(Gio.Action.__gtype__) == list_props(Gio.Action)
839 props = list_props(Gio.SimpleAction)
840 assert find_param(props, "enabled")
843 return [p.name for p in props]
845 assert (set(names(list_props(Gio.Action))) <=
846 set(names(list_props(Gio.SimpleAction))))
848 props = list_props(Gio.FileIcon)
849 param = find_param(props, "file")
851 assert param.value_type == Gio.File.__gtype__
853 assert list_props("GFileIcon") == list_props(Gio.FileIcon)
854 assert list_props(Gio.FileIcon.__gtype__) == list_props(Gio.FileIcon)
855 assert list_props(Gio.FileIcon(
856 file=Gio.File.new_for_path('.'))) == list_props(Gio.FileIcon)
858 for obj in [Gio.ActionEntry, Gio.DBusError, 0, object()]:
859 with pytest.raises(TypeError):