Source code for as3ninja.declaration

# -*- coding: utf-8 -*-
"""
The AS3Declaration module. Represents an AS3 Declaration as a python class.
"""

# pylint: disable=C0330 # Wrong hanging indentation before block
# pylint: disable=C0301 # Line too long

import json
from typing import Dict, Optional

from jinja2 import (
    ChoiceLoader,
    DictLoader,
    Environment,
    FileSystemLoader,
    StrictUndefined,
)
from jinja2.exceptions import TemplateSyntaxError, UndefinedError

from .exceptions import AS3JSONDecodeError, AS3TemplateSyntaxError, AS3UndefinedError
from .jinja2 import J2Ninja

__all__ = ["AS3Declaration"]


[docs]class AS3Declaration: """Creates an AS3Declaration instance representing the AS3 declaration. The AS3 declaration is created using the given template configuration, which can be either a dict or list of dicts. If a list is provided, the member dicts will be merged using :py:meth:`_dict_deep_update`. Optionally a jinja2 declaration_template can be provided, otherwise it is read from the configuration. The template file reference is expected to be at `as3ninja.declaration_template` within the configuration. An explicitly specified declaration_template takes precedence over any included template. :param template_configuration: AS3 Template Configuration as ``dict`` or ``list`` :param declaration_template: Optional Declaration Template as ``str`` (Default value = ````) :param jinja2_searchpath: The jinja2 search path for the FileSystemLoader. Important for jinja2 includes. (Default value = ``"."``) """ def __init__( self, template_configuration: Dict, declaration_template: Optional[str] = None, jinja2_searchpath: str = ".", ): self._template_configuration = template_configuration self._declaration_template = declaration_template or "" self._jinja2_searchpath = jinja2_searchpath if not self._declaration_template: try: declaration_template_file = self._template_configuration["as3ninja"][ "declaration_template" ] with open( f"{self._jinja2_searchpath}/{declaration_template_file}", "r" ) as declaration_template_file_fh: self._declaration_template = declaration_template_file_fh.read() except (KeyError, TypeError) as exc: raise KeyError( f"as3ninja.declaration_template not valid or missing in template_configuration: {exc}" ) self._transform()
[docs] def dict(self) -> dict: """Returns the AS3 Declaration.""" return self._declaration
[docs] def json(self) -> str: """Returns the AS3 Declaration as JSON.""" return self._declaration_json
@property def declaration_template(self) -> str: """Property contains the declaration template loaded or provided during instantiation""" return self._declaration_template
[docs] def _jinja2_render(self) -> str: """Renders the declaration using jinja2. Raises relevant exceptions which need to be handled by the caller. """ env = Environment( # nosec (bandit: autoescaping is not helpful for as3ninja's use-case) loader=ChoiceLoader( [ DictLoader({"template": self.declaration_template}), FileSystemLoader(searchpath=self._jinja2_searchpath), ] ), trim_blocks=False, lstrip_blocks=False, keep_trailing_newline=True, undefined=StrictUndefined, autoescape=False, ) env.globals["jinja2_searchpath"] = self._jinja2_searchpath + "/" env.globals["ninja"] = self._template_configuration env.globals.update(J2Ninja.functions) env.filters.update(J2Ninja.filters) env.tests.update(J2Ninja.tests) return env.get_template("template").render()
[docs] def _transform(self) -> None: """Transforms the declaration_template using the template_configuration to an AS3 declaration. On error raises: - AS3TemplateSyntaxError on jinja2 template syntax errors - AS3UndefinedError for undefined variables in the declaration template - AS3JSONDecodeError in case the rendered declaration is not valid JSON """ try: declaration = self._jinja2_render() self._declaration = json.loads(declaration) # remove $schema as AS3 currently fails to install declarattion when present # https://github.com/F5Networks/f5-appsvcs-extension/issues/173 try: del self._declaration["$schema"] except (KeyError, TypeError): pass # ignore missing $schema self._declaration_json = json.dumps( self._declaration ) # properly formats JSON except TemplateSyntaxError as exc: raise AS3TemplateSyntaxError( "AS3 declaration template caused jinja2 syntax error", self.declaration_template, exc, ) except UndefinedError as exc: raise AS3UndefinedError( "AS3 declaration template tried to operate on an Undefined variable, attribute or type", exc, ) except json.decoder.JSONDecodeError as exc: raise AS3JSONDecodeError("JSONDecodeError", exc)