I don't know if this is of any use to you, but here is how
the Action Chains plugin invokes templates, with hopes that @capink doesn't mind me copying his code here. I picked this because it uses all of the template types, attributes in the python context, plugin-defined template functions, and user-provided templates and functions.
The main invocation function:
Code:
from calibre.ebooks.metadata.book.formatter import SafeFormat
[...]
class ACTemplateContext(PythonTemplateContext):
pass
def get_template_output(template, kwargs, TEMPLATE_ERROR, book, global_vars={},
template_functions=None, context_attrs={}):
if not template_functions:
template_functions = get_template_functions[0]
try:
# calibre >= 6.7.0. support for python template context object
context = ACTemplateContext()
context.set_values(**context_attrs)
output = SafeFormat().safe_format(template, kwargs, TEMPLATE_ERROR, book,
global_vars=global_vars,
template_functions=template_functions,
python_context_object=context)
except:
output = SafeFormat().safe_format(template, kwargs, TEMPLATE_ERROR, book,
global_vars=global_vars,
template_functions=template_functions)
return output
The template functions are built by this function. Much of the complexity comes from the fact that Action Chains adds many new Formatter Functions and that the plugin users can define their own functions.
Code:
def get_template_functions(plugin_action):
all_functions = OrderedDict()
builtin_functions = OrderedDict()
for cls in BUILTIN_FUNCTIONS:
builtin_functions[cls.name] = cls
imported_functions = get_imported_functions(plugin_action)
user_functions = get_user_functions(plugin_action)
action_functions = get_action_functions(plugin_action)
calibre_funcs = formatter_functions().get_functions()
# Note: imported functions can either be class or instantiated object
for function_name, function_obj in imported_functions.items():
# dont override builtin functions
if function_name in builtin_functions.keys():
continue
try:
if isinstance(function_obj, (TemplateFunction, FormatterFunction)):
function = function_obj
elif issubclass(function_obj, TemplateFunction):
function = function_obj(plugin_action)
elif issubclass(function_obj, FormatterFunction):
function = function_obj()
all_functions[function_name] = function
except TypeError as e:
# TypeError: issubclass() arg 1 must be a class
import traceback
if DEBUG:
prints('Action Chains: Error intializing imported function: Un-reconized object: {}\n{}'.format(function_obj, traceback.format_exc()))
except Exception as e:
import traceback
if DEBUG:
prints('Action Chains: Error intializing imported function: {}\n{}'.format(function_name, traceback.format_exc()))
for function_name, cls in user_functions.items():
try:
function = cls(plugin_action)
all_functions[function_name] = function
except Exception as e:
import traceback
if DEBUG:
prints('Action Chains: Error intializing user function: {}\n{}'.format(function_name, traceback.format_exc()))
for function_name, function in action_functions.items():
try:
all_functions[function_name] = function
except Exception as e:
import traceback
if DEBUG:
prints('Action Chains: Error intializing action function: {}\n{}'.format(function_name, traceback.format_exc()))
for name, func in calibre_funcs.items():
all_functions[name] = func
# we keep this last in case we want to override some calibre formatter functions
for function_name, cls in builtin_functions.items():
function = cls(plugin_action)
all_functions[function_name] = function
return all_functions, builtin_functions, user_functions, action_functions, imported_functions