Source code for confs.template_interface

"""
Module
------

    template_interface.py

Description
-----------

    This module contains the base-class object for all file template
    rendering.

Classes
-------

    Template()

        This is the base-class object for all file template rendering.

Author(s)
---------

    Henry R. Winterbottom; 19 April 2023

History
-------

    2023-04-19: Henry Winterbottom -- Initial implementation.

"""

# ----

# pylint: disable=too-many-arguments
# pylint: disable=too-many-locals

# -----

from types import SimpleNamespace
from typing import Dict, Generic

from tools import parser_interface
from utils.decorator_interface import privatemethod
from utils.exceptions_interface import TemplateInterfaceError
from utils.logger_interface import Logger

# ----

# Define all available module properties.
__all__ = ["Template"]

# ----

TMPL_ITEM_LIST = [
    "@[%s]",
    "[@%s]",
    "{@%s}",
    "{%%%s%%}",
    "{{%% %s %%}}",
    "<%s>",
    "{%% %s %%}",
    "{{ %s }}",
]

# ----


[docs]class Template: """ Description ----------- This is the base-class object for all file generic template rendering. """ def __init__(self: Generic): """ Description ----------- Creates a new Template object. """ # Define the base-class attributes. self.logger = Logger(caller_name=f"{__name__}.{self.__class__.__name__}")
[docs] def read_tmpl(self: Generic, tmpl_path: str) -> str: """ Description ----------- This method reads a template file path and returns a Python string containing the attributes collected from the file. Parameters ---------- tmpl_path: ``str`` A Python string defining the template file path. Returns ------- tmpl_str_in: ``str`` A Python string containing the attributes collected from the template file path. """ # Read and return the attributes within the template file # path. with open(tmpl_path, "r", encoding="utf-8") as file: tmpl_str = file.read().split("\n") tmpl_str_in = " ".join([f"{item}\n" for item in tmpl_str]) return tmpl_str_in
@privatemethod def render_tmpl( self: Generic, tmpl_obj: SimpleNamespace, tmpl_str_in: str, fail_missing: bool, f90_bool: bool, warn: bool, ) -> str: """ Description ----------- This method renders a Python template string using the attributes specified in `tmpl_obj` upon entry and returns a Python string updated accordingly. Parameters ---------- tmpl_obj: ``SimpleNamespace`` A Python SimpleNamespace object containing the template attributes. tmpl_str_in: ``str`` A Python string containing template characters. fail_missing: ``bool`` A Python boolean valued variable specifying whether to fail if a template string cannot be fully rendered. f90_bool: ``bool`` A Python boolean valued variable specifying whether to transform boolean variables to a FORTRAN 90 format. warn: ``bool`` A Python boolean valued variable specifying whether to create `Logger` warning messages for missing template variables. Returns ------- tmpl_str_out: ``str`` A Python string for which template characters have been rendered and otherwise identical to `tmpl_str_in`. Raises ------ TemplateInterfaceError - raised if a template string has not been rendered and `fail_missing` is `True` upon entry. """ # Initialize the output string. tmpl_str_out = tmpl_str_in # Replace any instances of templated strings with specified # attributes accordingly. for attr_key, attr_value in vars(tmpl_obj).items(): for tmpl_item in TMPL_ITEM_LIST: try: check_str = tmpl_item % attr_key value = parser_interface.dict_key_value( dict_in=vars(tmpl_obj), key=attr_key, force=True, no_split=True ) # Update value accordingly. if value is not None: if f90_bool: value = parser_interface.f90_bool(value=value) attr_value = value tmpl_str_out = tmpl_str_out.replace(check_str, str(attr_value)) except TypeError: pass # Define all characters that represent templated values. tmpl_char_list = set( list("".join([item.replace("%s", "") for item in TMPL_ITEM_LIST])) ) tmpl_char_list = [item for item in tmpl_char_list if item != " "] # Check whether any templated strings remain; proceed # accordingly. tmpl_str_list = [] for tmpl_str in tmpl_str_out.split("\n"): if any(item for item in tmpl_char_list if item in tmpl_str): tmpl_str_list.append(tmpl_str.strip()) if warn: msg = ( "The following template(s) was (were) not rendered: " f"{', '.join(tmpl_str_list)}." ) if len(tmpl_str_list) > 0: if fail_missing: msg = msg + " Aborting!!!" raise TemplateInterfaceError(msg=msg) if not fail_missing: self.logger.warn(msg=msg) return tmpl_str_out @staticmethod def tmpl_obj(attr_dict: Dict) -> SimpleNamespace: """ Description ----------- This method builds a Python object containing the attributes within the Python dictionary `attr_dict` upon entry. Parameters ---------- attr_dict: ``Dict`` A Python dictionary containing the attributes to be used for updating a specified template. Returns ------- tmpl_obj: ``SimpleNamespace`` A Python SimpleNamespace object containing the template attributes provided by `attr_dict` upon entry and cast as an object. """ # Collect the attributes within the Python dictionary provided # upon entry and builds a Python object. tmpl_obj = parser_interface.object_define() for attr in attr_dict.keys(): value = parser_interface.dict_key_value( dict_in=attr_dict, key=attr, no_split=True ) tmpl_obj = parser_interface.object_setattr( object_in=tmpl_obj, key=attr, value=value ) return tmpl_obj
[docs] def write_tmpl( self: SimpleNamespace, attr_dict: Dict, tmpl_path: str, template_path: str, fail_missing: bool = False, f90_bool: bool = False, warn: bool = True, ) -> None: """ Description ----------- This method collects attribute values, renders a string containing template attributes, and writes the updated template to a specified file path `tmpl_path`. Parameters ---------- attr_dict: ``Dict`` A Python dictionary containing the attributes to be used for updating a specified template. tmpl_path: ``str`` A Python string specifying the rendered (e.g., output) file path. template_path: ``str`` A Python string specifying the template file path to be rendered. Keywords -------- fail_missing: ``bool``, optional A Python boolean valued variable specifying whether to fail if a template string cannot be fully rendered. f90_bool: ``bool``, optional A Python boolean valued variable specifying whether to transform boolean variables to a FORTRAN 90 format. warn: ``bool``, optional A Python boolean valued variable specifying whether to create `Logger` warning messages for missing template variables. """ # Read, render, and write the template file. tmpl_obj = self.tmpl_obj(attr_dict=attr_dict) tmpl_str_in = self.read_tmpl(tmpl_path=template_path) tmpl_str_out = self.render_tmpl( tmpl_obj=tmpl_obj, tmpl_str_in=tmpl_str_in, fail_missing=fail_missing, f90_bool=f90_bool, warn=warn, ) with open(tmpl_path, "w", encoding="utf-8") as file: for item in tmpl_str_out.split("\n"): file.write(f"{item.strip()}\n")