3 from __future__
import absolute_import
12 from gi
.repository
import GObject
, GLib
, Gio
13 from gi
import PyGIDeprecationWarning
14 from gi
.module
import get_introspection_module
20 class TestGObjectAPI(unittest
.TestCase
):
22 def test_call_method_uninitialized_instance(self
):
23 obj
= GObject
.Object
.__new
__(GObject
.Object
)
24 with self
.assertRaisesRegex(RuntimeError, '.*is not initialized'):
27 def test_gobject_inheritance(self
):
28 # GObject.Object is a class hierarchy as follows:
29 # overrides.Object -> introspection.Object -> static.GObject
30 GIObjectModule
= get_introspection_module('GObject')
31 self
.assertTrue(issubclass(GObject
.Object
, GIObjectModule
.Object
))
32 self
.assertTrue(issubclass(GIObjectModule
.Object
, _gi
.GObject
))
34 self
.assertEqual(_gi
.GObject
.__gtype
__, GObject
.TYPE_OBJECT
)
35 self
.assertEqual(GIObjectModule
.Object
.__gtype
__, GObject
.TYPE_OBJECT
)
36 self
.assertEqual(GObject
.Object
.__gtype
__, GObject
.TYPE_OBJECT
)
38 # The pytype wrapper should hold the outer most Object class from overrides.
39 self
.assertEqual(GObject
.TYPE_OBJECT
.pytype
, GObject
.Object
)
41 def test_gobject_unsupported_overrides(self
):
42 obj
= GObject
.Object()
44 with self
.assertRaisesRegex(RuntimeError, 'Data access methods are unsupported.*'):
47 with self
.assertRaisesRegex(RuntimeError, 'This method is currently unsupported.*'):
50 def test_compat_api(self
):
51 with warnings
.catch_warnings(record
=True) as w
:
52 warnings
.simplefilter('always')
53 # GObject formerly exposed a lot of GLib's functions
54 self
.assertEqual(GObject
.markup_escape_text('foo'), 'foo')
56 ml
= GObject
.MainLoop()
57 self
.assertFalse(ml
.is_running())
59 context
= GObject
.main_context_default()
60 self
.assertTrue(context
.pending() in [False, True])
62 context
= GObject
.MainContext()
63 self
.assertFalse(context
.pending())
65 self
.assertTrue(issubclass(w
[0].category
, PyGIDeprecationWarning
))
66 self
.assertTrue('GLib.markup_escape_text' in str(w
[0]), str(w
[0]))
68 self
.assertLess(GObject
.PRIORITY_HIGH
, GObject
.PRIORITY_DEFAULT
)
70 def test_min_max_int(self
):
71 with warnings
.catch_warnings():
72 warnings
.simplefilter('ignore', PyGIDeprecationWarning
)
74 self
.assertEqual(GObject
.G_MAXINT16
, 2 ** 15 - 1)
75 self
.assertEqual(GObject
.G_MININT16
, -2 ** 15)
76 self
.assertEqual(GObject
.G_MAXUINT16
, 2 ** 16 - 1)
78 self
.assertEqual(GObject
.G_MAXINT32
, 2 ** 31 - 1)
79 self
.assertEqual(GObject
.G_MININT32
, -2 ** 31)
80 self
.assertEqual(GObject
.G_MAXUINT32
, 2 ** 32 - 1)
82 self
.assertEqual(GObject
.G_MAXINT64
, 2 ** 63 - 1)
83 self
.assertEqual(GObject
.G_MININT64
, -2 ** 63)
84 self
.assertEqual(GObject
.G_MAXUINT64
, 2 ** 64 - 1)
87 class TestReferenceCounting(unittest
.TestCase
):
88 def test_regular_object(self
):
89 obj
= GObject
.GObject()
90 self
.assertEqual(obj
.__grefcount
__, 1)
92 obj
= GObject
.new(GObject
.GObject
)
93 self
.assertEqual(obj
.__grefcount
__, 1)
95 def test_floating(self
):
96 obj
= testhelper
.Floating()
97 self
.assertEqual(obj
.__grefcount
__, 1)
99 obj
= GObject
.new(testhelper
.Floating
)
100 self
.assertEqual(obj
.__grefcount
__, 1)
102 def test_owned_by_library(self
):
103 # Upon creation, the refcount of the object should be 2:
104 # - someone already has a reference on the new object.
105 # - the python wrapper should hold its own reference.
106 obj
= testhelper
.OwnedByLibrary()
107 self
.assertEqual(obj
.__grefcount
__, 2)
109 # We ask the library to release its reference, so the only
110 # remaining ref should be our wrapper's. Once the wrapper
111 # will run out of scope, the object will get finalized.
113 self
.assertEqual(obj
.__grefcount
__, 1)
115 def test_owned_by_library_out_of_scope(self
):
116 obj
= testhelper
.OwnedByLibrary()
117 self
.assertEqual(obj
.__grefcount
__, 2)
119 # We are manually taking the object out of scope. This means
120 # that our wrapper has been freed, and its reference dropped. We
121 # cannot check it but the refcount should now be 1 (the ref held
122 # by the library is still there, we didn't call release()
125 # When we get the object back from the lib, the wrapper is
126 # re-created, so our refcount will be 2 once again.
127 obj
= testhelper
.owned_by_library_get_instance_list()[0]
128 self
.assertEqual(obj
.__grefcount
__, 2)
131 self
.assertEqual(obj
.__grefcount
__, 1)
133 def test_owned_by_library_using_gobject_new(self
):
134 # Upon creation, the refcount of the object should be 2:
135 # - someone already has a reference on the new object.
136 # - the python wrapper should hold its own reference.
137 obj
= GObject
.new(testhelper
.OwnedByLibrary
)
138 self
.assertEqual(obj
.__grefcount
__, 2)
140 # We ask the library to release its reference, so the only
141 # remaining ref should be our wrapper's. Once the wrapper
142 # will run out of scope, the object will get finalized.
144 self
.assertEqual(obj
.__grefcount
__, 1)
146 def test_owned_by_library_out_of_scope_using_gobject_new(self
):
147 obj
= GObject
.new(testhelper
.OwnedByLibrary
)
148 self
.assertEqual(obj
.__grefcount
__, 2)
150 # We are manually taking the object out of scope. This means
151 # that our wrapper has been freed, and its reference dropped. We
152 # cannot check it but the refcount should now be 1 (the ref held
153 # by the library is still there, we didn't call release()
156 # When we get the object back from the lib, the wrapper is
157 # re-created, so our refcount will be 2 once again.
158 obj
= testhelper
.owned_by_library_get_instance_list()[0]
159 self
.assertEqual(obj
.__grefcount
__, 2)
162 self
.assertEqual(obj
.__grefcount
__, 1)
164 def test_floating_and_sunk(self
):
165 # Upon creation, the refcount of the object should be 2:
166 # - someone already has a reference on the new object.
167 # - the python wrapper should hold its own reference.
168 obj
= testhelper
.FloatingAndSunk()
169 self
.assertEqual(obj
.__grefcount
__, 2)
171 # We ask the library to release its reference, so the only
172 # remaining ref should be our wrapper's. Once the wrapper
173 # will run out of scope, the object will get finalized.
175 self
.assertEqual(obj
.__grefcount
__, 1)
177 def test_floating_and_sunk_out_of_scope(self
):
178 obj
= testhelper
.FloatingAndSunk()
179 self
.assertEqual(obj
.__grefcount
__, 2)
181 # We are manually taking the object out of scope. This means
182 # that our wrapper has been freed, and its reference dropped. We
183 # cannot check it but the refcount should now be 1 (the ref held
184 # by the library is still there, we didn't call release()
187 # When we get the object back from the lib, the wrapper is
188 # re-created, so our refcount will be 2 once again.
189 obj
= testhelper
.floating_and_sunk_get_instance_list()[0]
190 self
.assertEqual(obj
.__grefcount
__, 2)
193 self
.assertEqual(obj
.__grefcount
__, 1)
195 def test_floating_and_sunk_using_gobject_new(self
):
196 # Upon creation, the refcount of the object should be 2:
197 # - someone already has a reference on the new object.
198 # - the python wrapper should hold its own reference.
199 obj
= GObject
.new(testhelper
.FloatingAndSunk
)
200 self
.assertEqual(obj
.__grefcount
__, 2)
202 # We ask the library to release its reference, so the only
203 # remaining ref should be our wrapper's. Once the wrapper
204 # will run out of scope, the object will get finalized.
206 self
.assertEqual(obj
.__grefcount
__, 1)
208 def test_floating_and_sunk_out_of_scope_using_gobject_new(self
):
209 obj
= GObject
.new(testhelper
.FloatingAndSunk
)
210 self
.assertEqual(obj
.__grefcount
__, 2)
212 # We are manually taking the object out of scope. This means
213 # that our wrapper has been freed, and its reference dropped. We
214 # cannot check it but the refcount should now be 1 (the ref held
215 # by the library is still there, we didn't call release()
218 # When we get the object back from the lib, the wrapper is
219 # re-created, so our refcount will be 2 once again.
220 obj
= testhelper
.floating_and_sunk_get_instance_list()[0]
221 self
.assertEqual(obj
.__grefcount
__, 2)
224 self
.assertEqual(obj
.__grefcount
__, 1)
226 def test_uninitialized_object(self
):
227 class Obj(GObject
.GObject
):
229 x
= self
.__grefcount
__
230 super(Obj
, self
).__init
__()
231 assert x
>= 0 # quiesce pyflakes
233 # Accessing __grefcount__ before the object is initialized is wrong.
234 # Ensure we get a proper exception instead of a crash.
235 self
.assertRaises(TypeError, Obj
)
238 class A(GObject
.GObject
):
240 super(A
, self
).__init
__()
243 class TestPythonReferenceCounting(unittest
.TestCase
):
244 # Newly created instances should alwayshave two references: one for
245 # the GC, and one for the bound variable in the local scope.
247 def test_new_instance_has_two_refs(self
):
248 obj
= GObject
.GObject()
249 if hasattr(sys
, "getrefcount"):
250 self
.assertEqual(sys
.getrefcount(obj
), 2)
252 def test_new_instance_has_two_refs_using_gobject_new(self
):
253 obj
= GObject
.new(GObject
.GObject
)
254 if hasattr(sys
, "getrefcount"):
255 self
.assertEqual(sys
.getrefcount(obj
), 2)
257 def test_new_subclass_instance_has_two_refs(self
):
259 if hasattr(sys
, "getrefcount"):
260 self
.assertEqual(sys
.getrefcount(obj
), 2)
262 def test_new_subclass_instance_has_two_refs_using_gobject_new(self
):
264 if hasattr(sys
, "getrefcount"):
265 self
.assertEqual(sys
.getrefcount(obj
), 2)
268 class TestContextManagers(unittest
.TestCase
):
269 class ContextTestObject(GObject
.GObject
):
270 prop
= GObject
.Property(default
=0, type=int)
272 def on_prop_set(self
, obj
, prop
):
273 # Handler which tracks property changed notifications.
274 self
.tracking
.append(obj
.get_property(prop
.name
))
278 self
.obj
= self
.ContextTestObject()
279 self
.handler
= self
.obj
.connect('notify::prop', self
.on_prop_set
)
281 def test_freeze_notify_context(self
):
282 # Verify prop tracking list
283 self
.assertEqual(self
.tracking
, [])
284 self
.obj
.props
.prop
= 1
285 self
.assertEqual(self
.tracking
, [1])
286 self
.obj
.props
.prop
= 2
287 self
.assertEqual(self
.tracking
, [1, 2])
288 self
.assertEqual(self
.obj
.__grefcount
__, 1)
290 if hasattr(sys
, "getrefcount"):
291 pyref_count
= sys
.getrefcount(self
.obj
)
293 # Using the context manager the tracking list should not be affected.
294 # The GObject reference count should stay the same and the python
295 # object ref-count should go up.
296 with self
.obj
.freeze_notify():
297 self
.assertEqual(self
.obj
.__grefcount
__, 1)
298 if hasattr(sys
, "getrefcount"):
299 self
.assertEqual(sys
.getrefcount(self
.obj
), pyref_count
+ 1)
300 self
.obj
.props
.prop
= 3
301 self
.assertEqual(self
.obj
.props
.prop
, 3)
302 self
.assertEqual(self
.tracking
, [1, 2])
304 # After the context manager, the prop should have been modified,
305 # the tracking list will be modified, and the python object ref
306 # count goes back down.
308 self
.assertEqual(self
.obj
.props
.prop
, 3)
309 self
.assertEqual(self
.tracking
, [1, 2, 3])
310 self
.assertEqual(self
.obj
.__grefcount
__, 1)
311 if hasattr(sys
, "getrefcount"):
312 self
.assertEqual(sys
.getrefcount(self
.obj
), pyref_count
)
314 def test_handler_block_context(self
):
315 # Verify prop tracking list
316 self
.assertEqual(self
.tracking
, [])
317 self
.obj
.props
.prop
= 1
318 self
.assertEqual(self
.tracking
, [1])
319 self
.obj
.props
.prop
= 2
320 self
.assertEqual(self
.tracking
, [1, 2])
321 self
.assertEqual(self
.obj
.__grefcount
__, 1)
323 if hasattr(sys
, "getrefcount"):
324 pyref_count
= sys
.getrefcount(self
.obj
)
326 # Using the context manager the tracking list should not be affected.
327 # The GObject reference count should stay the same and the python
328 # object ref-count should go up.
329 with self
.obj
.handler_block(self
.handler
):
330 self
.assertEqual(self
.obj
.__grefcount
__, 1)
331 if hasattr(sys
, "getrefcount"):
332 self
.assertEqual(sys
.getrefcount(self
.obj
), pyref_count
+ 1)
333 self
.obj
.props
.prop
= 3
334 self
.assertEqual(self
.obj
.props
.prop
, 3)
335 self
.assertEqual(self
.tracking
, [1, 2])
337 # After the context manager, the prop should have been modified
338 # the tracking list should have stayed the same and the GObject ref
339 # count goes back down.
341 self
.assertEqual(self
.obj
.props
.prop
, 3)
342 self
.assertEqual(self
.tracking
, [1, 2])
343 self
.assertEqual(self
.obj
.__grefcount
__, 1)
344 if hasattr(sys
, "getrefcount"):
345 self
.assertEqual(sys
.getrefcount(self
.obj
), pyref_count
)
347 def test_freeze_notify_context_nested(self
):
348 self
.assertEqual(self
.tracking
, [])
349 with self
.obj
.freeze_notify():
350 self
.obj
.props
.prop
= 1
351 self
.assertEqual(self
.tracking
, [])
353 with self
.obj
.freeze_notify():
354 self
.obj
.props
.prop
= 2
355 self
.assertEqual(self
.tracking
, [])
357 with self
.obj
.freeze_notify():
358 self
.obj
.props
.prop
= 3
359 self
.assertEqual(self
.tracking
, [])
360 self
.assertEqual(self
.tracking
, [])
361 self
.assertEqual(self
.tracking
, [])
363 # Finally after last context, the notifications should have collapsed
364 # and the last one sent.
365 self
.assertEqual(self
.tracking
, [3])
367 def test_handler_block_context_nested(self
):
368 self
.assertEqual(self
.tracking
, [])
369 with self
.obj
.handler_block(self
.handler
):
370 self
.obj
.props
.prop
= 1
371 self
.assertEqual(self
.tracking
, [])
373 with self
.obj
.handler_block(self
.handler
):
374 self
.obj
.props
.prop
= 2
375 self
.assertEqual(self
.tracking
, [])
377 with self
.obj
.handler_block(self
.handler
):
378 self
.obj
.props
.prop
= 3
379 self
.assertEqual(self
.tracking
, [])
380 self
.assertEqual(self
.tracking
, [])
381 self
.assertEqual(self
.tracking
, [])
383 # Finally after last context, the notifications should have collapsed
384 # and the last one sent.
385 self
.assertEqual(self
.obj
.props
.prop
, 3)
386 self
.assertEqual(self
.tracking
, [])
388 def test_freeze_notify_normal_usage_ref_counts(self
):
389 # Ensure ref counts without using methods as context managers
390 # maintain the same count.
391 self
.assertEqual(self
.obj
.__grefcount
__, 1)
392 self
.obj
.freeze_notify()
393 self
.assertEqual(self
.obj
.__grefcount
__, 1)
394 self
.obj
.thaw_notify()
395 self
.assertEqual(self
.obj
.__grefcount
__, 1)
397 def test_handler_block_normal_usage_ref_counts(self
):
398 self
.assertEqual(self
.obj
.__grefcount
__, 1)
399 self
.obj
.handler_block(self
.handler
)
400 self
.assertEqual(self
.obj
.__grefcount
__, 1)
401 self
.obj
.handler_unblock(self
.handler
)
402 self
.assertEqual(self
.obj
.__grefcount
__, 1)
404 def test_freeze_notify_context_error(self
):
405 # Test an exception occurring within a freeze context exits the context
407 with self
.obj
.freeze_notify():
408 self
.obj
.props
.prop
= 1
409 self
.assertEqual(self
.tracking
, [])
410 raise ValueError('Simulation')
414 # Verify the property set within the context called notify.
415 self
.assertEqual(self
.obj
.props
.prop
, 1)
416 self
.assertEqual(self
.tracking
, [1])
418 # Verify we are still not in a frozen context.
419 self
.obj
.props
.prop
= 2
420 self
.assertEqual(self
.tracking
, [1, 2])
422 def test_handler_block_context_error(self
):
423 # Test an exception occurring within a handler block exits the context
425 with self
.obj
.handler_block(self
.handler
):
426 self
.obj
.props
.prop
= 1
427 self
.assertEqual(self
.tracking
, [])
428 raise ValueError('Simulation')
432 # Verify the property set within the context didn't call notify.
433 self
.assertEqual(self
.obj
.props
.prop
, 1)
434 self
.assertEqual(self
.tracking
, [])
436 # Verify we are still not in a handler block context.
437 self
.obj
.props
.prop
= 2
438 self
.assertEqual(self
.tracking
, [2])
441 @unittest.skipUnless(hasattr(GObject
.Binding
, 'unbind'),
442 'Requires newer GLib which has g_binding_unbind')
443 class TestPropertyBindings(unittest
.TestCase
):
444 class TestObject(GObject
.GObject
):
445 int_prop
= GObject
.Property(default
=0, type=int)
448 self
.source
= self
.TestObject()
449 self
.target
= self
.TestObject()
451 def test_default_binding(self
):
452 binding
= self
.source
.bind_property('int_prop', self
.target
, 'int_prop',
453 GObject
.BindingFlags
.DEFAULT
)
454 binding
= binding
# PyFlakes
456 # Test setting value on source gets pushed to target
457 self
.source
.int_prop
= 1
458 self
.assertEqual(self
.source
.int_prop
, 1)
459 self
.assertEqual(self
.target
.int_prop
, 1)
461 # Test setting value on target does not change source
462 self
.target
.props
.int_prop
= 2
463 self
.assertEqual(self
.source
.int_prop
, 1)
464 self
.assertEqual(self
.target
.int_prop
, 2)
466 def test_bidirectional_binding(self
):
467 binding
= self
.source
.bind_property('int_prop', self
.target
, 'int_prop',
468 GObject
.BindingFlags
.BIDIRECTIONAL
)
469 binding
= binding
# PyFlakes
471 # Test setting value on source gets pushed to target
472 self
.source
.int_prop
= 1
473 self
.assertEqual(self
.source
.int_prop
, 1)
474 self
.assertEqual(self
.target
.int_prop
, 1)
476 # Test setting value on target also changes source
477 self
.target
.props
.int_prop
= 2
478 self
.assertEqual(self
.source
.int_prop
, 2)
479 self
.assertEqual(self
.target
.int_prop
, 2)
481 def test_transform_to_only(self
):
482 def transform_to(binding
, value
, user_data
=None):
483 self
.assertEqual(user_data
, 'test-data')
486 binding
= self
.source
.bind_property('int_prop', self
.target
, 'int_prop',
487 GObject
.BindingFlags
.DEFAULT
,
488 transform_to
, None, 'test-data')
489 binding
= binding
# PyFlakes
491 self
.source
.int_prop
= 1
492 self
.assertEqual(self
.source
.int_prop
, 1)
493 self
.assertEqual(self
.target
.int_prop
, 2)
495 self
.target
.props
.int_prop
= 1
496 self
.assertEqual(self
.source
.int_prop
, 1)
497 self
.assertEqual(self
.target
.int_prop
, 1)
499 def test_transform_from_only(self
):
500 def transform_from(binding
, value
, user_data
=None):
501 self
.assertEqual(user_data
, None)
504 binding
= self
.source
.bind_property('int_prop', self
.target
, 'int_prop',
505 GObject
.BindingFlags
.BIDIRECTIONAL
,
506 None, transform_from
)
507 binding
= binding
# PyFlakes
509 self
.source
.int_prop
= 1
510 self
.assertEqual(self
.source
.int_prop
, 1)
511 self
.assertEqual(self
.target
.int_prop
, 1)
513 self
.target
.props
.int_prop
= 1
514 self
.assertEqual(self
.source
.int_prop
, 2)
515 self
.assertEqual(self
.target
.int_prop
, 1)
517 def test_transform_bidirectional(self
):
520 def transform_to(binding
, value
, user_data
=None):
521 self
.assertEqual(user_data
, test_data
)
524 def transform_from(binding
, value
, user_data
=None):
525 self
.assertEqual(user_data
, test_data
)
528 if hasattr(sys
, "getrefcount"):
529 test_data_ref_count
= sys
.getrefcount(test_data
)
530 transform_to_ref_count
= sys
.getrefcount(transform_to
)
531 transform_from_ref_count
= sys
.getrefcount(transform_from
)
533 # bidirectional bindings
534 binding
= self
.source
.bind_property('int_prop', self
.target
, 'int_prop',
535 GObject
.BindingFlags
.BIDIRECTIONAL
,
536 transform_to
, transform_from
, test_data
)
537 binding
= binding
# PyFlakes
538 if hasattr(sys
, "getrefcount"):
539 binding_ref_count
= sys
.getrefcount(binding
)
540 binding_gref_count
= binding
.__grefcount
__
542 self
.source
.int_prop
= 1
543 self
.assertEqual(self
.source
.int_prop
, 1)
544 self
.assertEqual(self
.target
.int_prop
, 2)
546 self
.target
.props
.int_prop
= 4
547 self
.assertEqual(self
.source
.int_prop
, 2)
548 self
.assertEqual(self
.target
.int_prop
, 4)
550 if hasattr(sys
, "getrefcount"):
551 self
.assertEqual(sys
.getrefcount(binding
), binding_ref_count
)
552 self
.assertEqual(binding
.__grefcount
__, binding_gref_count
)
554 # test_data ref count increases by 2, once for each callback.
555 if hasattr(sys
, "getrefcount"):
556 self
.assertEqual(sys
.getrefcount(test_data
), test_data_ref_count
+ 2)
557 self
.assertEqual(sys
.getrefcount(transform_to
), transform_to_ref_count
+ 1)
558 self
.assertEqual(sys
.getrefcount(transform_from
), transform_from_ref_count
+ 1)
560 # Unbind should clear out the binding and its transforms
563 # Setting source or target should not change the other.
564 self
.target
.int_prop
= 3
565 self
.source
.int_prop
= 5
566 self
.assertEqual(self
.target
.int_prop
, 3)
567 self
.assertEqual(self
.source
.int_prop
, 5)
569 if hasattr(sys
, "getrefcount"):
570 self
.assertEqual(sys
.getrefcount(test_data
), test_data_ref_count
)
571 self
.assertEqual(sys
.getrefcount(transform_to
), transform_to_ref_count
)
572 self
.assertEqual(sys
.getrefcount(transform_from
), transform_from_ref_count
)
574 def test_explicit_unbind_clears_connection(self
):
575 self
.assertEqual(self
.source
.int_prop
, 0)
576 self
.assertEqual(self
.target
.int_prop
, 0)
578 # Test deleting binding reference removes binding.
579 binding
= self
.source
.bind_property('int_prop', self
.target
, 'int_prop')
580 self
.source
.int_prop
= 1
581 self
.assertEqual(self
.source
.int_prop
, 1)
582 self
.assertEqual(self
.target
.int_prop
, 1)
584 # unbind should clear out the bindings self reference
586 self
.assertEqual(binding
.__grefcount
__, 1)
588 self
.source
.int_prop
= 10
589 self
.assertEqual(self
.source
.int_prop
, 10)
590 self
.assertEqual(self
.target
.int_prop
, 1)
592 glib_version
= (GLib
.MAJOR_VERSION
, GLib
.MINOR_VERSION
, GLib
.MICRO_VERSION
)
594 # calling unbind() on an already unbound binding
595 if glib_version
>= (2, 57, 2):
596 # Fixed in newer glib:
597 # https://gitlab.gnome.org/GNOME/glib/merge_requests/244
601 self
.assertRaises(ValueError, binding
.unbind
)
603 def test_reference_counts(self
):
604 self
.assertEqual(self
.source
.__grefcount
__, 1)
605 self
.assertEqual(self
.target
.__grefcount
__, 1)
607 # Binding ref count will be 2 do to the initial ref implicitly held by
608 # the act of binding and the ref incurred by using __call__ to generate
609 # a wrapper from the weak binding ref within python.
610 binding
= self
.source
.bind_property('int_prop', self
.target
, 'int_prop')
611 self
.assertEqual(binding
.__grefcount
__, 2)
613 # Creating a binding does not inc refs on source and target (they are weak
614 # on the binding object itself)
615 self
.assertEqual(self
.source
.__grefcount
__, 1)
616 self
.assertEqual(self
.target
.__grefcount
__, 1)
618 # Use GObject.get_property because the "props" accessor leaks.
619 # Note property names are canonicalized.
620 self
.assertEqual(binding
.get_property('source'), self
.source
)
621 self
.assertEqual(binding
.get_property('source_property'), 'int-prop')
622 self
.assertEqual(binding
.get_property('target'), self
.target
)
623 self
.assertEqual(binding
.get_property('target_property'), 'int-prop')
624 self
.assertEqual(binding
.get_property('flags'), GObject
.BindingFlags
.DEFAULT
)
626 # Delete reference to source or target and the binding will remove its own
628 ref
= self
.source
.weak_ref()
631 self
.assertEqual(ref(), None)
632 self
.assertEqual(binding
.__grefcount
__, 1)
634 # Finally clear out the last ref held by the python wrapper
635 ref
= binding
.weak_ref()
638 self
.assertEqual(ref(), None)
641 class TestGValue(unittest
.TestCase
):
642 def test_type_constant(self
):
643 self
.assertEqual(GObject
.TYPE_VALUE
, GObject
.Value
.__gtype
__)
644 self
.assertEqual(GObject
.type_name(GObject
.TYPE_VALUE
), 'GValue')
646 def test_no_type(self
):
647 value
= GObject
.Value()
648 self
.assertEqual(value
.g_type
, GObject
.TYPE_INVALID
)
649 self
.assertRaises(TypeError, value
.set_value
, 23)
650 self
.assertEqual(value
.get_value(), None)
653 value
= GObject
.Value(GObject
.TYPE_UINT
)
654 self
.assertEqual(value
.g_type
, GObject
.TYPE_UINT
)
656 self
.assertEqual(value
.get_value(), 23)
657 value
.set_value(42.0)
658 self
.assertEqual(value
.get_value(), 42)
660 def test_multi_del(self
):
661 value
= GObject
.Value(str, 'foo_bar')
666 def test_string(self
):
667 value
= GObject
.Value(str, 'foo_bar')
668 self
.assertEqual(value
.g_type
, GObject
.TYPE_STRING
)
669 self
.assertEqual(value
.get_value(), 'foo_bar')
671 def test_float(self
):
672 # python float is G_TYPE_DOUBLE
673 value
= GObject
.Value(float, 23.4)
674 self
.assertEqual(value
.g_type
, GObject
.TYPE_DOUBLE
)
675 value
.set_value(1e50
)
676 self
.assertAlmostEqual(value
.get_value(), 1e50
)
678 value
= GObject
.Value(GObject
.TYPE_FLOAT
, 23.4)
679 self
.assertEqual(value
.g_type
, GObject
.TYPE_FLOAT
)
680 self
.assertRaises(TypeError, value
.set_value
, 'string')
681 self
.assertRaises(OverflowError, value
.set_value
, 1e50
)
683 def test_float_inf_nan(self
):
685 for type_
in [GObject
.TYPE_FLOAT
, GObject
.TYPE_DOUBLE
]:
686 for x
in [float('inf'), float('-inf'), nan
]:
687 value
= GObject
.Value(type_
, x
)
688 # assertEqual() is False for (nan, nan)
690 self
.assertEqual(str(value
.get_value()), 'nan')
692 self
.assertEqual(value
.get_value(), x
)
695 value
= GObject
.Value(GLib
.FileError
, GLib
.FileError
.FAILED
)
696 self
.assertEqual(value
.get_value(), GLib
.FileError
.FAILED
)
698 def test_flags(self
):
699 value
= GObject
.Value(GLib
.IOFlags
, GLib
.IOFlags
.IS_READABLE
)
700 self
.assertEqual(value
.get_value(), GLib
.IOFlags
.IS_READABLE
)
702 def test_object(self
):
703 class TestObject(GObject
.Object
):
706 value
= GObject
.Value(GObject
.TYPE_OBJECT
, obj
)
707 self
.assertEqual(value
.get_value(), obj
)
709 def test_value_array(self
):
710 value
= GObject
.Value(GObject
.ValueArray
)
711 self
.assertEqual(value
.g_type
, GObject
.type_from_name('GValueArray'))
712 value
.set_value([32, 'foo_bar', 0.3])
713 self
.assertEqual(value
.get_value(), [32, 'foo_bar', 0.3])
715 def test_value_array_from_gvalue_list(self
):
716 value
= GObject
.Value(GObject
.ValueArray
, [
717 GObject
.Value(GObject
.TYPE_UINT
, 0xffffffff),
718 GObject
.Value(GObject
.TYPE_STRING
, 'foo_bar')])
719 self
.assertEqual(value
.g_type
, GObject
.type_from_name('GValueArray'))
720 self
.assertEqual(value
.get_value(), [0xffffffff, 'foo_bar'])
721 self
.assertEqual(testhelper
.value_array_get_nth_type(value
, 0), GObject
.TYPE_UINT
)
722 self
.assertEqual(testhelper
.value_array_get_nth_type(value
, 1), GObject
.TYPE_STRING
)
724 def test_value_array_append_gvalue(self
):
725 with warnings
.catch_warnings():
726 warnings
.simplefilter('ignore', DeprecationWarning)
728 arr
= GObject
.ValueArray
.new(0)
729 arr
.append(GObject
.Value(GObject
.TYPE_UINT
, 0xffffffff))
730 arr
.append(GObject
.Value(GObject
.TYPE_STRING
, 'foo_bar'))
731 self
.assertEqual(arr
.get_nth(0), 0xffffffff)
732 self
.assertEqual(arr
.get_nth(1), 'foo_bar')
733 self
.assertEqual(testhelper
.value_array_get_nth_type(arr
, 0), GObject
.TYPE_UINT
)
734 self
.assertEqual(testhelper
.value_array_get_nth_type(arr
, 1), GObject
.TYPE_STRING
)
736 def test_gerror_boxing(self
):
737 error
= GLib
.Error('test message', domain
='mydomain', code
=42)
738 value
= GObject
.Value(GLib
.Error
, error
)
739 self
.assertEqual(value
.g_type
, GObject
.type_from_name('GError'))
741 unboxed
= value
.get_value()
742 self
.assertEqual(unboxed
.message
, error
.message
)
743 self
.assertEqual(unboxed
.domain
, error
.domain
)
744 self
.assertEqual(unboxed
.code
, error
.code
)
746 def test_gerror_novalue(self
):
747 GLib
.Error('test message', domain
='mydomain', code
=42)
748 value
= GObject
.Value(GLib
.Error
)
749 self
.assertEqual(value
.g_type
, GObject
.type_from_name('GError'))
750 self
.assertEqual(value
.get_value(), None)
753 def test_list_properties():
755 def find_param(l
, name
):
757 if param
.name
== name
:
761 list_props
= GObject
.list_properties
763 props
= list_props(Gio
.Action
)
764 param
= find_param(props
, "enabled")
766 assert param
.value_type
== GObject
.TYPE_BOOLEAN
767 assert list_props("GAction") == list_props(Gio
.Action
)
768 assert list_props(Gio
.Action
.__gtype
__) == list_props(Gio
.Action
)
770 props
= list_props(Gio
.SimpleAction
)
771 assert find_param(props
, "enabled")
774 return [p
.name
for p
in l
]
776 assert (set(names(list_props(Gio
.Action
))) <=
777 set(names(list_props(Gio
.SimpleAction
))))
779 props
= list_props(Gio
.FileIcon
)
780 param
= find_param(props
, "file")
782 assert param
.value_type
== Gio
.File
.__gtype
__
784 assert list_props("GFileIcon") == list_props(Gio
.FileIcon
)
785 assert list_props(Gio
.FileIcon
.__gtype
__) == list_props(Gio
.FileIcon
)
786 assert list_props(Gio
.FileIcon()) == list_props(Gio
.FileIcon
)
788 for obj
in [Gio
.ActionEntry
, Gio
.DBusError
, 0, object()]:
789 with pytest
.raises(TypeError):