Source code for hbutils.string.template

"""
String template utilities with environment-like substitution.

This module provides utilities to perform string templating using a mapping
of values that behave similarly to environment variables. It supports both
strict and safe substitution modes and allows supplying a default value for
missing keys.

The module exposes the following public API:

* :func:`env_template` - Apply template substitution using a mapping

.. note::
   This module does not read from system environment variables. The mapping
   must be provided explicitly.

Example::

    >>> from hbutils.string.template import env_template
    >>> env_template('${A} + 1 = ${B}', {'A': '1', 'B': '2'})
    '1 + 1 = 2'
    >>> env_template('${A} + 1 = ${B}', {'A': '1'}, safe=True)
    '1 + 1 = ${B}'
    >>> env_template('${A} + 1 = ${B}', {'A': '1'}, default='')
    '1 + 1 = '

"""
from string import Template
from typing import Optional, Mapping, Any

from ..design import SingletonMark

__all__ = [
    'env_template'
]

_NO_DEFAULT_VALUE = SingletonMark('_NO_DEFAULT_VALUE')


[docs] def env_template(template: str, environ: Optional[Mapping[str, Any]] = None, safe: bool = False, default: Any = _NO_DEFAULT_VALUE) -> str: """ Map values from a provided mapping into a template string. This function substitutes variables in a template string with values from ``environ``. It supports strict substitution (raising on missing keys) and safe substitution (leaving missing keys unchanged). A default value may be provided to substitute for missing keys even in strict mode. :param template: Template string containing variables in ``${VAR}`` format. :type template: str :param environ: Mapping for variable substitution. If ``None``, an empty mapping is used. :type environ: Optional[Mapping[str, Any]] :param safe: Whether to use safe substitution. If ``True``, missing variables are left as-is. If ``False``, missing variables raise :class:`KeyError` unless a default is provided. Defaults to ``False``. :type safe: bool :param default: Default value to use when a variable is not found in ``environ``. If set to ``_NO_DEFAULT_VALUE`` (the default), missing variables raise :class:`KeyError` when ``safe`` is ``False``. :type default: Any :return: Substituted string with variables replaced by their values. :rtype: str :raises KeyError: If a variable is not found in ``environ`` and ``safe`` is ``False`` and no default is provided. Example:: >>> from hbutils.string.template import env_template >>> env_template('${A} + 1 = ${B}', {'A': '1', 'B': '2'}) '1 + 1 = 2' >>> env_template('${A} + 1 = ${B}', {'A': '1'}) Traceback (most recent call last): ... KeyError: 'B' >>> env_template('${A} + 1 = ${B}', {'A': '1'}, safe=True) '1 + 1 = ${B}' >>> env_template('${A} + 1 = ${B}', {'A': '1'}, default='') '1 + 1 = ' """ class _DefaultDict(dict): """ Internal dictionary class that returns a default value for missing keys. This class extends :class:`dict` to provide a fixed default value when a key is not found. It is used internally to emulate environment-like default values during template substitution. """ def __getitem__(self, item: Any) -> Any: """ Get a value for the key, returning the default when missing. :param item: The key to look up in the dictionary. :type item: Any :return: The value for the key, or the provided default when the key is not present. :rtype: Any """ return dict.get(self, item, default) _template = Template(template) env = environ or {} if default is not _NO_DEFAULT_VALUE: env = _DefaultDict(env) _func = _template.safe_substitute if safe else _template.substitute # noinspection PyArgumentList return _func(env)