Source code for fgen.jinja_environment

"""
Jinja environment to use while generating wrappers
"""

from __future__ import annotations

from pathlib import Path

import jinja2

JINJA_ENV = jinja2.Environment(
    loader=jinja2.FileSystemLoader(Path(__file__).parent.absolute()),
    autoescape=jinja2.select_autoescape(),
    trim_blocks=True,
    lstrip_blocks=True,
    undefined=jinja2.StrictUndefined,
)
"""Jinja2 environment to use for template rendering"""


[docs]def indent_based_on_first_line( code: str, indent: str, ) -> str: """ Indent code based on the indent of the first line. If the first line does not have indent equal to ``indent``, all the code except the first line will have an indent added such that the first line would have an indent of ``indent``. We exclude the first line so that the indent can be included in the jinja template too, which makes it easier to read what is going on. Parameters ---------- code Code to indent indent Indent to ensure that the first line has Returns ------- Indented code """ if not code: # Empty line return code code_split = code.splitlines() if len(code_split) == 1: # Nothing to indent return code first_line = code_split[0] first_line_indent = len(first_line) - len(first_line.lstrip()) indent_len = len(indent) if first_line_indent >= indent_len: return code required_extra_indent = " " * (indent_len - first_line_indent) after_first_line = code_split[1:] return "\n".join( [first_line, *[f"{required_extra_indent}{line}" for line in after_first_line]] )
[docs]def strip_empty_lines(inp: str) -> str: """ Strip empty lines More specifically, turn lines that only have whitespace into a single newline character. This is a workaround until we start formatting our Fortran as part of the generation process (https://gitlab.com/magicc/fgen/-/issues/26). Parameters ---------- inp Input string Returns ------- Input string, with all whitespace lines replaced by a single newline character. """ out = [line if line.strip() else "\n" for line in inp.splitlines()] return "\n".join(out)
JINJA_ENV.filters["indent_based_on_first_line"] = indent_based_on_first_line JINJA_ENV.filters["strip_empty_lines"] = strip_empty_lines
[docs]def get_template_in_directory( template_name: str, template_directory: Path, env: jinja2.Environment ) -> jinja2.Template: """ Get template that is in the directory specified by ``file_dunder`` Parameters ---------- template_name Name of the template to get template_directory The directory from which to retrieve the template. If you want to retrieve a template in the same directory as the file that is calling this function, call ``get_template_in_directory(template_name, Path(__file__).parent), env)``. env Jinja2 environment to use when loading the template. This must be using a :obj:`jinja2.loaders.FileSystemLoader` loader. The loader must only have one search path. Returns ------- Loaded template """ if not isinstance(env.loader, jinja2.loaders.FileSystemLoader): raise NotImplementedError(f"{env.loader=}") if len(env.loader.searchpath) > 1: raise NotImplementedError( f"More than one search path: {env.loader.searchpath=}" ) loader_searchpath = env.loader.searchpath[0] template_path = (template_directory / template_name).relative_to(loader_searchpath) return env.get_template(str(template_path))
[docs]def post_process_jinja_rendering(inp: str) -> str: """ Post-process the result from Jinja This fixes things we can't work out how to fix with jinja Parameters ---------- inp Result of formatting with jinja Returns ------- Post-processed result """ # Strip out two blank lines in a row two_blank_lines = "\n\n\n" one_blank_line = "\n\n" while two_blank_lines in inp: inp = inp.replace(two_blank_lines, one_blank_line) # Jinja trims the trailing line-break from the end of the rendered text, # add that back in too return inp + "\n"