From d06bfe528bb8d5e2ad2b4844c36fe43155739b3d Mon Sep 17 00:00:00 2001 From: "John (J5) Palmieri" Date: Tue, 12 Jul 2005 18:16:07 +0000 Subject: * python/dbus_bindings.pyx.in: removed * python/dbus_bindings.pyx: Added. - Fixed some memleaks (patch from Sean Meiners ) - Broke out the #include "dbus_h_wrapper.h" and put it in its own pxd file (Pyrex definition) - Broke out glib dependancies into its own pyx module * python/dbus_bindings.pdx: Added. - Defines C class Connection for exporting to other modules * python/dbus_glib_bindings.pyx: Added. - New module to handle lowlevel dbus-glib mainloop integration * python/glib.py: Added. - Registers the glib mainloop when you import this module * python/services.py: Removed (renamed to service.py) * python/service.py: Added. - (class Server): renamed Name * python/__init__.py: Bump ro version (0,41,0) - don't import the decorators or service module by default. These now reside in the dbus.service namespace * python/_dbus.py (Bus::__init__): Add code run the main loop setup function on creation * python/examples/example-service.py, python/examples/example-signal-emitter.py: update examples * python/examples/gconf-proxy-service.py, python/examples/gconf-proxy-service2.py: TODO fix these up * doc/TODO: Addition - Added a Python Bindings 1.0 section - added "Add match on args or match on details to match rules" --- python/service.py | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 python/service.py (limited to 'python/service.py') diff --git a/python/service.py b/python/service.py new file mode 100644 index 00000000..fc044af0 --- /dev/null +++ b/python/service.py @@ -0,0 +1,187 @@ +from decorators import * + +import dbus_bindings + +class Name: + """A base class for exporting your own Named Services across the Bus + + Just inherit from Name, providing the name of your service + (e.g. org.designfu.SampleService). + """ + def __init__(self, named_service, bus=None): + self._named_service = named_service + + if bus == None: + # Get the default bus + self._bus = 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 + ' \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 + ' \n' + + for interface in reflection_interface_signal_hash.keys(): + reflection_data = reflection_data + ' \n'%(interface) + + for func in reflection_interface_signal_hash[interface]: + reflection_data = reflection_data + cls._reflect_on_signal(func) + + reflection_data = reflection_data + ' \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 = ' \n'%(func.__name__) + for arg in func._dbus_args: + reflection_data = reflection_data + ' \n'%(arg) + + #reclaim some memory + func._dbus_args = None + reflection_data = reflection_data + ' \n' + + return reflection_data + + def _reflect_on_signal(cls, func): + reflection_data = ' \n'%(func.__name__) + for arg in func._dbus_args: + reflection_data = reflection_data + ' \n'%(arg) + #reclaim some memory + func._dbus_args = None + reflection_data = reflection_data + ' \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. These will appear as member functions of your + ServiceObject. + """ + __metaclass__ = ObjectType + + def __init__(self, object_path, name): + self._object_path = object_path + self._name = name + self._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 = '\n' + reflection_data = reflection_data + '\n'%(self._object_path) + reflection_data = reflection_data + self._dbus_reflection_data + reflection_data = reflection_data + '\n' + + return reflection_data + -- cgit