Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
debug.py192 linesDownload Raw Back to jinja2
1import sys2import typing as t3from types import CodeType4from types import TracebackType5 6from .exceptions import TemplateSyntaxError7from .utils import internal_code8from .utils import missing9 10if t.TYPE_CHECKING:11    from .runtime import Context12 13 14def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException:15    """Rewrite the current exception to replace any tracebacks from16    within compiled template code with tracebacks that look like they17    came from the template source.18 19    This must be called within an ``except`` block.20 21    :param source: For ``TemplateSyntaxError``, the original source if22        known.23    :return: The original exception with the rewritten traceback.24    """25    _, exc_value, tb = sys.exc_info()26    exc_value = t.cast(BaseException, exc_value)27    tb = t.cast(TracebackType, tb)28 29    if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated:30        exc_value.translated = True31        exc_value.source = source32        # Remove the old traceback, otherwise the frames from the33        # compiler still show up.34        exc_value.with_traceback(None)35        # Outside of runtime, so the frame isn't executing template36        # code, but it still needs to point at the template.37        tb = fake_traceback(38            exc_value, None, exc_value.filename or "<unknown>", exc_value.lineno39        )40    else:41        # Skip the frame for the render function.42        tb = tb.tb_next43 44    stack = []45 46    # Build the stack of traceback object, replacing any in template47    # code with the source file and line information.48    while tb is not None:49        # Skip frames decorated with @internalcode. These are internal50        # calls that aren't useful in template debugging output.51        if tb.tb_frame.f_code in internal_code:52            tb = tb.tb_next53            continue54 55        template = tb.tb_frame.f_globals.get("__jinja_template__")56 57        if template is not None:58            lineno = template.get_corresponding_lineno(tb.tb_lineno)59            fake_tb = fake_traceback(exc_value, tb, template.filename, lineno)60            stack.append(fake_tb)61        else:62            stack.append(tb)63 64        tb = tb.tb_next65 66    tb_next = None67 68    # Assign tb_next in reverse to avoid circular references.69    for tb in reversed(stack):70        tb.tb_next = tb_next71        tb_next = tb72 73    return exc_value.with_traceback(tb_next)74 75 76def fake_traceback(  # type: ignore77    exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int78) -> TracebackType:79    """Produce a new traceback object that looks like it came from the80    template source instead of the compiled code. The filename, line81    number, and location name will point to the template, and the local82    variables will be the current template context.83 84    :param exc_value: The original exception to be re-raised to create85        the new traceback.86    :param tb: The original traceback to get the local variables and87        code info from.88    :param filename: The template filename.89    :param lineno: The line number in the template source.90    """91    if tb is not None:92        # Replace the real locals with the context that would be93        # available at that point in the template.94        locals = get_template_locals(tb.tb_frame.f_locals)95        locals.pop("__jinja_exception__", None)96    else:97        locals = {}98 99    globals = {100        "__name__": filename,101        "__file__": filename,102        "__jinja_exception__": exc_value,103    }104    # Raise an exception at the correct line number.105    code: CodeType = compile(106        "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec"107    )108 109    # Build a new code object that points to the template file and110    # replaces the location with a block name.111    location = "template"112 113    if tb is not None:114        function = tb.tb_frame.f_code.co_name115 116        if function == "root":117            location = "top-level template code"118        elif function.startswith("block_"):119            location = f"block {function[6:]!r}"120 121    if sys.version_info >= (3, 8):122        code = code.replace(co_name=location)123    else:124        code = CodeType(125            code.co_argcount,126            code.co_kwonlyargcount,127            code.co_nlocals,128            code.co_stacksize,129            code.co_flags,130            code.co_code,131            code.co_consts,132            code.co_names,133            code.co_varnames,134            code.co_filename,135            location,136            code.co_firstlineno,137            code.co_lnotab,138            code.co_freevars,139            code.co_cellvars,140        )141 142    # Execute the new code, which is guaranteed to raise, and return143    # the new traceback without this frame.144    try:145        exec(code, globals, locals)146    except BaseException:147        return sys.exc_info()[2].tb_next  # type: ignore148 149 150def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]:151    """Based on the runtime locals, get the context that would be152    available at that point in the template.153    """154    # Start with the current template context.155    ctx: t.Optional[Context] = real_locals.get("context")156 157    if ctx is not None:158        data: t.Dict[str, t.Any] = ctx.get_all().copy()159    else:160        data = {}161 162    # Might be in a derived context that only sets local variables163    # rather than pushing a context. Local variables follow the scheme164    # l_depth_name. Find the highest-depth local that has a value for165    # each name.166    local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {}167 168    for name, value in real_locals.items():169        if not name.startswith("l_") or value is missing:170            # Not a template variable, or no longer relevant.171            continue172 173        try:174            _, depth_str, name = name.split("_", 2)175            depth = int(depth_str)176        except ValueError:177            continue178 179        cur_depth = local_overrides.get(name, (-1,))[0]180 181        if cur_depth < depth:182            local_overrides[name] = (depth, value)183 184    # Modify the context with any derived context.185    for name, (_, value) in local_overrides.items():186        if value is missing:187            data.pop(name, None)188        else:189            data[name] = value190 191    return data192 
codekingpro/portable-devtools · Team Ai