1 "Convenience wrappers around dbus-python"
6 # TODO rename to adaptors
7 from func
import Adaptor
, MethodAdaptor
, PropertyAdaptor
, SignalAdaptor
10 """Return the object path of o.
12 If o is a proxy object, use its appropriate attribute.
13 Otherwise assume that o already is an object path.
15 if isinstance(o
, dbus
.proxies
.ProxyObject
):
20 class DBusMio(dbus
.proxies
.ProxyObject
):
21 """Multi-interface object.
23 Will look into introspection data to find which interface
24 to use for a method or a property, obviating the need for
25 dbus.proxies.Interface.
26 If introspection is not available, provide default_interface
29 BUGS: 1st method call will block with introspection"""
35 def __init__(self
, conn
=None, bus_name
=None, object_path
=None, introspect
=True, follow_name_owner_changes
=False, **kwargs
):
38 kwargs may contain default_interface, to be used
39 if introspection does not provide it for a method/property
42 # FIXME common for this class, all classes?
43 self
.__default
_interface
= kwargs
.pop("default_interface", None)
44 # print "OP:", object_path
45 super(DBusMio
, self
).__init
__(conn
, bus_name
, object_path
, introspect
, follow_name_owner_changes
, **kwargs
)
47 def __getattr__(self
, name
):
48 """Proxied DBus methods.
50 Uses introspection or default_interface to find the interface.
53 # iface = self._interface_cache.get(name)
55 iface
= self
.__default
_interface
56 # _introspect_method_map comes from ProxyObject
57 # But it will be empty until the async introspection finishes
58 self
._introspect
_block
() # FIXME makeit work with async methods
59 methods
= self
._introspect
_method
_map
.keys()
61 (i
, m
) = im
.rsplit(".", 1)
64 # print "METHOD %s INTERFACE %s" %(name, iface)
65 callable = super(DBusMio
, self
).__getattr
__(name
)
66 return functools
.partial(callable, dbus_interface
=iface
, **DBusMio
.API_OPTIONS
)
69 def __getitem__(self
, key
):
70 """Proxies DBus properties as dictionary items.
75 Uses default_interface (because dbus.proxies.ProxyObject
76 does not store introspection data for properties, boo. TODO.)
79 iface
= self
.__default
_interface
# TODO cache
80 # TODO _introspect_property_map
81 pmi
= dbus
.Interface(self
, "org.freedesktop.DBus.Properties")
82 return pmi
.Get(iface
, key
, **DBusMio
.API_OPTIONS
)
84 def __setitem__(self
, key
, value
):
85 """Proxies DBus properties as dictionary items.
90 Uses default_interface (because dbus.proxies.ProxyObject
91 does not store introspection data for properties, boo. TODO.)
94 iface
= self
.__default
_interface
# TODO cache
95 # TODO _introspect_property_map
96 pmi
= dbus
.Interface(self
, "org.freedesktop.DBus.Properties")
97 return pmi
.Set(iface
, key
, value
, **DBusMio
.API_OPTIONS
)
102 Tuples are made into lists, everything else a singleton list.
104 if isinstance(x
, list):
106 elif isinstance(x
, tuple):
107 return [i
for i
in x
]
111 class DBusClient(DBusMio
):
122 def _get_adaptor(cls
, kind
, name
):
123 # print "GET", cls, kind, name
125 a
= cls
._adaptors
[kind
][name
]
127 # TODO cache somehow?
130 scls
= cls
.__mro
__[1] # can use "super"? how?
132 return scls
._get
_adaptor
(kind
, name
)
133 except AttributeError: # no _get_adaptor there
134 raise KeyError(":".join((kind
, name
)))
137 def _add_adaptor(cls
, kind
, name
, adaptor
):
138 # print "ADD", cls, kind, name, adaptor
139 assert(isinstance(adaptor
, Adaptor
))
140 cls
._adaptors
[kind
][name
] = adaptor
143 def _add_adaptors_dict(cls
, andict
):
145 a nested dictionary of kind:name:adaptor,
147 if not cls
.__dict
__.has_key("_adaptors"):
148 # do not use inherited attribute
149 cls
._adaptors
= {"methods":{}, "properties":{}, "signals":{}}
151 for section
in cls
._adaptors
.keys():
152 secsource
= andict
.pop(section
, {})
153 for name
, adaptor
in secsource
.iteritems():
154 cls
._add
_adaptor
(section
, name
, adaptor
)
155 assert len(andict
) == 0
156 # print "AA", cls, cls._adaptors
159 def _add_adaptors(cls
, **kwargs
):
160 """kwargs: a *flat* dictionary of name: adaptor"""
161 adict
= {"methods":{}, "properties":{}, "signals":{}}
162 for k
, v
in kwargs
.iteritems():
165 cls
._add
_adaptors
_dict
(adict
)
167 def __getattr__(self
, name
):
170 callable = super(DBusClient
, self
).__getattr
__(name
)
172 adaptor
= self
._get
_adaptor
("methods", name
)
173 return adaptor
.adapt(callable)
178 def __getitem__(self
, key
):
179 value
= super(DBusClient
, self
).__getitem
__(key
)
181 adaptor
= self
._get
_adaptor
("properties", key
)
182 return adaptor
.adapt(value
)
186 def __setitem__(self
, key
, value
):
188 adaptor
= self
._get
_adaptor
("properties", key
)
189 value
= adaptor
.adapt_write(value
)
192 return super(DBusClient
, self
).__setitem
__(key
, value
)
196 # overrides a ProxyObject method
197 def _connect_to_signal(self
, signame
, handler
, interface
=None, **kwargs
):
198 "Wrap signal handler, with arg adaptors"
200 # TODO also demarshal kwargs
201 adaptor
= self
._get
_adaptor
("signals", signame
)
202 wrap_handler
= adaptor
.adapt(handler
)
203 return self
.connect_to_signal(signame
, wrap_handler
, interface
, **kwargs
)