* python/dbus_bindings.pyx.in:
authorJohn (J5) Palmieri <johnp@redhat.com>
Sun, 1 May 2005 19:34:58 +0000 (19:34 +0000)
committerJohn (J5) Palmieri <johnp@redhat.com>
Sun, 1 May 2005 19:34:58 +0000 (19:34 +0000)
- added new type classes for hinting to the marashaler what type
to send over the wire
- added int16 and uint16 marshalers
- Fixed a bug in the type constants that caused int32 to go out
as uint16 over the wire
* python/dbus.py: split up into different files and renamed _dbus.py
* python/__init__.py, python/_util.py, python/decorators.py,
python/exceptions.py, python/proxies.py, python/services.py,
python/types.py: new files split off from dbus.py
* python/Makefile.am: Add new files, remove dbus.py and
install all python files to <python module dir>/dbus
* python/examples/*: Added #!/usr/bin/env python to the top of
every example.  Patch provided by Tatavarty Kalyan

19 files changed:
ChangeLog
python/Makefile.am
python/__init__.py [new file with mode: 0644]
python/_dbus.py [new file with mode: 0644]
python/_util.py [new file with mode: 0644]
python/dbus.py [deleted file]
python/dbus_bindings.pyx.in
python/decorators.py [new file with mode: 0644]
python/examples/example-service.py
python/examples/example-signal-emitter.py
python/examples/example-signal-recipient.py
python/examples/gconf-proxy-client.py
python/examples/gconf-proxy-service.py
python/examples/gconf-proxy-service2.py
python/examples/list-system-services.py
python/exceptions.py [new file with mode: 0644]
python/proxies.py [new file with mode: 0644]
python/services.py [new file with mode: 0644]
python/types.py [new file with mode: 0644]

index a47a2bb..8d04438 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2005-05-01  John (J5) Palmieri  <johnp@redhat.com>
+
+       * python/dbus_bindings.pyx.in: 
+       - added new type classes for hinting to the marashaler what type 
+       to send over the wire
+       - added int16 and uint16 marshalers
+       - Fixed a bug in the type constants that caused int32 to go out
+       as uint16 over the wire
+       * python/dbus.py: split up into different files and renamed _dbus.py
+       * python/__init__.py, python/_util.py, python/decorators.py, 
+       python/exceptions.py, python/proxies.py, python/services.py,
+       python/types.py: new files split off from dbus.py
+       * python/Makefile.am: Add new files, remove dbus.py and 
+       install all python files to <python module dir>/dbus
+       * python/examples/*: Added #!/usr/bin/env python to the top of
+       every example.  Patch provided by Tatavarty Kalyan
+
 2005-04-25  John (J5) Palmieri  <johnp@redhat.com>
 
        * NEWS: Update to 0.33
index 2519163..f7a5631 100644 (file)
@@ -2,10 +2,10 @@ SUBDIRS=examples
 
 INCLUDES=-I$(top_builddir) -I$(top_builddir)/dbus $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) $(PYTHON_INCLUDES)
 
-dbusdir = $(pythondir)
-dbus_PYTHON = dbus.py
+dbusdir = $(pythondir)/dbus
+dbus_PYTHON = __init__.py _dbus.py decorators.py exceptions.py services.py proxies.py _util.py types.py
 
-dbusbindingsdir = $(pythondir)
+dbusbindingsdir = $(pythondir)/dbus
 dbusbindings_LTLIBRARIES = dbus_bindings.la
 
 dbus_bindings_la_LDFLAGS = -module -avoid-version -fPIC -export-symbols-regex initdbus_bindings
diff --git a/python/__init__.py b/python/__init__.py
new file mode 100644 (file)
index 0000000..0fd1d80
--- /dev/null
@@ -0,0 +1,6 @@
+from _dbus import *
+from decorators import *
+from services import *
+from types import *
+
+version = (0, 40, 1)
diff --git a/python/_dbus.py b/python/_dbus.py
new file mode 100644 (file)
index 0000000..9dc3bd0
--- /dev/null
@@ -0,0 +1,219 @@
+
+"""Module for high-level communication over the FreeDesktop.org Bus (DBus)
+
+DBus allows you to share and access remote objects between processes
+running on the desktop, and also to access system services (such as
+the print spool).
+
+To use DBus, first get a Bus object, which provides a connection to one
+of a few standard dbus-daemon instances that might be running. From the
+Bus you can get a RemoteService. A service is provided by an application or
+process connected to the Bus, and represents a set of objects. Once you
+have a RemoteService you can get a RemoteObject that implements a specific interface
+(an interface is just a standard group of member functions). Then you can call
+those member functions directly.
+
+You can think of a complete method call as looking something like:
+
+Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org')
+
+This communicates over the SESSION Bus to the org.gnome.Evolution process to call the
+Forward method of the /org/gnome/Evolution/Inbox object (which provides the
+org.gnome.Evolution.MailFolder interface) with two string arguments.
+
+For example, the dbus-daemon itself provides a service and some objects:
+
+# Get a connection to the desktop-wide SESSION bus
+bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
+
+# Get the service provided by the dbus-daemon named org.freedesktop.DBus
+dbus_service = bus.get_service('org.freedesktop.DBus')
+
+# Get a reference to the desktop bus' standard object, denoted
+# by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus
+# implements the 'org.freedesktop.DBus' interface
+dbus_object = dbus_service.get_object('/org/freedesktop/DBus',
+                                       'org.freedesktop.DBus')
+
+# One of the member functions in the org.freedesktop.DBus interface
+# is ListServices(), which provides a list of all the other services
+# registered on this bus. Call it, and print the list.
+print(dbus_object.ListServices())
+"""
+
+import dbus_bindings
+from decorators import *
+from proxies import *
+from exceptions import *
+from services import *
+
+import re
+import inspect
+
+_threads_initialized = 0
+def init_gthreads ():
+    global _threads_initialized
+    if not _threads_initialized:
+        dbus_bindings.init_gthreads ()
+        _threads_initialized = 1
+
+class Bus:
+    """A connection to a DBus daemon.
+
+    One of three possible standard buses, the SESSION, SYSTEM,
+    or STARTER bus
+    """
+    TYPE_SESSION    = dbus_bindings.BUS_SESSION
+    TYPE_SYSTEM     = dbus_bindings.BUS_SYSTEM
+    TYPE_STARTER = dbus_bindings.BUS_STARTER
+
+    """bus_type=[Bus.TYPE_SESSION | Bus.TYPE_SYSTEM | Bus.TYPE_STARTER]
+    """
+
+    START_REPLY_SUCCESS = dbus_bindings.DBUS_START_REPLY_SUCCESS
+    START_REPLY_ALREADY_RUNNING = dbus_bindings.DBUS_START_REPLY_ALREADY_RUNNING 
+
+    def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True):
+        self._connection = dbus_bindings.bus_get(bus_type)
+
+        self._connection.add_filter(self._signal_func)
+        self._match_rule_to_receivers = { }
+        if (glib_mainloop):
+            self._connection.setup_with_g_main()
+
+    def get_connection(self):
+        return self._connection
+
+    def get_session():
+        """Static method that returns the session bus"""
+        return SessionBus()
+
+    get_session = staticmethod(get_session)
+
+    def get_system():
+        """Static method that returns the system bus"""
+        return SystemBus()
+
+    get_system = staticmethod(get_system)
+
+
+    def get_starter():
+        """Static method that returns the starter bus"""
+        return StarterBus()
+
+    get_starter = staticmethod(get_starter)
+
+
+    def get_object(self, named_service, object_path):
+        """Get a proxy object to call over the bus"""
+        return ProxyObject(self, named_service, object_path)
+
+    def add_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None):
+        match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path)
+
+        if (not self._match_rule_to_receivers.has_key(match_rule)):
+            self._match_rule_to_receivers[match_rule] = [handler_function]
+       else:
+           self._match_rule_to_receivers[match_rule].append(handler_function)
+
+        dbus_bindings.bus_add_match(self._connection, match_rule)
+
+    def remove_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None):
+        match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path)
+
+        if self._match_rule_to_receivers.has_key(match_rule):
+            if self._match_rule_to_receivers[match_rule].__contains__(handler_function):
+                self._match_rule_to_receivers[match_rule].pop(handler_function)
+                dbus_bindings.bus_remove_match(self._connection, match_rule)
+
+    def get_unix_user(self, named_service):
+        """Get the unix user for the given named_service on this Bus"""
+        return dbus_bindings.bus_get_unix_user(self._connection, named_service)
+
+    #TODO: Rethink match rules.  Right now matches have to be exact.
+    def _get_match_rule(self, signal_name, dbus_interface, named_service, path):
+        match_rule = "type='signal'"
+        if (dbus_interface):
+            match_rule = match_rule + ",interface='%s'" % (dbus_interface)
+        if (named_service):
+            if (named_service[0] != ':' and named_service != "org.freedesktop.DBus"):
+                bus_object = self.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
+                named_service = bus_object.GetNameOwner(named_service, dbus_interface='org.freedesktop.DBus')
+
+            match_rule = match_rule + ",sender='%s'" % (named_service)
+        if (path):
+            match_rule = match_rule + ",path='%s'" % (path)
+        if (signal_name):
+            match_rule = match_rule + ",member='%s'" % (signal_name)
+        return match_rule
+    
+    def _signal_func(self, connection, message):
+        if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL):
+            return dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED
+        
+        dbus_interface      = message.get_interface()
+        named_service  = message.get_sender()
+        path           = message.get_path()
+        signal_name    = message.get_member()
+
+        match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path)
+
+        if (self._match_rule_to_receivers.has_key(match_rule)):
+            receivers = self._match_rule_to_receivers[match_rule]
+
+            for receiver in receivers:
+               args = message.get_args_list()
+               receiver(*args)
+
+    def start_service_by_name(self, named_service):
+        return dbus_bindings.bus_start_service_by_name(self._connection, named_service)
+
+class SystemBus(Bus):
+    """The system-wide message bus
+    """
+    def __init__(self):
+        Bus.__init__(self, Bus.TYPE_SYSTEM)
+
+class SessionBus(Bus):
+    """The session (current login) message bus
+    """
+    def __init__(self):
+        Bus.__init__(self, Bus.TYPE_SESSION)
+
+class StarterBus(Bus):
+    """The bus that activated this process (if
+    this process was launched by DBus activation)
+    """
+    def __init__(self):
+        Bus.__init__(self, Bus.TYPE_STARTER)
+
+
+class Interface:
+    """An inteface into a remote object
+
+    An Interface can be used to wrap ProxyObjects
+    so that calls can be routed to their correct
+    dbus interface
+    """
+
+    def __init__(self, object, dbus_interface):
+        self._obj = object
+        self._dbus_interface = dbus_interface
+
+    def connect_to_signal(self, signal_name, handler_function, dbus_interface = None):
+        if not dbus_interface:
+           dbus_interface = self._dbus_interface
+               
+        self._obj.connect_to_signal(signal_name, handler_function, dbus_interface)
+
+    def __getattr__(self, member, **keywords):
+        if (keywords.has_key('dbus_interface')):
+            _dbus_interface = keywords['dbus_interface']
+        else:
+            _dbus_interface = self._dbus_interface
+
+        if member == '__call__':
+            return object.__call__
+        else:
+            return self._obj.__getattr__(member, dbus_interface=_dbus_interface)
+
diff --git a/python/_util.py b/python/_util.py
new file mode 100644 (file)
index 0000000..3f7061c
--- /dev/null
@@ -0,0 +1,12 @@
+import re
+
+def _validate_interface_or_name(value):
+    elements = value.split('.')
+    if len(elements) <= 1:
+        raise ValidationException("%s must contain at least two elements seperated by a period ('.')"%(value))
+
+    validate = re.compile('[A-Za-z][\w_]*')
+    for element in elements:
+        if not validate.match(element):
+            raise ValidationException("Element %s of %s has invalid characters"%(element ,value))
+
diff --git a/python/dbus.py b/python/dbus.py
deleted file mode 100644 (file)
index 6b1ea55..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-
-"""Module for high-level communication over the FreeDesktop.org Bus (DBus)
-
-DBus allows you to share and access remote objects between processes
-running on the desktop, and also to access system services (such as
-the print spool).
-
-To use DBus, first get a Bus object, which provides a connection to one
-of a few standard dbus-daemon instances that might be running. From the
-Bus you can get a RemoteService. A service is provided by an application or
-process connected to the Bus, and represents a set of objects. Once you
-have a RemoteService you can get a RemoteObject that implements a specific interface
-(an interface is just a standard group of member functions). Then you can call
-those member functions directly.
-
-You can think of a complete method call as looking something like:
-
-Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org')
-
-This communicates over the SESSION Bus to the org.gnome.Evolution process to call the
-Forward method of the /org/gnome/Evolution/Inbox object (which provides the
-org.gnome.Evolution.MailFolder interface) with two string arguments.
-
-For example, the dbus-daemon itself provides a service and some objects:
-
-# Get a connection to the desktop-wide SESSION bus
-bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
-
-# Get the service provided by the dbus-daemon named org.freedesktop.DBus
-dbus_service = bus.get_service('org.freedesktop.DBus')
-
-# Get a reference to the desktop bus' standard object, denoted
-# by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus
-# implements the 'org.freedesktop.DBus' interface
-dbus_object = dbus_service.get_object('/org/freedesktop/DBus',
-                                       'org.freedesktop.DBus')
-
-# One of the member functions in the org.freedesktop.DBus interface
-# is ListServices(), which provides a list of all the other services
-# registered on this bus. Call it, and print the list.
-print(dbus_object.ListServices())
-"""
-
-import dbus_bindings
-import re
-import inspect
-
-
-version = (0, 40, 0)
-
-_threads_initialized = 0
-def init_gthreads ():
-    global _threads_initialized
-    if not _threads_initialized:
-        dbus_bindings.init_gthreads ()
-        _threads_initialized = 1
-
-def _validate_interface_or_name(value):
-    elements = value.split('.')
-    if len(elements) <= 1:
-        raise ValidationException("%s must contain at least two elements seperated by a period ('.')"%(value))
-
-    validate = re.compile('[A-Za-z][\w_]*')
-    for element in elements:
-        if not validate.match(element):
-            raise ValidationException("Element %s of %s has invalid characters"%(element ,value))
-
-
-#Decorators
-def method(dbus_interface):
-    _validate_interface_or_name(dbus_interface)
-
-    def decorator(func):
-        func._dbus_is_method = True
-        func._dbus_interface = dbus_interface
-        func._dbus_args = inspect.getargspec(func)[0]
-        func._dbus_args.pop(0)
-        return func
-
-    return decorator
-
-def signal(dbus_interface):
-    _validate_interface_or_name(dbus_interface)
-    def decorator(func):
-        def emit_signal(self, *args, **keywords):
-           func(self, *args, **keywords)
-           message = dbus_bindings.Signal(self._object_path, dbus_interface, func.__name__)
-            iter = message.get_iter(True)
-            for arg in args:
-                iter.append(arg)
-        
-            self._connection.send(message)
-       
-        emit_signal._dbus_is_signal = True
-        emit_signal._dbus_interface = dbus_interface
-        emit_signal.__name__ = func.__name__
-        emit_signal._dbus_args = inspect.getargspec(func)[0]
-        emit_signal._dbus_args.pop(0)
-        return emit_signal
-
-    return decorator
-
-
-class Bus:
-    """A connection to a DBus daemon.
-
-    One of three possible standard buses, the SESSION, SYSTEM,
-    or STARTER bus
-    """
-    TYPE_SESSION    = dbus_bindings.BUS_SESSION
-    TYPE_SYSTEM     = dbus_bindings.BUS_SYSTEM
-    TYPE_STARTER = dbus_bindings.BUS_STARTER
-
-    """bus_type=[Bus.TYPE_SESSION | Bus.TYPE_SYSTEM | Bus.TYPE_STARTER]
-    """
-
-    START_REPLY_SUCCESS = dbus_bindings.DBUS_START_REPLY_SUCCESS
-    START_REPLY_ALREADY_RUNNING = dbus_bindings.DBUS_START_REPLY_ALREADY_RUNNING 
-
-    def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True):
-        self._connection = dbus_bindings.bus_get(bus_type)
-
-        self._connection.add_filter(self._signal_func)
-        self._match_rule_to_receivers = { }
-        if (glib_mainloop):
-            self._connection.setup_with_g_main()
-
-    def get_connection(self):
-        return self._connection
-
-    def get_session():
-        """Static method that returns the session bus"""
-        return SessionBus()
-
-    get_session = staticmethod(get_session)
-
-    def get_system():
-        """Static method that returns the system bus"""
-        return SystemBus()
-
-    get_system = staticmethod(get_system)
-
-
-    def get_starter():
-        """Static method that returns the starter bus"""
-        return StarterBus()
-
-    get_starter = staticmethod(get_starter)
-
-
-    def get_object(self, named_service, object_path):
-        """Get a proxy object to call over the bus"""
-        return ProxyObject(self, named_service, object_path)
-
-    def add_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None):
-        match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path)
-
-        if (not self._match_rule_to_receivers.has_key(match_rule)):
-            self._match_rule_to_receivers[match_rule] = [handler_function]
-       else:
-           self._match_rule_to_receivers[match_rule].append(handler_function)
-
-        dbus_bindings.bus_add_match(self._connection, match_rule)
-
-    def remove_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None):
-        match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path)
-
-        if self._match_rule_to_receivers.has_key(match_rule):
-            if self._match_rule_to_receivers[match_rule].__contains__(handler_function):
-                self._match_rule_to_receivers[match_rule].pop(handler_function)
-                dbus_bindings.bus_remove_match(self._connection, match_rule)
-
-    def get_unix_user(self, named_service):
-        """Get the unix user for the given named_service on this Bus"""
-        return dbus_bindings.bus_get_unix_user(self._connection, named_service)
-
-    def _get_match_rule(self, signal_name, dbus_interface, named_service, path):
-        match_rule = "type='signal'"
-        if (dbus_interface):
-            match_rule = match_rule + ",interface='%s'" % (dbus_interface)
-        if (named_service):
-            if (named_service[0] != ':' and named_service != "org.freedesktop.DBus"):
-                bus_object = self.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
-                named_service = bus_object.GetNameOwner(named_service, dbus_interface='org.freedesktop.DBus')
-
-            match_rule = match_rule + ",sender='%s'" % (named_service)
-        if (path):
-            match_rule = match_rule + ",path='%s'" % (path)
-        if (signal_name):
-            match_rule = match_rule + ",member='%s'" % (signal_name)
-        return match_rule
-    
-    def _signal_func(self, connection, message):
-        if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL):
-            return dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED
-        
-        dbus_interface      = message.get_interface()
-        named_service  = message.get_sender()
-        path           = message.get_path()
-        signal_name    = message.get_member()
-
-        match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path)
-
-        if (self._match_rule_to_receivers.has_key(match_rule)):
-            receivers = self._match_rule_to_receivers[match_rule]
-
-            for receiver in receivers:
-               args = message.get_args_list()
-               receiver(*args)
-
-    def start_service_by_name(self, named_service):
-        return dbus_bindings.bus_start_service_by_name(self._connection, named_service)
-
-class SystemBus(Bus):
-    """The system-wide message bus
-    """
-    def __init__(self):
-        Bus.__init__(self, Bus.TYPE_SYSTEM)
-
-class SessionBus(Bus):
-    """The session (current login) message bus
-    """
-    def __init__(self):
-        Bus.__init__(self, Bus.TYPE_SESSION)
-
-class StarterBus(Bus):
-    """The bus that activated this process (if
-    this process was launched by DBus activation)
-    """
-    def __init__(self):
-        Bus.__init__(self, Bus.TYPE_STARTER)
-
-
-class Interface:
-    """An inteface into a remote object
-
-    An Interface can be used to wrap ProxyObjects
-    so that calls can be routed to their correct
-    dbus interface
-    """
-
-    def __init__(self, object, dbus_interface):
-        self._obj = object
-        self._dbus_interface = dbus_interface
-
-    def connect_to_signal(self, signal_name, handler_function, dbus_interface = None):
-        if not dbus_interface:
-           dbus_interface = self._dbus_interface
-               
-        self._obj.connect_to_signal(signal_name, handler_function, dbus_interface)
-
-    def __getattr__(self, member, **keywords):
-        if (keywords.has_key('dbus_interface')):
-            _dbus_interface = keywords['dbus_interface']
-        else:
-            _dbus_interface = self._dbus_interface
-
-        if member == '__call__':
-            return object.__call__
-        else:
-            return self._obj.__getattr__(member, dbus_interface=_dbus_interface)
-
-class ProxyObject:
-    """A proxy to the remote Object.
-
-    A ProxyObject is provided by the Bus. ProxyObjects
-    have member functions, and can be called like normal Python objects.
-    """
-    def __init__(self, bus, named_service, object_path):
-        self._bus          = bus
-        self._named_service = named_service
-        self._object_path  = object_path
-
-    def connect_to_signal(self, signal_name, handler_function, dbus_interface=None):
-        self._bus.add_signal_receiver(handler_function,
-                                      signal_name=signal_name,
-                                      dbus_interface=dbus_interface,
-                                      named_service=self._named_service,
-                                      path=self._object_path)
-
-
-
-    def __getattr__(self, member, **keywords):
-        if member == '__call__':
-            return object.__call__
-        else:
-            iface = None
-            if (keywords.has_key('dbus_interface')):
-                iface = keywords['dbus_interface']
-
-            return ProxyMethod(self._bus.get_connection(),
-                                self._named_service,
-                                self._object_path, iface, member)
-
-
-class ProxyMethod:
-    """A proxy Method.
-
-    Typically a member of a ProxyObject. Calls to the
-    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):
-        self._connection   = connection
-        self._named_service = named_service
-        self._object_path  = object_path
-        self._method_name  = method_name
-        self._dbus_interface = dbus_interface
-
-    def __call__(self, *args, **keywords):
-        dbus_interface = self._dbus_interface
-        if (keywords.has_key('dbus_interface')):
-            dbus_interface = keywords['dbus_interface']
-
-        reply_handler = None
-        if (keywords.has_key('reply_handler')):
-            reply_handler = keywords['reply_handler']
-
-        error_handler = None
-        if (keywords.has_key('error_handler')):
-            error_handler = keywords['error_handler']            
-
-        if not(reply_handler and error_handler):
-            if reply_handler:
-                raise MissingErrorself, HandlerException()
-            elif error_handler:
-                raise MissingReplyHandlerException()
-
-        message = dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name)
-        message.set_destination(self._named_service)
-        
-        # Add the arguments to the function
-        iter = message.get_iter(True)
-        for arg in args:
-            iter.append(arg)
-
-        if reply_handler:
-            result = self._connection.send_with_reply_handlers(message, -1, reply_handler, error_handler)
-            args_tuple = (result,)
-        else:
-            reply_message = self._connection.send_with_reply_and_block(message, -1)
-            args_tuple = reply_message.get_args_list()
-            
-        if len(args_tuple) == 0:
-            return
-        elif len(args_tuple) == 1:
-            return args_tuple[0]
-        else:
-            return args_tuple
-
-class Service:
-    """A base class for exporting your own Services across the Bus
-
-    Just inherit from Service, 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 + '  <interface name="%s">\n'%(interface)
-            for func in reflection_interface_method_hash[interface]:
-                reflection_data = 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'
-            if reflection_interface_signal_hash.has_key(interface):
-                for func in reflection_interface_signal_hash[interface]:
-                    reflection_data = 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'
-
-                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 + '    <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'
-
-            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)
-
-
-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, service):
-        self._object_path = object_path
-        self._service = service
-        self._bus = service.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
-
-#Exceptions
-class MissingErrorHandlerException(Exception):
-    def __init__(self):
-        Exception.__init__(self)
-
-
-    def __str__(self):
-        return "error_handler not defined: if you define a reply_handler you must also define an error_handler"
-
-
-class MissingReplyHandlerException(Exception):
-    def __init__(self):
-        Exception.__init__(self)
-
-    def __str__(self):
-        return "reply_handler not defined: if you define an error_handler you must also define a reply_handler"
-
-class ValidationException(Exception):
-    def __init__(self, msg=''):
-        self.msg = msg
-        Exception.__init__(self)
-
-    def __str__(self):
-        return "Error validating string: %s" % self.msg
-
-class UnknownMethodException(Exception):
-    def __init__(self, msg=''):
-        self.msg = msg
-        Exception.__init__(self)
-
-    def __str__(self):
-        return "Unknown method: %s" % self.msg
-
-ObjectPath = dbus_bindings.ObjectPath
-ByteArray = dbus_bindings.ByteArray
-
index 0bfb994..8d41b1e 100644 (file)
@@ -82,6 +82,64 @@ class Signature(str):
     def __init__(self, value):
         str.__init__(value)
 
+class Byte(int):
+    def __init__(self, value):
+        int.__init__(value)
+
+class Boolean(int):
+    def __init__(self, value):
+        int.__init__(value)
+
+class Int16(int):
+    def __init__(self, value):
+        int.__init__(value)
+
+class UInt16(int):
+    def __init__(self, value):
+        if value < 0:
+            raise TypeError('Unsigned integers must not have a negitive value') 
+        int.__init__(value)
+
+class Int32(int):
+    def __init__(self, value):
+        int.__init__(value)
+
+class UInt32(long):
+    def __init__(self, value):
+        if value < 0:
+            raise TypeError('Unsigned integers must not have a negitive value') 
+        long.__init__(value)
+
+class Int64(long):
+    def __init__(self, value):
+        long.__init__(value)
+
+class UInt64(long):
+    def __init__(self, value):
+        if value < 0:
+            raise TypeError('Unsigned integers must not have a negitive value') 
+        long.__init__(value)
+
+class Double(float):
+    def __init__(self, value):
+        float.__init__(self, value)
+
+class String(str):
+    def __init__(self, value):
+        str.__init__(value)
+
+class Array(list):
+    def __init__(self, value):
+        list.__init__(value)
+
+class Struct(tuple):
+    def __init__(self, value):
+        tuple.__init__(value)
+
+class Dictionary(dict):
+    def __init__(self, value):
+        dict.__init__(value)
+
 #forward delcerations
 cdef class Connection
 cdef class Message
@@ -707,7 +765,7 @@ cdef class MessageIter:
             ret = TYPE_STRING
             ret = str(chr(ret))
         elif ptype == float:
-            ret = TYPE_FLOAT
+            ret = TYPE_DOUBLE
             ret = str(chr(ret))
         elif ptype == dict:
             dict_list = value.items()
@@ -734,6 +792,52 @@ cdef class MessageIter:
         elif isinstance(Signature):
             ret = TYPE_SIGNATURE
             ret = str(chr(ret))
+        elif isinstance(value, Byte):
+            ret = TYPE_BYTE
+            ret = str(chr(ret))
+        elif isinstance(value, Boolean):
+            ret = TYPE_BOOL
+            ret = str(chr(ret))
+        elif isinstance(value, Int16):
+            ret = TYPE_INT16
+            ret = str(chr(ret))
+        elif isinstance(value, UInt16):
+            ret = TYPE_UINT16
+            ret = str(chr(ret))
+        elif isinstance(value, Int32):
+            ret = TYPE_INT32
+            ret = str(chr(ret))
+        elif isinstance(value, UInt32):
+            ret = TYPE_UINT32
+            ret = str(chr(ret))
+        elif isinstance(value, Int64):
+            ret = TYPE_INT64
+            ret = str(chr(ret))
+        elif isinstance(value, UInt64):
+            ret = TYPE_UINT64
+            ret = str(chr(ret))
+        elif isinstance(value, Double):
+            ret = TYPE_DOUBLE
+            ret = str(chr(ret))
+        elif isinstance(value, String):
+            ret = TYPE_STRING
+            ret = str(chr(ret))
+        elif isinstance(value, Array):
+            ret = str(chr(TYPE_ARRAY))
+            ret = ret + self.python_value_to_dbus_sig(value[0], level)
+        elif isinstance(value, Struct):
+            ret = str(chr(STRUCT_BEGIN))
+            for item in value:
+                ret = ret + self.python_value_to_dbus_sig(item, level)
+            ret = ret + str(chr(STRUCT_END))
+        elif isinstance(value, Dictionary):
+            dict_list = value.items()
+            key, value = dict_list[0]
+
+            ret = str(chr(TYPE_ARRAY)) + str(chr(DICT_ENTRY_BEGIN))
+            ret = ret + self.python_value_to_dbus_sig(key, level)
+            ret = ret + self.python_value_to_dbus_sig(value, level)
+            ret = ret + str(chr(DICT_ENTRY_END))
         else:
             raise TypeError, "Argument of unknown type '%s'" % (ptype)
 
@@ -767,6 +871,32 @@ cdef class MessageIter:
             retval = self.append_array(value)
         elif isinstance(value, Signature):
             retval = self.append_signature(value)
+        elif isinstance(value, Byte):
+            retval = self.append_byte(value)
+        elif isinstance(value, Boolean):
+            retval = self.append_boolean(value)
+        elif isinstance(value, Int16):
+            retval = self.append_int16(value)
+        elif isinstance(value, UInt16):
+            retval = self.append_uint16(value)
+        elif isinstance(value, Int32):
+            retval = self.append_int32(value)
+        elif isinstance(value, UInt32):
+            retval = self.append_uint32(value)
+        elif isinstance(value, Int64):
+            retval = self.append_int64(value)
+        elif isinstance(value, UInt64):
+            retval = self.append_uint64(value)
+        elif isinstance(value, Double):
+            retval = self.append_double(value)
+        elif isinstance(value, String):
+            retval = self.append_string(value)
+        elif isinstance(value, Array):
+            retval = self.append_array(value)
+        elif isinstance(value, Struct):
+            retval = self.append_struct(value)
+        elif isinstance(value, Dictionary):
+            retval = self.append_dict(value)
         else:
             raise TypeError, "Argument of unknown type '%s'" % (value_type)
 
@@ -784,7 +914,17 @@ cdef class MessageIter:
 
         b = ord(value)
         return dbus_message_iter_append_basic(self.iter, TYPE_BYTE, <char *>&b)
-    
+
+    def append_int16(self, value):
+        cdef dbus_int32_t c_value
+        c_value = value
+        return dbus_message_iter_append_basic(self.iter, TYPE_INT16, <dbus_int32_t *>&c_value)
+
+    def append_uint16(self, value):
+        cdef dbus_uint32_t c_value
+        c_value = value
+        return dbus_message_iter_append_basic(self.iter, TYPE_UINT16, <dbus_uint32_t *>&c_value)
+
     def append_int32(self, value):
         cdef dbus_int32_t c_value
         c_value = value
@@ -952,7 +1092,7 @@ cdef class MessageIter:
 
 
 (MESSAGE_TYPE_INVALID, MESSAGE_TYPE_METHOD_CALL, MESSAGE_TYPE_METHOD_RETURN, MESSAGE_TYPE_ERROR, MESSAGE_TYPE_SIGNAL) = range(5)
-(TYPE_INVALID, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT16, TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_OBJECT_PATH, TYPE_SIGNATURE, TYPE_ARRAY, TYPE_STRUCT, STRUCT_BEGIN, STRUCT_END, TYPE_VARIANT, TYPE_DICT_ENTRY, DICT_ENTRY_BEGIN, DICT_ENTRY_END) = (0, ord('y'), ord('b'), ord('n'), ord('i'), ord('u'), ord('q'), ord('x'), ord('t'), ord('d'), ord('s'), ord('o'), ord('g'), ord('a'), ord('r'), ord('('), ord(')'), ord('v'), ord('e'), ord('{'), ord('}'))
+(TYPE_INVALID, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT16, TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_OBJECT_PATH, TYPE_SIGNATURE, TYPE_ARRAY, TYPE_STRUCT, STRUCT_BEGIN, STRUCT_END, TYPE_VARIANT, TYPE_DICT_ENTRY, DICT_ENTRY_BEGIN, DICT_ENTRY_END) = (0, ord('y'), ord('b'), ord('n'), ord('q'), ord('i'), ord('u'), ord('x'), ord('t'), ord('d'), ord('s'), ord('o'), ord('g'), ord('a'), ord('r'), ord('('), ord(')'), ord('v'), ord('e'), ord('{'), ord('}'))
 (HANDLER_RESULT_HANDLED, HANDLER_RESULT_NOT_YET_HANDLED, HANDLER_RESULT_NEED_MEMORY) = range(3)
     
 cdef class Message:
diff --git a/python/decorators.py b/python/decorators.py
new file mode 100644 (file)
index 0000000..4be6e20
--- /dev/null
@@ -0,0 +1,37 @@
+import _util 
+import inspect
+
+
+def method(dbus_interface):
+    _util._validate_interface_or_name(dbus_interface)
+
+    def decorator(func):
+        func._dbus_is_method = True
+        func._dbus_interface = dbus_interface
+        func._dbus_args = inspect.getargspec(func)[0]
+        func._dbus_args.pop(0)
+        return func
+
+    return decorator
+
+def signal(dbus_interface):
+    _util._validate_interface_or_name(dbus_interface)
+    def decorator(func):
+        def emit_signal(self, *args, **keywords):
+           func(self, *args, **keywords)
+           message = dbus_bindings.Signal(self._object_path, dbus_interface, func.__name__)
+            iter = message.get_iter(True)
+            for arg in args:
+                iter.append(arg)
+        
+            self._connection.send(message)
+       
+        emit_signal._dbus_is_signal = True
+        emit_signal._dbus_interface = dbus_interface
+        emit_signal.__name__ = func.__name__
+        emit_signal._dbus_args = inspect.getargspec(func)[0]
+        emit_signal._dbus_args.pop(0)
+        return emit_signal
+
+    return decorator
+
index 2209ff9..9963454 100644 (file)
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 import dbus
 
 import pygtk
index 2da65ec..1dbf6a6 100644 (file)
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 import gtk
 import dbus
 import gobject
index f9c6309..f763e3f 100644 (file)
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 import dbus
 
 gconf_key = "/desktop/gnome/file_views/icon_theme"
index 80f63f9..d428055 100644 (file)
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 """Lists services on the system bus
 """
 import dbus
diff --git a/python/exceptions.py b/python/exceptions.py
new file mode 100644 (file)
index 0000000..66b8c56
--- /dev/null
@@ -0,0 +1,32 @@
+class MissingErrorHandlerException(Exception):
+    def __init__(self):
+        Exception.__init__(self)
+
+
+    def __str__(self):
+        return "error_handler not defined: if you define a reply_handler you must also define an error_handler"
+
+
+class MissingReplyHandlerException(Exception):
+    def __init__(self):
+        Exception.__init__(self)
+
+    def __str__(self):
+        return "reply_handler not defined: if you define an error_handler you must also define a reply_handler"
+
+class ValidationException(Exception):
+    def __init__(self, msg=''):
+        self.msg = msg
+        Exception.__init__(self)
+
+    def __str__(self):
+        return "Error validating string: %s" % self.msg
+
+class UnknownMethodException(Exception):
+    def __init__(self, msg=''):
+        self.msg = msg
+        Exception.__init__(self)
+
+    def __str__(self):
+        return "Unknown method: %s" % self.msg
+
diff --git a/python/proxies.py b/python/proxies.py
new file mode 100644 (file)
index 0000000..0e00d64
--- /dev/null
@@ -0,0 +1,90 @@
+import dbus_bindings
+
+class ProxyObject:
+    """A proxy to the remote Object.
+
+    A ProxyObject is provided by the Bus. ProxyObjects
+    have member functions, and can be called like normal Python objects.
+    """
+    def __init__(self, bus, named_service, object_path):
+        self._bus          = bus
+        self._named_service = named_service
+        self._object_path  = object_path
+
+    def connect_to_signal(self, signal_name, handler_function, dbus_interface=None):
+        self._bus.add_signal_receiver(handler_function,
+                                      signal_name=signal_name,
+                                      dbus_interface=dbus_interface,
+                                      named_service=self._named_service,
+                                      path=self._object_path)
+
+
+
+    def __getattr__(self, member, **keywords):
+        if member == '__call__':
+            return object.__call__
+        else:
+            iface = None
+            if (keywords.has_key('dbus_interface')):
+                iface = keywords['dbus_interface']
+
+            return ProxyMethod(self._bus.get_connection(),
+                                self._named_service,
+                                self._object_path, iface, member)
+
+
+class ProxyMethod:
+    """A proxy Method.
+
+    Typically a member of a ProxyObject. Calls to the
+    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):
+        self._connection   = connection
+        self._named_service = named_service
+        self._object_path  = object_path
+        self._method_name  = method_name
+        self._dbus_interface = dbus_interface
+
+    def __call__(self, *args, **keywords):
+        dbus_interface = self._dbus_interface
+        if (keywords.has_key('dbus_interface')):
+            dbus_interface = keywords['dbus_interface']
+
+        reply_handler = None
+        if (keywords.has_key('reply_handler')):
+            reply_handler = keywords['reply_handler']
+
+        error_handler = None
+        if (keywords.has_key('error_handler')):
+            error_handler = keywords['error_handler']            
+
+        if not(reply_handler and error_handler):
+            if reply_handler:
+                raise MissingErrorself, HandlerException()
+            elif error_handler:
+                raise MissingReplyHandlerException()
+
+        message = dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name)
+        message.set_destination(self._named_service)
+        
+        # Add the arguments to the function
+        iter = message.get_iter(True)
+        for arg in args:
+            iter.append(arg)
+
+        if reply_handler:
+            result = self._connection.send_with_reply_handlers(message, -1, reply_handler, error_handler)
+            args_tuple = (result,)
+        else:
+            reply_message = self._connection.send_with_reply_and_block(message, -1)
+            args_tuple = reply_message.get_args_list()
+            
+        if len(args_tuple) == 0:
+            return
+        elif len(args_tuple) == 1:
+            return args_tuple[0]
+        else:
+            return args_tuple
+
diff --git a/python/services.py b/python/services.py
new file mode 100644 (file)
index 0000000..7e0b58b
--- /dev/null
@@ -0,0 +1,187 @@
+from decorators import *
+
+import dbus_bindings 
+
+class Service:
+    """A base class for exporting your own Services across the Bus
+
+    Just inherit from Service, 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 + '  <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. These will appear as member functions of your
+    ServiceObject.
+    """
+    __metaclass__ = ObjectType
+    
+    def __init__(self, object_path, service):
+        self._object_path = object_path
+        self._service = service
+        self._bus = service.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
+
diff --git a/python/types.py b/python/types.py
new file mode 100644 (file)
index 0000000..1a01d8e
--- /dev/null
@@ -0,0 +1,18 @@
+import dbus_bindings
+
+ObjectPath = dbus_bindings.ObjectPath
+ByteArray = dbus_bindings.ByteArray
+Signature = dbus_bindings.Signature
+Byte = dbus_bindings.Byte
+Boolean = dbus_bindings.Boolean
+Int16 = dbus_bindings.Int16
+UInt16 = dbus_bindings.UInt16
+Int32 = dbus_bindings.Int32
+UInt32 = dbus_bindings.UInt32
+Int64 = dbus_bindings.Int64
+UInt64 = dbus_bindings.UInt64
+Double = dbus_bindings.Double
+String = dbus_bindings.String
+Array = dbus_bindings.Array
+Struct = dbus_bindings.Struct
+Dictionary = dbus_bindings.Dictionary