Software Freedom Law Center

root/trunk/trac/trac/core.py

Revision 106, 7.9 kB (checked in by bkuhn, 8 months ago)

r135@hughes: bkuhn | 2008-05-03 21:34:30 -0400

  • Merged in upstream r7002 with: svk smerge /loblaw/local/branches/trac.upstream-r7002 .
Line 
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2003-2008 Edgewall Software
4 # Copyright (C) 2003-2004 Jonas Borgström <jonas@edgewall.com>
5 # Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>
6 # All rights reserved.
7 #
8 # This software is licensed as described in the file COPYING, which
9 # you should have received as part of this distribution. The terms
10 # are also available at http://trac.edgewall.org/wiki/TracLicense.
11 #
12 # This software consists of voluntary contributions made by many
13 # individuals. For the exact contribution history, see the revision
14 # history and logs, available at http://trac.edgewall.org/log/.
15 #
16 # Author: Jonas Borgström <jonas@edgewall.com>
17 #         Christopher Lenz <cmlenz@gmx.de>
18
19 __all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface',
20            'TracError']
21
22
23 class TracError(Exception):
24     """Exception base class for errors in Trac."""
25
26     title = 'Trac Error'
27    
28     def __init__(self, message, title=None, show_traceback=False):
29         """If message is a genshi.builder.tag object, everything up to the
30         first <p> will be displayed in the red box, and everything after will
31         be displayed below the red box.
32         If title is given, it will be displayed as the large header above the
33         error message.
34         """
35         Exception.__init__(self, message)
36         self.message = message
37         if title:
38             self.title = title
39         self.show_traceback = show_traceback
40
41     def __unicode__(self):
42         return unicode(self.message)
43
44 class Interface(object):
45     """Marker base class for extension point interfaces."""
46
47
48 class ExtensionPoint(property):
49     """Marker class for extension points in components."""
50
51     def __init__(self, interface):
52         """Create the extension point.
53        
54         @param interface: the `Interface` subclass that defines the protocol
55             for the extension point
56         """
57         property.__init__(self, self.extensions)
58         self.interface = interface
59         self.__doc__ = 'List of components that implement `%s`' % \
60                        self.interface.__name__
61
62     def extensions(self, component):
63         """Return a list of components that declare to implement the extension
64         point interface.
65         """
66         extensions = ComponentMeta._registry.get(self.interface, [])
67         return filter(None, [component.compmgr[cls] for cls in extensions])
68
69     def __repr__(self):
70         """Return a textual representation of the extension point."""
71         return '<ExtensionPoint %s>' % self.interface.__name__
72
73
74 class ComponentMeta(type):
75     """Meta class for components.
76    
77     Takes care of component and extension point registration.
78     """
79     _components = []
80     _registry = {}
81
82     def __new__(cls, name, bases, d):
83         """Create the component class."""
84
85         new_class = type.__new__(cls, name, bases, d)
86         if name == 'Component':
87             # Don't put the Component base class in the registry
88             return new_class
89
90         # Only override __init__ for Components not inheriting ComponentManager
91         if True not in [issubclass(x, ComponentManager) for x in bases]:
92             # Allow components to have a no-argument initializer so that
93             # they don't need to worry about accepting the component manager
94             # as argument and invoking the super-class initializer
95             init = d.get('__init__')
96             if not init:
97                 # Because we're replacing the initializer, we need to make sure
98                 # that any inherited initializers are also called.
99                 for init in [b.__init__._original for b in new_class.mro()
100                              if issubclass(b, Component)
101                              and '__init__' in b.__dict__]:
102                     break
103             def maybe_init(self, compmgr, init=init, cls=new_class):
104                 if cls not in compmgr.components:
105                     compmgr.components[cls] = self
106                     if init:
107                         try:
108                             init(self)
109                         except:
110                             del compmgr.components[cls]
111                             raise
112             maybe_init._original = init
113             new_class.__init__ = maybe_init
114
115         if d.get('abstract'):
116             # Don't put abstract component classes in the registry
117             return new_class
118
119         ComponentMeta._components.append(new_class)
120         registry = ComponentMeta._registry
121         for interface in d.get('_implements', []):
122             registry.setdefault(interface, []).append(new_class)
123         for base in [base for base in bases if hasattr(base, '_implements')]:
124             for interface in base._implements:
125                 registry.setdefault(interface, []).append(new_class)
126
127         return new_class
128
129
130 class Component(object):
131     """Base class for components.
132
133     Every component can declare what extension points it provides, as well as
134     what extension points of other components it extends.
135     """
136     __metaclass__ = ComponentMeta
137
138     def __new__(cls, *args, **kwargs):
139         """Return an existing instance of the component if it has already been
140         activated, otherwise create a new instance.
141         """
142         # If this component is also the component manager, just invoke that
143         if issubclass(cls, ComponentManager):
144             self = super(Component, cls).__new__(cls)
145             self.compmgr = self
146             return self
147
148         # The normal case where the component is not also the component manager
149         compmgr = args[0]
150         self = compmgr.components.get(cls)
151         if self is None:
152             self = super(Component, cls).__new__(cls)
153             self.compmgr = compmgr
154             compmgr.component_activated(self)
155         return self
156
157     def implements(*interfaces):
158         """Can be used in the class definiton of `Component` subclasses to
159         declare the extension points that are extended.
160         """
161         import sys
162
163         frame = sys._getframe(1)
164         locals_ = frame.f_locals
165
166         # Some sanity checks
167         assert locals_ is not frame.f_globals and '__module__' in locals_, \
168                'implements() can only be used in a class definition'
169
170         locals_.setdefault('_implements', []).extend(interfaces)
171     implements = staticmethod(implements)
172
173
174 implements = Component.implements
175
176
177 class ComponentManager(object):
178     """The component manager keeps a pool of active components."""
179
180     def __init__(self):
181         """Initialize the component manager."""
182         self.components = {}
183         self.enabled = {}
184         if isinstance(self, Component):
185             self.components[self.__class__] = self
186
187     def __contains__(self, cls):
188         """Return wether the given class is in the list of active components."""
189         return cls in self.components
190
191     def __getitem__(self, cls):
192         """Activate the component instance for the given class, or return the
193         existing the instance if the component has already been activated.
194         """
195         if cls not in self.enabled:
196             self.enabled[cls] = self.is_component_enabled(cls)
197         if not self.enabled[cls]:
198             return None
199         component = self.components.get(cls)
200         if not component:
201             if cls not in ComponentMeta._components:
202                 raise TracError('Component "%s" not registered' % cls.__name__)
203             try:
204                 component = cls(self)
205             except TypeError, e:
206                 raise TracError('Unable to instantiate component %r (%s)' %
207                                 (cls, e))
208         return component
209
210     def component_activated(self, component):
211         """Can be overridden by sub-classes so that special initialization for
212         components can be provided.
213         """
214
215     def is_component_enabled(self, cls):
216         """Can be overridden by sub-classes to veto the activation of a
217         component.
218
219         If this method returns False, the component with the given class will
220         not be available.
221         """
222         return True
Note: See TracBrowser for help on using the browser.

SFLC Main Page

[frdm] Support SFLC