Source code for colander_data_converter.exporters.template

  1import os
  2from typing import TextIO, Sequence
  3
  4from jinja2 import FileSystemLoader, Template
  5from jinja2.sandbox import SandboxedEnvironment
  6
  7from colander_data_converter.base.models import ColanderFeed
  8from colander_data_converter.exporters.exporter import BaseExporter
  9
 10
[docs] 11class TemplateExporter(BaseExporter): 12 """ 13 Template-based exporter using Jinja2_ templating engine. 14 15 This exporter allows for flexible data export by using Jinja2_ templates to format 16 the output. It supports both file-based templates loaded from the filesystem and 17 pre-compiled :py:obj:`~jinja2.Template` object. The implementation uses a sandboxed environment 18 for security when processing templates. 19 20 The exporter streams the template output, making it memory-efficient for large 21 datasets by processing data in chunks rather than loading everything into memory. 22 23 .. _Jinja2: https://jinja.palletsprojects.com/ 24 25 """ 26
[docs] 27 def __init__( 28 self, 29 feed: ColanderFeed, 30 template_search_path: str | os.PathLike[str] | Sequence[str | os.PathLike[str]], 31 template_name: str, 32 template: Template = None, 33 **loader_options, 34 ): 35 """ 36 Initialize the TemplateExporter with feed data and template configuration. 37 38 This constructor sets up the Jinja2 templating environment and loads the specified 39 template. If a pre-compiled :py:obj:`~jinja2.Template` object is provided, it will be used directly. 40 Otherwise, the template will be loaded from the filesystem using the provided 41 search path and template name. 42 43 Args: 44 feed (~colander_data_converter.base.models.ColanderFeed): The data feed containing entities to 45 be exported. This feed will be passed to the template as the :py:obj:`feed` variable. 46 template_search_path (str | os.PathLike[str] | Sequence[str | os.PathLike[str]]): 47 Path or sequence of paths where template files are located. Can be a single 48 path string, PathLike object, or sequence of paths for multiple search locations. 49 template_name (str): The name of the template file to load from the search path. 50 Should include the file extension (e.g., "template.j2", "export.html"). 51 template (~jinja2.Template): A pre-compiled Jinja2 Template object. If provided, 52 :py:obj:`template_search_path` and :py:obj:`template_name` are ignored. Defaults to None. 53 **loader_options: Additional keyword arguments passed to the :py:obj:`~jinja2.FileSystemLoader`. 54 55 Note: 56 The exporter uses a :py:obj:`~jinja2.sandbox.SandboxedEnvironment` for security, which restricts 57 access to potentially dangerous operations in templates. Auto-reload is 58 enabled by default for development convenience. 59 60 Warning: 61 When a pre-compiled Template object is provided via the :py:obj:`template` parameter, 62 it will NOT be executed in a sandboxed environment. This means the template 63 can access all Python built-ins and potentially execute dangerous operations. 64 Only use trusted templates when providing pre-compiled Template objects. 65 """ 66 self.feed = feed 67 self.template = template 68 if not self.template: 69 self.template_search_path = template_search_path 70 self.template_name = template_name 71 self.loader = FileSystemLoader(self.template_search_path, **loader_options) 72 self.environment = SandboxedEnvironment(loader=self.loader, auto_reload=True) 73 self.template: Template = self.environment.get_template(self.template_name)
74
[docs] 75 def export(self, output: TextIO, **kwargs): 76 """ 77 Export data by rendering the template and writing output to the provided stream. 78 79 This method uses Jinja2's streaming to render the template in chunks, 80 making it memory-efficient for large datasets. The feed data is passed to the 81 template as the 'feed' variable, and any additional keyword arguments are also 82 made available as template variables. 83 84 Args: 85 output (io.TextIO): A text-based output stream where the rendered template 86 will be written. This can be a file object, StringIO, 87 or any object implementing the TextIO interface. 88 **kwargs: Additional keyword arguments that will be passed as variables 89 to the template context. These can be used within the template 90 to customize the output or provide additional data. 91 92 Raises: 93 :py:obj:`jinja2.TemplateError`: If there are errors in template syntax or rendering 94 :py:obj:`jinja2.TemplateNotFound`: If the specified template file cannot be found 95 IOError: If there are issues writing to the output stream 96 97 Warning: 98 If this exporter was initialized with a pre-compiled Template object, 99 the template will NOT execute in a sandboxed environment and may have 100 access to dangerous Python operations. Ensure only trusted templates 101 are used in such cases. 102 """ 103 for chunk in self.template.stream(feed=self.feed, **kwargs): 104 output.write(chunk)