Source code for eds4jinja2.builders.report_builder
#!/usr/bin/python3
# report_generator
# Created: 08/03/2019
# Author: Laurentiu Mandru
# Email: mclaurentiu79@gmail.com
"""
this module implements the report generation functionality.
"""
import json
import pathlib
from typing import Union
import jinja2
from eds4jinja2.adapters import deep_update
from eds4jinja2.builders.jinja_builder import build_eds_environment, inject_environment_globals
# aims to be close to the J2 default env syntax definition, but explicitly specified
HTML_TEMPLATE_SYNTAX = {'block_start_string': '{%',
'block_end_string': '%}',
'variable_start_string': '{{',
'variable_end_string': '}}',
'comment_start_string': '{#',
'comment_end_string': '#}',
'line_statement_prefix': '#',
'line_comment_prefix': '##',
'trim_blocks': False, }
# do not change anything
DEFAULT_TEMPLATE_SYNTAX = {}
######################################################################
# Jinja2 Environment ARGS
# Constant borrowed from Marc Brinkmann's latex repository (mbr/latex on github)
# Reused also by Samuel Roeca's in his latex repository (pappasam/latexbuild on github)
######################################################################
LATEX_TEMPLATE_SYNTAX = {'block_start_string': r'\BLOCK{',
'block_end_string': '}',
'variable_start_string': r'\VAR{',
'variable_end_string': '}',
'comment_start_string': r'\#{',
'comment_end_string': '}',
'line_statement_prefix': '%-',
'line_comment_prefix': '%#',
'trim_blocks': True,
'autoescape': False, }
[docs]class ReportBuilder:
"""
generic report builder that takes templates and configuration as input and produces an output report
"""
configuration_context: dict = {}
def __init__(self, target_path: Union[str, pathlib.Path], config_file: str = "config.json",
output_path: str = None, additional_config: dict = {}):
"""
Instantiates builders form a template providing an optional configuration context.
:type additional_config: additional config parameters that are added to the default
ones be overwritten (deep update) in the project config.json
:param target_path: the folder where the required resources are found
:param config_file: the configuration file (default 'config.json')
:param output_path: the output folder where the result of the rendering will be created
"""
with open(pathlib.Path(target_path) / config_file, encoding='utf-8') as configFile:
self.configuration_context = json.loads(configFile.read())
deep_update(self.configuration_context, additional_config)
template_path = str(pathlib.Path(target_path) / "templates")
static_folder = pathlib.Path(target_path) / "static"
if output_path is not None:
output_folder = pathlib.Path(output_path)
else:
# in case you don't specify an output, the rendered content will be placed
# in the target folder, in an default directory named "output"
# this is to prevent creating files wherever you happen to run the CLI
output_folder = pathlib.Path(target_path) / "output"
self.configuration_context["template_path"] = template_path
self.configuration_context["static_folder"] = str(static_folder)
self.configuration_context["output_folder"] = str(output_folder)
self.configuration_context["conf"]["template_path"] = template_path
self.template = self.configuration_context["template"]
# Provides a configuration of the templating syntax flavour. By default it is configured
# for HTML but could be adapted as necessary. For LaTex, LATEX_TEMPLATE_SYNTAX is available.
# TODO: this code might need to be externalised in the next refactoring
if "template_flavour_syntax" in self.configuration_context:
if str.lower(self.configuration_context["template_flavour_syntax"]) in ("latex", "tex"):
self.template_flavour_syntax_spec = LATEX_TEMPLATE_SYNTAX
elif str.lower(self.configuration_context["template_flavour_syntax"]) in ("xml", "html", "xhtml"):
self.template_flavour_syntax_spec = HTML_TEMPLATE_SYNTAX
else:
self.template_flavour_syntax_spec = DEFAULT_TEMPLATE_SYNTAX
else:
self.template_flavour_syntax_spec = DEFAULT_TEMPLATE_SYNTAX
template_loader = jinja2.FileSystemLoader(searchpath=template_path)
self.template_env = build_eds_environment(loader=template_loader, **self.template_flavour_syntax_spec)
inject_environment_globals(self.template_env, {'conf': self.configuration_context["conf"]},
False if self.configuration_context is None else True)
self.__before_rendering_listeners = []
self.__after_rendering_listeners = []
[docs] def add_before_rendering_listener(self, listener):
"""
At the moment there is no use for this.
"""
self.__before_rendering_listeners.append(listener)
[docs] def add_after_rendering_listener(self, listener):
"""
At the moment, this is used just to copy static files to the output directory.
For example, CSS, JavaScript and other static resources.
"""
self.__after_rendering_listeners.append(listener)
def __get_template(self, template_name=None) -> jinja2.Template:
"""
Standard JINJA2 get_template() functionality.
:param template_name:
:return:
"""
if not template_name:
return self.template_env.get_template(self.template)
else:
return self.template_env.get_template(template_name)
[docs] def make_document(self):
for listener in self.__before_rendering_listeners:
listener(self.configuration_context)
template = self.__get_template(self.template)
pathlib.Path(self.configuration_context["output_folder"]).mkdir(parents=True, exist_ok=True)
template.stream().dump(str(pathlib.Path(self.configuration_context["output_folder"]) / self.template))
for listener in self.__after_rendering_listeners:
listener(self.configuration_context)