Source code for zoti_gen.jinja_extensions

import operator
from functools import reduce
from typing import Any, Dict

from jinja2 import Environment, pass_context


class JinjaExtensions:
    """Apart from the `Jinja2 builtin functions
    <https://jinja.palletsprojects.com/en/3.1.x/templates/#list-of-builtin-filters>`_,
    ZOTI-Gen adds the following functions that can be called from
    within code templates.

    """

[docs] @staticmethod def find(json: Dict, path: str) -> Any: """Returns the element with (the dot-separated) *path* in a *json* dictionary, where *path* is specified as a string. E.g. .. code-block:: jinja {# considering the context {'a': None, 'b':{'foo':{'bar': 'baz'}}} #} { b | find("foo.bar") } {# is the same as #} { b.foo.bar } both rendering ``baz``. """ return reduce(operator.getitem, path.split("."), json)
[docs] @staticmethod def setdefaults(json: Any, defaults: Dict) -> Dict: """For every direct child of the given *json* element it (possibly recursively) sets the *defaults* values if undefined. E.g.: .. code-block:: jinja {% set json = {'a': None, 'b':{'foo':'bar'}} %} {% set defaults = {'foo':'biff', 'baz':'buzz'} %} {% set example = setdefaults(json, defaults) %} results in ``example`` containing the dictionary .. code-block:: python {'a': {'foo':'biff', 'baz':'buzz'}, 'b':{'foo':'bar', 'baz':'buzz'}} """ newdict = {} if isinstance(json, dict): newdict = json.copy() elif isinstance(json, list): newdict = {k: {} for k in json} else: newdict[json] = {} for k, v in newdict.items(): for kd, vd in defaults.items(): if not v: newdict[k] = {kd: vd} elif isinstance(v, dict) and not v.get(kd): newdict[k].update({kd: vd}) return newdict
[docs] @staticmethod @pass_context def eval(context: Dict, string: str) -> str: """Renders a Jinja2 string within a *context*. Useful if both *string* and *context* are passed to the current template context.""" return Template(string).render(context)
[docs] @staticmethod def error(msg: str, *args) -> None: """Raise an exception from within the template logic.""" raise Exception(msg.format(*args))
[docs] @staticmethod @pass_context def getter(context, elem, *args) -> str: """ZOTI-Gen specific formatter that retrieves the type getter macro created by ZOTI-FTN and stored in each label's ``glue`` entry and creates an access expresion based on it: .. code-block:: jinja {{ getter("data.data.LEN") }} {# is equivalent to #} {{ label.data.glue.data.LEN._get }}({{ label.data.name }}) """ lab, path = (elem.split(".", 1) + [''])[:2] try: glue = context["label"][lab]["glue"] prefix = glue.get("prefix", "") if glue else "" name = prefix + context["label"][lab]["name"] expargs = ",".join([name] + list(args)) expr = JinjaExtensions.find( glue, path)["_get"] if path else glue["_get"] return f"{expr}({expargs})" except Exception as e: from pprint import pformat msg = f"Cannot get element '{path}' from label '{lab}'" msg += f" in the context:\n {pformat(context['label'])}" print(msg) raise Exception
[docs] @staticmethod @pass_context def setter(context, elem, *args) -> str: """ZOTI-Gen specific formatter that retrieves the type setter macro created by ZOTI-FTN and stored in each label's ``glue`` entry and creates an access expression based on it: .. code-block:: jinja {{ setter("data.data.c", "i", "x" }} {# is equivalent to #} {{ label.data.glue.data.c._set }}({{ label.data.name }}, i, x) """ lab, path = (elem.split(".", 1) + [''])[:2] try: glue = context["label"][lab]["glue"] prefix = glue.get("prefix", "") if glue else "" name = prefix + context["label"][lab]["name"] expargs = ",".join([name] + list(args)) expr = JinjaExtensions.find( glue, path)["_set"] if path else glue["_set"] return f"{expr}({expargs})" except Exception as e: from pprint import pformat msg = f"Cannot set element '{path}' from label '{lab}'" msg += f" in the context:\n {pformat(context['label'])}" print(msg) raise Exception
class ZotiEnvironment(Environment): def __init__(self): super(ZotiEnvironment, self).__init__(extensions=["jinja2.ext.do"]) for f in [a for a in dir(JinjaExtensions) if a[0] != "_"]: self.filters[f] = vars(JinjaExtensions)[f].__func__ self.globals[f] = vars(JinjaExtensions)[f].__func__ __zoti_gen_env__ = ZotiEnvironment()