Source code for testplan.common.utils.context

"""TODO."""
import warnings
from typing import Union, Dict

from testplan.vendor.tempita import Template as TempitaTemplate
from jinja2 import Template


[docs]def parse_template(template: str) -> Union[TempitaTemplate, Template]: tempita_failed = False parsed_template = None try: parsed_template = Template(template) except Exception: try: # Jinja failed try with tempita parsed_template = TempitaTemplate(template) except Exception: tempita_failed = True else: tempita_warning = f"The template: '{template}' is not a valid Jinja2 template. Falling back to Tempita. Tempita will be decommisioned soon, please update your template." warnings.warn(tempita_warning, FutureWarning) pass finally: if tempita_failed: # raise the original jinja exception so user will fix it for jinja raise return parsed_template
[docs]class ContextValue: """ A context value represents a combination of a driver name and a Jinja2 template, to be resolved on driver start. """ def __init__(self, driver: str, value: str): """ Create a new context value """ self.driver = driver self.value = value self.template = parse_template(value) def __str__(self): return f"context('{self.driver}', '{self.value}')" def __call__(self, ctx): """ Resolve the template. """ if ctx is None: raise ValueError( f'Could not retrieve driver "{self.driver}" value' " from NoneType context." ) if self.driver not in ctx: raise RuntimeError( f'Driver "{self.driver}" is not present in context.' ) return render(self.template, ctx[self.driver].context_input())
[docs]def context(driver, value): """ Create a context extractor from a driver name and a value expression. Value expressions must be valid Jinja2 templates, which will be resolved from the context. """ return ContextValue(driver, value)
[docs]def is_context(value): """ Checks if a value is a context value :param value: Value which may have been constructed through `context` :type value: ``object`` :return: True if it is a context value, otherwise False :rtype: ``bool`` """ return isinstance(value, ContextValue)
[docs]def expand(value, contextobj, constructor=None): """ Take a value and a context and return the expanded result. Apply a constructor if necessary. """ if is_context(value): expanded_value = value(contextobj) if constructor: expanded_value = constructor(expanded_value) return expanded_value else: return value
[docs]def render(template: Union[Template, TempitaTemplate, str], context) -> str: """ Renders the template with the given context, that used for expression resolution. :param template: A template in str, Jinja2 or Tempita form that will be rendered with the context :type template: Union[Template, TempitaTemplate, str] :param context: The context object which is the base context of the template expansion :return: The rendered template :rtype: str """ if isinstance(template, str): template = parse_template(template) return ( template.substitute(context) if isinstance(template, TempitaTemplate) else template.render(context) )