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_source: str = 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: 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: Path or sequence of paths where template files are located. Can be a single 47 path string, PathLike object, or sequence of paths for multiple search locations. 48 template_name: The name of the template file to load from the search path. 49 Should include the file extension (e.g., "template.j2", "export.html"). 50 template_source: The source code of the Jinja2 template. If provided, 51 :py:obj:`template_search_path` and :py:obj:`template_name` are ignored. Defaults to None. 52 **loader_options: Additional keyword arguments passed to the :py:obj:`~jinja2.FileSystemLoader`. 53 54 Note: 55 The exporter uses a :py:obj:`~jinja2.sandbox.SandboxedEnvironment` for security, which restricts 56 access to potentially dangerous operations in templates. Auto-reload is 57 enabled by default for development convenience. 58 """ 59 self.feed = feed 60 self.template_search_path = template_search_path 61 self.template_name = template_name 62 if template_source: 63 self.environment = SandboxedEnvironment() 64 self.template = self.environment.from_string(template_source) 65 else: 66 self.loader = FileSystemLoader(self.template_search_path, **loader_options) 67 self.environment = SandboxedEnvironment(loader=self.loader, auto_reload=True) 68 self.template: Template = self.environment.get_template(self.template_name)
69
[docs] 70 def export(self, output: TextIO, **kwargs): 71 """ 72 Export data by rendering the template and writing output to the provided stream. 73 74 This method uses Jinja2's streaming to render the template in chunks, 75 making it memory-efficient for large datasets. The feed data is passed to the 76 template as the 'feed' variable, and any additional keyword arguments are also 77 made available as template variables. 78 79 Args: 80 output: A text-based output stream where the rendered template 81 will be written. This can be a file object, StringIO, 82 or any object implementing the TextIO interface. 83 **kwargs: Additional keyword arguments that will be passed as variables 84 to the template context. These can be used within the template 85 to customize the output or provide additional data. 86 87 Raises: 88 ~jinja2.TemplateError: If there are errors in template syntax or rendering 89 ~jinja2.TemplateNotFound: If the specified template file cannot be found 90 IOError: If there are issues writing to the output stream 91 """ 92 for chunk in self.template.stream(feed=self.feed, **kwargs): 93 output.write(chunk)