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"""
31 def __init__(self
, conn
=None, bus_name
=None, object_path
=None, introspect
=True, follow_name_owner_changes
=False, **kwargs
):
34 kwargs may contain default_interface, to be used
35 if introspection does not provide it for a method/property
38 # FIXME common for this class, all classes?
39 self
.__default
_interface
= kwargs
.pop("default_interface", None)
40 super(DBusMio
, self
).__init
__(conn
, bus_name
, object_path
, introspect
, follow_name_owner_changes
, **kwargs
)
42 def __getattr__(self
, name
):
43 """Proxied DBus methods.
45 Uses introspection or default_interface to find the interface.
48 # iface = self._interface_cache.get(name)
50 iface
= self
.__default
_interface
51 # _introspect_method_map comes from ProxyObject
52 # But it will be empty until the async introspection finishes
53 self
._introspect
_block
() # FIXME makeit work with async methods
54 methods
= self
._introspect
_method
_map
.keys()
56 (i
, m
) = im
.rsplit(".", 1)
59 # print "METHOD %s INTERFACE %s" %(name, iface)
60 callable = super(DBusMio
, self
).__getattr
__(name
)
61 return functools
.partial(callable, dbus_interface
=iface
, byte_arrays
=True)
64 def __getitem__(self
, key
):
65 """Proxies DBus properties as dictionary items.
70 Uses default_interface (because dbus.proxies.ProxyObject
71 does not store introspection data for properties, boo. TODO.)
74 iface
= self
.__default
_interface
# TODO cache
75 # TODO _introspect_property_map
76 pmi
= dbus
.Interface(self
, "org.freedesktop.DBus.Properties")
77 return pmi
.Get(iface
, key
, byte_arrays
=True)
79 def __setitem__(self
, key
, value
):
80 """Proxies DBus properties as dictionary items.
85 Uses default_interface (because dbus.proxies.ProxyObject
86 does not store introspection data for properties, boo. TODO.)
89 iface
= self
.__default
_interface
# TODO cache
90 # TODO _introspect_property_map
91 pmi
= dbus
.Interface(self
, "org.freedesktop.DBus.Properties")
92 return pmi
.Set(iface
, key
, value
, byte_arrays
=True)
97 Tuples are made into lists, everything else a singleton list.
99 if isinstance(x
, list):
101 elif isinstance(x
, tuple):
102 return [i
for i
in x
]
106 class DBusClient(DBusMio
):
117 def _get_adaptor(cls
, kind
, name
):
118 # print "GET", cls, kind, name
120 a
= cls
._adaptors
[kind
][name
]
122 # TODO cache somehow?
125 scls
= cls
.__mro
__[1] # can use "super"? how?
127 return scls
._get
_adaptor
(kind
, name
)
128 except AttributeError: # no _get_adaptor there
129 raise KeyError(":".join((kind
, name
)))
132 def _add_adaptor(cls
, kind
, name
, adaptor
):
133 # print "ADD", cls, kind, name, adaptor
134 assert(isinstance(adaptor
, Adaptor
))
135 cls
._adaptors
[kind
][name
] = adaptor
138 def _add_adaptors_dict(cls
, andict
):
140 a nested dictionary of kind:name:adaptor,
142 if not cls
.__dict
__.has_key("_adaptors"):
143 # do not use inherited attribute
144 cls
._adaptors
= {"methods":{}, "properties":{}, "signals":{}}
146 for section
in cls
._adaptors
.keys():
147 secsource
= andict
.pop(section
, {})
148 for name
, adaptor
in secsource
.iteritems():
149 cls
._add
_adaptor
(section
, name
, adaptor
)
150 assert len(andict
) == 0
151 # print "AA", cls, cls._adaptors
154 def _add_adaptors(cls
, **kwargs
):
155 """kwargs: a *flat* dictionary of name: adaptor"""
156 adict
= {"methods":{}, "properties":{}, "signals":{}}
157 for k
, v
in kwargs
.iteritems():
160 cls
._add
_adaptors
_dict
(adict
)
162 def __getattr__(self
, name
):
165 callable = super(DBusClient
, self
).__getattr
__(name
)
167 adaptor
= self
._get
_adaptor
("methods", name
)
168 return adaptor
.adapt(callable)
173 def __getitem__(self
, key
):
174 value
= super(DBusClient
, self
).__getitem
__(key
)
176 adaptor
= self
._get
_adaptor
("properties", key
)
177 return adaptor
.adapt(value
)
181 def __setitem__(self
, key
, value
):
183 adaptor
= self
._get
_adaptor
("properties", key
)
184 value
= adaptor
.adapt_write(value
)
187 return super(DBusClient
, self
).__setitem
__(key
, value
)
191 # overrides a ProxyObject method
192 def _connect_to_signal(self
, signame
, handler
, interface
=None, **kwargs
):
193 "Wrap signal handler, with arg adaptors"
195 # TODO also demarshal kwargs
196 adaptor
= self
._get
_adaptor
("signals", signame
)
197 wrap_handler
= adaptor
.adapt(handler
)
198 return self
.connect_to_signal(signame
, wrap_handler
, interface
, **kwargs
)