Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
Toggle table of contents sidebar

# Source code for betty.render

    """
    Provide the Render API.
    """

    from abc import ABC, abstractmethod
    from pathlib import Path
    from typing import final

    from typing_extensions import override

    from betty.locale.localizer import Localizer
    from betty.job import Context

    class Renderer(ABC):
        """
        Define a (file) content renderer.

        Renderers can be implemented for a variety of purposes:
        - invoking templating engines
        - file conversions
        """

        @property
        @abstractmethod
        def file_extensions(self) -> set[str]:
            """
            The extensions of the files this renderer can render.
            """
            pass

        @abstractmethod
        async def render_file(
            self,
            file_path: Path,
            *,
            job_context: Context | None = None,
            localizer: Localizer | None = None,
        ) -> Path:
            """
            Render a single file.

            :return: The file's new path, which may have been changed, e.g. a
                renderer-specific extension may have been stripped from the end.
            """
            pass

    @final
    class SequentialRenderer(Renderer):
        """
        Render using a sequence of other renderers.
        """

        def __init__(self, renderers: list[Renderer]):
            self._renderers = renderers
            self._file_extensions = {
                file_extension
                for renderer in self._renderers
                for file_extension in renderer.file_extensions
            }

        @override
        @property
        def file_extensions(self) -> set[str]:
            return self._file_extensions

        @override
        async def render_file(
            self,
            file_path: Path,
            *,
            job_context: Context | None = None,
            localizer: Localizer | None = None,
        ) -> Path:
            for renderer in self._renderers:
                if file_path.suffix in renderer.file_extensions:
                    return await self.render_file(
                        await renderer.render_file(
                            file_path,
                            job_context=job_context,
                            localizer=localizer,
                        )
                    )
            return file_path