from pathlib import Path from typing import Any, Callable, Optional, TYPE_CHECKING try: import jinja2 except ImportError: jinja2 = None if TYPE_CHECKING: _JinjaEnv = jinja2.Environment else: _JinjaEnv = object def is_jinja_installed() -> bool: return jinja2 is not None def verify_jinja() -> None: if not is_jinja_installed(): raise RuntimeError('Python module Jinja2 is not installed.') def make_env(filters: Optional[dict[str, Callable]] = None, tests: Optional[dict[str, Callable[[Any], bool]]] = None, environment: Optional[dict[str, Any]] = None, templates_path: Optional[Path] = None) -> _JinjaEnv: if templates_path is None: templates_path = (Path(__file__).parent.parent / 'templates').absolute() jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path)) if filters is not None: jinja_env.filters.update(filters) if tests is not None: jinja_env.tests.update(tests) if environment is not None: jinja_env.globals.update(environment) return jinja_env def generate_file(template_name: str, target: Path, context: dict[str, Any], **kwargs) -> None: jinja_env = make_env(**kwargs) template = jinja_env.get_template(template_name) result = template.render(**context) target.parent.mkdir(parents=True, exist_ok=True) with target.open('w') as f: f.write(result) def render_string(input: str, context: dict[str, Any], **kwargs) -> str: jinja_env = make_env(**kwargs) template = jinja_env.from_string(input) return template.render(**context)