What is a Component?
For our purposes, a component is an object that provides a certain type of service within the context of the application. There is at most one instance of any component: components are singletons. That implies that a component doesnot map to an entity of the application's object model; instead, components represent functional subsystems. 功能子系统, 提供service
A component can extend any number of other components and still offer its own extension points. This allows a plugin to itself offer a plugin API (i.e. extension point). This feature is the basis for a plugin-based architecture.
Public classes
http://archive.ipython.org/release/0.12/ipython-0.12.win32-setup.exe
https://pypi.python.org/pypi/pyreadline/2.0
python中基于descriptor的一些概念(上)
python中基于descriptor的一些概念(下)
Descriptor Protocol(协议)
The Trac Configuration File
Trac configuration is done by editing thetrac.ini
config file, located in<projectenv>/conf/trac.ini
. Changes to the configuration are usually reflected immediately, though changes to the[components]
or[logging]
sections will require restarting the web server. You may also need to restart the web server after creating a global configuration file when none was previously present.
The trac.ini
configuration file and its parent directory should be writable by the web server, as Trac currently relies on the possibility to trigger a complete environment reload to flush its caches.
Enabling a component is done in the[components]
section of trac.ini.
[components]
trac.ticket.report.ReportModule = disabled
webadmin.* = enabled
Miscellaneous noPackaging plugins
TracPlugins are packaged as Python Eggs. You can use setuptools to make a setup.py script that will produce a Python egg for your plugin.
The egg needs to export an entry point group named trac.plugins, listing the names of the modules that Trac should import for the plugin-provided components to get registered. For example:
from setuptools import find_packages, setup
setup(
name='TracHelloWorld', version='1.0',
packages=find_packages(exclude=['*.tests*']),
entry_points = {
'trac.plugins': [
'helloworld = myplugs.helloworld',
],
},
)
This assumes that the HelloWorldPlugin example above is defined in the module helloworld.py in the myplugs package. The entry point name (in this example “helloworld”) is required by the Python egg runtime, but not currently used by Trac. In most cases, you can simply use the qualified module name there.
For backwards-compatibility reasons, Trac still supports an alternative to entry points: you can have a file named trac_plugin.txt in the EGG-INFO directory. This file should contain the names of all modules that need to be imported by Trac to register your components. Note that this method is deprecated and will be removed in a future version of Trac (probably as soon as 0.11).tes:
Components can be marked "abstract". This is done simply by adding a member field abstract = True to the component class.
class MyAbstractComponent(Component):
abstract = True
# implementation stuff here
Abstract components can't be enabled and therefore don't appear in the plugin panel of Trac's web interface.
Not all components require to be enabled to work properly. Only components implementing an extension point interface (using implements) need to be enabled and therefore listed in the entry_points section of a plugin. If you just want to have the utility class (like a database manager) that takes the benefits of a component (like being a singleton and/or having access to Trac's database or configuration) that doesn't implement any extension point interfaces, it doesn't need to be enabled (or even listed in the entry_points section). Such a component should then be marked "abstract".
Components should be listed in the entry_points section, if they define any options (from trac.config). This way trac.ini editors can find this option even if it still has its default value. Options are registered when the component is registered. The component that defines the option doesn't need to be enabled for the option to be registered and can even be abstract.
Note that there are actually three ways to define an extension point:
trac.core.ExtensionPoint
: This is an unordered list of all enabled components implementing a specific extension point interface.trac.config.ExtensionOption
: An option for trac.ini that describes exactly one enabled component implementing a specific extension point interface.trac.config.OrderedExtensionsOption
: An option for trac.ini that describes an ordered list of enabled components implementing a specific extension point interface. (Components that also implement the same interface but are not listed in the option can automatically be appended to the list.)
class IPermissionRequestor(Interface):
"""Extension point interface for components that define actions."""
def get_permission_actions():
"""Return a list of actions defined by this component."""
class PermissionSystem(Component):
"""Sub-system that manages user permissions."""
implements(IPermissionRequestor)
requestors = ExtensionPoint(IPermissionRequestor)
store = ExtensionOption('trac', 'permission_store', IPermissionStore,
'DefaultPermissionStore',
"""Name of the component implementing `IPermissionStore`, which is used
for managing user and group permissions.""")
def get_all_permissions(self):
"""Return all permissions for all users.
The permissions are returned as a list of (subject, action)
formatted tuples."""
return self.store.get_all_permissions()
permission_system = trac.perm.PermissionSystem(env)
actions = permission_system.get_permission_actions()
#trac.ini
[trac]
permission_store = DefaultPermissionStore
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.