Source code for pypreset.template_engine

"""Template engine for rendering project files."""

import logging
from pathlib import Path
from typing import Any

from jinja2 import Environment, FileSystemLoader, select_autoescape

from pypreset.docker_utils import resolve_docker_base_image as _resolve_base_image
from pypreset.models import ProjectConfig

logger = logging.getLogger(__name__)


[docs] def get_templates_dir() -> Path: """Get the directory containing built-in templates.""" return Path(__file__).parent / "templates"
[docs] def create_jinja_environment() -> Environment: """Create a Jinja2 environment with the templates directory.""" templates_dir = get_templates_dir() return Environment( loader=FileSystemLoader(templates_dir), autoescape=select_autoescape(["html", "xml"]), trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True, )
[docs] def get_template_context(config: ProjectConfig) -> dict[str, Any]: """Build the template context from a project configuration.""" # Convert package name to module name (replace hyphens with underscores) package_name = config.metadata.name.replace("-", "_") return { "project": { "name": config.metadata.name, "package_name": package_name, "version": config.metadata.version, "description": config.metadata.description, "authors": config.metadata.authors, "license": config.metadata.license, "readme": config.metadata.readme, "python_version": config.metadata.python_version, "keywords": config.metadata.keywords, "classifiers": config.metadata.classifiers, "repository_url": config.metadata.repository_url, "homepage_url": config.metadata.homepage_url, "documentation_url": config.metadata.documentation_url, "bug_tracker_url": config.metadata.bug_tracker_url, }, "dependencies": { "main": config.dependencies.main, "dev": config.dependencies.dev, "optional": config.dependencies.optional, }, "testing": { "enabled": config.testing.enabled, "framework": config.testing.framework.value, "coverage": config.testing.coverage_config.enabled, "coverage_config": { "enabled": config.testing.coverage_config.enabled, "tool": config.testing.coverage_config.tool.value, "threshold": config.testing.coverage_config.threshold, "ignore_patterns": config.testing.coverage_config.ignore_patterns, }, }, "formatting": { "enabled": config.formatting.enabled, "tool": config.formatting.tool.value, "line_length": config.formatting.line_length, "radon": config.formatting.radon, "pre_commit": config.formatting.pre_commit, "version_bumping": config.formatting.version_bumping, "type_checker": config.formatting.type_checker.value, "version_sync_guard": config.formatting.version_sync_guard, }, "dependabot": { "enabled": config.dependabot.enabled, "schedule": config.dependabot.schedule, "open_pull_requests_limit": config.dependabot.open_pull_requests_limit, }, "docker": { "enabled": config.docker.enabled, "base_image": _resolve_base_image( config.metadata.python_version, config.docker.base_image ), "devcontainer": config.docker.devcontainer, "container_runtime": config.docker.container_runtime.value, }, "documentation": { "enabled": config.documentation.enabled, "tool": config.documentation.tool.value, "deploy_gh_pages": config.documentation.deploy_gh_pages, }, "tox": { "enabled": config.tox.enabled, }, "typing_level": config.typing_level.value, "layout": config.layout.value, "package_manager": config.package_manager.value, "pyenv": config.pyenv, "entry_points": [{"name": ep.name, "module": ep.module} for ep in config.entry_points], "extras": config.extras, }
[docs] def render_template(env: Environment, template_name: str, context: dict[str, Any]) -> str: """Render a template with the given context.""" template = env.get_template(template_name) return template.render(**context)
[docs] def render_content(content: str, context: dict[str, Any]) -> str: """Render inline content (not from a template file).""" env = Environment( trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True, ) template = env.from_string(content) return template.render(**context)
[docs] def render_path(path_template: str, context: dict[str, Any]) -> str: """Render a path template (e.g., 'src/{{ project.package_name }}').""" env = Environment() template = env.from_string(path_template) return template.render(**context)