Framework Extensions
Introduction to the Extension Interface
Cement defines an Extension Interface, as well as the default CementExtensionHandler that implements the interface. Its purpose is to manage loading framework extensions and making them usable by the application. Extensions are similar to Application Plugins, but at the framework level (application agnostic).
Cement often includes multiple handler implementations of an interface that may or may not have additional features or functionality than the interface requires. The documentation below only references usage based on the interface and default handler (not the full capabilities of an implementation).
API References:
Configuration
Application Meta Options
The following options under App.Meta
modify extension handling:
Option
Description
extension_handler
extensions
Working with Extensions
In general, extensions are only loaded and accessed by the framework. That said the extension handler can be used to access information about loaded extensions, as well as manually load extensions if necessary.
from cement import App
with App('myapp') as app:
# list loaded extensions
app.ext.list()
# load an extension
app.ext.load_extension('myapp.ext.myextension')
# load a list of extensions
app.ext.load_extensions(['myapp.ext.ext1',
'myapp.ext.ext2'])
Creating an Extension
The extension system is a mechanism for dynamically loading code to extend the functionality of the framework. In general, this includes the registration of interfaces, handlers, and/or hooks but can include controllers, command-line options, or anything else.
The preferred method of creating an extension would be via the included developer tools:
$ cement generate extension /path/to/myapp/ext
This would produce something like the following:
from cement import minimal_logger
LOG = minimal_logger(__name__)
def myextension_pre_run_hook(app):
# do something with app
LOG.debug('Inside myextension_pre_run_hook!')
def load(app):
# do something to extend cement
app.hook.register('pre_run', myextension_pre_run_hook)
You will notice that extensions are essentially the same as application plugins. The difference is found both in when/how the code is loaded, as well as the purpose of that code.
Loading Extensions
Extensions are loaded when App.setup()
is called on an application. Cement automatically loads all extensions listed under the application's App.Meta.core_extensions
and App.Meta.extensions
meta options.
To load the above example into our application, we just add it to the list of App.Meta.extensions
. Let's assume the extension code lives in myapp/ext/ext_myextension.py
:
from cement import App
class MyApp(App):
class Meta:
label = 'myapp'
extensions = 'myapp.ext.ext_myextension'
Loading Extensions via a Configuration File
Some use cases may require that end-users be able to modify what framework extensions are loaded depending on the needs of the application, while most extensions are defined by the developer to support key features.
The following example demonstrates an application loading extensions defined via the extensions
setting under the application's configuration settings.
from cement import App
with App('myapp') as app:
app.run()
for e in app.extension.list():
print(e)
[myapp]
exensions = json, yaml, myapp.ext.ext_myextension
Note that extensions loaded in this way will happen after the config handler is setup. Normally, extensions are loaded just before the configuration files are read. Therefore, some extensions may not be compatible with this method if they attempt to perform any actions before app.setup()
completes (such as in early framework hooks before configuration files are loaded).
Last updated