Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
meta.py113 linesDownload Raw Back to jinja2
1"""Functions that expose information about templates that might be2interesting for introspection.3"""4 5import typing as t6 7from . import nodes8from .compiler import CodeGenerator9from .compiler import Frame10 11if t.TYPE_CHECKING:12    from .environment import Environment13 14 15class TrackingCodeGenerator(CodeGenerator):16    """We abuse the code generator for introspection."""17 18    def __init__(self, environment: "Environment") -> None:19        super().__init__(environment, "<introspection>", "<introspection>")20        self.undeclared_identifiers: t.Set[str] = set()21 22    def write(self, x: str) -> None:23        """Don't write."""24 25    def enter_frame(self, frame: Frame) -> None:26        """Remember all undeclared identifiers."""27        super().enter_frame(frame)28 29        for _, (action, param) in frame.symbols.loads.items():30            if action == "resolve" and param not in self.environment.globals:31                self.undeclared_identifiers.add(param)32 33 34def find_undeclared_variables(ast: nodes.Template) -> t.Set[str]:35    """Returns a set of all variables in the AST that will be looked up from36    the context at runtime.  Because at compile time it's not known which37    variables will be used depending on the path the execution takes at38    runtime, all variables are returned.39 40    >>> from jinja2 import Environment, meta41    >>> env = Environment()42    >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')43    >>> meta.find_undeclared_variables(ast) == {'bar'}44    True45 46    .. admonition:: Implementation47 48       Internally the code generator is used for finding undeclared variables.49       This is good to know because the code generator might raise a50       :exc:`TemplateAssertionError` during compilation and as a matter of51       fact this function can currently raise that exception as well.52    """53    codegen = TrackingCodeGenerator(ast.environment)  # type: ignore54    codegen.visit(ast)55    return codegen.undeclared_identifiers56 57 58_ref_types = (nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include)59_RefType = t.Union[nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include]60 61 62def find_referenced_templates(ast: nodes.Template) -> t.Iterator[t.Optional[str]]:63    """Finds all the referenced templates from the AST.  This will return an64    iterator over all the hardcoded template extensions, inclusions and65    imports.  If dynamic inheritance or inclusion is used, `None` will be66    yielded.67 68    >>> from jinja2 import Environment, meta69    >>> env = Environment()70    >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')71    >>> list(meta.find_referenced_templates(ast))72    ['layout.html', None]73 74    This function is useful for dependency tracking.  For example if you want75    to rebuild parts of the website after a layout template has changed.76    """77    template_name: t.Any78 79    for node in ast.find_all(_ref_types):80        template: nodes.Expr = node.template  # type: ignore81 82        if not isinstance(template, nodes.Const):83            # a tuple with some non consts in there84            if isinstance(template, (nodes.Tuple, nodes.List)):85                for template_name in template.items:86                    # something const, only yield the strings and ignore87                    # non-string consts that really just make no sense88                    if isinstance(template_name, nodes.Const):89                        if isinstance(template_name.value, str):90                            yield template_name.value91                    # something dynamic in there92                    else:93                        yield None94            # something dynamic we don't know about here95            else:96                yield None97            continue98        # constant is a basestring, direct template name99        if isinstance(template.value, str):100            yield template.value101        # a tuple or list (latter *should* not happen) made of consts,102        # yield the consts that are strings.  We could warn here for103        # non string values104        elif isinstance(node, nodes.Include) and isinstance(105            template.value, (tuple, list)106        ):107            for template_name in template.value:108                if isinstance(template_name, str):109                    yield template_name110        # something else we don't care about, we could warn here111        else:112            yield None113 
codekingpro/portable-devtools · Team Ai