Provisionally implement -n as -a.
[cnetworkmanager.git] / networkmanager / dbusclient.py
blob159b8a9ed683493ceb96ffbcc6b5937206ef62ee
1 import dbus
2 import functools
3 from func import *
5 def object_path(o):
6 if isinstance(o, dbus.proxies.ProxyObject):
7 return o.object_path
8 # hope it is ok
9 return o
11 class DBusMio(dbus.proxies.ProxyObject):
12 """Multi-interface object
14 BUGS: 1st method call will block with introspection"""
16 def __init__(self, conn=None, bus_name=None, object_path=None, introspect=True, follow_name_owner_changes=False, **kwargs):
17 # FIXME common for this class, all classes?
18 self.__default_interface = kwargs.pop("default_interface", None)
19 super(DBusMio, self).__init__(conn, bus_name, object_path, introspect, follow_name_owner_changes, **kwargs)
21 def __getattr__(self, name):
22 # TODO cache
23 # iface = self._interface_cache.get(name)
24 # if iface == None:
25 iface = self.__default_interface
26 # _introspect_method_map comes from ProxyObject
27 # But it will be empty until the async introspection finishes
28 self._introspect_block() # FIXME makeit work with async methods
29 methods = self._introspect_method_map.keys()
30 for im in methods:
31 (i, m) = im.rsplit(".", 1)
32 if m == name:
33 iface = i
34 # print "METHOD %s INTERFACE %s" %(name, iface)
35 callable = super(DBusMio, self).__getattr__(name)
36 return functools.partial(callable, dbus_interface=iface)
38 # properties
39 def __getitem__(self, key):
40 iface = self.__default_interface # TODO cache
41 # TODO _introspect_property_map
42 pmi = dbus.Interface(self, "org.freedesktop.DBus.Properties")
43 return pmi.Get(iface, key)
45 def __setitem__(self, key, value):
46 iface = self.__default_interface # TODO cache
47 # TODO _introspect_property_map
48 pmi = dbus.Interface(self, "org.freedesktop.DBus.Properties")
49 return pmi.Set(iface, key, value)
51 def mklist(x):
52 if isinstance(x, list):
53 return x
54 elif isinstance(x, tuple):
55 return [i for i in x]
56 else:
57 return [x]
59 #class DBusClient(dbus.proxies.Interface):
60 class DBusClient(DBusMio):
61 _adaptors = {
62 "methods": {},
63 "signals": {},
64 "properties": {},
68 @classmethod
69 def _get_adaptor(cls, kind, name):
70 # print "GET", cls, kind, name
71 try:
72 return cls._adaptors[kind][name]
73 except KeyError:
74 scls = cls.__mro__[1] # can use "super"? how?
75 try:
76 return scls._get_adaptor(kind, name)
77 except AttributeError: # no _get_adaptor there
78 raise KeyError(":".join((kind, name)))
80 @classmethod
81 def _add_adaptor(cls, kind, name, adaptor):
82 # print "ADD", cls, kind, name, adaptor
83 adaptor = mklist(adaptor)
84 try:
85 args = adaptor[1]
86 except:
87 args = []
88 args = mklist(args)
89 try:
90 kwargs = adaptor[2]
91 except:
92 kwargs = {}
93 cls._adaptors[kind][name] = [adaptor[0], args, kwargs]
96 @classmethod
97 def _add_adaptors(cls, *args, **kwargs):
98 """
99 either
101 if not cls.__dict__.has_key("_adaptors"):
102 # do not use inherited attribute
103 cls._adaptors = {"methods":{}, "properties":{}, "signals":{}}
104 if len(args) != 0:
105 assert len(kwargs) == 0
106 assert len(args) == 1
107 kwargs = args[0]
109 for section in cls._adaptors.keys():
110 secsource = kwargs.pop(section, {})
111 for name, adaptor in secsource.iteritems():
112 cls._add_adaptor(section, name, adaptor)
113 assert len(kwargs) == 0
114 # print "AA", cls, cls._adaptors
116 def __getattr__(self, name):
117 "Wrap return values"
119 callable = super(DBusClient, self).__getattr__(name)
120 try:
121 adaptor = self._get_adaptor("methods", name)
122 return callable_universal_adaptor(callable, adaptor)
123 except KeyError:
124 return callable
126 # properties
127 def __getitem__(self, key):
128 value = super(DBusClient, self).__getitem__(key)
129 try:
130 adaptor = self._get_adaptor("properties", key)[0]
131 except KeyError, IndexError:
132 adaptor = identity
133 return adaptor(value)
135 def __setitem__(self, key, value):
136 try:
137 adaptor = self._get_adaptor("properties", key)[1][0]
138 except KeyError, IndexError:
139 adaptor = identity
140 value = adaptor(value)
141 return super(DBusClient, self).__setitem__(key, value)
144 # signals
145 # overrides a ProxyObject method
146 def _connect_to_signal(self, signame, handler, interface=None, **kwargs):
147 "Wrap signal handler, with arg adaptors"
149 # TODO also demarshal kwargs
150 adaptor = self._get_adaptor("signals", signame)
151 wrap_handler = callable_universal_adaptor(handler, adaptor)
152 return self.connect_to_signal(signame, wrap_handler, interface, **kwargs)
154 #class ObjectAddress:
155 # """An object path, optionally with a service/connection where to find it"""
156 # pass