mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2025-12-26 02:50:08 +01:00
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.
187 lines
7.1 KiB
Python
187 lines
7.1 KiB
Python
|
|
import dbus_bindings
|
|
import _dbus
|
|
from exceptions import UnknownMethodException
|
|
from decorators import method
|
|
from decorators import signal
|
|
|
|
class BusName:
|
|
"""A base class for exporting your own Named Services across the Bus
|
|
"""
|
|
def __init__(self, named_service, bus=None):
|
|
self._named_service = named_service
|
|
|
|
if bus == None:
|
|
# Get the default bus
|
|
self._bus = _dbus.Bus()
|
|
else:
|
|
self._bus = bus
|
|
|
|
dbus_bindings.bus_request_name(self._bus.get_connection(), named_service)
|
|
|
|
def get_bus(self):
|
|
"""Get the Bus this Service is on"""
|
|
return self._bus
|
|
|
|
def get_name(self):
|
|
"""Get the name of this service"""
|
|
return self._named_service
|
|
|
|
def _dispatch_dbus_method_call(target_methods, self, argument_list, message):
|
|
"""Calls method_to_call using argument_list, but handles
|
|
exceptions, etc, and generates a reply to the DBus Message message
|
|
"""
|
|
try:
|
|
target_method = None
|
|
|
|
dbus_interface = message.get_interface()
|
|
if dbus_interface == None:
|
|
if target_methods:
|
|
target_method = target_methods[0]
|
|
else:
|
|
for dbus_method in target_methods:
|
|
if dbus_method._dbus_interface == dbus_interface:
|
|
target_method = dbus_method
|
|
break
|
|
|
|
if target_method:
|
|
retval = target_method(self, *argument_list)
|
|
else:
|
|
if not dbus_interface:
|
|
raise UnknownMethodException('%s is not a valid method'%(message.get_member()))
|
|
else:
|
|
raise UnknownMethodException('%s is not a valid method of interface %s'%(message.get_member(), dbus_interface))
|
|
except Exception, e:
|
|
if e.__module__ == '__main__':
|
|
# FIXME: is it right to use .__name__ here?
|
|
error_name = e.__class__.__name__
|
|
else:
|
|
error_name = e.__module__ + '.' + str(e.__class__.__name__)
|
|
error_contents = str(e)
|
|
reply = dbus_bindings.Error(message, error_name, error_contents)
|
|
else:
|
|
reply = dbus_bindings.MethodReturn(message)
|
|
if retval != None:
|
|
iter = reply.get_iter(append=True)
|
|
iter.append(retval)
|
|
|
|
return reply
|
|
|
|
class ObjectType(type):
|
|
def __init__(cls, name, bases, dct):
|
|
|
|
#generate out vtable
|
|
method_vtable = getattr(cls, '_dbus_method_vtable', {})
|
|
reflection_data = getattr(cls, '_dbus_reflection_data', "")
|
|
|
|
reflection_interface_method_hash = {}
|
|
reflection_interface_signal_hash = {}
|
|
|
|
for func in dct.values():
|
|
if getattr(func, '_dbus_is_method', False):
|
|
if method_vtable.has_key(func.__name__):
|
|
method_vtable[func.__name__].append(func)
|
|
else:
|
|
method_vtable[func.__name__] = [func]
|
|
|
|
#generate a hash of interfaces so we can group
|
|
#methods in the xml data
|
|
if reflection_interface_method_hash.has_key(func._dbus_interface):
|
|
reflection_interface_method_hash[func._dbus_interface].append(func)
|
|
else:
|
|
reflection_interface_method_hash[func._dbus_interface] = [func]
|
|
|
|
elif getattr(func, '_dbus_is_signal', False):
|
|
if reflection_interface_signal_hash.has_key(func._dbus_interface):
|
|
reflection_interface_signal_hash[func._dbus_interface].append(func)
|
|
else:
|
|
reflection_interface_signal_hash[func._dbus_interface] = [func]
|
|
|
|
for interface in reflection_interface_method_hash.keys():
|
|
reflection_data = reflection_data + ' <interface name="%s">\n'%(interface)
|
|
for func in reflection_interface_method_hash[interface]:
|
|
reflection_data = reflection_data + cls._reflect_on_method(func)
|
|
|
|
if reflection_interface_signal_hash.has_key(interface):
|
|
for func in reflection_interface_signal_hash[interface]:
|
|
reflection_data = reflection_data + cls._reflect_on_signal(func)
|
|
|
|
del reflection_interface_signal_hash[interface]
|
|
|
|
reflection_data = reflection_data + ' </interface>\n'
|
|
|
|
for interface in reflection_interface_signal_hash.keys():
|
|
reflection_data = reflection_data + ' <interface name="%s">\n'%(interface)
|
|
|
|
for func in reflection_interface_signal_hash[interface]:
|
|
reflection_data = reflection_data + cls._reflect_on_signal(func)
|
|
|
|
reflection_data = reflection_data + ' </interface>\n'
|
|
|
|
cls._dbus_reflection_data = reflection_data
|
|
cls._dbus_method_vtable = method_vtable
|
|
|
|
super(ObjectType, cls).__init__(name, bases, dct)
|
|
|
|
#reflections on methods and signals may look like similar code but may in fact
|
|
#diverge in the future so keep them seperate
|
|
def _reflect_on_method(cls, func):
|
|
reflection_data = ' <method name="%s">\n'%(func.__name__)
|
|
for arg in func._dbus_args:
|
|
reflection_data = reflection_data + ' <arg name="%s" type="v" />\n'%(arg)
|
|
|
|
#reclaim some memory
|
|
func._dbus_args = None
|
|
|
|
reflection_data = reflection_data + ' </method>\n'
|
|
|
|
return reflection_data
|
|
|
|
def _reflect_on_signal(cls, func):
|
|
reflection_data = ' <signal name="%s">\n'%(func.__name__)
|
|
for arg in func._dbus_args:
|
|
reflection_data = reflection_data + ' <arg name="%s" type="v" />\n'%(arg)
|
|
#reclaim some memory
|
|
func._dbus_args = None
|
|
reflection_data = reflection_data + ' </signal>\n'
|
|
|
|
return reflection_data
|
|
|
|
class Object:
|
|
"""A base class for exporting your own Objects across the Bus.
|
|
|
|
Just inherit from Object and provide a list of methods to share
|
|
across the Bus
|
|
"""
|
|
__metaclass__ = ObjectType
|
|
|
|
def __init__(self, bus_name, object_path):
|
|
self._object_path = object_path
|
|
self._name = bus_name
|
|
self._bus = bus_name.get_bus()
|
|
|
|
self._connection = self._bus.get_connection()
|
|
|
|
self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb)
|
|
|
|
def _unregister_cb(self, connection):
|
|
print ("Unregister")
|
|
|
|
def _message_cb(self, connection, message):
|
|
target_method_name = message.get_member()
|
|
target_methods = self._dbus_method_vtable[target_method_name]
|
|
args = message.get_args_list()
|
|
|
|
reply = _dispatch_dbus_method_call(target_methods, self, args, message)
|
|
|
|
self._connection.send(reply)
|
|
|
|
@method('org.freedesktop.DBus.Introspectable')
|
|
def Introspect(self):
|
|
reflection_data = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">\n'
|
|
reflection_data = reflection_data + '<node name="%s">\n'%(self._object_path)
|
|
reflection_data = reflection_data + self._dbus_reflection_data
|
|
reflection_data = reflection_data + '</node>\n'
|
|
|
|
return reflection_data
|
|
|