dbus/python Makefile.am, 1.20, 1.21 dbus_bindings.pyx, 1.8, 1.9 exceptions.py, 1.2, 1.3 proxies.py, 1.8, 1.9 service.py, 1.6, 1.7

John Palmieri johnp at freedesktop.org
Wed Oct 5 13:43:49 PDT 2005


Update of /cvs/dbus/dbus/python
In directory gabe:/tmp/cvs-serv16663/python

Modified Files:
	Makefile.am dbus_bindings.pyx exceptions.py proxies.py 
	service.py 
Log Message:
* glib/dbus-gvalue.c (marshal_variant): call _dbus_gvalue_marshal
  instead of marshal basic so we can handle recursive types in a variant

* test/glib/test-dbus-glib.c: Add test for marshaling recurive types
  in variants

* test/glib/test-service-glib.c, test-service-glib.xml
  (my_object_echo_variant [EchoVariant],
  my_object_process_variant_of_array_of_ints123
  [ProcessVariantOfArrayOfInts123]):
  Add two test methods

* python/introspect_parser.py: New module for parsing introspect
  data.

* python/dbus_bindings.pyx:
  (various places): when throwing errors fix to use errormsg instead
  of message local variable because Pyrex can get confused with other
  message variables (initial patch by Robert McQueen
  <robert.mcqueen at collabora.co.uk>)
  (MessageIter::parse_signature_block): new method for getting the next
  block in a signiture.
  (MessageIter::append_strict): new method for appending values strictly
  using the passed in signature instead of guessing at the type
  (MessageItter:: append_dict, append_struct, append_array): use
  signatures to marshal children if the signature is available

* python/exceptions.py (IntrospectionParserException): new exception

* python/proxies.py (ProxyMethod::__call__): Marshal args with
  introspected signatures if available, else we fall back to the
  old way of doing things.
  (ProxyObject::_introspect_reply_handler ): parse introspection data

* python/service.py (ObjectType::_reflect_on_method): Properly
  terminate <method> if there are no args in the reflection data

* test/python/test-client.py: add tests for talking with the GLib
  test server.  This gives us better coverage for introspection since
  python to python will always generate arguments as variants.  It also
  allows us to test the robustness of the GLib bindings and interlanguage
  communications.



Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/python/Makefile.am,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- Makefile.am	1 Sep 2005 01:22:06 -0000	1.20
+++ Makefile.am	5 Oct 2005 20:43:46 -0000	1.21
@@ -6,7 +6,18 @@
 dbusmodule_PYTHON = dbus.pth
 
 dbusdir = $(pyexecdir)/dbus
-dbus_PYTHON = __init__.py _dbus.py decorators.py exceptions.py service.py proxies.py _util.py types.py matchrules.py glib.py
+dbus_PYTHON =		\
+	__init__.py 	\
+	_dbus.py 	\
+	decorators.py 	\
+	exceptions.py 	\
+	service.py 	\
+	proxies.py 	\
+	_util.py 	\
+	types.py 	\
+	matchrules.py 	\
+	glib.py 	\
+	introspect_parser.py
 
 dbusbindingsdir = $(pyexecdir)/dbus
 dbusbindings_LTLIBRARIES = dbus_bindings.la dbus_glib_bindings.la

Index: dbus_bindings.pyx
===================================================================
RCS file: /cvs/dbus/dbus/python/dbus_bindings.pyx,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- dbus_bindings.pyx	26 Sep 2005 22:12:17 -0000	1.8
+++ dbus_bindings.pyx	5 Oct 2005 20:43:46 -0000	1.9
@@ -261,9 +261,9 @@
             self.conn = dbus_connection_open(address,
                                          &error)
             if dbus_error_is_set(&error):
-                message = error.message
+                errormsg = error.message
                 dbus_error_free (&error)
-                raise DBusException, message
+                raise DBusException, errormsg
 
     def __dealloc__(self):
         if self.conn != NULL:
@@ -388,9 +388,9 @@
             &error)
 
         if dbus_error_is_set(&error):
-            message = error.message
+            errormsg = error.message
             dbus_error_free (&error)
-            raise DBusException, message
+            raise DBusException, errormsg
 
         if retval == NULL:
             raise AssertionError
@@ -936,8 +936,105 @@
 
         return ret
 
+    def parse_signature_block(self, signature):
+        remainder = ''
+        sig = ''
+        block_depth = 0
+        block_type = None
+       
+        for marker in range(0, len(signature)):
+            cur_sig = ord(signature[marker])
+
+            if cur_sig == TYPE_ARRAY:
+                pass
+            elif cur_sig == DICT_ENTRY_BEGIN or cur_sig == STRUCT_BEGIN:
+                if block_type == None:
+                    block_type = cur_sig
+
+                if block_type == cur_sig:
+                    block_depth = block_depth + 1
+
+            elif cur_sig == DICT_ENTRY_END:
+                if block_type == DICT_ENTRY_BEGIN:
+                    block_depth = block_depth - 1
+
+                if block_depth == 0:
+                    break
+
+            elif cur_sig == STRUCT_END:
+                if block_type == STRUCT_BEGIN:
+                    block_depth = block_depth - 1
+
+                if block_depth == 0:
+                    break
+
+            else:
+                if block_depth == 0:
+                    break
+        
+        marker = marker + 1
+        sig = signature[0:marker]
+        remainder = signature[marker:]
+        return (sig, remainder)
+  
+    def append_strict(self, value, sig):
+        
     
-    #FIXME: handle all the different types?
+        if sig == TYPE_INVALID or sig == None:
+            raise TypeError, 'Invalid arg type sent to append_strict'
+
+        sig_type = ord(sig[0])
+	    
+        if sig_type == TYPE_STRING:
+            retval = self.append(value)
+        elif sig_type == TYPE_INT16:
+            retval = self.append_int16(value)
+        elif sig_type == TYPE_UINT16:
+            retval = self.append_uint16(value)
+        elif sig_type == TYPE_INT32:
+            retval = self.append_int32(value)
+        elif sig_type == TYPE_UINT32:
+            retval = self.append_uint32(value)
+        elif sig_type == TYPE_INT64:
+            retval = self.append_int64(value)
+        elif sig_type == TYPE_UINT64:
+            retval = self.append_uint64(value)
+        elif sig_type == TYPE_DOUBLE:
+            retval = self.append_double(value)
+        elif sig_type == TYPE_BYTE:
+            retval = self.append_byte(value)
+        elif sig_type == TYPE_BOOLEAN:
+            retval = self.append_boolean(value)
+        elif sig_type == TYPE_SIGNATURE:
+            retval = self.append_signature(value)
+        elif sig_type == TYPE_ARRAY:
+            if len(sig) < 2:
+                raise TypeError, "Invalid array signature in append_strict.  Arrays must be followed by a type."
+
+            array_type = ord(sig[1])            
+            if array_type == DICT_ENTRY_BEGIN:
+                if ord(sig[-1]) != DICT_ENTRY_END:
+                    raise TypeError, "Invalid dict entry in append_strict.  No termination in signature %s."%(sig)
+
+                tmp_sig = sig[2:-1]
+                retval = self.append_dict(Dictionary(value, signature=tmp_sig))
+            else:
+                tmp_sig = sig[1:]
+                retval = self.append_array(Array(value, signature=tmp_sig))
+        elif sig_type == TYPE_OBJECT_PATH:
+            retval = self.append_object_path(value)
+        elif sig_type == TYPE_STRUCT:
+            tmp_sig = sig[1:-1]
+            retval = self.append_struct(value, signature = tmp_sig)
+        elif sig_type == TYPE_VARIANT:
+            retval = self.append_variant(Variant(value))
+        elif sig_type == DICT_ENTRY_BEGIN:
+            raise TypeError, "Signiture is invalid in append_strict. A dict entry must be part of an array." 
+        else:
+            raise TypeError, "Argument of unknown type '%s' in append_strict" % (sig)
+
+        return retval
+
     def append(self, value):
         value_type = type(value)
         if value_type == bool:
@@ -1102,15 +1199,29 @@
             dict_entry_iter = MessageIter(level)
             dict_entry_iter.__cinit__(&c_dict_entry_iter)
 
-            if not dict_entry_iter.append(key):
-                dbus_message_iter_close_container(dict_iter.iter, dict_entry_iter.iter)
-                dbus_message_iter_close_container(self.iter, dict_iter.iter)
-                return False
+            if signature:
+                (tmp_sig, remainder) = self.parse_signature_block(signature)
+                if not dict_entry_iter.append_strict(key, tmp_sig):
+                    dbus_message_iter_close_container(dict_iter.iter, dict_entry_iter.iter)
+                    dbus_message_iter_close_container(self.iter, dict_iter.iter)
+                    return False
+
+                (tmp_sig, remainder) = self.parse_signature_block(remainder)
+                if not dict_entry_iter.append_strict(value, tmp_sig):
+                    dbus_message_iter_close_container(dict_iter.iter, dict_entry_iter.iter)
+                    dbus_message_iter_close_container(self.iter, dict_iter.iter)
+                    return False
+
+            else:
+                if not dict_entry_iter.append(key):
+                    dbus_message_iter_close_container(dict_iter.iter, dict_entry_iter.iter)
+                    dbus_message_iter_close_container(self.iter, dict_iter.iter)
+                    return False
                 
-            if not dict_entry_iter.append(value):
-                dbus_message_iter_close_container(dict_iter.iter, dict_entry_iter.iter)
-                dbus_message_iter_close_container(self.iter, dict_iter.iter)
-                return False
+                if not dict_entry_iter.append(value):
+                    dbus_message_iter_close_container(dict_iter.iter, dict_entry_iter.iter)
+                    dbus_message_iter_close_container(self.iter, dict_iter.iter)
+                    return False
 
             dbus_message_iter_close_container(dict_iter.iter, dict_entry_iter.iter)
 
@@ -1118,7 +1229,7 @@
 
         return True
 
-    def append_struct(self, python_struct):
+    def append_struct(self, python_struct, signature = None):
         cdef DBusMessageIter c_struct_iter
         cdef MessageIter struct_iter
 
@@ -1126,11 +1237,23 @@
         dbus_message_iter_open_container(self.iter, TYPE_STRUCT, NULL, <DBusMessageIter *>&c_struct_iter)
         struct_iter = MessageIter(level)
         struct_iter.__cinit__(&c_struct_iter)
-        
+
+        remainder = signature
         for item in python_struct:
-            if not struct_iter.append(item):
-                dbus_message_iter_close_container(self.iter, struct_iter.iter)
-                return False
+            if signature:
+                (sig, remainder) = self.parse_signature_block(remainder)
+
+                if sig == '':
+                    dbus_message_iter_close_container(self.iter, struct_iter.iter)
+                    return False
+
+                if not struct_iter.append_strict(item, sig):
+                    dbus_message_iter_close_container(self.iter, struct_iter.iter)
+                    return False
+            else:
+                if not struct_iter.append(item):
+                    dbus_message_iter_close_container(self.iter, struct_iter.iter)
+                    return False
 
         dbus_message_iter_close_container(self.iter, struct_iter.iter)
 
@@ -1159,7 +1282,7 @@
 
         length = len(python_list)
         for item in python_list:
-            if not array_iter.append(item):
+            if not array_iter.append_strict(item, sig):
                 dbus_message_iter_close_container(self.iter, array_iter.iter)
                 return False
 
@@ -1485,9 +1608,9 @@
         self.server = dbus_server_listen(address,
                                          &error)
         if dbus_error_is_set(&error):
-            message = error.message
+            errormsg = error.message
             dbus_error_free (&error)
-            raise DBusException, message
+            raise DBusException, errormsg
 
     def disconnect(self):
         dbus_server_disconnect(self.server)
@@ -1526,9 +1649,9 @@
                               &error)
 
     if dbus_error_is_set(&error):
-        message = error.message
+        errormsg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg 
 
     conn = Connection()
     conn.__cinit__(None, connection)
@@ -1549,9 +1672,9 @@
     retval = dbus_bus_get_unix_user(conn, service_name, &error)
 
     if dbus_error_is_set(&error):
-        message = error.message
+        errormsg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg 
 
     return retval
 
@@ -1571,9 +1694,9 @@
     retval = dbus_bus_start_service_by_name(conn, service_name, flags, &results, &error)
 
     if dbus_error_is_set(&error):
-        message = error.message
+        errormsg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg
 
     return (retval, results) 
 
@@ -1587,9 +1710,9 @@
     retval = dbus_bus_register(conn,
                                &error)
     if dbus_error_is_set(&error):
-        message = error.message
+        msg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg 
 
     return retval
 
@@ -1608,9 +1731,9 @@
                                    flags,
                                    &error)
     if dbus_error_is_set(&error):
-        message = error.message
+        errormsg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg
         
     return retval
     
@@ -1625,9 +1748,9 @@
                                      service_name,
                                      &error)
     if dbus_error_is_set(&error):
-        message = error.message
+        errormsg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg
         
     return retval
 
@@ -1641,9 +1764,9 @@
     dbus_bus_add_match (conn, rule, &error)
     
     if dbus_error_is_set(&error):
-        message = error.message
+        errormsg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg
 
 def bus_remove_match(Connection connection, rule):
     cdef DBusError error
@@ -1655,7 +1778,7 @@
     dbus_bus_remove_match (conn, rule, &error)
     
     if dbus_error_is_set(&error):
-        message = error.message
+        errormsg = error.message
         dbus_error_free(&error)
-        raise DBusException, message
+        raise DBusException, errormsg
 

Index: exceptions.py
===================================================================
RCS file: /cvs/dbus/dbus/python/exceptions.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- exceptions.py	5 May 2005 18:01:45 -0000	1.2
+++ exceptions.py	5 Oct 2005 20:43:46 -0000	1.3
@@ -15,6 +15,10 @@
     def __init__(self, msg=''):
         DBusException.__init__(self, "Error validating string: %s"%msg)
 
+class IntrospectionParserException(DBusException):
+    def __init__(self, msg=''):
+            DBusException.__init__(self, "Error parsing introspect data: %s"%msg)
+
 class UnknownMethodException(DBusException):
     def __init__(self, msg=''):
         DBusException.__init__("Unknown method: %s"%msg)

Index: proxies.py
===================================================================
RCS file: /cvs/dbus/dbus/python/proxies.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- proxies.py	26 Aug 2005 03:09:59 -0000	1.8
+++ proxies.py	5 Oct 2005 20:43:46 -0000	1.9
@@ -1,5 +1,7 @@
 import dbus_bindings
-from exceptions import MissingReplyHandlerException, MissingErrorHandlerException
+import introspect_parser
+import sys
+from exceptions import MissingReplyHandlerException, MissingErrorHandlerException, IntrospectionParserException
 
 class DeferedMethod:
     """A DeferedMethod
@@ -19,12 +21,13 @@
     method produce messages that travel over the Bus and are routed
     to a specific named Service.
     """
-    def __init__(self, connection, named_service, object_path, dbus_interface, method_name):
+    def __init__(self, connection, named_service, object_path, dbus_interface, method_name, introspect_sig):
         self._connection   = connection
         self._named_service = named_service
         self._object_path  = object_path
         self._method_name  = method_name
         self._dbus_interface = dbus_interface
+        self._introspect_sig = introspect_sig
 
     def __call__(self, *args, **keywords):
         dbus_interface = self._dbus_interface
@@ -54,8 +57,14 @@
         
         # Add the arguments to the function
         iter = message.get_iter(True)
+
+	remainder = self._introspect_sig
         for arg in args:
-            iter.append(arg)
+            if self._introspect_sig:
+                (sig, remainder) = iter.parse_signature_block(remainder)
+                iter.append_strict(arg, sig)
+            else:
+                iter.append(arg)
 
         if reply_handler:
             result = self._connection.send_with_reply_handlers(message, timeout, reply_handler, error_handler)
@@ -87,16 +96,18 @@
 
     #TODO: default introspect to False right now because it is not done yet
     #      make sure to default to True later
-    def __init__(self, bus, named_service, object_path, introspect=False):
+    def __init__(self, bus, named_service, object_path, introspect=True):
         self._bus           = bus
         self._named_service = named_service
         self._object_path   = object_path
-        
+
         #PendingCall object for Introspect call
         self._pending_introspect = None
         #queue of async calls waiting on the Introspect to return 
         self._pending_introspect_queue = []
- 
+        #dictionary mapping method names to their input signatures
+        self._introspect_method_map = {}
+
         if not introspect:
             self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
         else:
@@ -118,23 +129,47 @@
         message.set_destination(self._named_service)
         
         result = self._bus.get_connection().send_with_reply_handlers(message, -1, 
-                                                                                           self._introspect_reply_handler, 
-                                                                                           self._introspect_error_handler)
+                                                                     self._introspect_reply_handler, 
+                                                                     self._introspect_error_handler)
         return result   
-            
+
+    
+    
+
     def _introspect_reply_handler(self, data):
-        self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE
+        try:
+            self._introspect_method_map = introspect_parser.process_introspection_data(data)
+        except IntrospectionParserException, e:
+            self._introspect_error_handler(e)
+            return
         
+        self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE
+
+        #TODO: we should actually call these even if introspection fails
         for call in self._pending_introspect_queue:
             (member, iface, args, keywords) = call
+
+            introspect_sig = None
+
+            tmp_iface = ''
+            if iface:
+                tmp_iface = iface + '.'
+                    
+            key = tmp_iface + '.' + member
+            if self._introspect_method_map.has_key (key):
+                introspect_sig = self._introspect_method_map[key]
+
+            
             call_object = self.ProxyMethodClass(self._bus.get_connection(),
-                                                                       self._named_service,
-                                                                       self._object_path, iface, member)
+                                                self._named_service,
+                                                self._object_path, iface, member,
+                                                introspect_sig)
                                                                        
             call_object(args, keywords)
 
     def _introspect_error_handler(self, error):
         self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
+        sys.stderr.write(str(error))
 
     def __getattr__(self, member, **keywords):
         if member == '__call__':
@@ -142,6 +177,8 @@
         elif member.startswith('__') and member.endswith('__'):
             raise AttributeError(member)
         else:
+            introspect_sig = None
+        
             iface = None
             if keywords.has_key('dbus_interface'):
                 iface = keywords['dbus_interface']
@@ -163,10 +200,20 @@
                     
                     ret = self.DeferedMethodClass()
                     return ret
-                   
+                    
+            if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_DONE:
+                tmp_iface = ''
+                if iface:
+                    tmp_iface = iface + '.'
+
+                key = tmp_iface + member
+                if self._introspect_method_map.has_key (key):
+                    introspect_sig = self._introspect_method_map[key]
+            
             ret = self.ProxyMethodClass(self._bus.get_connection(),
                                 self._named_service,
-                                self._object_path, iface, member)
+                                self._object_path, iface, member,
+                                introspect_sig)
             return ret
 
     def __repr__(self):

Index: service.py
===================================================================
RCS file: /cvs/dbus/dbus/python/service.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- service.py	16 Aug 2005 22:54:04 -0000	1.6
+++ service.py	5 Oct 2005 20:43:46 -0000	1.7
@@ -132,7 +132,8 @@
 
             #reclaim some memory
             func._dbus_args = None
-            reflection_data = reflection_data + '    </method>\n'
+	    
+        reflection_data = reflection_data + '    </method>\n'
 
         return reflection_data  
              



More information about the dbus-commit mailing list