[pygobject] Start implementing something equivalent to g_variant_new



commit 9714d765a34e246899f11b6792eea3aecce0b7ec
Author: Tomeu Vizoso <tomeu vizoso collabora co uk>
Date:   Mon Sep 13 16:36:47 2010 +0200

    Start implementing something equivalent to g_variant_new
    
    https://bugzilla.gnome.org/show_bug.cgi?id=629367

 gi/gimodule.c              |   20 +++++++
 gi/overrides/GLib.py       |  131 +++++++++++++++++++++++++++++++++++++++++--
 gi/pygi-foreign-gvariant.c |    2 +-
 tests/test_everything.py   |   16 -----
 tests/test_overrides.py    |   25 ++++++++
 5 files changed, 170 insertions(+), 24 deletions(-)
---
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 42b5f3c..89caf4e 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -272,6 +272,25 @@ _wrap_pyg_variant_new_tuple (PyObject *self, PyObject *args)
     return py_variant;
 }
 
+static PyObject *
+_wrap_pyg_variant_type_from_string (PyObject *self, PyObject *args)
+{
+    char *type_string;
+    PyObject *py_type;
+    PyObject *py_variant = NULL;
+
+    if (!PyArg_ParseTuple (args, "s:variant_type_from_string",
+                           &type_string)) {
+        return NULL;
+    }
+
+    py_type = _pygi_type_import_by_name ("GLib", "VariantType");
+
+    py_variant = _pygi_struct_new ( (PyTypeObject *) py_type, type_string, FALSE);
+
+    return py_variant;
+}
+
 static PyMethodDef _gi_functions[] = {
     { "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
     { "flags_add", (PyCFunction) _wrap_pyg_flags_add, METH_VARARGS | METH_KEYWORDS },
@@ -280,6 +299,7 @@ static PyMethodDef _gi_functions[] = {
     { "register_interface_info", (PyCFunction) _wrap_pyg_register_interface_info, METH_VARARGS },
     { "hook_up_vfunc_implementation", (PyCFunction) _wrap_pyg_hook_up_vfunc_implementation, METH_VARARGS },
     { "variant_new_tuple", (PyCFunction) _wrap_pyg_variant_new_tuple, METH_VARARGS },
+    { "variant_type_from_string", (PyCFunction) _wrap_pyg_variant_type_from_string, METH_VARARGS },
     { NULL, NULL, 0 }
 };
 
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index 7f163f9..78d8c35 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -1,8 +1,7 @@
 # -*- Mode: Python; py-indent-offset: 4 -*-
 # vim: tabstop=4 shiftwidth=4 expandtab
 #
-# Copyright (C) 2009 Johan Dahlin <johan gnome org>
-#               2010 Simon van der Linden <svdlinden src gnome org>
+# Copyright (C) 2010 Tomeu Vizoso <tomeu vizoso collabora co uk>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -19,17 +18,135 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 # USA
 
-import ctypes
-
-from ..types import override
 from ..importer import modules
-from .._gi import variant_new_tuple
+from .._gi import variant_new_tuple, variant_type_from_string
 
-GLib = modules['GLib']
+GLib = modules['GLib'].introspection_module
 
 __all__ = []
 
+class _VariantCreator(object):
+
+    _LEAF_CONSTRUCTORS = {
+        'b': GLib.Variant.new_boolean,
+        'y': GLib.Variant.new_byte,
+        'n': GLib.Variant.new_int16,
+        'q': GLib.Variant.new_uint16,
+        'i': GLib.Variant.new_int32,
+        'u': GLib.Variant.new_uint32,
+        'x': GLib.Variant.new_int64,
+        't': GLib.Variant.new_uint64,
+        'h': GLib.Variant.new_handle,
+        'd': GLib.Variant.new_double,
+        's': GLib.Variant.new_string,
+        'o': GLib.Variant.new_object_path,
+        'g': GLib.Variant.new_signature,
+        'v': GLib.Variant.new_variant,
+    }
+
+    def __init__(self, format_string, args):
+        self._format_string = format_string
+        self._args = args
+
+    def create(self):
+        if self._format_string_is_leaf():
+            return self._new_variant_leaf()
+
+        format_char = self._pop_format_char()
+        arg = self._pop_arg()
+
+        if format_char == 'm':
+            raise NotImplementedError()
+        else:
+            builder = GLib.VariantBuilder()
+            if format_char == '(':
+                builder.init(variant_type_from_string('r'))
+            elif format_char == '{':
+                builder.init(variant_type_from_string('{?*}'))
+            else:
+                raise NotImplementedError()
+            format_char = self._pop_format_char()
+            while format_char not in [')', '}']:
+                builder.add_value(Variant(format_char, arg))
+                format_char = self._pop_format_char()
+                if self._args:
+                    arg = self._pop_arg()
+            return builder.end()
+
+    def _format_string_is_leaf(self):
+        format_char = self._format_string[0]
+        return not format_char in ['m', '(', '{']
+
+    def _format_string_is_nnp(self):
+        format_char = self._format_string[0]
+        return format_char in ['a', 's', 'o', 'g', '^', '@', '*', '?', 'r',
+                               'v', '&']
+
+    def _new_variant_leaf(self):
+        if self._format_string_is_nnp():
+            return self._new_variant_nnp()
+
+        format_char = self._pop_format_char()
+        arg = self._pop_arg()
+
+        return _VariantCreator._LEAF_CONSTRUCTORS[format_char](arg)
+
+    def _new_variant_nnp(self):
+        format_char = self._pop_format_char()
+        arg = self._pop_arg()
+
+        if format_char == '&':
+            format_char = self._pop_format_char()
+
+        if format_char == 'a':
+            builder = GLib.VariantBuilder()
+            builder.init(variant_type_from_string('a*'))
+
+            element_format_string = self._pop_leaf_format_string()
+
+            if isinstance(arg, dict):
+                for element in arg.items():
+                    value = Variant(element_format_string, *element)
+                    builder.add_value(value)
+            else:
+                for element in arg:
+                    value = Variant(element_format_string, element)
+                    builder.add_value(value)
+            return builder.end()
+        elif format_char == '^':
+            raise NotImplementedError()
+        elif format_char == '@':
+            raise NotImplementedError()
+        elif format_char == '*':
+            raise NotImplementedError()
+        elif format_char == 'r':
+            raise NotImplementedError()
+        elif format_char == '?':
+            raise NotImplementedError()
+        else:
+            return _VariantCreator._LEAF_CONSTRUCTORS[format_char](arg)
+
+    def _pop_format_char(self):
+        format_char = self._format_string[0]
+        self._format_string = self._format_string[1:]
+        return format_char
+
+    def _pop_leaf_format_string(self):
+        # FIXME: This will break when the leaf is inside a tuple or dict entry
+        format_string = self._format_string
+        self._format_string = ''
+        return format_string
+
+    def _pop_arg(self):
+        arg = self._args[0]
+        self._args = self._args[1:]
+        return arg
+
 class Variant(GLib.Variant):
+    def __new__(cls, format_string, *args):
+        creator = _VariantCreator(format_string, args)
+        return creator.create()
+
     def __repr__(self):
         return '<GLib.Variant(%s)>' % getattr(self, 'print')(True)
 
diff --git a/gi/pygi-foreign-gvariant.c b/gi/pygi-foreign-gvariant.c
index 81afaaa..ac16395 100644
--- a/gi/pygi-foreign-gvariant.c
+++ b/gi/pygi-foreign-gvariant.c
@@ -48,7 +48,7 @@ g_variant_from_arg (GITypeInfo *type_info,
     GITypeInfo *interface_info = g_type_info_get_interface (type_info);
     PyObject *type = _pygi_type_import_by_gi_info (interface_info);
 
-    g_variant_ref (variant);
+    g_variant_ref_sink (variant);
 
     return _pygi_struct_new ( (PyTypeObject *) type, variant, FALSE);
 }
diff --git a/tests/test_everything.py b/tests/test_everything.py
index 171ef8d..5bb635c 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -48,22 +48,6 @@ class TestEverything(unittest.TestCase):
         self.assertEquals(surface.get_width(), 10)
         self.assertEquals(surface.get_height(), 10)
 
-    def test_gvariant(self):
-        variant = GLib.Variant.new_int32(42);
-        self.assertTrue(isinstance(variant, GLib.Variant))
-        self.assertEquals(variant.get_int32(), 42)
-
-        variant = GLib.Variant.new_strv(['mec', 'mac']);
-        self.assertTrue(isinstance(variant, GLib.Variant))
-        self.assertEquals(variant.get_strv(), ['mec', 'mac'])
-
-        variant = GLib.Variant.new_tuple(GLib.Variant.new_string('mec'), GLib.Variant.new_string('mac'))
-        self.assertTrue(isinstance(variant, GLib.Variant))
-        self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant))
-        self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant))
-        self.assertEquals(variant.get_child_value(0).get_string(), 'mec')
-        self.assertEquals(variant.get_child_value(1).get_string(), 'mac')
-
     def test_floating(self):
         Everything.TestFloating()
 
diff --git a/tests/test_overrides.py b/tests/test_overrides.py
index 8791f94..b1e3617 100644
--- a/tests/test_overrides.py
+++ b/tests/test_overrides.py
@@ -9,11 +9,36 @@ import unittest
 import sys
 sys.path.insert(0, "../")
 
+from gi.repository import GLib
 from gi.repository import GObject
 from gi.repository import Gdk
 from gi.repository import Gtk
 import gi.overrides as overrides
 
+class TestGLib(unittest.TestCase):
+
+    def test_gvariant(self):
+        variant = GLib.Variant('i', 42)
+        self.assertTrue(isinstance(variant, GLib.Variant))
+        self.assertEquals(variant.get_int32(), 42)
+
+        variant = GLib.Variant('(ss)', 'mec', 'mac')
+        self.assertTrue(isinstance(variant, GLib.Variant))
+        self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant))
+        self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant))
+        self.assertEquals(variant.get_child_value(0).get_string(), 'mec')
+        self.assertEquals(variant.get_child_value(1).get_string(), 'mac')
+
+        variant = GLib.Variant('a{si}', {'key1': 1, 'key2': 2})
+        self.assertTrue(isinstance(variant, GLib.Variant))
+        self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant))
+        self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant))
+        # Looks like order is not preserved
+        self.assertEquals(variant.get_child_value(1).get_child_value(0).get_string(), 'key1')
+        self.assertEquals(variant.get_child_value(1).get_child_value(1).get_int32(), 1)
+        self.assertEquals(variant.get_child_value(0).get_child_value(0).get_string(), 'key2')
+        self.assertEquals(variant.get_child_value(0).get_child_value(1).get_int32(), 2)
+
 class TestGdk(unittest.TestCase):
 
     def test_color(self):



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]