[pygobject] Unify property getters
- From: Simon Feltman <sfeltman src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] Unify property getters
- Date: Mon, 18 Aug 2014 08:32:53 +0000 (UTC)
commit b0236d6fde137e0b2ecf7f5556ad5d53c22874bc
Author: Simon Feltman <sfeltman src gnome org>
Date: Fri Aug 8 20:55:28 2014 -0700
Unify property getters
Consolidate duplicate logic into pygi_get_property_value().
Use the function for GObject.get_property(), GObject.get_properties(),
and GObject.props.
Remove overridden expected failures in TestCGetPropertyMethod which
now work due to the unification.
https://bugzilla.gnome.org/show_bug.cgi?id=733893
https://bugzilla.gnome.org/show_bug.cgi?id=726999
gi/pygi-property.c | 85 ++++++++++++++++++++++++++++------------
gi/pygi-property.h | 4 ++
gi/pygobject.c | 97 ++++++---------------------------------------
tests/test_properties.py | 38 ------------------
4 files changed, 77 insertions(+), 147 deletions(-)
---
diff --git a/gi/pygi-property.c b/gi/pygi-property.c
index 65fc325..9a6e0ea 100644
--- a/gi/pygi-property.c
+++ b/gi/pygi-property.c
@@ -101,47 +101,82 @@ pygi_get_property_value (PyGObject *instance, GParamSpec *pspec)
{
GIPropertyInfo *property_info = NULL;
GValue value = { 0, };
- GIArgument arg = { 0, };
PyObject *py_value = NULL;
- GITypeInfo *type_info = NULL;
- gboolean free_array = FALSE;
- /* The owner_type of the pspec gives us the exact type that introduced the
- * property, even if it is a parent class of the instance in question. */
- property_info = _pygi_lookup_property_from_g_type (pspec->owner_type, pspec->name);
-
- if (property_info == NULL)
- goto out;
+ if (!(pspec->flags & G_PARAM_READABLE)) {
+ PyErr_Format(PyExc_TypeError, "property %s is not readable",
+ g_param_spec_get_name (pspec));
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS;
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
g_object_get_property (instance->obj, pspec->name, &value);
+ Py_END_ALLOW_THREADS;
- type_info = g_property_info_get_type (property_info);
- arg = _pygi_argument_from_g_value (&value, type_info);
-
- /* Arrays are special cased, see note in _pygi_argument_to_array. */
- if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY) {
- arg.v_pointer = _pygi_argument_to_array (&arg, NULL, NULL, NULL,
- type_info, &free_array);
+ /* Fast path which checks if this is a Python implemented Property.
+ * TODO: Make it even faster by calling the Python getter implementation
+ * directly. See: https://bugzilla.gnome.org/show_bug.cgi?id=723872 */
+ if (pyg_gtype_is_custom (pspec->owner_type)) {
+ py_value = pyg_param_gvalue_as_pyobject (&value, TRUE, pspec);
+ goto out;
}
- py_value = _pygi_argument_to_object (&arg, type_info, GI_TRANSFER_NOTHING);
+ /* Attempt to marshal through GI.
+ * The owner_type of the pspec gives us the exact type that introduced the
+ * property, even if it is a parent class of the instance in question. */
+ property_info = _pygi_lookup_property_from_g_type (pspec->owner_type, pspec->name);
+ if (property_info) {
+ GITypeInfo *type_info = NULL;
+ gboolean free_array = FALSE;
+ GIArgument arg = { 0, };
+
+ type_info = g_property_info_get_type (property_info);
+ arg = _pygi_argument_from_g_value (&value, type_info);
+
+ /* Arrays are special cased, see note in _pygi_argument_to_array. */
+ if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY) {
+ arg.v_pointer = _pygi_argument_to_array (&arg, NULL, NULL, NULL,
+ type_info, &free_array);
+ }
- if (free_array) {
- g_array_free (arg.v_pointer, FALSE);
- }
+ py_value = _pygi_argument_to_object (&arg, type_info, GI_TRANSFER_NOTHING);
- g_value_unset (&value);
+ if (free_array) {
+ g_array_free (arg.v_pointer, FALSE);
+ }
-out:
- if (property_info != NULL)
- g_base_info_unref (property_info);
- if (type_info != NULL)
g_base_info_unref (type_info);
+ g_base_info_unref (property_info);
+ }
+
+ /* Fallback to GValue marshalling. */
+ if (py_value == NULL) {
+ py_value = pyg_param_gvalue_as_pyobject (&value, TRUE, pspec);
+ }
+out:
+ g_value_unset (&value);
return py_value;
}
+PyObject *
+pygi_get_property_value_by_name (PyGObject *self, gchar *param_name)
+{
+ GParamSpec *pspec;
+
+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self->obj),
+ param_name);
+ if (!pspec) {
+ PyErr_Format (PyExc_TypeError,
+ "object of type `%s' does not have property `%s'",
+ g_type_name (G_OBJECT_TYPE (self->obj)), param_name);
+ return NULL;
+ }
+
+ return pygi_get_property_value (self, pspec);
+}
+
gint
pygi_set_property_value (PyGObject *instance,
GParamSpec *pspec,
diff --git a/gi/pygi-property.h b/gi/pygi-property.h
index 5678bc3..a08fa40 100644
--- a/gi/pygi-property.h
+++ b/gi/pygi-property.h
@@ -33,6 +33,10 @@ PyObject *
pygi_get_property_value (PyGObject *instance,
GParamSpec *pspec);
+PyObject *
+pygi_get_property_value_by_name (PyGObject *self,
+ gchar *param_name);
+
gint
pygi_set_property_value (PyGObject *instance,
GParamSpec *pspec,
diff --git a/gi/pygobject.c b/gi/pygobject.c
index d006c33..83e460a 100644
--- a/gi/pygobject.c
+++ b/gi/pygobject.c
@@ -248,15 +248,12 @@ build_parameter_list(GObjectClass *class)
return props_list;
}
-
static PyObject*
PyGProps_getattro(PyGProps *self, PyObject *attr)
{
char *attr_name, *property_name;
GObjectClass *class;
GParamSpec *pspec;
- GValue value = { 0, };
- PyObject *ret;
attr_name = PYGLIB_PyUnicode_AsString(attr);
if (!attr_name) {
@@ -279,36 +276,12 @@ PyGProps_getattro(PyGProps *self, PyObject *attr)
return PyObject_GenericGetAttr((PyObject *)self, attr);
}
- if (!(pspec->flags & G_PARAM_READABLE)) {
- PyErr_Format(PyExc_TypeError,
- "property '%s' is not readable", attr_name);
- return NULL;
- }
-
if (!self->pygobject) {
/* If we're doing it without an instance, return a GParamSpec */
return pyg_param_spec_new(pspec);
}
- if (!pyg_gtype_is_custom (pspec->owner_type)) {
- /* The GType is not implemented at the Python level: see if we can
- * read the property value via gi. */
- ret = pygi_get_property_value (self->pygobject, pspec);
- if (ret)
- return ret;
- }
-
- /* The GType is implemented in Python, or we failed to read it via gi:
- * do a straightforward read. */
- Py_BEGIN_ALLOW_THREADS;
- g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
- g_object_get_property(self->pygobject->obj, pspec->name, &value);
- Py_END_ALLOW_THREADS;
-
- ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec);
- g_value_unset(&value);
-
- return ret;
+ return pygi_get_property_value (self->pygobject, pspec);
}
static gboolean
@@ -1323,45 +1296,22 @@ pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs)
}
static PyObject *
-pygobject_get_property(PyGObject *self, PyObject *args)
+pygobject_get_property (PyGObject *self, PyObject *args)
{
gchar *param_name;
- GParamSpec *pspec;
- GValue value = { 0, };
- PyObject *ret;
- if (!PyArg_ParseTuple(args, "s:GObject.get_property", ¶m_name))
- return NULL;
+ if (!PyArg_ParseTuple (args, "s:GObject.get_property", ¶m_name)) {
+ return NULL;
+ }
CHECK_GOBJECT(self);
-
- pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj),
- param_name);
- if (!pspec) {
- PyErr_Format(PyExc_TypeError,
- "object of type `%s' does not have property `%s'",
- g_type_name(G_OBJECT_TYPE(self->obj)), param_name);
- return NULL;
- }
- if (!(pspec->flags & G_PARAM_READABLE)) {
- PyErr_Format(PyExc_TypeError, "property %s is not readable",
- param_name);
- return NULL;
- }
- g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
- Py_BEGIN_ALLOW_THREADS;
- g_object_get_property(self->obj, param_name, &value);
- Py_END_ALLOW_THREADS;
- ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec);
- g_value_unset(&value);
- return ret;
+ return pygi_get_property_value_by_name (self, param_name);
}
static PyObject *
pygobject_get_properties(PyGObject *self, PyObject *args)
{
- GObjectClass *class;
int len, i;
PyObject *tuple;
@@ -1371,48 +1321,27 @@ pygobject_get_properties(PyGObject *self, PyObject *args)
}
tuple = PyTuple_New(len);
- class = G_OBJECT_GET_CLASS(self->obj);
for (i = 0; i < len; i++) {
PyObject *py_property = PyTuple_GetItem(args, i);
gchar *property_name;
- GParamSpec *pspec;
- GValue value = { 0 };
PyObject *item;
if (!PYGLIB_PyUnicode_Check(py_property)) {
PyErr_SetString(PyExc_TypeError,
"Expected string argument for property.");
- return NULL;
+ goto fail;
}
property_name = PYGLIB_PyUnicode_AsString(py_property);
-
- pspec = g_object_class_find_property(class,
- property_name);
- if (!pspec) {
- PyErr_Format(PyExc_TypeError,
- "object of type `%s' does not have property `%s'",
- g_type_name(G_OBJECT_TYPE(self->obj)), property_name);
- return NULL;
- }
- if (!(pspec->flags & G_PARAM_READABLE)) {
- PyErr_Format(PyExc_TypeError, "property %s is not readable",
- property_name);
- return NULL;
- }
- g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
-
- Py_BEGIN_ALLOW_THREADS;
- g_object_get_property(self->obj, property_name, &value);
- Py_END_ALLOW_THREADS;
-
- item = pyg_value_as_pyobject(&value, TRUE);
- PyTuple_SetItem(tuple, i, item);
-
- g_value_unset(&value);
+ item = pygi_get_property_value_by_name (self, property_name);
+ PyTuple_SetItem (tuple, i, item);
}
return tuple;
+
+fail:
+ Py_DECREF (tuple);
+ return NULL;
}
static PyObject *
diff --git a/tests/test_properties.py b/tests/test_properties.py
index 9138361..999bff1 100644
--- a/tests/test_properties.py
+++ b/tests/test_properties.py
@@ -1280,44 +1280,6 @@ class TestCGetPropertyMethod(CPropertiesTestBase, unittest.TestCase):
def set_prop(self, obj, name, value):
obj.set_property(name, value)
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=733893
- def test_boxed_glist(self):
- # get_property() returns None or a GIMarshallingTestsBoxedGList
- CPropertiesTestBase.test_boxed_glist(self)
-
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=733893
- def test_annotated_glist(self):
- # get_property() returns None
- CPropertiesTestBase.test_annotated_glist(self)
-
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=733893
- def test_char(self):
- # get_property() returns a single element string which cannot represent
- # tested values for G_TYPE_CHAR
- CPropertiesTestBase.test_char(self)
-
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=733893
- def test_uchar(self):
- # get_property() returns a single element string which cannot represent
- # tested values for G_TYPE_UCHAR
- CPropertiesTestBase.test_uchar(self)
-
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=733893
- def test_setting_several_properties(self):
- # get_property() returns a single element string which cannot represent
- # tested values for G_TYPE_UCHAR
- CPropertiesTestBase.test_setting_several_properties(self)
-
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=733893
- def test_parent_class(self):
- # get_property() returns gpointer instead of a list
- CPropertiesTestBase.test_annotated_glist(self)
-
- @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=733893
- def test_hash_table(self):
- # get_property() returns gpointer instead of a dict
- CPropertiesTestBase.test_hash_table(self)
-
if __name__ == '__main__':
unittest.main()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]