Edgewall Software

Changes between Version 5 and Version 6 of TracDev/ComponentArchitecture


Ignore:
Timestamp:
Jul 4, 2007, 3:26:07 PM (17 years ago)
Author:
Dave Abrahams <dave@…>
Comment:

Added usage explanation, syntax highlighting.

Legend:

Unmodified
Added
Removed
Modified
  • TracDev/ComponentArchitecture

    v5 v6  
    3636
    3737{{{
     38#!python
    3839from trac.core import *
    3940
     
    4546
    4647{{{
     48#!python
    4749    comp_mgr = ComponentManager()
    4850    my_comp = MyComponent(comp_mgr)
     
    5254
    5355{{{
     56#!python
    5457    my_comp1 = MyComponent(comp_mgr)
    5558    my_comp2 = MyComponent(comp_mgr)
     
    6063
    6164{{{
     65#!python
    6266    from trac.core import *
    6367
     
    7983
    8084{{{
     85#!python
    8186    from trac.core import *
    8287   
     
    107112
    108113{{{
     114#!python
    109115    class TodoPrinter(Component):
    110116        implements(ITodoObserver)
     
    126132
    127133{{{
     134#!python
    128135    comp_mgr = ComponentManager()
    129136    todo_list = TodoList(comp_mgr)
     
    146153This output obviously comes from the `TodoPrinter`. Note however that the code snippet above doesn't even mention that class. All that is needed to have it participating in the action is to declare the class. ''(That implies that an extending class needs to be imported by a python script to be registered. The aspect of loading components is however separate from the extension mechanism itself.)''
    147154
     155== How Trac Uses Components ==
     156
     157The typical use of components in Trac starts with a top-level “service provider” that we'll pick up and use directly. Take, for example, {{{trac.perm.PermissionSystem}}}:
     158{{{
     159#!python
     160permission_system = trac.perm.PermissionSystem()
     161actions = permission_system.get_permission_actions()
     162}}}
     163
     164These are the first few lines of {{{PermissionSystem}}} as of r5790 (or [browser:trunk/trac/perm.py:r5790#L230 in context]):
     165{{{
     166#!python
     167class PermissionSystem(Component):
     168    """Sub-system that manages user permissions."""
     169
     170    implements(IPermissionRequestor)
     171
     172    requestors = ExtensionPoint(IPermissionRequestor)
     173}}}
     174
     175Note that it has a list of extension points implementing {{{IPermissionRequestor}}} ([browser:trunk/trac/perm.py:r5790#L40 in context]):
     176{{{
     177#!python
     178class IPermissionRequestor(Interface):
     179    """Extension point interface for components that define actions."""
     180
     181    def get_permission_actions():
     182        """Return a list of actions defined by this component."""
     183}}}
     184
     185  ''Note that interface authors have not always been consistent about declaring the "{{{self}}}" parameter in signatures.''
     186
     187When we use {{{PermissionSystem}}}, the plugin system will have automatically gathered up all implementations of {{{IPermissionRequestor}}} and placed them in {{{PermissionSystem}}}'s list of {{{requestors}}}.
     188
     189 '''Notes that I hope a Trac dev will check:'''
     190   * ''As far as I understand,the line in {{{PermissionSystem}}} that declares it to implement {{{IPermissionRequestor}}} is completely superfluous except for documentation purposes, because it will always be used directly''
     191   * ''Does something avoid putting {{{PermissionSystem}}} in its own list?'' [[br]]—dave
     192
     193Next in {{{PermissionSystem}}} there is a declaration of an {{{ExtensionOption}}} called {{{store}}}:
     194{{{
     195#!python
     196    store = ExtensionOption('trac', 'permission_store', IPermissionStore,
     197                            'DefaultPermissionStore',
     198        """Name of the component implementing `IPermissionStore`, which is used
     199        for managing user and group permissions.""")
     200
     201}}}
     202The above adds an option called {{{permission_store}}} to {{{trac.ini}}}, declares that the component named by the option implements {{{IPermissionStore}}}, and sets its default to {{{DefaultPermissionStore}}}.  See [browser:trunk/trac/config.py trac.config] for {{{ExtensionOption}}} and friends.  Methods of service providers such as {{{PermissionSystem}}} are commonly a thin forwarding layer over such an {{{ExtensionOption}}}.  For example:
     203{{{
     204#!python
     205    def get_all_permissions(self):
     206        """Return all permissions for all users.
     207
     208        The permissions are returned as a list of (subject, action)
     209        formatted tuples."""
     210        return self.store.get_all_permissions()
     211}}}
     212Thus, service providers are directly manipulated from Python, and are customized through the automatic aggregation of components implementing {{{ExtensionPoint}}}s and through configuration of {{{ExtensionOption}}}s by Trac administrators.
     213
    148214----
    149215See also: TracDev