From 4f47b6bc9d5a655bb0062226ba2258967e930b7e Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Tue, 28 Jul 2009 13:53:32 +0200 Subject: [PATCH] Adaptors cleaned up. more consistent registration fixed them to be per class, with superclass fallback fixed writable properties --- Makefile | 3 ++ cnetworkmanager | 1 + networkmanager/accesspoint.py | 17 +++---- networkmanager/dbusclient.py | 90 +++++++++++++++++++++++++------- networkmanager/device.py | 96 +++++++++++++++++------------------ networkmanager/func.py | 29 +++++++---- networkmanager/networkmanager.py | 32 ++++++++---- networkmanager/settings/connection.py | 8 +-- networkmanager/settings/settings.py | 17 +++---- 9 files changed, 183 insertions(+), 110 deletions(-) diff --git a/Makefile b/Makefile index 916f969..3fc9af4 100644 --- a/Makefile +++ b/Makefile @@ -47,4 +47,7 @@ dist: tar cvfz ${PACKAGE}-${VERSION}.tar.gz ${PACKAGE}-${VERSION} rm -rf ${PACKAGE}-${VERSION} +notes: + find -name \*.py | xargs grep -nH -E 'TODO|FIXME' + # bikemake: serves similar purpose as automake, but is much less resource hungry diff --git a/cnetworkmanager b/cnetworkmanager index 2d1c517..76a01bf 100755 --- a/cnetworkmanager +++ b/cnetworkmanager @@ -183,6 +183,7 @@ if options.demo: # TODO: generic signal (adapt cnm monitor), print name and args nm._connect_to_signal("StateChanged", print_state_changed) + nm["WirelessEnabled"] = "yes" devs = nm.GetDevices() print "ActiveConnections:", nm["ActiveConnections"] diff --git a/networkmanager/accesspoint.py b/networkmanager/accesspoint.py index 38f021b..7908040 100644 --- a/networkmanager/accesspoint.py +++ b/networkmanager/accesspoint.py @@ -55,14 +55,14 @@ class AccessPoint(DBusClient): def __init__(self, opath): super(AccessPoint, self).__init__(dbus.SystemBus(), self.SERVICE, opath, default_interface=self.IFACE) - DBusClient._add_adaptors({ - "signals": { - "PropertiesChanged": (identity, [identity], {}), +AccessPoint._add_adaptors( + signals = { + "PropertiesChanged": [void, [identity]], }, - "properties": { - "Flags": Flags, - "WpaFlags": Sec, - "RsnFlags": Sec, + properties = { + "Flags": AccessPoint.Flags, + "WpaFlags": AccessPoint.Sec, + "RsnFlags": AccessPoint.Sec, "Ssid": compose_ocers("".join, seq_adaptor(chr)), # byte array->str # "Frequency": identity, # "HwAddress": identity, @@ -70,5 +70,4 @@ class AccessPoint(DBusClient): # "MaxBitrate": identity, "Strength": int, }, - }) - + ) diff --git a/networkmanager/dbusclient.py b/networkmanager/dbusclient.py index b0107eb..159b8a9 100644 --- a/networkmanager/dbusclient.py +++ b/networkmanager/dbusclient.py @@ -45,9 +45,16 @@ class DBusMio(dbus.proxies.ProxyObject): def __setitem__(self, key, value): iface = self.__default_interface # TODO cache # TODO _introspect_property_map - pmi = dbus.Interface(self._obj, "org.freedesktop.DBus.Properties") + pmi = dbus.Interface(self, "org.freedesktop.DBus.Properties") return pmi.Set(iface, key, value) +def mklist(x): + if isinstance(x, list): + return x + elif isinstance(x, tuple): + return [i for i in x] + else: + return [x] #class DBusClient(dbus.proxies.Interface): class DBusClient(DBusMio): @@ -57,44 +64,91 @@ class DBusClient(DBusMio): "properties": {}, } - # FIXME all mashed together?! - @staticmethod - def _add_adaptors(adict): - target = DBusClient._adaptors - for section in target.keys(): - target[section].update(adict.get(section, {})) + + @classmethod + def _get_adaptor(cls, kind, name): +# print "GET", cls, kind, name + try: + return cls._adaptors[kind][name] + except KeyError: + scls = cls.__mro__[1] # can use "super"? how? + try: + return scls._get_adaptor(kind, name) + except AttributeError: # no _get_adaptor there + raise KeyError(":".join((kind, name))) + + @classmethod + def _add_adaptor(cls, kind, name, adaptor): +# print "ADD", cls, kind, name, adaptor + adaptor = mklist(adaptor) + try: + args = adaptor[1] + except: + args = [] + args = mklist(args) + try: + kwargs = adaptor[2] + except: + kwargs = {} + cls._adaptors[kind][name] = [adaptor[0], args, kwargs] + + + @classmethod + def _add_adaptors(cls, *args, **kwargs): + """ + either + """ + if not cls.__dict__.has_key("_adaptors"): + # do not use inherited attribute + cls._adaptors = {"methods":{}, "properties":{}, "signals":{}} + if len(args) != 0: + assert len(kwargs) == 0 + assert len(args) == 1 + kwargs = args[0] + + for section in cls._adaptors.keys(): + secsource = kwargs.pop(section, {}) + for name, adaptor in secsource.iteritems(): + cls._add_adaptor(section, name, adaptor) + assert len(kwargs) == 0 +# print "AA", cls, cls._adaptors def __getattr__(self, name): "Wrap return values" callable = super(DBusClient, self).__getattr__(name) try: - adaptor = self._adaptors["methods"][name] - except KeyError: - adaptor = identity - - if isinstance(adaptor, tuple): + adaptor = self._get_adaptor("methods", name) return callable_universal_adaptor(callable, adaptor) - return callable_adaptor(callable, adaptor) + except KeyError: + return callable # properties def __getitem__(self, key): value = super(DBusClient, self).__getitem__(key) try: - adaptor = self._adaptors["properties"][key] - except KeyError: + adaptor = self._get_adaptor("properties", key)[0] + except KeyError, IndexError: adaptor = identity return adaptor(value) -# def __setitem__(self, key,value): -# TODO + def __setitem__(self, key, value): + try: + adaptor = self._get_adaptor("properties", key)[1][0] + except KeyError, IndexError: + adaptor = identity + value = adaptor(value) + return super(DBusClient, self).__setitem__(key, value) + # signals + # overrides a ProxyObject method def _connect_to_signal(self, signame, handler, interface=None, **kwargs): "Wrap signal handler, with arg adaptors" # TODO also demarshal kwargs - wrap_handler = callable_universal_adaptor(handler, self._adaptors["signals"][signame]) + adaptor = self._get_adaptor("signals", signame) + wrap_handler = callable_universal_adaptor(handler, adaptor) return self.connect_to_signal(signame, wrap_handler, interface, **kwargs) #class ObjectAddress: diff --git a/networkmanager/device.py b/networkmanager/device.py index 5c0b09c..f5371b5 100644 --- a/networkmanager/device.py +++ b/networkmanager/device.py @@ -13,7 +13,7 @@ class Ip4Address: def __str__(self): ret = [] i32 = self.a - for i in (1, 2, 3, 4): + for i in range(4): ret.append("%d" % (i32 % 256)) i32 /= 256 return ".".join(ret) @@ -27,21 +27,21 @@ class Ip4Config(DBusClient): Routes - aau - (read) """ - DBusClient._add_adaptors({ - "properties": { - "Addresses": identity, #TODO - "Nameservers": seq_adaptor(Ip4Address), - #"Domains": identity, - "Routes": identity, #TODO - }, - }) - SERVICE = "org.freedesktop.NetworkManager" IFACE = "org.freedesktop.NetworkManager.Ip4Config" def __init__(self, opath): super(Ip4Config, self).__init__(dbus.SystemBus(), self.SERVICE, opath, default_interface = self.IFACE) +Ip4Config._add_adaptors( + properties = { + "Addresses": identity, #TODO + "Nameservers": seq_adaptor(Ip4Address), + #"Domains": identity, + "Routes": identity, #TODO + }, + ) + class Dhcp4Config(DBusClient): """ Signals: @@ -50,21 +50,21 @@ class Dhcp4Config(DBusClient): Options - a{sv} - (read) """ - DBusClient._add_adaptors({ - "signals": { - "PropertiesChanged": (identity, [identity], {}), - }, - "properties": { - "Options": identity, - }, - }) - SERVICE = "org.freedesktop.NetworkManager" IFACE = "org.freedesktop.NetworkManager.Dhcp4Config" def __init__(self, opath): super(Dhcp4Config, self).__init__(dbus.SystemBus(), self.SERVICE, opath, default_interface = self.IFACE) +Dhcp4Config._add_adaptors( + signals = { + "PropertiesChanged": [void, [identity]], + }, + properties = { + "Options": identity, + }, + ) + class Device(DBusClient): """networkmanager device @@ -162,21 +162,6 @@ class Device(DBusClient): """The matching settings["connection"]["type"]""" AbstractMethodCalled # no standard way for saying 'abstract' - DBusClient._add_adaptors({ - "signals": { - "StateChanged": (identity, [State, State, StateReason], {}) - }, - "properties": { - "Capabilities": Cap, - "Ip4Address": Ip4Address, - "State": State, - "Ip4Config": Ip4Config, - "Dhcp4Config": Dhcp4Config, - "Managed": bool, - "DeviceType": DeviceType, - }, - }) - SERVICE = "org.freedesktop.NetworkManager" IFACE = "org.freedesktop.NetworkManager.Device" @@ -210,6 +195,21 @@ class Device(DBusClient): # def __repr__(self): # return "DEVICE " + self.object_path +Device._add_adaptors( + signals = { + "StateChanged": [void, [Device.State, Device.State, Device.StateReason]], + }, + properties = { + "Capabilities": Device.Cap, + "Ip4Address": Ip4Address, + "State": Device.State, + "Ip4Config": Ip4Config, + "Dhcp4Config": Dhcp4Config, + "Managed": bool, + "DeviceType": Device.DeviceType, + }, + ) + # FIXME make them separate to enable plugins class Wired(Device): "TODO docstring, move them to the class" @@ -221,16 +221,16 @@ class Wired(Device): # FIXME but also use parent iface IFACE = "org.freedesktop.NetworkManager.Device" # FIXME how to get parent adaptors? - DBusClient._add_adaptors({ - "signals": { - "PropertiesChanged": (identity, [identity], {}) +Wired._add_adaptors( + signals = { + "PropertiesChanged": [void, [identity]], }, - "properties": { + properties = { # "HwAddress": identity, # "Speed": identity, "Carrier": bool, }, - }) + ) Device._register_constructor(Device.DeviceType.ETHERNET, Wired) @@ -250,20 +250,20 @@ class Wireless(Device): def _settings_type(cls): return "802-11-wireless" - DBusClient._add_adaptors({ - "methods": { +Wireless._add_adaptors( + methods = { "GetAccessPoints": seq_adaptor(AccessPoint), }, - "signals": { - "PropertiesChanged": (identity, [identity], {}), - "AccessPointAdded": (identity, [AccessPoint], {}), - "AccessPointRemoved": (identity, [AccessPoint], {}), + signals = { + "PropertiesChanged": [void, [identity]], + "AccessPointAdded": [void, [AccessPoint]], + "AccessPointRemoved": [void, [AccessPoint]], }, - "properties": { + properties = { "Mode": Mode, "ActiveAccessPoint": AccessPoint, - "WirelessCapabilities": DeviceCap, + "WirelessCapabilities": Wireless.DeviceCap, }, - }) + ) Device._register_constructor(Device.DeviceType.WIRELESS, Wireless) diff --git a/networkmanager/func.py b/networkmanager/func.py index 3b68d14..a2f621f 100644 --- a/networkmanager/func.py +++ b/networkmanager/func.py @@ -1,4 +1,3 @@ -# TODO! understand functools # FIXME do we need to ensure that objects get unique proxies? how? # TODO object conversions should be more automatic @@ -7,24 +6,32 @@ def seq_adaptor(item_adaptor): return lambda seq: map(item_adaptor, seq) -def callable_adaptor(callable, value_adaptor): - return lambda *args, **kwargs: value_adaptor(callable(*args, **kwargs)) +# glossary: +# ocer: object converter. a function taking one object and returning on object +""" +raw value, cooked value (RV, CV) -def callable_args_demarshaller(callable, demarshaller): - l = lambda *args, **kwargs: callable(* map(demarshaller, args), **kwargs) +basic operations: +wrap(RV), unwrap(CV) like marshall(CV), demarshall(RV) +proxy: combines both directions +censor, censorer: knows how to both unwrap and wrap +(but does not do both at a time, unlike the real one) +translator + +pretty, ugly -> masker +""" -# glossary: -# ocer: object converter. a function taking one object and returning on object def convert_seq(seq, ocers): """Convert seq's items using respective ocer from ocers. seq and ocers must have same length.""" - assert(len(seq) == len(ocers)) # FIXME exception instead -# print "SEQ:", seq -# print "OCERS:", ocers + if len(seq) != len(ocers): + print "SEQ:", seq + print "OCERS:", ocers + raise return [ocer(obj) for obj, ocer in zip(seq, ocers)] def convert_dict(dict, ocer_dict): @@ -61,3 +68,5 @@ def compose_ocers(outer, inner): def identity(x): return x +def void(x): + return None diff --git a/networkmanager/networkmanager.py b/networkmanager/networkmanager.py index a1c5aa7..4aa6f52 100644 --- a/networkmanager/networkmanager.py +++ b/networkmanager/networkmanager.py @@ -10,6 +10,16 @@ from func import * SYSTEM_SERVICE = "org.freedesktop.NetworkManagerSystemSettings" USER_SERVICE = "org.freedesktop.NetworkManagerUserSettings" +ActiveConnection = identity # TODO + +# gratuitous convertor to test writable properties +def english_to_bool(v): + if v == "yes": + return True + elif v == "no": + return False + return v + class NetworkManager(DBusClient): """networkmanager @@ -53,20 +63,20 @@ class NetworkManager(DBusClient): DISCONNECTED = 4 "TODO find a good term for 'adaptor'" - _adaptors = { - "methods": { +NetworkManager._add_adaptors( + methods = { "GetDevices": seq_adaptor(Device._create), - "ActivateConnection": (identity, [identity, object_path, object_path, object_path], {}), - "DeactivateConnection": (identity, [object_path], {}) + "ActivateConnection": [ActiveConnection, [identity, object_path, object_path, object_path]], + "DeactivateConnection": [void, [object_path]], }, - "properties": { - "State": State, - "WirelessEnabled": bool, + properties = { + "State": NetworkManager.State, + "WirelessEnabled": [bool, english_to_bool], "WirelessHardwareEnabled": bool, - "ActiveConnections": seq_adaptor(identity), # TODO + "ActiveConnections": seq_adaptor(ActiveConnection), }, - "signals": { - "StateChanged": (identity, [State], {}), + signals = { + "StateChanged": [void, [NetworkManager.State]], }, - } + ) diff --git a/networkmanager/settings/connection.py b/networkmanager/settings/connection.py index 633fe0f..7ba8a8e 100644 --- a/networkmanager/settings/connection.py +++ b/networkmanager/settings/connection.py @@ -27,9 +27,9 @@ class Connection(DBusClient): def __init__(self, service, opath): super(Connection, self).__init__(dbus.SystemBus(), service, opath, default_interface=self.IFACE) - DBusClient._add_adaptors({ - "methods": { +Connection._add_adaptors( + methods = { }, - "signals": { + signals = { }, - }) + ) diff --git a/networkmanager/settings/settings.py b/networkmanager/settings/settings.py index c6b5395..0eeabce 100644 --- a/networkmanager/settings/settings.py +++ b/networkmanager/settings/settings.py @@ -6,6 +6,8 @@ from connection import Connection from ..func import * +# TODO NMS.System, not in spec + class NetworkManagerSettings(DBusClient): """NetworkManagerSettings @@ -26,18 +28,13 @@ class NetworkManagerSettings(DBusClient): # default_interface because knetworkmanager doesnt provide introspection super(NetworkManagerSettings, self).__init__(dbus.SystemBus(), service, self.OPATH, default_interface = self.IFACE) # need instance specific adaptors for user/system conn factories - self._adaptors["methods"]["ListConnections"] = seq_adaptor(self._create_connection) + self._add_adaptor("methods", "ListConnections", seq_adaptor(self._create_connection)) def _create_connection(self, opath): return Connection(self.bus_name, opath) - # FIXME better API for this - DBusClient._add_adaptors({ - "methods": { - "ListConnections": seq_adaptor(Connection), # overriden? - }, - "signals": { - "NewConnection": (identity, [Connection], {}), +NetworkManagerSettings._add_adaptors( + signals = { + "NewConnection": [void, [Connection]], }, - }) - + ) -- 2.11.4.GIT