Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
templating.py221 linesDownload Raw Back to flask
1from __future__ import annotations2 3import typing as t4 5from jinja2 import BaseLoader6from jinja2 import Environment as BaseEnvironment7from jinja2 import Template8from jinja2 import TemplateNotFound9 10from .globals import _cv_app11from .globals import _cv_request12from .globals import current_app13from .globals import request14from .helpers import stream_with_context15from .signals import before_render_template16from .signals import template_rendered17 18if t.TYPE_CHECKING:  # pragma: no cover19    from .app import Flask20    from .sansio.app import App21    from .sansio.scaffold import Scaffold22 23 24def _default_template_ctx_processor() -> dict[str, t.Any]:25    """Default template context processor.  Replaces the ``request`` and ``g``26    proxies with their concrete objects for faster access.27    """28    appctx = _cv_app.get(None)29    reqctx = _cv_request.get(None)30    rv: dict[str, t.Any] = {}31    if appctx is not None:32        rv["g"] = appctx.g33    if reqctx is not None:34        rv["request"] = reqctx.request35        # The session proxy cannot be replaced, accessing it gets36        # RequestContext.session, which sets session.accessed.37    return rv38 39 40class Environment(BaseEnvironment):41    """Works like a regular Jinja environment but has some additional42    knowledge of how Flask's blueprint works so that it can prepend the43    name of the blueprint to referenced templates if necessary.44    """45 46    def __init__(self, app: App, **options: t.Any) -> None:47        if "loader" not in options:48            options["loader"] = app.create_global_jinja_loader()49        BaseEnvironment.__init__(self, **options)50        self.app = app51 52 53class DispatchingJinjaLoader(BaseLoader):54    """A loader that looks for templates in the application and all55    the blueprint folders.56    """57 58    def __init__(self, app: App) -> None:59        self.app = app60 61    def get_source(62        self, environment: BaseEnvironment, template: str63    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:64        if self.app.config["EXPLAIN_TEMPLATE_LOADING"]:65            return self._get_source_explained(environment, template)66        return self._get_source_fast(environment, template)67 68    def _get_source_explained(69        self, environment: BaseEnvironment, template: str70    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:71        attempts = []72        rv: tuple[str, str | None, t.Callable[[], bool] | None] | None73        trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None74 75        for srcobj, loader in self._iter_loaders(template):76            try:77                rv = loader.get_source(environment, template)78                if trv is None:79                    trv = rv80            except TemplateNotFound:81                rv = None82            attempts.append((loader, srcobj, rv))83 84        from .debughelpers import explain_template_loading_attempts85 86        explain_template_loading_attempts(self.app, template, attempts)87 88        if trv is not None:89            return trv90        raise TemplateNotFound(template)91 92    def _get_source_fast(93        self, environment: BaseEnvironment, template: str94    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:95        for _srcobj, loader in self._iter_loaders(template):96            try:97                return loader.get_source(environment, template)98            except TemplateNotFound:99                continue100        raise TemplateNotFound(template)101 102    def _iter_loaders(self, template: str) -> t.Iterator[tuple[Scaffold, BaseLoader]]:103        loader = self.app.jinja_loader104        if loader is not None:105            yield self.app, loader106 107        for blueprint in self.app.iter_blueprints():108            loader = blueprint.jinja_loader109            if loader is not None:110                yield blueprint, loader111 112    def list_templates(self) -> list[str]:113        result = set()114        loader = self.app.jinja_loader115        if loader is not None:116            result.update(loader.list_templates())117 118        for blueprint in self.app.iter_blueprints():119            loader = blueprint.jinja_loader120            if loader is not None:121                for template in loader.list_templates():122                    result.add(template)123 124        return list(result)125 126 127def _render(app: Flask, template: Template, context: dict[str, t.Any]) -> str:128    app.update_template_context(context)129    before_render_template.send(130        app, _async_wrapper=app.ensure_sync, template=template, context=context131    )132    rv = template.render(context)133    template_rendered.send(134        app, _async_wrapper=app.ensure_sync, template=template, context=context135    )136    return rv137 138 139def render_template(140    template_name_or_list: str | Template | list[str | Template],141    **context: t.Any,142) -> str:143    """Render a template by name with the given context.144 145    :param template_name_or_list: The name of the template to render. If146        a list is given, the first name to exist will be rendered.147    :param context: The variables to make available in the template.148    """149    app = current_app._get_current_object()  # type: ignore[attr-defined]150    template = app.jinja_env.get_or_select_template(template_name_or_list)151    return _render(app, template, context)152 153 154def render_template_string(source: str, **context: t.Any) -> str:155    """Render a template from the given source string with the given156    context.157 158    :param source: The source code of the template to render.159    :param context: The variables to make available in the template.160    """161    app = current_app._get_current_object()  # type: ignore[attr-defined]162    template = app.jinja_env.from_string(source)163    return _render(app, template, context)164 165 166def _stream(167    app: Flask, template: Template, context: dict[str, t.Any]168) -> t.Iterator[str]:169    app.update_template_context(context)170    before_render_template.send(171        app, _async_wrapper=app.ensure_sync, template=template, context=context172    )173 174    def generate() -> t.Iterator[str]:175        yield from template.generate(context)176        template_rendered.send(177            app, _async_wrapper=app.ensure_sync, template=template, context=context178        )179 180    rv = generate()181 182    # If a request context is active, keep it while generating.183    if request:184        rv = stream_with_context(rv)185 186    return rv187 188 189def stream_template(190    template_name_or_list: str | Template | list[str | Template],191    **context: t.Any,192) -> t.Iterator[str]:193    """Render a template by name with the given context as a stream.194    This returns an iterator of strings, which can be used as a195    streaming response from a view.196 197    :param template_name_or_list: The name of the template to render. If198        a list is given, the first name to exist will be rendered.199    :param context: The variables to make available in the template.200 201    .. versionadded:: 2.2202    """203    app = current_app._get_current_object()  # type: ignore[attr-defined]204    template = app.jinja_env.get_or_select_template(template_name_or_list)205    return _stream(app, template, context)206 207 208def stream_template_string(source: str, **context: t.Any) -> t.Iterator[str]:209    """Render a template from the given source string with the given210    context as a stream. This returns an iterator of strings, which can211    be used as a streaming response from a view.212 213    :param source: The source code of the template to render.214    :param context: The variables to make available in the template.215 216    .. versionadded:: 2.2217    """218    app = current_app._get_current_object()  # type: ignore[attr-defined]219    template = app.jinja_env.from_string(source)220    return _stream(app, template, context)221 
codekingpro/portable-devtools · Team Ai