1import os 2import gc 3import sys 4import struct 5import types 6import unittest 7import tempfile 8 9import pytest 10 11from gi.repository import GObject 12from gi.repository.GObject import ParamFlags, GType, new 13from gi.repository.GObject import \ 14 TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_INT64, \ 15 TYPE_UINT64, TYPE_GTYPE, TYPE_INVALID, TYPE_NONE, TYPE_STRV, \ 16 TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, TYPE_BOOLEAN, TYPE_FLOAT, \ 17 TYPE_DOUBLE, TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \ 18 TYPE_STRING, TYPE_PYOBJECT, TYPE_VARIANT 19 20from gi.repository.GLib import \ 21 MININT, MAXINT, MAXUINT, MINLONG, MAXLONG, MAXULONG, \ 22 MAXUINT64, MAXINT64, MININT64 23 24from gi.repository import Gio 25from gi.repository import GLib 26from gi.repository import GIMarshallingTests 27from gi.repository import Regress 28from gi import _propertyhelper as propertyhelper 29 30from .helper import capture_glib_warnings 31 32 33class PropertyObject(GObject.GObject): 34 normal = GObject.Property(type=str) 35 construct = GObject.Property( 36 type=str, 37 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT, 38 default='default') 39 40 construct_only = GObject.Property( 41 type=str, 42 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT_ONLY) 43 44 uint64 = GObject.Property( 45 type=TYPE_UINT64, 46 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) 47 48 enum = GObject.Property( 49 type=Gio.SocketType, default=Gio.SocketType.STREAM) 50 51 boxed = GObject.Property( 52 type=GLib.Regex, 53 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) 54 55 flags = GObject.Property( 56 type=GIMarshallingTests.Flags, 57 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT, 58 default=GIMarshallingTests.Flags.VALUE1) 59 60 gtype = GObject.Property( 61 type=TYPE_GTYPE, 62 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) 63 64 strings = GObject.Property( 65 type=TYPE_STRV, 66 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) 67 68 variant = GObject.Property( 69 type=TYPE_VARIANT, 70 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) 71 72 variant_def = GObject.Property( 73 type=TYPE_VARIANT, 74 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT, 75 default=GLib.Variant('i', 42)) 76 77 interface = GObject.Property( 78 type=Gio.File, 79 flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) 80 81 82class PropertyInheritanceObject(Regress.TestObj): 83 # override property from the base class, with a different type 84 string = GObject.Property(type=int) 85 86 # a property entirely defined at the Python level 87 python_prop = GObject.Property(type=str) 88 89 90class PropertySubClassObject(PropertyInheritanceObject): 91 # override property from the base class, with a different type 92 python_prop = GObject.Property(type=int) 93 94 95class TestPropertyInheritanceObject(unittest.TestCase): 96 def test_override_gi_property(self): 97 self.assertNotEqual(Regress.TestObj.props.string.value_type, 98 PropertyInheritanceObject.props.string.value_type) 99 obj = PropertyInheritanceObject() 100 self.assertEqual(type(obj.props.string), int) 101 obj.props.string = 4 102 self.assertEqual(obj.props.string, 4) 103 104 def test_override_python_property(self): 105 obj = PropertySubClassObject() 106 self.assertEqual(type(obj.props.python_prop), int) 107 obj.props.python_prop = 5 108 self.assertEqual(obj.props.python_prop, 5) 109 110 111class TestPropertyObject(unittest.TestCase): 112 def test_get_set(self): 113 obj = PropertyObject() 114 obj.props.normal = "value" 115 self.assertEqual(obj.props.normal, "value") 116 117 def test_hasattr_on_object(self): 118 obj = PropertyObject() 119 self.assertTrue(hasattr(obj.props, "normal")) 120 121 def test_hasattr_on_class(self): 122 self.assertTrue(hasattr(PropertyObject.props, "normal")) 123 124 def test_set_on_class(self): 125 def set(obj): 126 obj.props.normal = "foobar" 127 128 self.assertRaises(TypeError, set, PropertyObject) 129 130 def test_iteration(self): 131 for obj in (PropertyObject.props, PropertyObject().props): 132 names = [] 133 for pspec in obj: 134 gtype = GType(pspec) 135 self.assertEqual(gtype.parent.name, 'GParam') 136 names.append(pspec.name) 137 138 names.sort() 139 self.assertEqual(names, ['boxed', 140 'construct', 141 'construct-only', 142 'enum', 143 'flags', 144 'gtype', 145 'interface', 146 'normal', 147 'strings', 148 'uint64', 149 'variant', 150 'variant-def']) 151 152 def test_normal(self): 153 obj = new(PropertyObject, normal="123") 154 self.assertEqual(obj.props.normal, "123") 155 obj.set_property('normal', '456') 156 self.assertEqual(obj.props.normal, "456") 157 obj.props.normal = '789' 158 self.assertEqual(obj.props.normal, "789") 159 160 def test_construct(self): 161 obj = new(PropertyObject, construct="123") 162 self.assertEqual(obj.props.construct, "123") 163 obj.set_property('construct', '456') 164 self.assertEqual(obj.props.construct, "456") 165 obj.props.construct = '789' 166 self.assertEqual(obj.props.construct, "789") 167 168 def test_utf8(self): 169 test_utf8 = "♥" 170 unicode_utf8 = u"♥" 171 obj = new(PropertyObject, construct_only=unicode_utf8) 172 self.assertEqual(obj.props.construct_only, test_utf8) 173 obj.set_property('construct', unicode_utf8) 174 self.assertEqual(obj.props.construct, test_utf8) 175 obj.props.normal = unicode_utf8 176 self.assertEqual(obj.props.normal, test_utf8) 177 178 def test_utf8_lone_surrogate(self): 179 obj = PropertyObject() 180 with pytest.raises(TypeError): 181 obj.set_property('construct', '\ud83d') 182 183 def test_int_to_str(self): 184 obj = new(PropertyObject, construct_only=1) 185 self.assertEqual(obj.props.construct_only, '1') 186 obj.set_property('construct', '2') 187 self.assertEqual(obj.props.construct, '2') 188 obj.props.normal = 3 189 self.assertEqual(obj.props.normal, '3') 190 191 def test_construct_only(self): 192 obj = new(PropertyObject, construct_only="123") 193 self.assertEqual(obj.props.construct_only, "123") 194 self.assertRaises(TypeError, 195 setattr, obj.props, 'construct_only', '456') 196 self.assertRaises(TypeError, 197 obj.set_property, 'construct-only', '456') 198 199 def test_uint64(self): 200 obj = new(PropertyObject) 201 self.assertEqual(obj.props.uint64, 0) 202 obj.props.uint64 = 1 203 self.assertEqual(obj.props.uint64, 1) 204 obj.props.uint64 = 1 205 self.assertEqual(obj.props.uint64, 1) 206 207 self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1) 208 self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1) 209 210 def test_uint64_default_value(self): 211 try: 212 class TimeControl(GObject.GObject): 213 __gproperties__ = { 214 'time': (TYPE_UINT64, 'Time', 'Time', 215 0, (1 << 64) - 1, 0, 216 ParamFlags.READABLE) 217 } 218 except OverflowError: 219 (etype, ex) = sys.exc_info()[2:] 220 self.fail(str(ex)) 221 222 def test_enum(self): 223 obj = new(PropertyObject) 224 self.assertEqual(obj.props.enum, Gio.SocketType.STREAM) 225 self.assertEqual(obj.enum, Gio.SocketType.STREAM) 226 obj.enum = Gio.SocketType.DATAGRAM 227 self.assertEqual(obj.props.enum, Gio.SocketType.DATAGRAM) 228 self.assertEqual(obj.enum, Gio.SocketType.DATAGRAM) 229 obj.props.enum = Gio.SocketType.STREAM 230 self.assertEqual(obj.props.enum, Gio.SocketType.STREAM) 231 self.assertEqual(obj.enum, Gio.SocketType.STREAM) 232 obj.props.enum = 2 233 self.assertEqual(obj.props.enum, Gio.SocketType.DATAGRAM) 234 self.assertEqual(obj.enum, Gio.SocketType.DATAGRAM) 235 obj.enum = 1 236 self.assertEqual(obj.props.enum, Gio.SocketType.STREAM) 237 self.assertEqual(obj.enum, Gio.SocketType.STREAM) 238 239 self.assertRaises(TypeError, setattr, obj, 'enum', 'foo') 240 self.assertRaises(TypeError, setattr, obj, 'enum', object()) 241 242 self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType) 243 self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType, 244 default=Gio.SocketProtocol.TCP) 245 self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType, 246 default=object()) 247 self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType, 248 default=1) 249 250 def test_repr(self): 251 prop = GObject.Property(type=int) 252 assert repr(prop) == "<GObject Property (uninitialized) (gint)>" 253 254 def test_flags(self): 255 obj = new(PropertyObject) 256 self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE1) 257 self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE1) 258 259 obj.flags = GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3 260 self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3) 261 self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3) 262 263 self.assertRaises(TypeError, setattr, obj, 'flags', 'foo') 264 self.assertRaises(TypeError, setattr, obj, 'flags', object()) 265 self.assertRaises(TypeError, setattr, obj, 'flags', None) 266 267 self.assertRaises(TypeError, GObject.Property, 268 type=GIMarshallingTests.Flags, default='foo') 269 self.assertRaises(TypeError, GObject.Property, 270 type=GIMarshallingTests.Flags, default=object()) 271 self.assertRaises(TypeError, GObject.Property, 272 type=GIMarshallingTests.Flags, default=None) 273 274 def test_gtype(self): 275 obj = new(PropertyObject) 276 277 self.assertEqual(obj.props.gtype, TYPE_NONE) 278 self.assertEqual(obj.gtype, TYPE_NONE) 279 280 obj.gtype = TYPE_UINT64 281 self.assertEqual(obj.props.gtype, TYPE_UINT64) 282 self.assertEqual(obj.gtype, TYPE_UINT64) 283 284 obj.gtype = TYPE_INVALID 285 self.assertEqual(obj.props.gtype, TYPE_INVALID) 286 self.assertEqual(obj.gtype, TYPE_INVALID) 287 288 # GType parameters do not support defaults in GLib 289 self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, 290 default=TYPE_INT) 291 292 # incompatible type 293 self.assertRaises(TypeError, setattr, obj, 'gtype', 'foo') 294 self.assertRaises(TypeError, setattr, obj, 'gtype', object()) 295 296 self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, 297 default='foo') 298 self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, 299 default=object()) 300 301 # set in constructor 302 obj = new(PropertyObject, gtype=TYPE_UINT) 303 self.assertEqual(obj.props.gtype, TYPE_UINT) 304 self.assertEqual(obj.gtype, TYPE_UINT) 305 306 def test_boxed(self): 307 obj = new(PropertyObject) 308 309 regex = GLib.Regex.new('[a-z]*', 0, 0) 310 obj.props.boxed = regex 311 self.assertEqual(obj.props.boxed.get_pattern(), '[a-z]*') 312 self.assertEqual(obj.boxed.get_pattern(), '[a-z]*') 313 314 self.assertRaises(TypeError, setattr, obj, 'boxed', 'foo') 315 self.assertRaises(TypeError, setattr, obj, 'boxed', object()) 316 317 def test_strings(self): 318 obj = new(PropertyObject) 319 320 # Should work with actual GStrv objects as well as 321 # Python string lists 322 class GStrv(list): 323 __gtype__ = GObject.TYPE_STRV 324 325 self.assertEqual(obj.props.strings, GStrv([])) 326 self.assertEqual(obj.strings, GStrv([])) 327 self.assertEqual(obj.props.strings, []) 328 self.assertEqual(obj.strings, []) 329 330 obj.strings = ['hello', 'world'] 331 self.assertEqual(obj.props.strings, ['hello', 'world']) 332 self.assertEqual(obj.strings, ['hello', 'world']) 333 334 obj.strings = GStrv(['hello', 'world']) 335 self.assertEqual(obj.props.strings, GStrv(['hello', 'world'])) 336 self.assertEqual(obj.strings, GStrv(['hello', 'world'])) 337 338 obj.strings = [] 339 self.assertEqual(obj.strings, []) 340 obj.strings = GStrv([]) 341 self.assertEqual(obj.strings, GStrv([])) 342 343 p = GObject.Property(type=TYPE_STRV, default=['hello', '1']) 344 self.assertEqual(p.default, ['hello', '1']) 345 self.assertEqual(p.type, TYPE_STRV) 346 p = GObject.Property(type=TYPE_STRV, default=GStrv(['hello', '1'])) 347 self.assertEqual(p.default, ['hello', '1']) 348 self.assertEqual(p.type, TYPE_STRV) 349 350 # set in constructor 351 obj = new(PropertyObject, strings=['hello', 'world']) 352 self.assertEqual(obj.props.strings, ['hello', 'world']) 353 self.assertEqual(obj.strings, ['hello', 'world']) 354 355 # wrong types 356 self.assertRaises(TypeError, setattr, obj, 'strings', 1) 357 self.assertRaises(TypeError, setattr, obj, 'strings', 'foo') 358 self.assertRaises(TypeError, setattr, obj, 'strings', ['foo', 1]) 359 360 self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, 361 default=1) 362 self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, 363 default='foo') 364 self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, 365 default=['hello', 1]) 366 367 def test_variant(self): 368 obj = new(PropertyObject) 369 370 self.assertEqual(obj.props.variant, None) 371 self.assertEqual(obj.variant, None) 372 373 obj.variant = GLib.Variant('s', 'hello') 374 self.assertEqual(obj.variant.print_(True), "'hello'") 375 376 obj.variant = GLib.Variant('b', True) 377 self.assertEqual(obj.variant.print_(True), "true") 378 379 obj.props.variant = GLib.Variant('y', 2) 380 self.assertEqual(obj.variant.print_(True), "byte 0x02") 381 382 obj.variant = None 383 self.assertEqual(obj.variant, None) 384 385 # set in constructor 386 obj = new(PropertyObject, variant=GLib.Variant('u', 5)) 387 self.assertEqual(obj.props.variant.print_(True), 'uint32 5') 388 389 GObject.Property(type=TYPE_VARIANT, default=GLib.Variant('i', 1)) 390 391 # incompatible types 392 self.assertRaises(TypeError, setattr, obj, 'variant', 'foo') 393 self.assertRaises(TypeError, setattr, obj, 'variant', 42) 394 395 self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT, 396 default='foo') 397 self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT, 398 default=object()) 399 400 def test_variant_default(self): 401 obj = new(PropertyObject) 402 403 self.assertEqual(obj.props.variant_def.print_(True), '42') 404 self.assertEqual(obj.variant_def.print_(True), '42') 405 406 obj.props.variant_def = GLib.Variant('y', 2) 407 self.assertEqual(obj.variant_def.print_(True), "byte 0x02") 408 409 # set in constructor 410 obj = new(PropertyObject, variant_def=GLib.Variant('u', 5)) 411 self.assertEqual(obj.props.variant_def.print_(True), 'uint32 5') 412 413 def test_interface(self): 414 obj = new(PropertyObject) 415 416 path = os.path.join(tempfile.gettempdir(), "some", "path") 417 file = Gio.File.new_for_path(path) 418 obj.props.interface = file 419 self.assertEqual(obj.props.interface.get_path(), path) 420 self.assertEqual(obj.interface.get_path(), path) 421 422 self.assertRaises(TypeError, setattr, obj, 'interface', 'foo') 423 self.assertRaises(TypeError, setattr, obj, 'interface', object()) 424 425 def test_range(self): 426 # kiwi code 427 def max(c): 428 return 2 ** ((8 * struct.calcsize(c)) - 1) - 1 429 430 def umax(c): 431 return 2 ** (8 * struct.calcsize(c)) - 1 432 433 maxint = max('i') 434 minint = -maxint - 1 435 maxuint = umax('I') 436 maxlong = max('l') 437 minlong = -maxlong - 1 438 maxulong = umax('L') 439 maxint64 = max('q') 440 minint64 = -maxint64 - 1 441 maxuint64 = umax('Q') 442 443 types_ = dict(int=(TYPE_INT, minint, maxint), 444 uint=(TYPE_UINT, 0, maxuint), 445 long=(TYPE_LONG, minlong, maxlong), 446 ulong=(TYPE_ULONG, 0, maxulong), 447 int64=(TYPE_INT64, minint64, maxint64), 448 uint64=(TYPE_UINT64, 0, maxuint64)) 449 450 def build_gproperties(types_): 451 d = {} 452 for key, (gtype, min, max) in types_.items(): 453 d[key] = (gtype, 'blurb', 'desc', min, max, 0, 454 ParamFlags.READABLE | ParamFlags.WRITABLE) 455 return d 456 457 class RangeCheck(GObject.GObject): 458 __gproperties__ = build_gproperties(types_) 459 460 def __init__(self): 461 self.values = {} 462 GObject.GObject.__init__(self) 463 464 def do_set_property(self, pspec, value): 465 self.values[pspec.name] = value 466 467 def do_get_property(self, pspec): 468 return self.values.get(pspec.name, pspec.default_value) 469 470 self.assertEqual(RangeCheck.props.int.minimum, minint) 471 self.assertEqual(RangeCheck.props.int.maximum, maxint) 472 self.assertEqual(RangeCheck.props.uint.minimum, 0) 473 self.assertEqual(RangeCheck.props.uint.maximum, maxuint) 474 self.assertEqual(RangeCheck.props.long.minimum, minlong) 475 self.assertEqual(RangeCheck.props.long.maximum, maxlong) 476 self.assertEqual(RangeCheck.props.ulong.minimum, 0) 477 self.assertEqual(RangeCheck.props.ulong.maximum, maxulong) 478 self.assertEqual(RangeCheck.props.int64.minimum, minint64) 479 self.assertEqual(RangeCheck.props.int64.maximum, maxint64) 480 self.assertEqual(RangeCheck.props.uint64.minimum, 0) 481 self.assertEqual(RangeCheck.props.uint64.maximum, maxuint64) 482 483 obj = RangeCheck() 484 for key, (gtype, min, max) in types_.items(): 485 self.assertEqual(obj.get_property(key), 486 getattr(RangeCheck.props, key).default_value) 487 488 obj.set_property(key, min) 489 self.assertEqual(obj.get_property(key), min) 490 491 obj.set_property(key, max) 492 self.assertEqual(obj.get_property(key), max) 493 494 def test_multi(self): 495 obj = PropertyObject() 496 obj.set_properties(normal="foo", 497 uint64=7) 498 normal, uint64 = obj.get_properties("normal", "uint64") 499 self.assertEqual(normal, "foo") 500 self.assertEqual(uint64, 7) 501 502 503class TestProperty(unittest.TestCase): 504 def test_simple(self): 505 class C(GObject.GObject): 506 str = GObject.Property(type=str) 507 float = GObject.Property(type=float) 508 long = GObject.Property(type=int) 509 int = GObject.Property(type=int) 510 511 self.assertTrue(hasattr(C.props, 'str')) 512 self.assertTrue(hasattr(C.props, 'int')) 513 self.assertTrue(hasattr(C.props, 'float')) 514 self.assertTrue(hasattr(C.props, 'long')) 515 516 o = C() 517 self.assertEqual(o.str, '') 518 o.str = 'str' 519 self.assertEqual(o.str, 'str') 520 521 self.assertEqual(o.int, 0) 522 o.int = 1138 523 self.assertEqual(o.int, 1138) 524 525 self.assertEqual(o.float, 0.0) 526 o.float = 3.14 527 self.assertEqual(o.float, 3.14) 528 529 self.assertEqual(o.long, 0) 530 o.long = 100 531 self.assertEqual(o.long, 100) 532 533 def test_custom_getter(self): 534 class C(GObject.GObject): 535 def get_prop(self): 536 return 'value' 537 prop = GObject.Property(getter=get_prop) 538 539 o = C() 540 self.assertEqual(o.prop, 'value') 541 self.assertRaises(TypeError, setattr, o, 'prop', 'xxx') 542 543 def test_getter_exception(self): 544 class C(GObject.Object): 545 @GObject.Property(type=int) 546 def prop(self): 547 raise ValueError('something bad happend') 548 549 o = C() 550 551 with self.assertRaisesRegex(ValueError, 'something bad happend'): 552 o.prop 553 554 with self.assertRaisesRegex(ValueError, 'something bad happend'): 555 o.get_property('prop') 556 557 with self.assertRaisesRegex(ValueError, 'something bad happend'): 558 o.props.prop 559 560 def test_custom_setter(self): 561 class C(GObject.GObject): 562 def set_prop(self, value): 563 self._value = value 564 prop = GObject.Property(setter=set_prop) 565 566 def __init__(self): 567 self._value = None 568 GObject.GObject.__init__(self) 569 570 o = C() 571 self.assertEqual(o._value, None) 572 o.prop = 'bar' 573 self.assertEqual(o._value, 'bar') 574 self.assertRaises(TypeError, getattr, o, 'prop') 575 576 def test_decorator_default(self): 577 class C(GObject.GObject): 578 _value = 'value' 579 580 @GObject.Property 581 def value(self): 582 return self._value 583 584 @value.setter 585 def value_setter(self, value): 586 self._value = value 587 588 o = C() 589 self.assertEqual(o.value, 'value') 590 o.value = 'blah' 591 self.assertEqual(o.value, 'blah') 592 self.assertEqual(o.props.value, 'blah') 593 594 def test_decorator_private_setter(self): 595 class C(GObject.GObject): 596 _value = 'value' 597 598 @GObject.Property 599 def value(self): 600 return self._value 601 602 @value.setter 603 def _set_value(self, value): 604 self._value = value 605 606 o = C() 607 self.assertEqual(o.value, 'value') 608 o.value = 'blah' 609 self.assertEqual(o.value, 'blah') 610 self.assertEqual(o.props.value, 'blah') 611 612 def test_decorator_with_call(self): 613 class C(GObject.GObject): 614 _value = 1 615 616 @GObject.Property(type=int, default=1, minimum=1, maximum=10) 617 def typedValue(self): 618 return self._value 619 620 @typedValue.setter 621 def typedValue_setter(self, value): 622 self._value = value 623 624 o = C() 625 self.assertEqual(o.typedValue, 1) 626 o.typedValue = 5 627 self.assertEqual(o.typedValue, 5) 628 self.assertEqual(o.props.typedValue, 5) 629 630 def test_errors(self): 631 self.assertRaises(TypeError, GObject.Property, type='str') 632 self.assertRaises(TypeError, GObject.Property, nick=False) 633 self.assertRaises(TypeError, GObject.Property, blurb=False) 634 # this never fail while bool is a subclass of int 635 # >>> bool.__bases__ 636 # (<type 'int'>,) 637 # self.assertRaises(TypeError, GObject.Property, type=bool, default=0) 638 self.assertRaises(TypeError, GObject.Property, type=bool, default='ciao mamma') 639 self.assertRaises(TypeError, GObject.Property, type=bool) 640 self.assertRaises(TypeError, GObject.Property, type=object, default=0) 641 self.assertRaises(TypeError, GObject.Property, type=complex) 642 643 def test_defaults(self): 644 GObject.Property(type=bool, default=True) 645 GObject.Property(type=bool, default=False) 646 647 def test_name_with_underscore(self): 648 class C(GObject.GObject): 649 prop_name = GObject.Property(type=int) 650 o = C() 651 o.prop_name = 10 652 self.assertEqual(o.prop_name, 10) 653 654 def test_range(self): 655 types_ = [ 656 (TYPE_INT, MININT, MAXINT), 657 (TYPE_UINT, 0, MAXUINT), 658 (TYPE_LONG, MINLONG, MAXLONG), 659 (TYPE_ULONG, 0, MAXULONG), 660 (TYPE_INT64, MININT64, MAXINT64), 661 (TYPE_UINT64, 0, MAXUINT64), 662 ] 663 664 for gtype, min, max in types_: 665 # Normal, everything is alright 666 prop = GObject.Property(type=gtype, minimum=min, maximum=max) 667 subtype = type('', (GObject.GObject,), dict(prop=prop)) 668 self.assertEqual(subtype.props.prop.minimum, min) 669 self.assertEqual(subtype.props.prop.maximum, max) 670 671 # Lower than minimum 672 self.assertRaises(TypeError, 673 GObject.Property, type=gtype, minimum=min - 1, 674 maximum=max) 675 676 # Higher than maximum 677 self.assertRaises(TypeError, 678 GObject.Property, type=gtype, minimum=min, 679 maximum=max + 1) 680 681 def test_min_max(self): 682 class C(GObject.GObject): 683 prop_int = GObject.Property(type=int, minimum=1, maximum=100, default=1) 684 prop_float = GObject.Property(type=float, minimum=0.1, maximum=10.5, default=1.1) 685 686 def __init__(self): 687 GObject.GObject.__init__(self) 688 689 # we test known-bad values here which cause Gtk-WARNING logs. 690 # Explicitly allow these for this test. 691 with capture_glib_warnings(allow_warnings=True): 692 o = C() 693 self.assertEqual(o.prop_int, 1) 694 695 o.prop_int = 5 696 self.assertEqual(o.prop_int, 5) 697 698 o.prop_int = 0 699 self.assertEqual(o.prop_int, 5) 700 701 o.prop_int = 101 702 self.assertEqual(o.prop_int, 5) 703 704 self.assertEqual(o.prop_float, 1.1) 705 706 o.prop_float = 7.75 707 self.assertEqual(o.prop_float, 7.75) 708 709 o.prop_float = 0.09 710 self.assertEqual(o.prop_float, 7.75) 711 712 o.prop_float = 10.51 713 self.assertEqual(o.prop_float, 7.75) 714 715 def test_multiple_instances(self): 716 class C(GObject.GObject): 717 prop = GObject.Property(type=str, default='default') 718 719 o1 = C() 720 o2 = C() 721 self.assertEqual(o1.prop, 'default') 722 self.assertEqual(o2.prop, 'default') 723 o1.prop = 'value' 724 self.assertEqual(o1.prop, 'value') 725 self.assertEqual(o2.prop, 'default') 726 727 def test_object_property(self): 728 class PropertyObject(GObject.GObject): 729 obj = GObject.Property(type=GObject.GObject) 730 731 pobj1 = PropertyObject() 732 obj1_hash = hash(pobj1) 733 pobj2 = PropertyObject() 734 735 pobj2.obj = pobj1 736 del pobj1 737 pobj1 = pobj2.obj 738 self.assertEqual(hash(pobj1), obj1_hash) 739 740 def test_object_subclass_property(self): 741 class ObjectSubclass(GObject.GObject): 742 __gtype_name__ = 'ObjectSubclass' 743 744 class PropertyObjectSubclass(GObject.GObject): 745 obj = GObject.Property(type=ObjectSubclass) 746 747 PropertyObjectSubclass(obj=ObjectSubclass()) 748 749 def test_property_subclass(self): 750 # test for #470718 751 class A(GObject.GObject): 752 prop1 = GObject.Property(type=int) 753 754 class B(A): 755 prop2 = GObject.Property(type=int) 756 757 b = B() 758 b.prop2 = 10 759 self.assertEqual(b.prop2, 10) 760 b.prop1 = 20 761 self.assertEqual(b.prop1, 20) 762 763 def test_property_subclass_c(self): 764 class A(Regress.TestSubObj): 765 prop1 = GObject.Property(type=int) 766 767 a = A() 768 a.prop1 = 10 769 self.assertEqual(a.prop1, 10) 770 771 # also has parent properties 772 a.props.int = 20 773 self.assertEqual(a.props.int, 20) 774 775 # Some of which are unusable without introspection 776 a.props.list = ("str1", "str2") 777 self.assertEqual(a.props.list, ["str1", "str2"]) 778 779 a.set_property("list", ("str3", "str4")) 780 self.assertEqual(a.props.list, ["str3", "str4"]) 781 782 def test_property_subclass_custom_setter(self): 783 # test for #523352 784 class A(GObject.GObject): 785 def get_first(self): 786 return 'first' 787 first = GObject.Property(type=str, getter=get_first) 788 789 class B(A): 790 def get_second(self): 791 return 'second' 792 second = GObject.Property(type=str, getter=get_second) 793 794 a = A() 795 self.assertEqual(a.first, 'first') 796 self.assertRaises(TypeError, setattr, a, 'first', 'foo') 797 798 b = B() 799 self.assertEqual(b.first, 'first') 800 self.assertRaises(TypeError, setattr, b, 'first', 'foo') 801 self.assertEqual(b.second, 'second') 802 self.assertRaises(TypeError, setattr, b, 'second', 'foo') 803 804 def test_property_subclass_custom_setter_error(self): 805 try: 806 class A(GObject.GObject): 807 def get_first(self): 808 return 'first' 809 first = GObject.Property(type=str, getter=get_first) 810 811 def do_get_property(self, pspec): 812 pass 813 except TypeError: 814 pass 815 else: 816 raise AssertionError 817 818 # Bug 587637. 819 820 def test_float_min(self): 821 GObject.Property(type=float, minimum=-1) 822 GObject.Property(type=GObject.TYPE_FLOAT, minimum=-1) 823 GObject.Property(type=GObject.TYPE_DOUBLE, minimum=-1) 824 825 # Bug 644039 826 @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") 827 def test_reference_count(self): 828 # We can check directly if an object gets finalized, so we will 829 # observe it indirectly through the refcount of a member object. 830 831 # We create our dummy object and store its current refcount 832 o = object() 833 rc = sys.getrefcount(o) 834 835 # We add our object as a member to our newly created object we 836 # want to observe. Its refcount is increased by one. 837 t = PropertyObject(normal="test") 838 t.o = o 839 self.assertEqual(sys.getrefcount(o), rc + 1) 840 841 # Now we want to ensure we do not leak any references to our 842 # object with properties. If no ref is leaked, then when deleting 843 # the local reference to this object, its reference count shoud 844 # drop to zero, and our dummy object should loose one reference. 845 del t 846 self.assertEqual(sys.getrefcount(o), rc) 847 848 def test_doc_strings(self): 849 class C(GObject.GObject): 850 foo_blurbed = GObject.Property(type=int, blurb='foo_blurbed doc string') 851 852 @GObject.Property 853 def foo_getter(self): 854 """foo_getter doc string""" 855 return 0 856 857 self.assertEqual(C.foo_blurbed.blurb, 'foo_blurbed doc string') 858 self.assertEqual(C.foo_blurbed.__doc__, 'foo_blurbed doc string') 859 860 self.assertEqual(C.foo_getter.blurb, 'foo_getter doc string') 861 self.assertEqual(C.foo_getter.__doc__, 'foo_getter doc string') 862 863 def test_python_to_glib_type_mapping(self): 864 tester = GObject.Property() 865 self.assertEqual(tester._type_from_python(int), GObject.TYPE_INT) 866 self.assertEqual(tester._type_from_python(bool), GObject.TYPE_BOOLEAN) 867 self.assertEqual(tester._type_from_python(float), GObject.TYPE_DOUBLE) 868 self.assertEqual(tester._type_from_python(str), GObject.TYPE_STRING) 869 self.assertEqual(tester._type_from_python(object), GObject.TYPE_PYOBJECT) 870 871 self.assertEqual(tester._type_from_python(GObject.GObject), GObject.GObject.__gtype__) 872 self.assertEqual(tester._type_from_python(GObject.GEnum), GObject.GEnum.__gtype__) 873 self.assertEqual(tester._type_from_python(GObject.GFlags), GObject.GFlags.__gtype__) 874 self.assertEqual(tester._type_from_python(GObject.GBoxed), GObject.GBoxed.__gtype__) 875 self.assertEqual(tester._type_from_python(GObject.GInterface), GObject.GInterface.__gtype__) 876 877 for type_ in [TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, 878 TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG, 879 TYPE_ULONG, TYPE_INT64, TYPE_UINT64, 880 TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER, 881 TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING, 882 TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV]: 883 self.assertEqual(tester._type_from_python(type_), type_) 884 885 self.assertRaises(TypeError, tester._type_from_python, types.CodeType) 886 887 888class TestInstallProperties(unittest.TestCase): 889 # These tests only test how signalhelper.install_signals works 890 # with the __gsignals__ dict and therefore does not need to use 891 # GObject as a base class because that would automatically call 892 # install_signals within the meta-class. 893 class Base(object): 894 __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)} 895 896 class Sub1(Base): 897 pass 898 899 class Sub2(Base): 900 @GObject.Property(type=int) 901 def sub2test(self): 902 return 123 903 904 class ClassWithPropertyAndGetterVFunc(object): 905 @GObject.Property(type=int) 906 def sub2test(self): 907 return 123 908 909 def do_get_property(self, name): 910 return 321 911 912 class ClassWithPropertyRedefined(object): 913 __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)} 914 test = GObject.Property(type=int) 915 916 def setUp(self): 917 self.assertEqual(len(self.Base.__gproperties__), 1) 918 propertyhelper.install_properties(self.Base) 919 self.assertEqual(len(self.Base.__gproperties__), 1) 920 921 def test_subclass_without_properties_is_not_modified(self): 922 self.assertFalse('__gproperties__' in self.Sub1.__dict__) 923 propertyhelper.install_properties(self.Sub1) 924 self.assertFalse('__gproperties__' in self.Sub1.__dict__) 925 926 def test_subclass_with_decorator_gets_gproperties_dict(self): 927 # Sub2 has Property instances but will not have a __gproperties__ 928 # until install_properties is called 929 self.assertFalse('__gproperties__' in self.Sub2.__dict__) 930 self.assertFalse('do_get_property' in self.Sub2.__dict__) 931 self.assertFalse('do_set_property' in self.Sub2.__dict__) 932 933 propertyhelper.install_properties(self.Sub2) 934 self.assertTrue('__gproperties__' in self.Sub2.__dict__) 935 self.assertEqual(len(self.Base.__gproperties__), 1) 936 self.assertEqual(len(self.Sub2.__gproperties__), 1) 937 self.assertTrue('sub2test' in self.Sub2.__gproperties__) 938 939 # get/set vfuncs should have been added 940 self.assertTrue('do_get_property' in self.Sub2.__dict__) 941 self.assertTrue('do_set_property' in self.Sub2.__dict__) 942 943 def test_object_with_property_and_do_get_property_vfunc_raises(self): 944 self.assertRaises(TypeError, propertyhelper.install_properties, 945 self.ClassWithPropertyAndGetterVFunc) 946 947 def test_same_name_property_definitions_raises(self): 948 self.assertRaises(ValueError, propertyhelper.install_properties, 949 self.ClassWithPropertyRedefined) 950 951 952class CPropertiesTestBase(object): 953 # Tests for properties implemented in C not Python. 954 955 def setUp(self): 956 self.obj = GIMarshallingTests.PropertiesObject() 957 958 def get_prop(self, obj, name): 959 raise NotImplementedError 960 961 def set_prop(self, obj, name, value): 962 raise NotImplementedError 963 964 # https://bugzilla.gnome.org/show_bug.cgi?id=780652 965 @unittest.skipUnless( 966 "some_flags" in dir(GIMarshallingTests.PropertiesObject.props), 967 "tool old gi") 968 def test_flags(self): 969 self.assertEqual( 970 self.get_prop(self.obj, 'some-flags'), 971 GIMarshallingTests.Flags.VALUE1) 972 self.set_prop(self.obj, 'some-flags', GIMarshallingTests.Flags.VALUE2) 973 self.assertEqual(self.get_prop(self.obj, 'some-flags'), 974 GIMarshallingTests.Flags.VALUE2) 975 976 obj = GIMarshallingTests.PropertiesObject( 977 some_flags=GIMarshallingTests.Flags.VALUE3) 978 self.assertEqual(self.get_prop(obj, 'some-flags'), 979 GIMarshallingTests.Flags.VALUE3) 980 981 # https://bugzilla.gnome.org/show_bug.cgi?id=780652 982 @unittest.skipUnless( 983 "some_enum" in dir(GIMarshallingTests.PropertiesObject.props), 984 "tool old gi") 985 def test_enum(self): 986 self.assertEqual( 987 self.get_prop(self.obj, 'some-enum'), 988 GIMarshallingTests.GEnum.VALUE1) 989 self.set_prop(self.obj, 'some-enum', GIMarshallingTests.GEnum.VALUE2) 990 self.assertEqual(self.get_prop(self.obj, 'some-enum'), 991 GIMarshallingTests.GEnum.VALUE2) 992 993 obj = GIMarshallingTests.PropertiesObject( 994 some_enum=GIMarshallingTests.GEnum.VALUE3) 995 self.assertEqual(self.get_prop(obj, 'some-enum'), 996 GIMarshallingTests.GEnum.VALUE3) 997 998 def test_boolean(self): 999 self.assertEqual(self.get_prop(self.obj, 'some-boolean'), False) 1000 self.set_prop(self.obj, 'some-boolean', True) 1001 self.assertEqual(self.get_prop(self.obj, 'some-boolean'), True) 1002 1003 obj = GIMarshallingTests.PropertiesObject(some_boolean=True) 1004 self.assertEqual(self.get_prop(obj, 'some-boolean'), True) 1005 1006 def test_char(self): 1007 self.assertEqual(self.get_prop(self.obj, 'some-char'), 0) 1008 self.set_prop(self.obj, 'some-char', GLib.MAXINT8) 1009 self.assertEqual(self.get_prop(self.obj, 'some-char'), GLib.MAXINT8) 1010 1011 obj = GIMarshallingTests.PropertiesObject(some_char=-42) 1012 self.assertEqual(self.get_prop(obj, 'some-char'), -42) 1013 1014 with pytest.raises(OverflowError): 1015 self.set_prop(obj, 'some-char', GLib.MAXINT8 + 1) 1016 with pytest.raises(OverflowError): 1017 self.set_prop(obj, 'some-char', GLib.MININT8 - 1) 1018 1019 self.set_prop(obj, 'some-char', b"\x44") 1020 assert self.get_prop(obj, 'some-char') == 0x44 1021 1022 self.set_prop(obj, 'some-char', b"\xff") 1023 assert self.get_prop(obj, 'some-char') == -1 1024 1025 obj = GIMarshallingTests.PropertiesObject(some_char=u"\x7f") 1026 assert self.get_prop(obj, 'some-char') == 0x7f 1027 1028 with pytest.raises(TypeError): 1029 GIMarshallingTests.PropertiesObject(some_char=u"€") 1030 1031 with pytest.raises(TypeError): 1032 GIMarshallingTests.PropertiesObject(some_char=u"\ud83d") 1033 1034 def test_uchar(self): 1035 self.assertEqual(self.get_prop(self.obj, 'some-uchar'), 0) 1036 self.set_prop(self.obj, 'some-uchar', GLib.MAXUINT8) 1037 self.assertEqual(self.get_prop(self.obj, 'some-uchar'), GLib.MAXUINT8) 1038 1039 obj = GIMarshallingTests.PropertiesObject(some_uchar=42) 1040 self.assertEqual(self.get_prop(obj, 'some-uchar'), 42) 1041 1042 with pytest.raises(OverflowError): 1043 self.set_prop(obj, 'some-uchar', GLib.MAXUINT8 + 1) 1044 with pytest.raises(OverflowError): 1045 self.set_prop(obj, 'some-uchar', -1) 1046 1047 self.set_prop(obj, 'some-uchar', b"\x57") 1048 assert self.get_prop(obj, 'some-uchar') == 0x57 1049 1050 self.set_prop(obj, 'some-uchar', b"\xff") 1051 assert self.get_prop(obj, 'some-uchar') == 255 1052 1053 obj = GIMarshallingTests.PropertiesObject(some_uchar=u"\x7f") 1054 assert self.get_prop(obj, 'some-uchar') == 127 1055 1056 with pytest.raises(TypeError): 1057 GIMarshallingTests.PropertiesObject(some_uchar=u"\x80") 1058 1059 with pytest.raises(TypeError): 1060 GIMarshallingTests.PropertiesObject(some_uchar=u"\ud83d") 1061 1062 def test_int(self): 1063 self.assertEqual(self.get_prop(self.obj, 'some_int'), 0) 1064 self.set_prop(self.obj, 'some-int', GLib.MAXINT) 1065 self.assertEqual(self.get_prop(self.obj, 'some_int'), GLib.MAXINT) 1066 1067 obj = GIMarshallingTests.PropertiesObject(some_int=-42) 1068 self.assertEqual(self.get_prop(obj, 'some-int'), -42) 1069 1070 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', 'foo') 1071 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', None) 1072 1073 self.assertEqual(self.get_prop(obj, 'some-int'), -42) 1074 1075 def test_uint(self): 1076 self.assertEqual(self.get_prop(self.obj, 'some_uint'), 0) 1077 self.set_prop(self.obj, 'some-uint', GLib.MAXUINT) 1078 self.assertEqual(self.get_prop(self.obj, 'some_uint'), GLib.MAXUINT) 1079 1080 obj = GIMarshallingTests.PropertiesObject(some_uint=42) 1081 self.assertEqual(self.get_prop(obj, 'some-uint'), 42) 1082 1083 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', 'foo') 1084 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', None) 1085 1086 self.assertEqual(self.get_prop(obj, 'some-uint'), 42) 1087 1088 def test_long(self): 1089 self.assertEqual(self.get_prop(self.obj, 'some_long'), 0) 1090 self.set_prop(self.obj, 'some-long', GLib.MAXLONG) 1091 self.assertEqual(self.get_prop(self.obj, 'some_long'), GLib.MAXLONG) 1092 1093 obj = GIMarshallingTests.PropertiesObject(some_long=-42) 1094 self.assertEqual(self.get_prop(obj, 'some-long'), -42) 1095 1096 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', 'foo') 1097 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', None) 1098 1099 self.assertEqual(self.get_prop(obj, 'some-long'), -42) 1100 1101 def test_ulong(self): 1102 self.assertEqual(self.get_prop(self.obj, 'some_ulong'), 0) 1103 self.set_prop(self.obj, 'some-ulong', GLib.MAXULONG) 1104 self.assertEqual(self.get_prop(self.obj, 'some_ulong'), GLib.MAXULONG) 1105 1106 obj = GIMarshallingTests.PropertiesObject(some_ulong=42) 1107 self.assertEqual(self.get_prop(obj, 'some-ulong'), 42) 1108 1109 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', 'foo') 1110 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', None) 1111 1112 self.assertEqual(self.get_prop(obj, 'some-ulong'), 42) 1113 1114 def test_int64(self): 1115 self.assertEqual(self.get_prop(self.obj, 'some-int64'), 0) 1116 self.set_prop(self.obj, 'some-int64', GLib.MAXINT64) 1117 self.assertEqual(self.get_prop(self.obj, 'some-int64'), GLib.MAXINT64) 1118 1119 obj = GIMarshallingTests.PropertiesObject(some_int64=-4200000000000000) 1120 self.assertEqual(self.get_prop(obj, 'some-int64'), -4200000000000000) 1121 1122 def test_uint64(self): 1123 self.assertEqual(self.get_prop(self.obj, 'some-uint64'), 0) 1124 self.set_prop(self.obj, 'some-uint64', GLib.MAXUINT64) 1125 self.assertEqual(self.get_prop(self.obj, 'some-uint64'), GLib.MAXUINT64) 1126 1127 obj = GIMarshallingTests.PropertiesObject(some_uint64=4200000000000000) 1128 self.assertEqual(self.get_prop(obj, 'some-uint64'), 4200000000000000) 1129 1130 def test_float(self): 1131 self.assertEqual(self.get_prop(self.obj, 'some-float'), 0) 1132 self.set_prop(self.obj, 'some-float', GLib.MAXFLOAT) 1133 self.assertEqual(self.get_prop(self.obj, 'some-float'), GLib.MAXFLOAT) 1134 1135 obj = GIMarshallingTests.PropertiesObject(some_float=42.42) 1136 self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.42, places=4) 1137 1138 obj = GIMarshallingTests.PropertiesObject(some_float=42) 1139 self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4) 1140 1141 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', 'foo') 1142 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', None) 1143 1144 self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4) 1145 1146 def test_double(self): 1147 self.assertEqual(self.get_prop(self.obj, 'some-double'), 0) 1148 self.set_prop(self.obj, 'some-double', GLib.MAXDOUBLE) 1149 self.assertEqual(self.get_prop(self.obj, 'some-double'), GLib.MAXDOUBLE) 1150 1151 obj = GIMarshallingTests.PropertiesObject(some_double=42.42) 1152 self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.42) 1153 1154 obj = GIMarshallingTests.PropertiesObject(some_double=42) 1155 self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0) 1156 1157 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', 'foo') 1158 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', None) 1159 1160 self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0) 1161 1162 def test_strv(self): 1163 self.assertEqual(self.get_prop(self.obj, 'some-strv'), []) 1164 self.set_prop(self.obj, 'some-strv', ['hello', 'world']) 1165 self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world']) 1166 1167 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 1) 1168 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 'foo') 1169 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', [1, 2]) 1170 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', ['foo', 1]) 1171 1172 self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world']) 1173 1174 obj = GIMarshallingTests.PropertiesObject(some_strv=['hello', 'world']) 1175 self.assertEqual(self.get_prop(obj, 'some-strv'), ['hello', 'world']) 1176 1177 # unicode on py2 1178 obj = GIMarshallingTests.PropertiesObject(some_strv=[u'foo']) 1179 self.assertEqual(self.get_prop(obj, 'some-strv'), [u'foo']) 1180 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 1181 [u'foo', 1]) 1182 1183 def test_boxed_struct(self): 1184 self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct'), None) 1185 1186 class GStrv(list): 1187 __gtype__ = GObject.TYPE_STRV 1188 1189 struct1 = GIMarshallingTests.BoxedStruct() 1190 struct1.long_ = 1 1191 1192 self.set_prop(self.obj, 'some-boxed-struct', struct1) 1193 self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct').long_, 1) 1194 self.assertEqual(self.obj.some_boxed_struct.long_, 1) 1195 1196 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 1) 1197 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 'foo') 1198 1199 obj = GIMarshallingTests.PropertiesObject(some_boxed_struct=struct1) 1200 self.assertEqual(self.get_prop(obj, 'some-boxed-struct').long_, 1) 1201 1202 def test_boxed_glist(self): 1203 self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), []) 1204 1205 list_ = [GLib.MININT, 42, GLib.MAXINT] 1206 self.set_prop(self.obj, 'some-boxed-glist', list_) 1207 self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), list_) 1208 self.set_prop(self.obj, 'some-boxed-glist', []) 1209 self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), []) 1210 1211 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 1) 1212 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 'foo') 1213 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', ['a']) 1214 1215 def test_annotated_glist(self): 1216 obj = Regress.TestObj() 1217 self.assertEqual(self.get_prop(obj, 'list'), []) 1218 1219 self.set_prop(obj, 'list', ['1', '2', '3']) 1220 self.assertTrue(isinstance(self.get_prop(obj, 'list'), list)) 1221 self.assertEqual(self.get_prop(obj, 'list'), ['1', '2', '3']) 1222 1223 @unittest.expectedFailure 1224 def test_boxed_glist_ctor(self): 1225 list_ = [GLib.MININT, 42, GLib.MAXINT] 1226 obj = GIMarshallingTests.PropertiesObject(some_boxed_glist=list_) 1227 self.assertEqual(self.get_prop(obj, 'some-boxed-glist'), list_) 1228 1229 def test_variant(self): 1230 self.assertEqual(self.get_prop(self.obj, 'some-variant'), None) 1231 1232 self.set_prop(self.obj, 'some-variant', GLib.Variant('o', '/myobj')) 1233 self.assertEqual(self.get_prop(self.obj, 'some-variant').get_type_string(), 'o') 1234 self.assertEqual(self.get_prop(self.obj, 'some-variant').print_(False), "'/myobj'") 1235 1236 self.set_prop(self.obj, 'some-variant', None) 1237 self.assertEqual(self.get_prop(self.obj, 'some-variant'), None) 1238 1239 obj = GIMarshallingTests.PropertiesObject(some_variant=GLib.Variant('b', True)) 1240 self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b') 1241 self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True) 1242 1243 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 'foo') 1244 self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 23) 1245 1246 self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b') 1247 self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True) 1248 1249 def test_setting_several_properties(self): 1250 obj = GIMarshallingTests.PropertiesObject() 1251 obj.set_properties(some_uchar=54, some_int=42) 1252 self.assertEqual(42, self.get_prop(obj, 'some-int')) 1253 self.assertEqual(54, self.get_prop(obj, 'some-uchar')) 1254 1255 def test_gtype(self): 1256 obj = Regress.TestObj() 1257 self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INVALID) 1258 self.set_prop(obj, 'gtype', int) 1259 self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT) 1260 1261 obj = Regress.TestObj(gtype=int) 1262 self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT) 1263 self.set_prop(obj, 'gtype', str) 1264 self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_STRING) 1265 1266 def test_hash_table(self): 1267 obj = Regress.TestObj() 1268 self.assertEqual(self.get_prop(obj, 'hash-table'), None) 1269 1270 self.set_prop(obj, 'hash-table', {'mec': 56}) 1271 self.assertTrue(isinstance(self.get_prop(obj, 'hash-table'), dict)) 1272 self.assertEqual(list(self.get_prop(obj, 'hash-table').items())[0], 1273 ('mec', 56)) 1274 1275 def test_parent_class(self): 1276 class A(Regress.TestObj): 1277 prop1 = GObject.Property(type=int) 1278 1279 a = A() 1280 self.set_prop(a, 'int', 20) 1281 self.assertEqual(self.get_prop(a, 'int'), 20) 1282 1283 # test parent property which needs introspection 1284 self.set_prop(a, 'list', ("str1", "str2")) 1285 self.assertEqual(self.get_prop(a, 'list'), ["str1", "str2"]) 1286 1287 def test_held_object_ref_count_getter(self): 1288 holder = GIMarshallingTests.PropertiesObject() 1289 held = GObject.Object() 1290 1291 self.assertEqual(holder.__grefcount__, 1) 1292 self.assertEqual(held.__grefcount__, 1) 1293 1294 self.set_prop(holder, 'some-object', held) 1295 self.assertEqual(holder.__grefcount__, 1) 1296 1297 initial_ref_count = held.__grefcount__ 1298 self.get_prop(holder, 'some-object') 1299 gc.collect() 1300 self.assertEqual(held.__grefcount__, initial_ref_count) 1301 1302 def test_held_object_ref_count_setter(self): 1303 holder = GIMarshallingTests.PropertiesObject() 1304 held = GObject.Object() 1305 1306 self.assertEqual(holder.__grefcount__, 1) 1307 self.assertEqual(held.__grefcount__, 1) 1308 1309 # Setting property should only increase ref count by 1 1310 self.set_prop(holder, 'some-object', held) 1311 self.assertEqual(holder.__grefcount__, 1) 1312 self.assertEqual(held.__grefcount__, 2) 1313 1314 # Clearing should pull it back down 1315 self.set_prop(holder, 'some-object', None) 1316 self.assertEqual(held.__grefcount__, 1) 1317 1318 def test_set_object_property_to_invalid_type(self): 1319 obj = GIMarshallingTests.PropertiesObject() 1320 self.assertRaises(TypeError, self.set_prop, obj, 'some-object', 'not_an_object') 1321 1322 1323class TestCPropsAccessor(CPropertiesTestBase, unittest.TestCase): 1324 # C property tests using the "props" accessor. 1325 def get_prop(self, obj, name): 1326 return getattr(obj.props, name.replace('-', '_')) 1327 1328 def set_prop(self, obj, name, value): 1329 setattr(obj.props, name.replace('-', '_'), value) 1330 1331 def test_props_accessor_dir(self): 1332 # Test class 1333 props = dir(GIMarshallingTests.PropertiesObject.props) 1334 self.assertTrue('some_float' in props) 1335 self.assertTrue('some_double' in props) 1336 self.assertTrue('some_variant' in props) 1337 1338 # Test instance 1339 obj = GIMarshallingTests.PropertiesObject() 1340 props = dir(obj.props) 1341 self.assertTrue('some_float' in props) 1342 self.assertTrue('some_double' in props) 1343 self.assertTrue('some_variant' in props) 1344 1345 def test_param_spec_dir(self): 1346 attrs = dir(GIMarshallingTests.PropertiesObject.props.some_float) 1347 self.assertTrue('name' in attrs) 1348 self.assertTrue('nick' in attrs) 1349 self.assertTrue('blurb' in attrs) 1350 self.assertTrue('flags' in attrs) 1351 self.assertTrue('default_value' in attrs) 1352 self.assertTrue('minimum' in attrs) 1353 self.assertTrue('maximum' in attrs) 1354 1355 1356class TestCGetPropertyMethod(CPropertiesTestBase, unittest.TestCase): 1357 # C property tests using the "props" accessor. 1358 def get_prop(self, obj, name): 1359 return obj.get_property(name) 1360 1361 def set_prop(self, obj, name, value): 1362 obj.set_property(name, value) 1363