1 "Convenience wrappers around dbus-python"
8 """Return the object path of o.
10 If o is a proxy object, use its appropriate attribute.
11 Otherwise assume that o already is an object path.
13 if isinstance(o
, dbus
.proxies
.ProxyObject
):
18 class DBusMio(dbus
.proxies
.ProxyObject
):
19 """Multi-interface object.
21 Will look into introspection data to find which interface
22 to use for a method or a property, obviating the need for
23 dbus.proxies.Interface.
24 If introspection is not available, provide default_interface
27 BUGS: 1st method call will block with introspection"""
29 def __init__(self
, conn
=None, bus_name
=None, object_path
=None, introspect
=True, follow_name_owner_changes
=False, **kwargs
):
32 kwargs may contain default_interface, to be used
33 if introspection does not provide it for a method/property
36 # FIXME common for this class, all classes?
37 self
.__default
_interface
= kwargs
.pop("default_interface", None)
38 super(DBusMio
, self
).__init
__(conn
, bus_name
, object_path
, introspect
, follow_name_owner_changes
, **kwargs
)
40 def __getattr__(self
, name
):
41 """Proxied DBus methods.
43 Uses introspection or default_interface to find the interface.
46 # iface = self._interface_cache.get(name)
48 iface
= self
.__default
_interface
49 # _introspect_method_map comes from ProxyObject
50 # But it will be empty until the async introspection finishes
51 self
._introspect
_block
() # FIXME makeit work with async methods
52 methods
= self
._introspect
_method
_map
.keys()
54 (i
, m
) = im
.rsplit(".", 1)
57 # print "METHOD %s INTERFACE %s" %(name, iface)
58 callable = super(DBusMio
, self
).__getattr
__(name
)
59 return functools
.partial(callable, dbus_interface
=iface
)
62 def __getitem__(self
, key
):
63 """Proxies DBus properties as dictionary items.
68 Uses default_interface (because dbus.proxies.ProxyObject
69 does not store introspection data for properties, boo. TODO.)
72 iface
= self
.__default
_interface
# TODO cache
73 # TODO _introspect_property_map
74 pmi
= dbus
.Interface(self
, "org.freedesktop.DBus.Properties")
75 return pmi
.Get(iface
, key
)
77 def __setitem__(self
, key
, value
):
78 """Proxies DBus properties as dictionary items.
83 Uses default_interface (because dbus.proxies.ProxyObject
84 does not store introspection data for properties, boo. TODO.)
87 iface
= self
.__default
_interface
# TODO cache
88 # TODO _introspect_property_map
89 pmi
= dbus
.Interface(self
, "org.freedesktop.DBus.Properties")
90 return pmi
.Set(iface
, key
, value
)
93 if isinstance(x
, list):
95 elif isinstance(x
, tuple):
100 #class DBusClient(dbus.proxies.Interface):
101 class DBusClient(DBusMio
):
110 def _get_adaptor(cls
, kind
, name
):
111 # print "GET", cls, kind, name
113 a
= cls
._adaptors
[kind
][name
]
115 # TODO cache somehow?
118 scls
= cls
.__mro
__[1] # can use "super"? how?
120 return scls
._get
_adaptor
(kind
, name
)
121 except AttributeError: # no _get_adaptor there
122 raise KeyError(":".join((kind
, name
)))
125 def _add_adaptor(cls
, kind
, name
, adaptor
):
126 # print "ADD", cls, kind, name, adaptor
127 adaptor
= mklist(adaptor
)
137 cls
._adaptors
[kind
][name
] = [adaptor
[0], args
, kwargs
]
141 def _add_adaptors(cls
, *args
, **kwargs
):
143 a nested dictionary of kind:name:adaptor,
144 either as kwargs (new) or as a single dict arg (old, newest)
146 if not cls
.__dict
__.has_key("_adaptors"):
147 # do not use inherited attribute
148 cls
._adaptors
= {"methods":{}, "properties":{}, "signals":{}}
150 assert len(kwargs
) == 0
151 assert len(args
) == 1
154 for section
in cls
._adaptors
.keys():
155 secsource
= kwargs
.pop(section
, {})
156 for name
, adaptor
in secsource
.iteritems():
157 cls
._add
_adaptor
(section
, name
, adaptor
)
158 assert len(kwargs
) == 0
159 # print "AA", cls, cls._adaptors
161 def __getattr__(self
, name
):
164 callable = super(DBusClient
, self
).__getattr
__(name
)
166 adaptor
= self
._get
_adaptor
("methods", name
)
167 return async_callable_universal_adaptor(callable, adaptor
)
172 def __getitem__(self
, key
):
173 value
= super(DBusClient
, self
).__getitem
__(key
)
175 adaptor
= self
._get
_adaptor
("properties", key
)[0]
176 except KeyError, IndexError:
178 return adaptor(value
)
180 def __setitem__(self
, key
, value
):
182 adaptor
= self
._get
_adaptor
("properties", key
)[1][0]
183 except KeyError, IndexError:
185 value
= adaptor(value
)
186 return super(DBusClient
, self
).__setitem
__(key
, value
)
190 # overrides a ProxyObject method
191 def _connect_to_signal(self
, signame
, handler
, interface
=None, **kwargs
):
192 "Wrap signal handler, with arg adaptors"
194 # TODO also demarshal kwargs
195 adaptor
= self
._get
_adaptor
("signals", signame
)
196 wrap_handler
= callable_universal_adaptor(handler
, adaptor
)
197 return self
.connect_to_signal(signame
, wrap_handler
, interface
, **kwargs
)
199 #class ObjectAddress:
200 # """An object path, optionally with a service/connection where to find it"""