import Permission from main import _ import types class Interface(object): """Abstract base class for interfaces.""" def __get_members(impl): """Simply returns all members found in a class.""" return [ (name, member) for name, member in impl.__dict__.items() ] __get_members = staticmethod(__get_members) def get_properties(iface): """Returns a list of the properties of the given implementation.""" return [ (n, p) for n, p in Interface.__get_members(iface) if (type(p) == property) ] get_properties = staticmethod(get_properties) def get_methods(iface): """Returns a list of the methods of the given implementation.""" return [ (n, "") for n, m in Interface.__get_members(iface) if (type(m) == types.FunctionType) ] # or MethodType ? get_methods = staticmethod(get_methods) def get_permissions(iface): """Returns a list of the permissions of the properties.""" perms = [ (n, perm) for n, perm in Interface.__get_members(iface) if (isinstance(perm, Permission._Permission)) ] return perms get_permissions = staticmethod(get_permissions) def get_taz_style_id(iface): """ Computes and returns the interface in the wrong way for maintaining backwards compatibility. """ import md5 import utils name = iface.__name__ ash = md5.new(name + ":").hexdigest() # encode it in base36 to get shorter ID ash = utils.radix( int(ash, 16), 36 ) # ID have to be 25 char long ash = '0' * (25 - len(ash)) + ash assert (len(ash) == 25) return ("%s:%s" % (name, ash)) get_taz_style_id = staticmethod(get_taz_style_id) def get_id(iface): """Returns the unique identifier of the given interface.""" # the algorithm is simple: # build a string containing the class name and a sorted list of the # properties and return the MD5 fingerprint of it import md5 import utils name = iface.__name__ items1 = Interface.get_permissions(iface) items1.sort() items2 = Interface.get_methods(iface) items2.sort() tmp = ["%s:%s" % (k, v) for k, v in items1 + items2] tmp = "%s:%s" % (name, ",".join(tmp)) ash = md5.new(tmp).hexdigest() # encode it in base36 to get shorter ID ash = utils.radix( int(ash, 16), 36 ) # ID have to be 25 char long ash = '0' * (25 - len(ash)) + ash assert (len(ash) == 25) # the "-2" suffix is for marking the ID as rev 2 iface_id = "%s:%s-2" % (name, ash) return iface_id get_id = staticmethod(get_id) def get_rev_of_id(ident): """Returns the revision of the format in which the ID is computed.""" if (ident[-2] != "-"): return "1" else: return ident[-1] get_rev_of_id = staticmethod(get_rev_of_id) def get_interfaces(impl): """Returns the interfaces implemented by the given class""" return [ c for c in impl.mro() if issubclass(c, Interface) and not c in (Interface, impl) ] get_interfaces = staticmethod(get_interfaces) def assert_interfaces(impl): """Static method for asserting that the interfaces are implemented properly in the given class. Throws exceptions otherwise.""" # find the implemented properties impl_props = dict(impl.get_properties()) # find the implemented methods impl_meths = dict(impl.get_methods()) # check all interfaces for iface in Interface.get_interfaces(impl): # check properties required = iface.get_permissions() for name, perm in required: if name not in impl_props: raise NotImplementedError("Missing implementation for " "%s.%s" % (iface.__name__, name)) # check if the property's mode is according to the interfaces if (perm != Permission.Permission(implemented[name])): raise NotImplementedError("Broken implementation for " "%s.%s" % (iface.__name__, name)) #end for # check methods required = iface.get_methods() for name, meth in required: if name not in impl_meths: raise NotImplementedError("Missing implementation for " "%s.%s" % (iface.__name__, name)) #end for #end for assert_interfaces = staticmethod(assert_interfaces) def text_describe(impl): """Returns a description of the interfaces of the given class.""" textlist = [] interfaces = Interface.get_interfaces(impl) for i in interfaces: out = "" ident = Interface.get_id(i) out += ident + '\n\n' for key in dir(i): value = impl.__dict__.get(key) if (not value): continue if (isinstance(value, property)): out += " " out += key.ljust(25) perm = str(Permission.Permission(value)).ljust(4) out += perm out += "%s \n" % (value.__doc__ or _("no description"), ) out += "\n" textlist.append(out) return ''.join(textlist) text_describe = staticmethod(text_describe) def gui_describe(impl): guilist = [] interfaces = Interface.get_interfaces(impl) for i in interfaces: items = [] for key in dir(i): value = impl.__dict__.get(key) if (not value): continue if (isinstance(value, property)): items.append((key, str(Permission.Permission(value)), value.__doc__ or _("no description"))) guilist.append( (Interface.get_id(i), items) ) return guilist gui_describe = staticmethod(gui_describe)