| 155 | == How Trac Uses Components == |
| 156 | |
| 157 | The 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 |
| 160 | permission_system = trac.perm.PermissionSystem() |
| 161 | actions = permission_system.get_permission_actions() |
| 162 | }}} |
| 163 | |
| 164 | These are the first few lines of {{{PermissionSystem}}} as of r5790 (or [browser:trunk/trac/perm.py:r5790#L230 in context]): |
| 165 | {{{ |
| 166 | #!python |
| 167 | class PermissionSystem(Component): |
| 168 | """Sub-system that manages user permissions.""" |
| 169 | |
| 170 | implements(IPermissionRequestor) |
| 171 | |
| 172 | requestors = ExtensionPoint(IPermissionRequestor) |
| 173 | }}} |
| 174 | |
| 175 | Note that it has a list of extension points implementing {{{IPermissionRequestor}}} ([browser:trunk/trac/perm.py:r5790#L40 in context]): |
| 176 | {{{ |
| 177 | #!python |
| 178 | class 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 | |
| 187 | When 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 | |
| 193 | Next 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 | }}} |
| 202 | The 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 | }}} |
| 212 | Thus, 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 | |