Package timeside :: Module component
[hide private]
[frames] | no frames]

Source Code for Module timeside.component

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (c) 2009 Olivier Guilyardi <olivier@samalyse.com> 
  4  # 
  5  # This file is part of TimeSide. 
  6   
  7  # TimeSide is free software: you can redistribute it and/or modify 
  8  # it under the terms of the GNU General Public License as published by 
  9  # the Free Software Foundation, either version 2 of the License, or 
 10  # (at your option) any later version. 
 11   
 12  # TimeSide is distributed in the hope that it will be useful, 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 15  # GNU General Public License for more details. 
 16   
 17  # You should have received a copy of the GNU General Public License 
 18  # along with TimeSide.  If not, see <http://www.gnu.org/licenses/>. 
 19   
 20   
 21  # This file defines a generic object interface mechanism and 
 22  # a way to determine which components implements a given interface. 
 23  # 
 24  # For example, the following defines the Music class as implementing the 
 25  # listenable interface. 
 26  # 
 27  # class Listenable(Interface): 
 28  #     pass 
 29  # 
 30  # class Music(Component): 
 31  #    implements(Listenable) 
 32  # 
 33  # Several class can implements a such interface, and it is possible to 
 34  # discover which class implements it with implementations(): 
 35  # 
 36  # list_of_classes = implementations(Listenable) 
 37  # 
 38  # This mechanism support inheritance of interfaces: a class implementing a given 
 39  # interface is also considered to implement all the ascendants of this interface. 
 40  # 
 41  # However, inheritance is not supported for components. The descendants of a class 
 42  # implementing a given interface are not automatically considered to implement this 
 43  # interface too. 
 44   
 45  __all__ = ['Component', 'MetaComponent', 'implements', 'abstract', 
 46             'interfacedoc', 'Interface', 'implementations', 'ComponentError'] 
 47   
48 -class Interface(object):
49 """Marker base class for interfaces."""
50
51 -def implements(*interfaces):
52 """Registers the interfaces implemented by a component when placed in the 53 class header""" 54 MetaComponent.implements.extend(interfaces)
55
56 -def abstract():
57 """Declare a component as abstract when placed in the class header""" 58 MetaComponent.abstract = True
59
60 -def implementations(interface, recurse=True, abstract=False):
61 """Returns the components implementing interface, and if recurse, any of 62 the descendants of interface. If abstract is True, also return the 63 abstract implementations.""" 64 result = [] 65 find_implementations(interface, recurse, abstract, result) 66 return result
67
68 -def interfacedoc(func):
69 if isinstance(func, staticmethod): 70 raise ComponentError("@interfacedoc can't handle staticmethod (try to put @staticmethod above @interfacedoc)") 71 72 if not func.__doc__: 73 func.__doc__ = "@interfacedoc" 74 func._interfacedoc = True 75 return func
76
77 -class MetaComponent(type):
78 """Metaclass of the Component class, used mainly to register the interface 79 declared to be implemented by a component.""" 80 81 implementations = [] 82 implements = [] 83 abstract = False 84
85 - def __new__(cls, name, bases, d):
86 new_class = type.__new__(cls, name, bases, d) 87 88 # Register implementations 89 if MetaComponent.implements: 90 for i in MetaComponent.implements: 91 MetaComponent.implementations.append({ 92 'interface': i, 93 'class': new_class, 94 'abstract': MetaComponent.abstract}) 95 96 # Propagate @interfacedoc 97 for name in new_class.__dict__: 98 member = new_class.__dict__[name] 99 if isinstance(member, staticmethod): 100 member = getattr(new_class, name) 101 102 if member.__doc__ == "@interfacedoc": 103 if_member = None 104 for i in MetaComponent.implements: 105 if hasattr(i, name): 106 if_member = getattr(i, name) 107 if not if_member: 108 raise ComponentError("@interfacedoc: %s.%s: no such member in implemented interfaces: %s" 109 % (new_class.__name__, name, str(MetaComponent.implements))) 110 member.__doc__ = if_member.__doc__ 111 112 MetaComponent.implements = [] 113 MetaComponent.abstract = False 114 115 return new_class
116
117 -class Component(object):
118 """Base class of all components""" 119 __metaclass__ = MetaComponent
120
121 -def extend_unique(list1, list2):
122 """Extend list1 with list2 as list.extend(), but doesn't append duplicates 123 to list1""" 124 for item in list2: 125 if item not in list1: 126 list1.append(item)
127
128 -def find_implementations(interface, recurse, abstract, result):
129 """Find implementations of an interface or of one of its descendants and 130 extend result with the classes found.""" 131 for item in MetaComponent.implementations: 132 if (item['interface'] == interface and (abstract or not item['abstract'])): 133 extend_unique(result, [item['class']]) 134 135 if recurse: 136 subinterfaces = interface.__subclasses__() 137 if subinterfaces: 138 for i in subinterfaces: 139 find_implementations(i, recurse, abstract, result)
140
141 -class ComponentError(Exception):
142 pass
143