-
Notifications
You must be signed in to change notification settings - Fork 0
Extending the Engine
Currently there is a single published API.
Extensions to cinje functionality are registered using the Python standard entry_points
mechanism using the cinje.translator
namespace. Within your setup.py
file you register plugins by writing something similar to the following:
setup(
name = "myproject",
# ...
entry_points = {'cinje.translator': [
'mytag = myproject.tag:MyTag'
]}
)
The entry point must refer to the class used as the code transformer. Cinje, when transforming template source into Python source, will automatically discover and utilize any plugins declared in this way.
It is important to note that pages are not "re-compiled" if they have a current and valid byte code cache file (matching .pyc
or .pyo
). Because of this, newly registered extensions won't be automatically utilized by previously compiled templates. This is a design feature; it armours production code (or third-party templates) from changes within your own application as a side-effect of highly performant caching. If ever you notice your directive wasn't used after adding, remember to clear byte code caches.
The basis for the cinje engine is the act of transforming lines from the cinje domain-specific-language into standard Python code. The API for an inline transformer is relatively simple:
class MagicWord:
"""Do something neat when someone uses the magic word."""
priority = 0 # Transformers are sorted on this attribute.
def match(self, context, line):
"""Are we to handle this line?"""
return line.kind == 'code' and line.stripped == "xyzzy"
def __call__(self, context):
"""Stream transform input lines into Python source."""
declaration = context.input.next()
yield declaration.clone(line="# Ssh, that's a secret.")
There's a few things going on here. Each translator has a priority
; because of the way things are sorted, higher priorities are actually lower numbers. The built-in translators offer a spread of priorities between -100 and 100, allowing you to easily inject your own transformers in such a way as to override any of the built-in ones. The match
method is used, passing in the current cinje.util.Context
instance and cinje.util.Line
instance, to evaluate if your plugin can process that line. If a truthy value is returned, the translator is then called (executing the __call__
method). Any state should be stored against the context
; as this code is run at import time use of global state is extremely dangerous.
If the translator matches, it's the job of the __call__
method to accept lines from context.input
and yield Line
instances of output.