[pygobject] Move property install function into propertyhelper.py
- From: Simon Feltman <sfeltman src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] Move property install function into propertyhelper.py
- Date: Mon, 22 Oct 2012 08:37:31 +0000 (UTC)
commit 438d3e68f19e2af5d027e18842ab05e0421d088d
Author: Simon Feltman <sfeltman src gnome org>
Date: Sat Oct 20 19:56:04 2012 -0700
Move property install function into propertyhelper.py
Move _install_properties() into gi/_gobject/propertyhelper.py
and add unittests.
https://bugzilla.gnome.org/show_bug.cgi?id=686559
gi/_gobject/__init__.py | 45 ++---------------------------
gi/_gobject/propertyhelper.py | 45 +++++++++++++++++++++++++++++
tests/test_properties.py | 63 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 111 insertions(+), 42 deletions(-)
---
diff --git a/gi/_gobject/__init__.py b/gi/_gobject/__init__.py
index 7b6ab36..f12d3fe 100644
--- a/gi/_gobject/__init__.py
+++ b/gi/_gobject/__init__.py
@@ -30,7 +30,7 @@ if 'gobject' in sys.modules:
from .. import _glib
from . import _gobject
from . import constants
-from .propertyhelper import Property
+from . import propertyhelper
from . import signalhelper
GBoxed = _gobject.GBoxed
@@ -211,6 +211,7 @@ G_MAXSSIZE = constants.G_MAXSSIZE
G_MINOFFSET = constants.G_MINOFFSET
G_MAXOFFSET = constants.G_MAXOFFSET
+Property = propertyhelper.Property
Signal = signalhelper.Signal
SignalOverride = signalhelper.SignalOverride
@@ -222,50 +223,10 @@ class GObjectMeta(type):
"Metaclass for automatically registering GObject classes"
def __init__(cls, name, bases, dict_):
type.__init__(cls, name, bases, dict_)
- cls._install_properties()
+ propertyhelper.install_properties(cls)
signalhelper.install_signals(cls)
cls._type_register(cls.__dict__)
- def _install_properties(cls):
- gproperties = getattr(cls, '__gproperties__', {})
-
- props = []
- for name, prop in cls.__dict__.items():
- if isinstance(prop, Property): # not same as the built-in
- if name in gproperties:
- raise ValueError
- prop.name = name
- gproperties[name] = prop.get_pspec_args()
- props.append(prop)
-
- if not props:
- return
-
- cls.__gproperties__ = gproperties
-
- if 'do_get_property' in cls.__dict__ or 'do_set_property' in cls.__dict__:
- for prop in props:
- if prop.fget != prop._default_getter or prop.fset != prop._default_setter:
- raise TypeError(
- "GObject subclass %r defines do_get/set_property"
- " and it also uses a property with a custom setter"
- " or getter. This is not allowed" % (
- cls.__name__,))
-
- def obj_get_property(self, pspec):
- name = pspec.name.replace('-', '_')
- prop = getattr(cls, name, None)
- if prop:
- return prop.fget(self)
- cls.do_get_property = obj_get_property
-
- def obj_set_property(self, pspec, value):
- name = pspec.name.replace('-', '_')
- prop = getattr(cls, name, None)
- if prop:
- prop.fset(self, value)
- cls.do_set_property = obj_set_property
-
def _type_register(cls, namespace):
## don't register the class if already registered
if '__gtype__' in namespace:
diff --git a/gi/_gobject/propertyhelper.py b/gi/_gobject/propertyhelper.py
index 82b06b0..a1e82c0 100644
--- a/gi/_gobject/propertyhelper.py
+++ b/gi/_gobject/propertyhelper.py
@@ -343,3 +343,48 @@ class Property(object):
raise NotImplementedError(ptype)
return (self.type, self.nick, self.blurb) + args + (self.flags,)
+
+
+def install_properties(cls):
+ """
+ Scans the given class for instances of Property and merges them
+ into the classes __gproperties__ dict if it exists or adds it if not.
+ """
+ gproperties = getattr(cls, '__gproperties__', {})
+
+ props = []
+ for name, prop in cls.__dict__.items():
+ if isinstance(prop, Property): # not same as the built-in
+ if name in gproperties:
+ raise ValueError('Property %s was already found in __gproperties__' % name)
+ prop.name = name
+ gproperties[name] = prop.get_pspec_args()
+ props.append(prop)
+
+ if not props:
+ return
+
+ cls.__gproperties__ = gproperties
+
+ if 'do_get_property' in cls.__dict__ or 'do_set_property' in cls.__dict__:
+ for prop in props:
+ if prop.fget != prop._default_getter or prop.fset != prop._default_setter:
+ raise TypeError(
+ "GObject subclass %r defines do_get/set_property"
+ " and it also uses a property with a custom setter"
+ " or getter. This is not allowed" % (
+ cls.__name__,))
+
+ def obj_get_property(self, pspec):
+ name = pspec.name.replace('-', '_')
+ prop = getattr(cls, name, None)
+ if prop:
+ return prop.fget(self)
+ cls.do_get_property = obj_get_property
+
+ def obj_set_property(self, pspec, value):
+ name = pspec.name.replace('-', '_')
+ prop = getattr(cls, name, None)
+ if prop:
+ prop.fset(self, value)
+ cls.do_set_property = obj_set_property
diff --git a/tests/test_properties.py b/tests/test_properties.py
index 405375d..230ccd3 100644
--- a/tests/test_properties.py
+++ b/tests/test_properties.py
@@ -21,6 +21,7 @@ from gi.repository.GObject import \
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import GIMarshallingTests
+from gi._gobject import propertyhelper
if sys.version_info < (3, 0):
TEST_UTF8 = "\xe2\x99\xa5"
@@ -722,5 +723,67 @@ class TestProperty(unittest.TestCase):
self.assertRaises(TypeError, tester._type_from_python, types.CodeType)
+
+class TestInstallProperties(unittest.TestCase):
+ # These tests only test how signalhelper.install_signals works
+ # with the __gsignals__ dict and therefore does not need to use
+ # GObject as a base class because that would automatically call
+ # install_signals within the meta-class.
+ class Base(object):
+ __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)}
+
+ class Sub1(Base):
+ pass
+
+ class Sub2(Base):
+ @GObject.Property(type=int)
+ def sub2test(self):
+ return 123
+
+ class ClassWithPropertyAndGetterVFunc(object):
+ @GObject.Property(type=int)
+ def sub2test(self):
+ return 123
+
+ def do_get_property(self, name):
+ return 321
+
+ class ClassWithPropertyRedefined(object):
+ __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)}
+ test = GObject.Property(type=int)
+
+ def setUp(self):
+ propertyhelper.install_properties(self.Base)
+
+ def test_subclass_without_properties_is_not_modified(self):
+ self.assertFalse('__gproperties__' in self.Sub1.__dict__)
+ propertyhelper.install_properties(self.Sub1)
+ self.assertFalse('__gproperties__' in self.Sub1.__dict__)
+
+ def test_subclass_with_decorator_gets_gproperties_dict(self):
+ # Sub2 has Property instances but will not have a __gproperties__
+ # until install_properties is called
+ self.assertFalse('__gproperties__' in self.Sub2.__dict__)
+ self.assertFalse('do_get_property' in self.Sub2.__dict__)
+ self.assertFalse('do_set_property' in self.Sub2.__dict__)
+
+ propertyhelper.install_properties(self.Sub2)
+ self.assertTrue('__gproperties__' in self.Sub2.__dict__)
+ self.assertEqual(len(self.Base.__gproperties__), 2)
+ self.assertEqual(len(self.Sub2.__gproperties__), 2)
+ self.assertTrue('sub2test' in self.Sub2.__gproperties__)
+
+ # get/set vfuncs should have been added
+ self.assertTrue('do_get_property' in self.Sub2.__dict__)
+ self.assertTrue('do_set_property' in self.Sub2.__dict__)
+
+ def test_object_with_property_and_do_get_property_vfunc_raises(self):
+ self.assertRaises(TypeError, propertyhelper.install_properties,
+ self.ClassWithPropertyAndGetterVFunc)
+
+ def test_same_name_property_definitions_raises(self):
+ self.assertRaises(ValueError, propertyhelper.install_properties,
+ self.ClassWithPropertyRedefined)
+
if __name__ == '__main__':
unittest.main()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]