trac.core
– the Trac “kernel”¶
Component model¶
The Trac component model is very simple, it is based on Interface
classes that are used to document a particular set of methods and
properties that must be defined by a Component
subclass when it
declares it implements that interface.
-
class
trac.core.
Component
¶ Bases:
object
Base class for components.
Every component can declare what extension points it provides, as well as what extension points of other components it extends.
The static method Component.implements
is never used as such, but
rather via the global implements
function. This globally registers
that particular component subclass as an implementation of the listed
interfaces.
-
trac.core.
implements
(*interfaces)¶ Can be used in the class definition of
Component
subclasses to declare the extension points that are extended.
For example:
class IStuffProvider(Interface):
"""All interfaces start by convention with an "I" and even if it's
not a convention, in practice most interfaces are "Provider" of
something ;-)
"""
def get_stuff(color=None):
"""We usually don't specify "self" here, but try to describe
as precisely as possible how the method might be called and
what is the expected return type."""
class ComponentA(Component):
implements(IStuffProvider)
# IStuffProvider methods
def get_stuff(self, color=None):
if not color or color == 'yellow':
yield ('duck', "the regular waterproof plastic duck")
The benefit of implementing an interface is to possibility to define
an ExtensionPoint
property for an Interface
, in a Component
subclass. Such a property provides a convenient way to retrieve all
registered and enabled component instances for that interface. The
enabling of components is the responsibility of the
ComponentManager
, see is_component_enabled
below.
-
class
trac.core.
ExtensionPoint
(interface)¶ Bases:
property
Marker class for extension points in components.
Create the extension point.
Parameters: interface – the Interface
subclass that defines the protocol for the extension point-
extensions
(component)¶ Return a list of components that declare to implement the extension point interface.
-
Continuing the example:
class StuffModule(Component):
stuff_providers = ExtensionPoint(IStuffProvider)
def get_all_stuff(self, color=None):
stuff = {}
for provider in self.stuff_provider:
for name, descr in provider.get_stuff(color) or []:
stuff[name] = descr
return stuff
Note that besides going through an extension point, Component
subclass instances can alternatively be retrieved directly by using
the instantiation syntax. This is not an usual instantiation though,
as this will always return the same instance in the given
ComponentManager
“scope” passed to the constructor:
>>> a1 = ComponentA(mgr)
>>> a2 = ComponentA(mgr)
>>> a1 is a2
True
The same thing happens when retrieving components via an extension point, the retrieved instances belong to the same “scope” as the instance used to access the extension point:
>>> b = StuffModule(mgr)
>>> any(a is a1 for a in b.stuff_providers)
True
-
class
trac.core.
ComponentManager
¶ Bases:
object
The component manager keeps a pool of active components.
Initialize the component manager.
-
component_activated
(component)¶ Can be overridden by sub-classes so that special initialization for components can be provided.
-
disable_component
(component)¶ Force a component to be disabled.
Parameters: component – can be a class or an instance.
-
enable_component
(component)¶ Force a component to be enabled.
Parameters: component – can be a class or an instance. Since: 1.0.13
-
is_component_enabled
(cls)¶ Can be overridden by sub-classes to veto the activation of a component.
If this method returns
False
, the component was disabled explicitly. If it returnsNone
, the component was neither enabled nor disabled explicitly. In both cases, the component with the given class will not be available.
-
is_enabled
(cls)¶ Return whether the given component class is enabled.
-
In practice, there’s only one kind of ComponentManager
in the Trac
application itself, the trac.env.Environment
.
More on components¶
We have seen above that one way to retrieve a Component
instance is
to call the constructor on a ComponentManager
instance mgr
:
a1 = ComponentA(mgr)
This will eventually trigger the creation of a new ComponentA
instance if there wasn’t already one created for mgr
[*]. At this
unique occasion, the constructor of the component subclass will be
called without arguments, so if you define a constructor it must
have the following signature:
def __init__(self):
self.all_colors = set()
Note that one should try to do as little as possible in a Component
constructor. The most complex operation could be for example the
allocation of a lock to control the concurrent access to some data
members and guarantee thread-safe initialization of more costly
resources on first use. Never do such costly initializations in the
constructor itself.
Exceptions¶
-
exception
trac.core.
TracBaseError
¶ Bases:
exceptions.Exception
Base class for all exceptions defined in Trac.
-
exception
trac.core.
TracError
(message, title=None, show_traceback=False)¶ Bases:
trac.core.TracBaseError
Standard exception for errors in Trac.
If message is an Element object, everything up to the first <p> will be displayed in the red box, and everything after will be displayed below the red box. If title is given, it will be displayed as the large header above the error message.
Miscellaneous¶
-
class
trac.core.
ComponentMeta
¶ Bases:
type
Meta class for components.
Takes care of component and extension point registration.
Create the component class.
-
classmethod
deregister
(component)¶ Remove a component from the registry.
-
classmethod
[*] | Ok, it might happen that more than one component instance get created due to a race condition. This is usually harmless, see #9418. |