summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gi/gimodule.c2
-rw-r--r--gi/overrides/GObject.py111
-rw-r--r--gi/pygi-basictype.c2
-rw-r--r--gi/pygi-value.c16
-rw-r--r--gi/pygi-value.h1
-rw-r--r--tests/test_gi.py5
-rw-r--r--tests/test_overrides_gobject.py197
7 files changed, 246 insertions, 88 deletions
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 7ff9b0eb..2be5e478 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -2291,6 +2291,8 @@ static PyMethodDef _gi_functions[] = {
(PyCFunction)pyg__install_metaclass, METH_O },
{ "_gvalue_get",
(PyCFunction)pyg__gvalue_get, METH_O },
+ { "_gvalue_get_type",
+ (PyCFunction)pyg__gvalue_get_type, METH_O },
{ "_gvalue_set",
(PyCFunction)pyg__gvalue_set, METH_VARARGS },
{ NULL, NULL, 0 }
diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py
index 938a19a8..81f214f0 100644
--- a/gi/overrides/GObject.py
+++ b/gi/overrides/GObject.py
@@ -209,69 +209,52 @@ class Value(GObjectModule.Value):
if py_value is not None:
self.set_value(py_value)
+ @property
+ def __g_type(self):
+ # XXX: This is the same as self.g_type, but the field marshalling
+ # code is currently very slow.
+ return _gi._gvalue_get_type(self)
+
def set_boxed(self, boxed):
+ if not self.__g_type.is_a(TYPE_BOXED):
+ warnings.warn('Calling set_boxed() on a non-boxed type deprecated',
+ PyGIDeprecationWarning, stacklevel=2)
# Workaround the introspection marshalers inability to know
# these methods should be marshaling boxed types. This is because
# the type information is stored on the GValue.
_gi._gvalue_set(self, boxed)
def get_boxed(self):
+ if not self.__g_type.is_a(TYPE_BOXED):
+ warnings.warn('Calling get_boxed() on a non-boxed type deprecated',
+ PyGIDeprecationWarning, stacklevel=2)
return _gi._gvalue_get(self)
def set_value(self, py_value):
- gtype = self.g_type
+ gtype = self.__g_type
- if gtype == _gi.TYPE_INVALID:
- raise TypeError("GObject.Value needs to be initialized first")
- elif gtype == TYPE_BOOLEAN:
- self.set_boolean(py_value)
- elif gtype == TYPE_CHAR:
+ if gtype == TYPE_CHAR:
self.set_char(py_value)
elif gtype == TYPE_UCHAR:
self.set_uchar(py_value)
- elif gtype == TYPE_INT:
- self.set_int(py_value)
- elif gtype == TYPE_UINT:
- self.set_uint(py_value)
- elif gtype == TYPE_LONG:
- self.set_long(py_value)
- elif gtype == TYPE_ULONG:
- self.set_ulong(py_value)
- elif gtype == TYPE_INT64:
- self.set_int64(py_value)
- elif gtype == TYPE_UINT64:
- self.set_uint64(py_value)
- elif gtype == TYPE_FLOAT:
- self.set_float(py_value)
- elif gtype == TYPE_DOUBLE:
- self.set_double(py_value)
elif gtype == TYPE_STRING:
- if isinstance(py_value, str):
- py_value = str(py_value)
- elif PY2:
- if isinstance(py_value, text_type):
- py_value = py_value.encode('UTF-8')
+ if not isinstance(py_value, str) and py_value is not None:
+ if PY2:
+ if isinstance(py_value, text_type):
+ py_value = py_value.encode('UTF-8')
+ else:
+ raise TypeError("Expected string or unicode but got %s%s" %
+ (py_value, type(py_value)))
else:
- raise TypeError("Expected string or unicode but got %s%s" %
+ raise TypeError("Expected string but got %s%s" %
(py_value, type(py_value)))
- else:
- raise TypeError("Expected string but got %s%s" %
- (py_value, type(py_value)))
- self.set_string(py_value)
+ _gi._gvalue_set(self, py_value)
elif gtype == TYPE_PARAM:
self.set_param(py_value)
- elif gtype == TYPE_PYOBJECT:
- self.set_boxed(py_value)
- elif gtype.is_a(TYPE_ENUM):
- self.set_enum(py_value)
elif gtype.is_a(TYPE_FLAGS):
self.set_flags(py_value)
- elif gtype.is_a(TYPE_BOXED):
- self.set_boxed(py_value)
elif gtype == TYPE_POINTER:
self.set_pointer(py_value)
- elif gtype.is_a(TYPE_OBJECT):
- self.set_object(py_value)
elif gtype == TYPE_GTYPE:
self.set_gtype(py_value)
elif gtype == TYPE_VARIANT:
@@ -279,62 +262,44 @@ class Value(GObjectModule.Value):
else:
# Fall back to _gvalue_set which handles some more cases
# like fundamentals for which a converter is registered
- _gi._gvalue_set(self, py_value)
+ try:
+ _gi._gvalue_set(self, py_value)
+ except TypeError:
+ if gtype == TYPE_INVALID:
+ raise TypeError("GObject.Value needs to be initialized first")
+ raise
def get_value(self):
- gtype = self.g_type
+ gtype = self.__g_type
- if gtype == TYPE_BOOLEAN:
- return self.get_boolean()
- elif gtype == TYPE_CHAR:
+ if gtype == TYPE_CHAR:
return self.get_char()
elif gtype == TYPE_UCHAR:
return self.get_uchar()
- elif gtype == TYPE_INT:
- return self.get_int()
- elif gtype == TYPE_UINT:
- return self.get_uint()
- elif gtype == TYPE_LONG:
- return self.get_long()
- elif gtype == TYPE_ULONG:
- return self.get_ulong()
- elif gtype == TYPE_INT64:
- return self.get_int64()
- elif gtype == TYPE_UINT64:
- return self.get_uint64()
- elif gtype == TYPE_FLOAT:
- return self.get_float()
- elif gtype == TYPE_DOUBLE:
- return self.get_double()
- elif gtype == TYPE_STRING:
- return self.get_string()
- elif gtype == TYPE_PYOBJECT:
- return self.get_boxed()
elif gtype == TYPE_PARAM:
return self.get_param()
elif gtype.is_a(TYPE_ENUM):
return self.get_enum()
elif gtype.is_a(TYPE_FLAGS):
return self.get_flags()
- elif gtype.is_a(TYPE_BOXED):
- return self.get_boxed()
elif gtype == TYPE_POINTER:
return self.get_pointer()
- elif gtype.is_a(TYPE_OBJECT):
- return self.get_object()
elif gtype == TYPE_GTYPE:
return self.get_gtype()
elif gtype == TYPE_VARIANT:
# get_variant was missing annotations
# https://gitlab.gnome.org/GNOME/glib/merge_requests/492
return self.dup_variant()
- elif gtype == _gi.TYPE_INVALID:
- return None
else:
- return _gi._gvalue_get(self)
+ try:
+ return _gi._gvalue_get(self)
+ except TypeError:
+ if gtype == TYPE_INVALID:
+ return None
+ raise
def __repr__(self):
- return '<Value (%s) %s>' % (self.g_type.name, self.get_value())
+ return '<Value (%s) %s>' % (self.__g_type.name, self.get_value())
Value = override(Value)
diff --git a/gi/pygi-basictype.c b/gi/pygi-basictype.c
index dafddf27..c0e5d1d0 100644
--- a/gi/pygi-basictype.c
+++ b/gi/pygi-basictype.c
@@ -1342,6 +1342,8 @@ arg_basic_type_setup_from_info (PyGIArgCache *arg_cache,
break;
case GI_TYPE_TAG_BOOLEAN:
+ arg_cache->allow_none = TRUE;
+ /* fall through */
case GI_TYPE_TAG_INT8:
case GI_TYPE_TAG_UINT8:
case GI_TYPE_TAG_INT16:
diff --git a/gi/pygi-value.c b/gi/pygi-value.c
index 93669345..8376231e 100644
--- a/gi/pygi-value.c
+++ b/gi/pygi-value.c
@@ -887,6 +887,22 @@ pyg__gvalue_get(PyObject *module, PyObject *pygvalue)
}
PyObject *
+pyg__gvalue_get_type(PyObject *module, PyObject *pygvalue)
+{
+ GValue *value;
+ GType type;
+
+ if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) {
+ PyErr_SetString (PyExc_TypeError, "Expected GValue argument.");
+ return NULL;
+ }
+
+ value = pyg_boxed_get (pygvalue, GValue);
+ type = G_VALUE_TYPE (value);
+ return pyg_type_wrapper_new (type);
+}
+
+PyObject *
pyg__gvalue_set(PyObject *module, PyObject *args)
{
PyObject *pygvalue;
diff --git a/gi/pygi-value.h b/gi/pygi-value.h
index 6450112d..5778a22c 100644
--- a/gi/pygi-value.h
+++ b/gi/pygi-value.h
@@ -45,6 +45,7 @@ PyObject *pygi_value_to_py_basic_type (const GValue *value,
PyObject *pyg__gvalue_get(PyObject *module, PyObject *pygvalue);
PyObject *pyg__gvalue_set(PyObject *module, PyObject *args);
+PyObject *pyg__gvalue_get_type(PyObject *module, PyObject *pygvalue);
G_END_DECLS
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 2b6f3c0a..61ad4f18 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -87,6 +87,11 @@ class TestBoolean(unittest.TestCase):
GIMarshallingTests.boolean_in_true(1)
GIMarshallingTests.boolean_in_false(0)
+ def test_boolean_in_other_types(self):
+ GIMarshallingTests.boolean_in_true([""])
+ GIMarshallingTests.boolean_in_false([])
+ GIMarshallingTests.boolean_in_false(None)
+
def test_boolean_out(self):
self.assertEqual(True, GIMarshallingTests.boolean_out_true())
self.assertEqual(False, GIMarshallingTests.boolean_out_false())
diff --git a/tests/test_overrides_gobject.py b/tests/test_overrides_gobject.py
index 37292dbb..7f20e81a 100644
--- a/tests/test_overrides_gobject.py
+++ b/tests/test_overrides_gobject.py
@@ -5,7 +5,7 @@ from __future__ import absolute_import
import pytest
from gi import PyGIDeprecationWarning
-from gi.repository import GObject, GLib
+from gi.repository import GObject, GLib, GIMarshallingTests
from gi._compat import PY2
from .helper import ignore_gi_deprecation_warnings
@@ -72,6 +72,12 @@ def test_value_invalid_type():
with pytest.raises(ValueError, match="Invalid GType"):
v.init(GObject.TYPE_INVALID)
+ with pytest.raises(
+ TypeError, match="GObject.Value needs to be initialized first"):
+ v.set_value(None)
+
+ assert v.get_value() is None
+
def test_value_long():
v = GObject.Value(GObject.TYPE_LONG)
@@ -107,6 +113,74 @@ def test_value_ulong():
with pytest.raises(OverflowError):
v.set_value(-1)
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+
+def test_value_float():
+ v = GObject.Value(GObject.TYPE_FLOAT)
+
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_float, v.set_float)]:
+
+ assert getter() == 0.0
+ setter(0)
+ assert getter() == 0
+
+ setter(GLib.MAXFLOAT)
+ assert getter() == GLib.MAXFLOAT
+
+ setter(GLib.MINFLOAT)
+ assert getter() == GLib.MINFLOAT
+
+ setter(-GLib.MAXFLOAT)
+ assert getter() == -GLib.MAXFLOAT
+
+ with pytest.raises(OverflowError):
+ setter(GLib.MAXFLOAT * 2)
+
+ with pytest.raises(OverflowError):
+ setter(-GLib.MAXFLOAT * 2)
+
+ with pytest.raises(TypeError):
+ setter(object())
+
+ with pytest.raises(TypeError):
+ setter(None)
+
+ with pytest.raises(TypeError):
+ setter(1j)
+
+ v.reset()
+
+
+def test_value_double():
+ v = GObject.Value(GObject.TYPE_DOUBLE)
+ assert v.get_value() == 0.0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXDOUBLE)
+ assert v.get_value() == GLib.MAXDOUBLE
+
+ v.set_value(GLib.MINDOUBLE)
+ assert v.get_value() == GLib.MINDOUBLE
+
+ v.set_value(-GLib.MAXDOUBLE)
+ assert v.get_value() == -GLib.MAXDOUBLE
+
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+ with pytest.raises(TypeError):
+ v.set_value(1j)
+
def test_value_uint64():
v = GObject.Value(GObject.TYPE_UINT64)
@@ -141,6 +215,12 @@ def test_value_int64():
with pytest.raises(OverflowError):
v.set_value(GLib.MININT64 - 1)
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
def test_value_pointer():
v = GObject.Value(GObject.TYPE_POINTER)
@@ -200,24 +280,29 @@ def test_value_param():
def test_value_string():
v = GObject.Value(GObject.TYPE_STRING)
- assert v.get_value() is None
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_string, v.set_string)]:
- if PY2:
- v.set_value(b"bar")
- assert v.get_value() == b"bar"
+ assert getter() is None
- v.set_value(u"öäü")
- assert v.get_value().decode("utf-8") == u"öäü"
- else:
- with pytest.raises(TypeError):
- v.set_value(b"bar")
+ if PY2:
+ setter(b"bar")
+ assert getter() == b"bar"
- v.set_value(u"quux")
- assert v.get_value() == u"quux"
- assert isinstance(v.get_value(), str)
+ setter(u"öäü")
+ assert getter().decode("utf-8") == u"öäü"
+ else:
+ with pytest.raises(TypeError):
+ setter(b"bar")
- with pytest.raises(TypeError):
- v.set_value(None)
+ setter(u"quux")
+ assert getter() == u"quux"
+ assert isinstance(getter(), str)
+
+ setter(None)
+ assert getter() is None
+
+ v.reset()
def test_value_pyobject():
@@ -266,3 +351,85 @@ def test_value_uchar():
with pytest.raises(OverflowError):
v.set_value(256)
+
+
+def test_value_set_boxed_deprecate_non_boxed():
+ v = GObject.Value(GObject.TYPE_POINTER)
+ with pytest.warns(PyGIDeprecationWarning):
+ v.get_boxed()
+ with pytest.warns(PyGIDeprecationWarning):
+ v.set_boxed(None)
+
+
+def test_value_boolean():
+ v = GObject.Value(GObject.TYPE_BOOLEAN)
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_boolean, v.set_boolean)]:
+ assert getter() is False
+ assert isinstance(getter(), bool)
+
+ setter(42)
+ assert getter() is True
+ setter(-1)
+ assert getter() is True
+ setter(0)
+ assert getter() is False
+
+ setter([])
+ assert getter() is False
+ setter(["foo"])
+ assert getter() is True
+
+ setter(None)
+ assert getter() is False
+ v.reset()
+
+
+def test_value_enum():
+ t = GIMarshallingTests.GEnum
+ v = GObject.Value(t)
+
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_enum, v.set_enum)]:
+ assert v.g_type == t.__gtype__
+ assert getter() == 0
+
+ setter(t.VALUE1)
+ assert getter() == t.VALUE1
+ # FIXME: we should try to return an enum type
+ assert type(getter()) is int
+
+ setter(2424242)
+ assert getter() == 2424242
+
+ setter(-1)
+ assert getter() == -1
+
+ with pytest.raises(TypeError):
+ setter(object())
+
+ with pytest.raises(TypeError):
+ setter(None)
+
+ v.reset()
+
+
+def test_value_object():
+ v = GObject.Value(GIMarshallingTests.Object)
+ assert v.g_type.is_a(GObject.TYPE_OBJECT)
+
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_object, v.set_object)]:
+ assert getter() is None
+
+ setter(None)
+ assert getter() is None
+
+ obj = GIMarshallingTests.Object()
+ setter(obj)
+ assert getter() is obj
+
+ with pytest.raises(TypeError):
+ setter(object())
+
+ v.reset()