From 5e6fa32bf95a0d17fe5ce6a4ecdcae5dd3f967d5 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 1 Aug 2007 19:10:37 +0100 Subject: [PATCH] Add rel_path_keyword to @method (fd.o #11623) --- dbus/decorators.py | 18 +++++++++++++++++- dbus/service.py | 25 ++++++++++++++++++++++++- test/test-client.py | 23 +++++++++++++++++++---- test/test-service.py | 15 ++++++++------- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/dbus/decorators.py b/dbus/decorators.py index 908d055..00cf20d 100644 --- a/dbus/decorators.py +++ b/dbus/decorators.py @@ -35,7 +35,8 @@ def method(dbus_interface, in_signature=None, out_signature=None, async_callbacks=None, sender_keyword=None, path_keyword=None, destination_keyword=None, message_keyword=None, connection_keyword=None, - utf8_strings=False, byte_arrays=False): + utf8_strings=False, byte_arrays=False, + rel_path_keyword=None): """Factory for decorators used to mark methods of a `dbus.service.Object` to be exported on the D-Bus. @@ -86,8 +87,20 @@ def method(dbus_interface, in_signature=None, out_signature=None, case of "fallback paths" you'll usually want to use the object path in the method's implementation. + For fallback objects, `rel_path_keyword` (new in 0.82.2) is + likely to be more useful. + :Since: 0.80.0? + `rel_path_keyword` : str or None + If not None (the default), the decorated method will receive + the destination object path, relative to the path at which the + object was exported, as a keyword argument with this + name. For non-fallback objects the relative path will always be + '/'. + + :Since: 0.82.2 + `destination_keyword` : str or None If not None (the default), the decorated method will receive the destination bus name as a keyword argument with this name. @@ -150,6 +163,8 @@ def method(dbus_interface, in_signature=None, out_signature=None, if sender_keyword: args.remove(sender_keyword) + if rel_path_keyword: + args.remove(rel_path_keyword) if path_keyword: args.remove(path_keyword) if destination_keyword: @@ -174,6 +189,7 @@ def method(dbus_interface, in_signature=None, out_signature=None, func._dbus_out_signature = out_signature func._dbus_sender_keyword = sender_keyword func._dbus_path_keyword = path_keyword + func._dbus_rel_path_keyword = rel_path_keyword func._dbus_destination_keyword = destination_keyword func._dbus_message_keyword = message_keyword func._dbus_connection_keyword = connection_keyword diff --git a/dbus/service.py b/dbus/service.py index 8ffec3e..21165c5 100644 --- a/dbus/service.py +++ b/dbus/service.py @@ -33,7 +33,7 @@ except ImportError: import _dbus_bindings from dbus import SessionBus, Signature, Struct, validate_bus_name, \ - validate_object_path, INTROSPECTABLE_IFACE + validate_object_path, INTROSPECTABLE_IFACE, ObjectPath from dbus.decorators import method, signal from dbus.exceptions import DBusException, \ NameExistsException, \ @@ -653,6 +653,29 @@ class Object(Interface): keywords[parent_method._dbus_sender_keyword] = message.get_sender() if parent_method._dbus_path_keyword: keywords[parent_method._dbus_path_keyword] = message.get_path() + if parent_method._dbus_rel_path_keyword: + path = message.get_path() + rel_path = path + for exp in self._locations: + # pathological case: if we're exported in two places, + # one of which is a subtree of the other, then pick the + # subtree by preference (i.e. minimize the length of + # rel_path) + if exp[0] is connection: + if path == exp[1]: + rel_path = '/' + break + if exp[1] == '/': + # we already have rel_path == path at the beginning + continue + if path.startswith(exp[1] + '/'): + # yes we're in this exported subtree + suffix = path[len(exp[1]):] + if len(suffix) < len(rel_path): + rel_path = suffix + rel_path = ObjectPath(rel_path) + keywords[parent_method._dbus_rel_path_keyword] = rel_path + if parent_method._dbus_destination_keyword: keywords[parent_method._dbus_destination_keyword] = message.get_destination() if parent_method._dbus_message_keyword: diff --git a/test/test-client.py b/test/test-client.py index 050ed46..085c208 100755 --- a/test/test-client.py +++ b/test/test-client.py @@ -422,17 +422,32 @@ class TestDBusBindings(unittest.TestCase): def testFallbackObjectTrivial(self): obj = self.bus.get_object(NAME, OBJECT + '/Fallback') iface = dbus.Interface(obj, IFACE) - path, unique_name = iface.TestPathAndConnKeywords() + path, rel, unique_name = iface.TestPathAndConnKeywords() self.assertEquals(path, OBJECT + '/Fallback') - #self.assertEquals(rel, '/Badger/Mushroom') + self.assertEquals(rel, '/') + self.assertEquals(unique_name, obj.bus_name) + + def testFallbackObjectNested(self): + obj = self.bus.get_object(NAME, OBJECT + '/Fallback/Nested') + iface = dbus.Interface(obj, IFACE) + path, rel, unique_name = iface.TestPathAndConnKeywords() + self.assertEquals(path, OBJECT + '/Fallback/Nested') + self.assertEquals(rel, '/') + self.assertEquals(unique_name, obj.bus_name) + + obj = self.bus.get_object(NAME, OBJECT + '/Fallback/Nested/Badger/Mushroom') + iface = dbus.Interface(obj, IFACE) + path, rel, unique_name = iface.TestPathAndConnKeywords() + self.assertEquals(path, OBJECT + '/Fallback/Nested/Badger/Mushroom') + self.assertEquals(rel, '/Badger/Mushroom') self.assertEquals(unique_name, obj.bus_name) def testFallbackObject(self): obj = self.bus.get_object(NAME, OBJECT + '/Fallback/Badger/Mushroom') iface = dbus.Interface(obj, IFACE) - path, unique_name = iface.TestPathAndConnKeywords() + path, rel, unique_name = iface.TestPathAndConnKeywords() self.assertEquals(path, OBJECT + '/Fallback/Badger/Mushroom') - #self.assertEquals(rel, '/Badger/Mushroom') + self.assertEquals(rel, '/Badger/Mushroom') self.assertEquals(unique_name, obj.bus_name) def testTimeoutSync(self): diff --git a/test/test-service.py b/test/test-service.py index 4488eb1..10bebc5 100755 --- a/test/test-service.py +++ b/test/test-service.py @@ -74,20 +74,21 @@ class TestInterface(dbus.service.Interface): return False class Fallback(dbus.service.FallbackObject): - def __init__(self, bus_name, object_path=OBJECT + '/Fallback'): - super(Fallback, self).__init__(bus_name, object_path) + def __init__(self, conn, object_path=OBJECT + '/Fallback'): + super(Fallback, self).__init__(conn, object_path) + self.add_to_connection(conn, object_path + '/Nested') - @dbus.service.method(IFACE, in_signature='', out_signature='os', - path_keyword='path', # rel_path_keyword='rel', + @dbus.service.method(IFACE, in_signature='', out_signature='oos', + path_keyword='path', rel_path_keyword='rel', connection_keyword='conn') - def TestPathAndConnKeywords(self, path=None, conn=None): - return path, conn.get_unique_name() + def TestPathAndConnKeywords(self, path=None, conn=None, rel=None): + return path, rel, conn.get_unique_name() @dbus.service.signal(IFACE, signature='s', rel_path_keyword='rel_path') def SignalOneString(self, test, rel_path=None): logger.info('SignalOneString(%r) @ %r', test, rel_path) - # Deprecated + # Deprecated usage @dbus.service.signal(IFACE, signature='ss', path_keyword='path') def SignalTwoStrings(self, test, test2, path=None): logger.info('SignalTwoStrings(%r, %r) @ %r', test, test2, path) -- 2.11.4.GIT