diff --git a/schilder2000/helpers.py b/schilder2000/helpers.py index b7be6615d617a29744418c96b8af8ad33c7f0df0..1a6a5752bd1ba66d9adb2708a4848347af227971 100644 --- a/schilder2000/helpers.py +++ b/schilder2000/helpers.py @@ -1,6 +1,11 @@ import typing as t -from flask import Flask as _Flask, Blueprint as FlaskBlueprint, render_template +from flask import ( + Flask as _Flask, + Blueprint as FlaskBlueprint, + current_app, + render_template, +) from jinja2 import BaseLoader, ChoiceLoader, PrefixLoader, Template @@ -43,3 +48,41 @@ class Flask(_Flask): self.jinja_env.loader.loaders[0].mapping[blueprint.name] = ( blueprint.jinja_loader ) + + +_sentinel = object() + + +def get_template_attribute( + template_name: str, + attribute: str, + default: t.Any = _sentinel, + vars: t.Dict[str, t.Any] | None = None, + shared: bool = False, + locals: t.Mapping[str, t.Any] | None = None, +) -> t.Any: + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + mod = current_app.jinja_env.get_template(template_name).make_module( + vars, shared, locals + ) + if default is _sentinel: + return getattr(mod, attribute) + else: + return getattr(mod, attribute, default)