summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--examples/properties.py50
-rw-r--r--gobject/Makefile.am21
-rw-r--r--gobject/__init__.py70
-rw-r--r--gobject/constants.py.in47
-rw-r--r--gobject/generate-constants.c21
-rw-r--r--gobject/propertyhelper.py285
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/test_enum.py15
-rw-r--r--tests/test_interface.py11
-rw-r--r--tests/test_properties.py170
11 files changed, 586 insertions, 125 deletions
diff --git a/ChangeLog b/ChangeLog
index a371484..4fd89ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2007-05-01 Johan Dahlin <johan@gnome.org>
+
+ * examples/properties.py:
+ * gobject/Makefile.am:
+ * gobject/__init__.py:
+ * gobject/constants.py.in:
+ * gobject/generate-constants.c: (main):
+ * gobject/propertyhelper.py:
+ * tests/Makefile.am:
+ * tests/test_enum.py:
+ * tests/test_interface.py:
+ * tests/test_properties.py:
+
+ Add a property helper, fixes #338098
+
2007-04-30 Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
* tests/common.py (importModules): Import testhelper first so that
diff --git a/examples/properties.py b/examples/properties.py
index 2d36afc..cc05920 100644
--- a/examples/properties.py
+++ b/examples/properties.py
@@ -1,43 +1,31 @@
import gobject
class MyObject(gobject.GObject):
- __gproperties__ = {
- 'foo': (gobject.TYPE_STRING, 'foo property', 'the foo of the object',
- 'bar', gobject.PARAM_READWRITE),
- 'boolprop': (gobject.TYPE_BOOLEAN, 'bool prop', 'a test boolean prop',
- 0, gobject.PARAM_READABLE),
- }
+
+ foo = gobject.property(type=str, default='bar')
+ boolprop = gobject.property(type=bool, default=False)
def __init__(self):
- self.__gobject_init__()
- self.foo = 'bar'
- def do_set_property(self, pspec, value):
- print ' do_set_property called for %s=%r' % (pspec.name, value)
- if pspec.name == 'foo':
- self.foo = value
- else:
- raise AttributeError, 'unknown property %s' % pspec.name
- def do_get_property(self, pspec):
- print ' do_get_property called for %s' % pspec.name
- if pspec.name == 'foo':
- return self.foo
- elif pspec.name == 'boolprop':
- return 1
- else:
- raise AttributeError, 'unknown property %s' % pspec.name
+ gobject.GObject.__init__(self)
+
+ @gobject.property
+ def readonly(self):
+ return 'readonly'
+
gobject.type_register(MyObject)
-print "MyObject properties: ", gobject.list_properties(MyObject)
+print "MyObject properties: ", list(MyObject.props)
+
obj = MyObject()
-val = obj.get_property('foo')
-print "obj.get_property('foo') == ", val
+print "obj.foo ==", obj.foo
+
+obj.foo = 'spam'
+print "obj.foo = spam"
-obj.set_property('foo', 'spam')
-print "obj.set_property('foo', 'spam')"
+print "obj.foo == ", obj.foo
-val = obj.get_property('foo')
-print "obj.get_property('foo') == ", val
+print "obj.boolprop == ", obj.boolprop
-val = obj.get_property('boolprop')
-print "obj.get_property('boolprop') == ", val
+print obj.readonly
+obj.readonly = 'does-not-work'
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index 6c4f242..32b4305 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -9,15 +9,29 @@ pkgpyexecdir = $(pyexecdir)/gtk-2.0
# gobject python scripts
pygobjectdir = $(pkgpyexecdir)/gobject
-pygobject_PYTHON = __init__.py option.py
+pygobject_PYTHON = \
+ __init__.py \
+ option.py \
+ propertyhelper.py
pygobject_LTLIBRARIES = _gobject.la
-
+nodist_pygobject_PYTHON = constants.py
common_ldflags = -module -avoid-version
if PLATFORM_WIN32
common_ldflags += -no-undefined
endif
+constants.py: generate-constants constants.py.in
+ rm -f constants.py
+ cp $(srcdir)/constants.py.in constants.py
+ chmod 644 constants.py
+ $(top_builddir)/gobject/generate-constants >> constants.py
+ chmod 444 constants.py
+
+generate_constants_CFLAGS = $(GLIB_CFLAGS)
+noinst_PROGRAMS = generate-constants
+CLEANFILES = constants.py
+EXTRA_DIST = constants.py.in
_gobject_la_CFLAGS = $(GLIB_CFLAGS)
_gobject_la_LDFLAGS = $(common_ldflags) -export-symbols-regex init_gobject
@@ -39,9 +53,10 @@ _gobject_la_SOURCES = \
pygtype.c \
pygoptioncontext.c \
pygoptiongroup.c
+_gobject_la_DEPENDENCIES = constants.py
if HAVE_LIBFFI
-_gobject_la_SOURCES += ffi-marshaller.c
+_gobject_la_SOURCES += ffi-marshaller.c ffi-marshaller.h
endif
if PLATFORM_WIN32
diff --git a/gobject/__init__.py b/gobject/__init__.py
index 43a2cfd..d251d31 100644
--- a/gobject/__init__.py
+++ b/gobject/__init__.py
@@ -27,15 +27,61 @@ try:
except ImportError:
pass
+from gobject.constants import *
from _gobject import *
_PyGObject_API = _gobject._PyGObject_API
+from propertyhelper import property
+
class GObjectMeta(type):
"Metaclass for automatically registering GObject classes"
def __init__(cls, name, bases, dict_):
type.__init__(cls, name, bases, dict_)
+ cls._install_properties()
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
+ props[name] = prop.get_pspec_args()
+
+ if not props:
+ return
+
+ if not gproperties:
+ cls.__gproperties__ = props
+ else:
+ gproperties.update(props)
+
+ if (hasattr(cls, 'do_get_property') or
+ hasattr(cls, 'do_set_property')):
+ for prop in props:
+ if (prop.getter != prop.default_getter or
+ prop.setter != prop.default_setter):
+ raise TypeError(
+ "GObject subclass %r defines do_get/set_property"
+ " and it also uses a property which a custom setter"
+ " or getter. This is not allowed" % (cls,))
+
+ def obj_get_property(self, pspec):
+ name = pspec.name.replace('-', '_')
+ prop = getattr(cls, name, None)
+ if prop:
+ return prop.getter(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.setter(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:
@@ -50,28 +96,4 @@ class GObjectMeta(type):
_gobject._install_metaclass(GObjectMeta)
-# TYPE_INVALID defined in gobjectmodule.c
-TYPE_NONE = type_from_name('void')
-TYPE_INTERFACE = type_from_name('GInterface')
-TYPE_CHAR = type_from_name('gchar')
-TYPE_UCHAR = type_from_name('guchar')
-TYPE_BOOLEAN = type_from_name('gboolean')
-TYPE_INT = type_from_name('gint')
-TYPE_UINT = type_from_name('guint')
-TYPE_LONG = type_from_name('glong')
-TYPE_ULONG = type_from_name('gulong')
-TYPE_INT64 = type_from_name('gint64')
-TYPE_UINT64 = type_from_name('guint64')
-TYPE_ENUM = type_from_name('GEnum')
-TYPE_FLAGS = type_from_name('GFlags')
-TYPE_FLOAT = type_from_name('gfloat')
-TYPE_DOUBLE = type_from_name('gdouble')
-TYPE_STRING = type_from_name('gchararray')
-TYPE_POINTER = type_from_name('gpointer')
-TYPE_BOXED = type_from_name('GBoxed')
-TYPE_PARAM = type_from_name('GParam')
-TYPE_OBJECT = type_from_name('GObject')
-TYPE_PYOBJECT = type_from_name('PyObject')
-TYPE_UNICHAR = TYPE_UINT
-
del _gobject
diff --git a/gobject/constants.py.in b/gobject/constants.py.in
new file mode 100644
index 0000000..6cb2d4f
--- /dev/null
+++ b/gobject/constants.py.in
@@ -0,0 +1,47 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# pygobject - Python bindings for the GObject library
+# Copyright (C) 2006-2007 Johan Dahlin
+#
+# gobject/constants.py: GObject type constants
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+from _gobject import type_from_name
+
+# TYPE_INVALID defined in gobjectmodule.c
+TYPE_NONE = type_from_name('void')
+TYPE_INTERFACE = type_from_name('GInterface')
+TYPE_CHAR = type_from_name('gchar')
+TYPE_UCHAR = type_from_name('guchar')
+TYPE_BOOLEAN = type_from_name('gboolean')
+TYPE_INT = type_from_name('gint')
+TYPE_UINT = type_from_name('guint')
+TYPE_LONG = type_from_name('glong')
+TYPE_ULONG = type_from_name('gulong')
+TYPE_INT64 = type_from_name('gint64')
+TYPE_UINT64 = type_from_name('guint64')
+TYPE_ENUM = type_from_name('GEnum')
+TYPE_FLAGS = type_from_name('GFlags')
+TYPE_FLOAT = type_from_name('gfloat')
+TYPE_DOUBLE = type_from_name('gdouble')
+TYPE_STRING = type_from_name('gchararray')
+TYPE_POINTER = type_from_name('gpointer')
+TYPE_BOXED = type_from_name('GBoxed')
+TYPE_PARAM = type_from_name('GParam')
+TYPE_OBJECT = type_from_name('GObject')
+TYPE_PYOBJECT = type_from_name('PyObject')
+TYPE_UNICHAR = TYPE_UINT
+
diff --git a/gobject/generate-constants.c b/gobject/generate-constants.c
new file mode 100644
index 0000000..ed66a07
--- /dev/null
+++ b/gobject/generate-constants.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <glibconfig.h>
+
+int main(void)
+{
+ printf("# This part is generated by generate-constants.c\n");
+ printf("G_MINFLOAT = %f\n", G_MINFLOAT);
+ printf("G_MINFLOAT = %f\n", G_MINFLOAT);
+ printf("G_MAXFLOAT = %f\n", G_MAXFLOAT);
+ printf("G_MINDOUBLE = %f\n", G_MINDOUBLE);
+ printf("G_MAXDOUBLE = %f\n", G_MAXDOUBLE);
+ printf("G_MINSHORT = %d\n", G_MINSHORT);
+ printf("G_MAXSHORT = %d\n", G_MAXSHORT);
+ printf("G_MAXUSHORT = %u\n", G_MAXUSHORT);
+ printf("G_MININT = %d\n", G_MININT);
+ printf("G_MAXINT = %d\n", G_MAXINT);
+ printf("G_MAXUINT = %u\n", G_MAXUINT);
+ printf("G_MINLONG = %ldL\n", G_MINLONG);
+ printf("G_MAXLONG = %ldL\n", G_MAXLONG);
+ printf("G_MAXULONG = %luL\n", G_MAXULONG);
+}
diff --git a/gobject/propertyhelper.py b/gobject/propertyhelper.py
new file mode 100644
index 0000000..f0c01e4
--- /dev/null
+++ b/gobject/propertyhelper.py
@@ -0,0 +1,285 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# pygobject - Python bindings for the GObject library
+# Copyright (C) 2007 Johan Dahlin
+#
+# gobject/_property.py: GObject property wrapper/helper
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+import _gobject
+from gobject.constants import \
+ TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, \
+ TYPE_BOOLEAN, TYPE_INT, TYPE_UINT, TYPE_LONG, \
+ TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_ENUM, \
+ TYPE_FLAGS, TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, \
+ TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \
+ TYPE_PYOBJECT
+from gobject.constants import \
+ G_MINFLOAT, G_MAXFLOAT, G_MINDOUBLE, G_MAXDOUBLE, \
+ G_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, \
+ G_MAXULONG
+
+
+class PropertyMeta(type):
+ def __repr__(self):
+ return "<class 'gobject.property'>"
+
+
+class property(object):
+ """
+ Creates a new property which in conjunction with GObjectMeta will
+ create a GObject property proxy:
+
+ >>> class MyObject(gobject.GObject):
+ >>> ... prop = gobject.property(type=str)
+
+ >>> obj = MyObject()
+ >>> obj.prop = 'value'
+
+ >>> obj.prop
+ 'value'
+ """
+
+ __metaclass__ = PropertyMeta
+
+ def __init__(self, getter=None, setter=None, type=None, default=None,
+ nick='', blurb='', flags=_gobject.PARAM_READWRITE,
+ minimum=None, maximum=None):
+ """
+ @param getter: getter to get the value of the property
+ @type getter: callable
+ @param setter: setter to set the value of the property
+ @type setter: callable
+ @param type: type of property
+ @type type: type
+ @param default: default value
+ @param nick: short description
+ @type bick: string
+ @param blurb: long description
+ @type blurb: string
+ @param flags: parameter flags, one of:
+ - gobject.PARAM_READABLE
+ - gobject.PARAM_READWRITE
+ - gobject.PARAM_WRITABLE
+ - gobject.PARAM_CONSTRUCT
+ - gobject.PARAM_CONSTRUCT_ONLY
+ - gobject.PARAM_LAX_VALIDATION
+ @keyword minimum: minimum allowed value (int, float, long only)
+ @keyword maximum: maximum allowed value (int, float, long only)
+ """
+
+ if getter and not setter:
+ setter = self._readonly_setter
+ elif setter and not getter:
+ getter = self._writeonly_getter
+ elif not setter and not getter:
+ getter = self._default_getter
+ setter = self._default_setter
+ self.getter = getter
+ self.setter = setter
+
+ if type is None:
+ type = object
+ self.type = self._type_from_python(type)
+ self.default = self._get_default(default)
+ self._check_default()
+
+ if not isinstance(nick, basestring):
+ raise TypeError("nick must be a string")
+ self.nick = nick
+
+ if not isinstance(blurb, basestring):
+ raise TypeError("blurb must be a string")
+ self.blurb = blurb
+
+ if flags < 0 or flags > 32:
+ raise TypeError("invalid flag value: %r" % (flags,))
+ self.flags = flags
+
+ if minimum is not None:
+ if minimum < self._get_minimum():
+ raise TypeError(
+ "Minimum for type %s cannot be lower than %d" % (
+ self.type, self._get_minimum()))
+ else:
+ minimum = self._get_minimum()
+ self.minimum = minimum
+ if maximum is not None:
+ if maximum > self._get_maximum():
+ raise TypeError(
+ "Maximum for type %s cannot be higher than %d" % (
+ self.type, self._get_maximum()))
+ else:
+ maximum = self._get_maximum()
+ self.maximum = maximum
+
+ self.name = None
+
+ self._value = self.default
+ self._exc = None
+
+ def __repr__(self):
+ return '<gobject property %s (%s)>' % (
+ self.name or '(uninitialized)',
+ _gobject.type_name(self.type))
+
+ def __get__(self, instance, klass):
+ if instance is None:
+ return self
+
+ self._exc = None
+ value = instance.get_property(self.name)
+ if self._exc:
+ exc = self._exc
+ self._exc = None
+ raise exc
+
+ return value
+
+ def __set__(self, instance, value):
+ if instance is None:
+ raise TypeError
+
+ self._exc = None
+ instance.set_property(self.name, value)
+ if self._exc:
+ exc = self._exc
+ self._exc = None
+ raise exc
+
+ def _type_from_python(self, type):
+ if type == int:
+ return TYPE_INT
+ elif type == bool:
+ return TYPE_BOOLEAN
+ elif type == long:
+ return TYPE_LONG
+ elif type == float:
+ return TYPE_DOUBLE
+ elif type == str:
+ return TYPE_STRING
+ elif type == object:
+ return TYPE_PYOBJECT
+ elif type in [TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR,
+ TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG,
+ TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_ENUM,
+ TYPE_FLAGS, TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER,
+ TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING,
+ TYPE_PYOBJECT]:
+ return type
+ else:
+ raise TypeError("Unsupported type: %r" % (type,))
+
+ def _get_default(self, default):
+ ptype = self.type
+ if default is not None:
+ return default
+
+ if ptype in [TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG,
+ TYPE_INT64, TYPE_UINT64]:
+ return 0
+ elif ptype == TYPE_STRING:
+ return ''
+ elif ptype == TYPE_FLOAT or ptype == TYPE_DOUBLE:
+ return 0.0
+ else:
+ return None
+
+ def _check_default(self):
+ ptype = self.type
+ default = self.default
+ if (ptype == TYPE_BOOLEAN and
+ (default is not True or
+ default is not False)):
+ raise TypeError(
+ "default must be True or False, not %r" % (default,))
+ elif ptype == TYPE_PYOBJECT:
+ if default is not None:
+ raise TypeError("object types does not have default values")
+
+ def _get_minimum(self):
+ ptype = self.type
+ if ptype in [TYPE_UINT, TYPE_ULONG, TYPE_UINT64]:
+ return 0
+ elif ptype == TYPE_FLOAT:
+ return G_MINFLOAT
+ elif ptype == TYPE_DOUBLE:
+ return G_MINDOUBLE
+ elif ptype == TYPE_INT:
+ return G_MININT
+ elif ptype == TYPE_LONG:
+ return G_MINLONG
+ elif ptype == TYPE_INT64:
+ return -2 ** 62 - 1
+
+ return None
+
+ def _get_maximum(self):
+ ptype = self.type
+ if ptype == TYPE_UINT:
+ return G_MAXUINT
+ elif ptype == TYPE_ULONG:
+ return G_MAXULONG
+ elif ptype == TYPE_INT64:
+ return 2 ** 62 - 1
+ elif ptype == TYPE_UINT64:
+ return 2 ** 63 - 1
+ elif ptype == TYPE_FLOAT:
+ return G_MAXFLOAT
+ elif ptype == TYPE_DOUBLE:
+ return G_MAXDOUBLE
+ elif ptype == TYPE_INT:
+ return G_MAXINT
+ elif ptype == TYPE_LONG:
+ return G_MAXLONG
+
+ return None
+
+ #
+ # Getter and Setter
+ #
+
+ def _default_setter(self, instance, value):
+ self._value = value
+
+ def _default_getter(self, instance):
+ return self._value
+
+ def _readonly_setter(self, instance, value):
+ self._exc = TypeError("%s property of %s is read-only" % (
+ self.name, type(instance).__name__))
+
+ def _writeonly_getter(self, instance):
+ self._exc = TypeError("%s property of %s is write-only" % (
+ self.name, type(instance).__name__))
+
+ #
+ # Public API
+ #
+
+ def get_pspec_args(self):
+ ptype = self.type
+ if ptype in [TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG,
+ TYPE_INT64, TYPE_UINT64, TYPE_FLOAT, TYPE_DOUBLE]:
+ args = self._get_minimum(), self._get_maximum(), self.default
+ elif ptype == TYPE_STRING or ptype == TYPE_BOOLEAN:
+ args = (self.default,)
+ elif ptype == TYPE_PYOBJECT:
+ args = ()
+ else:
+ raise NotImplementedError(ptype)
+
+ return (self.type, self.nick, self.blurb) + args + (self.flags,)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index fe627c2..3b05018 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -40,10 +40,10 @@ testhelper.la: $(testhelper_la_OBJECTS) $(testhelper_la_DEPENDENCIES)
check-local: $(top_srcdir)/gobject/__init__.py
@if test "$(top_builddir)" != "$(top_srcdir)"; then \
- cp $(top_srcdir)/gobject/__init__.py $(top_builddir)/gobject/__init__.py; \
+ cp $(top_srcdir)/gobject/*.py $(top_builddir)/gobject; \
fi
@$(PYTHON) $(srcdir)/runtests.py $(top_builddir) $(top_srcdir)
@if test "$(top_builddir)" != "$(top_srcdir)"; then \
- rm -f $(top_builddir)/gobject/__init__.py*; \
+ rm -f $(top_builddir)/gobject/*.py; \
fi
- @rm -fr *.pyc
+ @rm -fr $(top_builddir)/gobject/*.pyc
diff --git a/tests/test_enum.py b/tests/test_enum.py
index 88d8287..6543cec 100644
--- a/tests/test_enum.py
+++ b/tests/test_enum.py
@@ -1,20 +1,15 @@
import unittest
import warnings
+import gobject
from gobject import GEnum, GFlags, GObject, GType, PARAM_READWRITE
from common import gobject, atk, pango, gtk, gdk
class PObject(GObject):
- __gproperties__ = {
- 'enum': (gtk.WindowType, 'blurb', 'description',
- gtk.WINDOW_TOPLEVEL, PARAM_READWRITE),
- 'enum2': (gtk.WindowType, 'blurb', 'description',
- int(gtk.WINDOW_TOPLEVEL), PARAM_READWRITE),
- 'flags': (gtk.AttachOptions, 'blurb', 'description',
- gtk.EXPAND, PARAM_READWRITE),
- 'flags2': (gtk.AttachOptions, 'blurb', 'description',
- int(gtk.EXPAND), PARAM_READWRITE),
- }
+ enum = gobject.property(type=gtk.WindowType, default=gtk.WINDOW_TOPLEVEL)
+ enum2 = gobject.property(type=gtk.WindowType, default=int(gtk.WINDOW_TOPLEVEL))
+ flags = gobject.property(type=gtk.AttachOptions, default=gtk.EXPAND)
+ flags2 = gobject.property(type=gtk.AttachOptions, default=int(gtk.EXPAND))
class EnumTest(unittest.TestCase):
def testEnums(self):
diff --git a/tests/test_interface.py b/tests/test_interface.py
index d54515d..4413d64 100644
--- a/tests/test_interface.py
+++ b/tests/test_interface.py
@@ -3,15 +3,13 @@ import unittest
import testmodule
from common import gobject, testhelper
from gobject import GObject, GInterface
+import gobject
GUnknown = gobject.type_from_name("TestUnknown")
Unknown = GUnknown.pytype
class MyUnknown(Unknown, testhelper.Interface):
- __gproperties__ = {
- 'some-property': (str, 'blurb', 'description', 'default',
- gobject.PARAM_READWRITE),
- }
+ some_property = gobject.property(type=str)
def __init__(self):
Unknown.__init__(self)
@@ -24,10 +22,7 @@ class MyUnknown(Unknown, testhelper.Interface):
gobject.type_register(MyUnknown)
class MyObject(gobject.GObject, testhelper.Interface):
- __gproperties__ = {
- 'some-property': (str, 'blurb', 'description', 'default',
- gobject.PARAM_READWRITE),
- }
+ some_property = gobject.property(type=str)
def __init__(self):
GObject.__init__(self)
diff --git a/tests/test_properties.py b/tests/test_properties.py
index e155911..423a8f6 100644
--- a/tests/test_properties.py
+++ b/tests/test_properties.py
@@ -2,54 +2,26 @@
import struct
import unittest
-from common import testhelper
-from gobject import GObject, GType, new, PARAM_READWRITE, \
- PARAM_CONSTRUCT, PARAM_READABLE, PARAM_WRITABLE, PARAM_CONSTRUCT_ONLY, \
- TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, \
- TYPE_INT64, TYPE_UINT64
+import gobject
+from gobject import GObject, GType, GEnum, new, PARAM_READWRITE, \
+ PARAM_CONSTRUCT, PARAM_READABLE, PARAM_WRITABLE, PARAM_CONSTRUCT_ONLY
+from gobject.constants import \
+ TYPE_INT, TYPE_UINT, TYPE_LONG, \
+ TYPE_ULONG, TYPE_INT64, TYPE_UINT64
+from gobject.constants import \
+ G_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, \
+ G_MAXULONG
class PropertyObject(GObject):
- __gproperties__ = {
- 'normal': (str, 'blurb', 'description', 'default',
- PARAM_READWRITE),
- 'construct': (str, 'blurb', 'description', 'default',
- PARAM_READWRITE|PARAM_CONSTRUCT),
- 'construct-only': (str, 'blurb', 'description', 'default',
- PARAM_READWRITE|PARAM_CONSTRUCT_ONLY),
- 'uint64': (TYPE_UINT64, 'blurb', 'description', 0, 10, 0,
- PARAM_READWRITE),
- }
-
- def __init__(self):
- GObject.__init__(self)
- self._value = 'default'
- self._construct_only = None
- self._construct = None
- self._uint64 = 0L
-
- def do_get_property(self, pspec):
- if pspec.name == 'normal':
- return self._value
- elif pspec.name == 'construct':
- return self._construct
- elif pspec.name == 'construct-only':
- return self._construct_only
- elif pspec.name == 'uint64':
- return self._uint64
- else:
- raise AssertionError
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'normal':
- self._value = value
- elif pspec.name == 'construct':
- self._construct = value
- elif pspec.name == 'construct-only':
- self._construct_only = value
- elif pspec.name == 'uint64':
- self._uint64 = value
- else:
- raise AssertionError
+ normal = gobject.property(type=str)
+ construct = gobject.property(
+ type=str,
+ flags=PARAM_READWRITE|PARAM_CONSTRUCT, default='default')
+ construct_only = gobject.property(
+ type=str,
+ flags=PARAM_READWRITE|PARAM_CONSTRUCT_ONLY)
+ uint64 = gobject.property(
+ type=TYPE_UINT64, flags=PARAM_READWRITE|PARAM_CONSTRUCT)
class TestProperties(unittest.TestCase):
def testGetSet(self):
@@ -200,3 +172,109 @@ class TestProperties(unittest.TestCase):
normal, uint64 = obj.get_properties("normal", "uint64")
self.assertEqual(normal, "foo")
self.assertEqual(uint64, 7)
+
+class TestProperty(unittest.TestCase):
+ def testSimple(self):
+ class C(gobject.GObject):
+ str = gobject.property(type=str)
+ int = gobject.property(type=int)
+ float = gobject.property(type=float)
+ long = gobject.property(type=long)
+
+ self.failUnless(hasattr(C.props, 'str'))
+ self.failUnless(hasattr(C.props, 'int'))
+ self.failUnless(hasattr(C.props, 'float'))
+ self.failUnless(hasattr(C.props, 'long'))
+
+ o = C()
+ self.assertEqual(o.str, '')
+ o.str = 'str'
+ self.assertEqual(o.str, 'str')
+
+ self.assertEqual(o.int, 0)
+ o.int = 1138
+ self.assertEqual(o.int, 1138)
+
+ self.assertEqual(o.float, 0.0)
+ o.float = 3.14
+ self.assertEqual(o.float, 3.14)
+
+ self.assertEqual(o.long, 0L)
+ o.long = 100L
+ self.assertEqual(o.long, 100L)
+
+ def testCustomGetter(self):
+ class C(gobject.GObject):
+ def get_prop(self):
+ return 'value'
+ prop = gobject.property(getter=get_prop)
+
+ o = C()
+ self.assertEqual(o.prop, 'value')
+ self.assertRaises(TypeError, setattr, o, 'prop', 'xxx')
+
+ def testCustomSetter(self):
+ class C(gobject.GObject):
+ def set_prop(self, value):
+ self._value = value
+ prop = gobject.property(setter=set_prop)
+
+ def __init__(self):
+ self._value = None
+ gobject.GObject.__init__(self)
+
+ o = C()
+ self.assertEquals(o._value, None)
+ o.prop = 'bar'
+ self.assertEquals(o._value, 'bar')
+ self.assertRaises(TypeError, getattr, o, 'prop')
+
+ def testErrors(self):
+ self.assertRaises(TypeError, gobject.property, type='str')
+ self.assertRaises(TypeError, gobject.property, nick=False)
+ self.assertRaises(TypeError, gobject.property, blurb=False)
+ self.assertRaises(TypeError, gobject.property, type=bool, default=0)
+ self.assertRaises(TypeError, gobject.property, type=GEnum)
+ self.assertRaises(TypeError, gobject.property, type=GEnum, default=0)
+ self.assertRaises(TypeError, gobject.property, type=object, default=0)
+ self.assertRaises(TypeError, gobject.property, type=complex)
+ self.assertRaises(TypeError, gobject.property, flags=-10)
+
+ def testNameWithUnderscore(self):
+ class C(gobject.GObject):
+ prop_name = gobject.property(type=int)
+ o = C()
+ o.prop_name = 10
+ self.assertEqual(o.prop_name, 10)
+
+ def testRange(self):
+ maxint64 = 2 ** 62 - 1
+ minint64 = -2 ** 62 - 1
+ maxuint64 = 2 ** 63 - 1
+
+ types = [
+ (TYPE_INT, G_MININT, G_MAXINT),
+ (TYPE_UINT, 0, G_MAXUINT),
+ (TYPE_LONG, G_MINLONG, G_MAXLONG),
+ (TYPE_ULONG, 0, G_MAXULONG),
+ (TYPE_INT64, minint64, maxint64),
+ (TYPE_UINT64, 0, maxuint64),
+ ]
+
+ for gtype, min, max in types:
+ # Normal, everything is alright
+ prop = gobject.property(type=gtype, minimum=min, maximum=max)
+ subtype = type('', (gobject.GObject,),
+ dict(prop=prop))
+ self.assertEqual(subtype.props.prop.minimum, min)
+ self.assertEqual(subtype.props.prop.maximum, max)
+
+ # Lower than minimum
+ self.assertRaises(TypeError,
+ gobject.property, type=gtype, minimum=min-1,
+ maximum=max)
+
+ # Higher than maximum
+ self.assertRaises(TypeError,
+ gobject.property, type=gtype, minimum=min,
+ maximum=max+1)