Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
codegen.py1320 linesDownload Raw Back to mako
1# mako/codegen.py2# Copyright 2006-2024 the Mako authors and contributors <see AUTHORS file>3#4# This module is part of Mako and is released under5# the MIT License: http://www.opensource.org/licenses/mit-license.php6 7"""provides functionality for rendering a parsetree constructing into module8source code."""9 10import json11import re12import time13 14from mako import ast15from mako import exceptions16from mako import filters17from mako import parsetree18from mako import util19from mako.pygen import PythonPrinter20 21 22MAGIC_NUMBER = 1023 24# names which are hardwired into the25# template and are not accessed via the26# context itself27TOPLEVEL_DECLARED = {"UNDEFINED", "STOP_RENDERING"}28RESERVED_NAMES = {"context", "loop"}.union(TOPLEVEL_DECLARED)29 30 31def compile(  # noqa32    node,33    uri,34    filename=None,35    default_filters=None,36    buffer_filters=None,37    imports=None,38    future_imports=None,39    source_encoding=None,40    generate_magic_comment=True,41    strict_undefined=False,42    enable_loop=True,43    reserved_names=frozenset(),44):45    """Generate module source code given a parsetree node,46    uri, and optional source filename"""47 48    buf = util.FastEncodingBuffer()49 50    printer = PythonPrinter(buf)51    _GenerateRenderMethod(52        printer,53        _CompileContext(54            uri,55            filename,56            default_filters,57            buffer_filters,58            imports,59            future_imports,60            source_encoding,61            generate_magic_comment,62            strict_undefined,63            enable_loop,64            reserved_names,65        ),66        node,67    )68    return buf.getvalue()69 70 71class _CompileContext:72    def __init__(73        self,74        uri,75        filename,76        default_filters,77        buffer_filters,78        imports,79        future_imports,80        source_encoding,81        generate_magic_comment,82        strict_undefined,83        enable_loop,84        reserved_names,85    ):86        self.uri = uri87        self.filename = filename88        self.default_filters = default_filters89        self.buffer_filters = buffer_filters90        self.imports = imports91        self.future_imports = future_imports92        self.source_encoding = source_encoding93        self.generate_magic_comment = generate_magic_comment94        self.strict_undefined = strict_undefined95        self.enable_loop = enable_loop96        self.reserved_names = reserved_names97 98 99class _GenerateRenderMethod:100 101    """A template visitor object which generates the102    full module source for a template.103 104    """105 106    def __init__(self, printer, compiler, node):107        self.printer = printer108        self.compiler = compiler109        self.node = node110        self.identifier_stack = [None]111        self.in_def = isinstance(node, (parsetree.DefTag, parsetree.BlockTag))112 113        if self.in_def:114            name = "render_%s" % node.funcname115            args = node.get_argument_expressions()116            filtered = len(node.filter_args.args) > 0117            buffered = eval(node.attributes.get("buffered", "False"))118            cached = eval(node.attributes.get("cached", "False"))119            defs = None120            pagetag = None121            if node.is_block and not node.is_anonymous:122                args += ["**pageargs"]123        else:124            defs = self.write_toplevel()125            pagetag = self.compiler.pagetag126            name = "render_body"127            if pagetag is not None:128                args = pagetag.body_decl.get_argument_expressions()129                if not pagetag.body_decl.kwargs:130                    args += ["**pageargs"]131                cached = eval(pagetag.attributes.get("cached", "False"))132                self.compiler.enable_loop = self.compiler.enable_loop or eval(133                    pagetag.attributes.get("enable_loop", "False")134                )135            else:136                args = ["**pageargs"]137                cached = False138            buffered = filtered = False139        if args is None:140            args = ["context"]141        else:142            args = [a for a in ["context"] + args]143 144        self.write_render_callable(145            pagetag or node, name, args, buffered, filtered, cached146        )147 148        if defs is not None:149            for node in defs:150                _GenerateRenderMethod(printer, compiler, node)151 152        if not self.in_def:153            self.write_metadata_struct()154 155    def write_metadata_struct(self):156        self.printer.source_map[self.printer.lineno] = max(157            self.printer.source_map158        )159        struct = {160            "filename": self.compiler.filename,161            "uri": self.compiler.uri,162            "source_encoding": self.compiler.source_encoding,163            "line_map": self.printer.source_map,164        }165        self.printer.writelines(166            '"""',167            "__M_BEGIN_METADATA",168            json.dumps(struct),169            "__M_END_METADATA\n" '"""',170        )171 172    @property173    def identifiers(self):174        return self.identifier_stack[-1]175 176    def write_toplevel(self):177        """Traverse a template structure for module-level directives and178        generate the start of module-level code.179 180        """181        inherit = []182        namespaces = {}183        module_code = []184 185        self.compiler.pagetag = None186 187        class FindTopLevel:188            def visitInheritTag(s, node):189                inherit.append(node)190 191            def visitNamespaceTag(s, node):192                namespaces[node.name] = node193 194            def visitPageTag(s, node):195                self.compiler.pagetag = node196 197            def visitCode(s, node):198                if node.ismodule:199                    module_code.append(node)200 201        f = FindTopLevel()202        for n in self.node.nodes:203            n.accept_visitor(f)204 205        self.compiler.namespaces = namespaces206 207        module_ident = set()208        for n in module_code:209            module_ident = module_ident.union(n.declared_identifiers())210 211        module_identifiers = _Identifiers(self.compiler)212        module_identifiers.declared = module_ident213 214        # module-level names, python code215        if (216            self.compiler.generate_magic_comment217            and self.compiler.source_encoding218        ):219            self.printer.writeline(220                "# -*- coding:%s -*-" % self.compiler.source_encoding221            )222 223        if self.compiler.future_imports:224            self.printer.writeline(225                "from __future__ import %s"226                % (", ".join(self.compiler.future_imports),)227            )228        self.printer.writeline("from mako import runtime, filters, cache")229        self.printer.writeline("UNDEFINED = runtime.UNDEFINED")230        self.printer.writeline("STOP_RENDERING = runtime.STOP_RENDERING")231        self.printer.writeline("__M_dict_builtin = dict")232        self.printer.writeline("__M_locals_builtin = locals")233        self.printer.writeline("_magic_number = %r" % MAGIC_NUMBER)234        self.printer.writeline("_modified_time = %r" % time.time())235        self.printer.writeline("_enable_loop = %r" % self.compiler.enable_loop)236        self.printer.writeline(237            "_template_filename = %r" % self.compiler.filename238        )239        self.printer.writeline("_template_uri = %r" % self.compiler.uri)240        self.printer.writeline(241            "_source_encoding = %r" % self.compiler.source_encoding242        )243        if self.compiler.imports:244            buf = ""245            for imp in self.compiler.imports:246                buf += imp + "\n"247                self.printer.writeline(imp)248            impcode = ast.PythonCode(249                buf,250                source="",251                lineno=0,252                pos=0,253                filename="template defined imports",254            )255        else:256            impcode = None257 258        main_identifiers = module_identifiers.branch(self.node)259        mit = module_identifiers.topleveldefs260        module_identifiers.topleveldefs = mit.union(261            main_identifiers.topleveldefs262        )263        module_identifiers.declared.update(TOPLEVEL_DECLARED)264        if impcode:265            module_identifiers.declared.update(impcode.declared_identifiers)266 267        self.compiler.identifiers = module_identifiers268        self.printer.writeline(269            "_exports = %r"270            % [n.name for n in main_identifiers.topleveldefs.values()]271        )272        self.printer.write_blanks(2)273 274        if len(module_code):275            self.write_module_code(module_code)276 277        if len(inherit):278            self.write_namespaces(namespaces)279            self.write_inherit(inherit[-1])280        elif len(namespaces):281            self.write_namespaces(namespaces)282 283        return list(main_identifiers.topleveldefs.values())284 285    def write_render_callable(286        self, node, name, args, buffered, filtered, cached287    ):288        """write a top-level render callable.289 290        this could be the main render() method or that of a top-level def."""291 292        if self.in_def:293            decorator = node.decorator294            if decorator:295                self.printer.writeline(296                    "@runtime._decorate_toplevel(%s)" % decorator297                )298 299        self.printer.start_source(node.lineno)300        self.printer.writelines(301            "def %s(%s):" % (name, ",".join(args)),302            # push new frame, assign current frame to __M_caller303            "__M_caller = context.caller_stack._push_frame()",304            "try:",305        )306        if buffered or filtered or cached:307            self.printer.writeline("context._push_buffer()")308 309        self.identifier_stack.append(310            self.compiler.identifiers.branch(self.node)311        )312        if (not self.in_def or self.node.is_block) and "**pageargs" in args:313            self.identifier_stack[-1].argument_declared.add("pageargs")314 315        if not self.in_def and (316            len(self.identifiers.locally_assigned) > 0317            or len(self.identifiers.argument_declared) > 0318        ):319            self.printer.writeline(320                "__M_locals = __M_dict_builtin(%s)"321                % ",".join(322                    [323                        "%s=%s" % (x, x)324                        for x in self.identifiers.argument_declared325                    ]326                )327            )328 329        self.write_variable_declares(self.identifiers, toplevel=True)330 331        for n in self.node.nodes:332            n.accept_visitor(self)333 334        self.write_def_finish(self.node, buffered, filtered, cached)335        self.printer.writeline(None)336        self.printer.write_blanks(2)337        if cached:338            self.write_cache_decorator(339                node, name, args, buffered, self.identifiers, toplevel=True340            )341 342    def write_module_code(self, module_code):343        """write module-level template code, i.e. that which344        is enclosed in <%! %> tags in the template."""345        for n in module_code:346            self.printer.write_indented_block(n.text, starting_lineno=n.lineno)347 348    def write_inherit(self, node):349        """write the module-level inheritance-determination callable."""350 351        self.printer.writelines(352            "def _mako_inherit(template, context):",353            "_mako_generate_namespaces(context)",354            "return runtime._inherit_from(context, %s, _template_uri)"355            % (node.parsed_attributes["file"]),356            None,357        )358 359    def write_namespaces(self, namespaces):360        """write the module-level namespace-generating callable."""361        self.printer.writelines(362            "def _mako_get_namespace(context, name):",363            "try:",364            "return context.namespaces[(__name__, name)]",365            "except KeyError:",366            "_mako_generate_namespaces(context)",367            "return context.namespaces[(__name__, name)]",368            None,369            None,370        )371        self.printer.writeline("def _mako_generate_namespaces(context):")372 373        for node in namespaces.values():374            if "import" in node.attributes:375                self.compiler.has_ns_imports = True376            self.printer.start_source(node.lineno)377            if len(node.nodes):378                self.printer.writeline("def make_namespace():")379                export = []380                identifiers = self.compiler.identifiers.branch(node)381                self.in_def = True382 383                class NSDefVisitor:384                    def visitDefTag(s, node):385                        s.visitDefOrBase(node)386 387                    def visitBlockTag(s, node):388                        s.visitDefOrBase(node)389 390                    def visitDefOrBase(s, node):391                        if node.is_anonymous:392                            raise exceptions.CompileException(393                                "Can't put anonymous blocks inside "394                                "<%namespace>",395                                **node.exception_kwargs,396                            )397                        self.write_inline_def(node, identifiers, nested=False)398                        export.append(node.funcname)399 400                vis = NSDefVisitor()401                for n in node.nodes:402                    n.accept_visitor(vis)403                self.printer.writeline("return [%s]" % (",".join(export)))404                self.printer.writeline(None)405                self.in_def = False406                callable_name = "make_namespace()"407            else:408                callable_name = "None"409 410            if "file" in node.parsed_attributes:411                self.printer.writeline(412                    "ns = runtime.TemplateNamespace(%r,"413                    " context._clean_inheritance_tokens(),"414                    " templateuri=%s, callables=%s, "415                    " calling_uri=_template_uri)"416                    % (417                        node.name,418                        node.parsed_attributes.get("file", "None"),419                        callable_name,420                    )421                )422            elif "module" in node.parsed_attributes:423                self.printer.writeline(424                    "ns = runtime.ModuleNamespace(%r,"425                    " context._clean_inheritance_tokens(),"426                    " callables=%s, calling_uri=_template_uri,"427                    " module=%s)"428                    % (429                        node.name,430                        callable_name,431                        node.parsed_attributes.get("module", "None"),432                    )433                )434            else:435                self.printer.writeline(436                    "ns = runtime.Namespace(%r,"437                    " context._clean_inheritance_tokens(),"438                    " callables=%s, calling_uri=_template_uri)"439                    % (node.name, callable_name)440                )441            if eval(node.attributes.get("inheritable", "False")):442                self.printer.writeline("context['self'].%s = ns" % (node.name))443 444            self.printer.writeline(445                "context.namespaces[(__name__, %s)] = ns" % repr(node.name)446            )447            self.printer.write_blanks(1)448        if not len(namespaces):449            self.printer.writeline("pass")450        self.printer.writeline(None)451 452    def write_variable_declares(self, identifiers, toplevel=False, limit=None):453        """write variable declarations at the top of a function.454 455        the variable declarations are in the form of callable456        definitions for defs and/or name lookup within the457        function's context argument. the names declared are based458        on the names that are referenced in the function body,459        which don't otherwise have any explicit assignment460        operation. names that are assigned within the body are461        assumed to be locally-scoped variables and are not462        separately declared.463 464        for def callable definitions, if the def is a top-level465        callable then a 'stub' callable is generated which wraps466        the current Context into a closure. if the def is not467        top-level, it is fully rendered as a local closure.468 469        """470 471        # collection of all defs available to us in this scope472        comp_idents = {c.funcname: c for c in identifiers.defs}473        to_write = set()474 475        # write "context.get()" for all variables we are going to476        # need that arent in the namespace yet477        to_write = to_write.union(identifiers.undeclared)478 479        # write closure functions for closures that we define480        # right here481        to_write = to_write.union(482            [c.funcname for c in identifiers.closuredefs.values()]483        )484 485        # remove identifiers that are declared in the argument486        # signature of the callable487        to_write = to_write.difference(identifiers.argument_declared)488 489        # remove identifiers that we are going to assign to.490        # in this way we mimic Python's behavior,491        # i.e. assignment to a variable within a block492        # means that variable is now a "locally declared" var,493        # which cannot be referenced beforehand.494        to_write = to_write.difference(identifiers.locally_declared)495 496        if self.compiler.enable_loop:497            has_loop = "loop" in to_write498            to_write.discard("loop")499        else:500            has_loop = False501 502        # if a limiting set was sent, constraint to those items in that list503        # (this is used for the caching decorator)504        if limit is not None:505            to_write = to_write.intersection(limit)506 507        if toplevel and getattr(self.compiler, "has_ns_imports", False):508            self.printer.writeline("_import_ns = {}")509            self.compiler.has_imports = True510            for ident, ns in self.compiler.namespaces.items():511                if "import" in ns.attributes:512                    self.printer.writeline(513                        "_mako_get_namespace(context, %r)."514                        "_populate(_import_ns, %r)"515                        % (516                            ident,517                            re.split(r"\s*,\s*", ns.attributes["import"]),518                        )519                    )520 521        if has_loop:522            self.printer.writeline("loop = __M_loop = runtime.LoopStack()")523 524        for ident in to_write:525            if ident in comp_idents:526                comp = comp_idents[ident]527                if comp.is_block:528                    if not comp.is_anonymous:529                        self.write_def_decl(comp, identifiers)530                    else:531                        self.write_inline_def(comp, identifiers, nested=True)532                else:533                    if comp.is_root():534                        self.write_def_decl(comp, identifiers)535                    else:536                        self.write_inline_def(comp, identifiers, nested=True)537 538            elif ident in self.compiler.namespaces:539                self.printer.writeline(540                    "%s = _mako_get_namespace(context, %r)" % (ident, ident)541                )542            else:543                if getattr(self.compiler, "has_ns_imports", False):544                    if self.compiler.strict_undefined:545                        self.printer.writelines(546                            "%s = _import_ns.get(%r, UNDEFINED)"547                            % (ident, ident),548                            "if %s is UNDEFINED:" % ident,549                            "try:",550                            "%s = context[%r]" % (ident, ident),551                            "except KeyError:",552                            "raise NameError(\"'%s' is not defined\")" % ident,553                            None,554                            None,555                        )556                    else:557                        self.printer.writeline(558                            "%s = _import_ns.get"559                            "(%r, context.get(%r, UNDEFINED))"560                            % (ident, ident, ident)561                        )562                else:563                    if self.compiler.strict_undefined:564                        self.printer.writelines(565                            "try:",566                            "%s = context[%r]" % (ident, ident),567                            "except KeyError:",568                            "raise NameError(\"'%s' is not defined\")" % ident,569                            None,570                        )571                    else:572                        self.printer.writeline(573                            "%s = context.get(%r, UNDEFINED)" % (ident, ident)574                        )575 576        self.printer.writeline("__M_writer = context.writer()")577 578    def write_def_decl(self, node, identifiers):579        """write a locally-available callable referencing a top-level def"""580        funcname = node.funcname581        namedecls = node.get_argument_expressions()582        nameargs = node.get_argument_expressions(as_call=True)583 584        if not self.in_def and (585            len(self.identifiers.locally_assigned) > 0586            or len(self.identifiers.argument_declared) > 0587        ):588            nameargs.insert(0, "context._locals(__M_locals)")589        else:590            nameargs.insert(0, "context")591        self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls)))592        self.printer.writeline(593            "return render_%s(%s)" % (funcname, ",".join(nameargs))594        )595        self.printer.writeline(None)596 597    def write_inline_def(self, node, identifiers, nested):598        """write a locally-available def callable inside an enclosing def."""599 600        namedecls = node.get_argument_expressions()601 602        decorator = node.decorator603        if decorator:604            self.printer.writeline(605                "@runtime._decorate_inline(context, %s)" % decorator606            )607        self.printer.writeline(608            "def %s(%s):" % (node.funcname, ",".join(namedecls))609        )610        filtered = len(node.filter_args.args) > 0611        buffered = eval(node.attributes.get("buffered", "False"))612        cached = eval(node.attributes.get("cached", "False"))613        self.printer.writelines(614            # push new frame, assign current frame to __M_caller615            "__M_caller = context.caller_stack._push_frame()",616            "try:",617        )618        if buffered or filtered or cached:619            self.printer.writelines("context._push_buffer()")620 621        identifiers = identifiers.branch(node, nested=nested)622 623        self.write_variable_declares(identifiers)624 625        self.identifier_stack.append(identifiers)626        for n in node.nodes:627            n.accept_visitor(self)628        self.identifier_stack.pop()629 630        self.write_def_finish(node, buffered, filtered, cached)631        self.printer.writeline(None)632        if cached:633            self.write_cache_decorator(634                node,635                node.funcname,636                namedecls,637                False,638                identifiers,639                inline=True,640                toplevel=False,641            )642 643    def write_def_finish(644        self, node, buffered, filtered, cached, callstack=True645    ):646        """write the end section of a rendering function, either outermost or647        inline.648 649        this takes into account if the rendering function was filtered,650        buffered, etc.  and closes the corresponding try: block if any, and651        writes code to retrieve captured content, apply filters, send proper652        return value."""653 654        if not buffered and not cached and not filtered:655            self.printer.writeline("return ''")656            if callstack:657                self.printer.writelines(658                    "finally:", "context.caller_stack._pop_frame()", None659                )660 661        if buffered or filtered or cached:662            if buffered or cached:663                # in a caching scenario, don't try to get a writer664                # from the context after popping; assume the caching665                # implemenation might be using a context with no666                # extra buffers667                self.printer.writelines(668                    "finally:", "__M_buf = context._pop_buffer()"669                )670            else:671                self.printer.writelines(672                    "finally:",673                    "__M_buf, __M_writer = context._pop_buffer_and_writer()",674                )675 676            if callstack:677                self.printer.writeline("context.caller_stack._pop_frame()")678 679            s = "__M_buf.getvalue()"680            if filtered:681                s = self.create_filter_callable(682                    node.filter_args.args, s, False683                )684            self.printer.writeline(None)685            if buffered and not cached:686                s = self.create_filter_callable(687                    self.compiler.buffer_filters, s, False688                )689            if buffered or cached:690                self.printer.writeline("return %s" % s)691            else:692                self.printer.writelines("__M_writer(%s)" % s, "return ''")693 694    def write_cache_decorator(695        self,696        node_or_pagetag,697        name,698        args,699        buffered,700        identifiers,701        inline=False,702        toplevel=False,703    ):704        """write a post-function decorator to replace a rendering705        callable with a cached version of itself."""706 707        self.printer.writeline("__M_%s = %s" % (name, name))708        cachekey = node_or_pagetag.parsed_attributes.get(709            "cache_key", repr(name)710        )711 712        cache_args = {}713        if self.compiler.pagetag is not None:714            cache_args.update(715                (pa[6:], self.compiler.pagetag.parsed_attributes[pa])716                for pa in self.compiler.pagetag.parsed_attributes717                if pa.startswith("cache_") and pa != "cache_key"718            )719        cache_args.update(720            (pa[6:], node_or_pagetag.parsed_attributes[pa])721            for pa in node_or_pagetag.parsed_attributes722            if pa.startswith("cache_") and pa != "cache_key"723        )724        if "timeout" in cache_args:725            cache_args["timeout"] = int(eval(cache_args["timeout"]))726 727        self.printer.writeline("def %s(%s):" % (name, ",".join(args)))728 729        # form "arg1, arg2, arg3=arg3, arg4=arg4", etc.730        pass_args = [731            "%s=%s" % ((a.split("=")[0],) * 2) if "=" in a else a for a in args732        ]733 734        self.write_variable_declares(735            identifiers,736            toplevel=toplevel,737            limit=node_or_pagetag.undeclared_identifiers(),738        )739        if buffered:740            s = (741                "context.get('local')."742                "cache._ctx_get_or_create("743                "%s, lambda:__M_%s(%s),  context, %s__M_defname=%r)"744                % (745                    cachekey,746                    name,747                    ",".join(pass_args),748                    "".join(749                        ["%s=%s, " % (k, v) for k, v in cache_args.items()]750                    ),751                    name,752                )753            )754            # apply buffer_filters755            s = self.create_filter_callable(756                self.compiler.buffer_filters, s, False757            )758            self.printer.writelines("return " + s, None)759        else:760            self.printer.writelines(761                "__M_writer(context.get('local')."762                "cache._ctx_get_or_create("763                "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))"764                % (765                    cachekey,766                    name,767                    ",".join(pass_args),768                    "".join(769                        ["%s=%s, " % (k, v) for k, v in cache_args.items()]770                    ),771                    name,772                ),773                "return ''",774                None,775            )776 777    def create_filter_callable(self, args, target, is_expression):778        """write a filter-applying expression based on the filters779        present in the given filter names, adjusting for the global780        'default' filter aliases as needed."""781 782        def locate_encode(name):783            if re.match(r"decode\..+", name):784                return "filters." + name785            else:786                return filters.DEFAULT_ESCAPES.get(name, name)787 788        if "n" not in args:789            if is_expression:790                if self.compiler.pagetag:791                    args = self.compiler.pagetag.filter_args.args + args792                if self.compiler.default_filters and "n" not in args:793                    args = self.compiler.default_filters + args794        for e in args:795            # if filter given as a function, get just the identifier portion796            if e == "n":797                continue798            m = re.match(r"(.+?)(\(.*\))", e)799            if m:800                ident, fargs = m.group(1, 2)801                f = locate_encode(ident)802                e = f + fargs803            else:804                e = locate_encode(e)805                assert e is not None806            target = "%s(%s)" % (e, target)807        return target808 809    def visitExpression(self, node):810        self.printer.start_source(node.lineno)811        if (812            len(node.escapes)813            or (814                self.compiler.pagetag is not None815                and len(self.compiler.pagetag.filter_args.args)816            )817            or len(self.compiler.default_filters)818        ):819            s = self.create_filter_callable(820                node.escapes_code.args, "%s" % node.text, True821            )822            self.printer.writeline("__M_writer(%s)" % s)823        else:824            self.printer.writeline("__M_writer(%s)" % node.text)825 826    def visitControlLine(self, node):827        if node.isend:828            self.printer.writeline(None)829            if node.has_loop_context:830                self.printer.writeline("finally:")831                self.printer.writeline("loop = __M_loop._exit()")832                self.printer.writeline(None)833        else:834            self.printer.start_source(node.lineno)835            if self.compiler.enable_loop and node.keyword == "for":836                text = mangle_mako_loop(node, self.printer)837            else:838                text = node.text839            self.printer.writeline(text)840            children = node.get_children()841 842            # this covers the four situations where we want to insert a pass:843            # 1) a ternary control line with no children,844            # 2) a primary control line with nothing but its own ternary845            #       and end control lines, and846            # 3) any control line with no content other than comments847            # 4) the first control block with no content other than comments848            def _search_for_control_line():849                for c in children:850                    if isinstance(c, parsetree.Comment):851                        continue852                    elif isinstance(c, parsetree.ControlLine):853                        return True854                    return False855 856            if (857                not children858                or all(859                    isinstance(c, (parsetree.Comment, parsetree.ControlLine))860                    for c in children861                )862                and all(863                    (node.is_ternary(c.keyword) or c.isend)864                    for c in children865                    if isinstance(c, parsetree.ControlLine)866                )867                or _search_for_control_line()868            ):869                self.printer.writeline("pass")870 871    def visitText(self, node):872        self.printer.start_source(node.lineno)873        self.printer.writeline("__M_writer(%s)" % repr(node.content))874 875    def visitTextTag(self, node):876        filtered = len(node.filter_args.args) > 0877        if filtered:878            self.printer.writelines(879                "__M_writer = context._push_writer()", "try:"880            )881        for n in node.nodes:882            n.accept_visitor(self)883        if filtered:884            self.printer.writelines(885                "finally:",886                "__M_buf, __M_writer = context._pop_buffer_and_writer()",887                "__M_writer(%s)"888                % self.create_filter_callable(889                    node.filter_args.args, "__M_buf.getvalue()", False890                ),891                None,892            )893 894    def visitCode(self, node):895        if not node.ismodule:896            self.printer.write_indented_block(897                node.text, starting_lineno=node.lineno898            )899 900            if not self.in_def and len(self.identifiers.locally_assigned) > 0:901                # if we are the "template" def, fudge locally902                # declared/modified variables into the "__M_locals" dictionary,903                # which is used for def calls within the same template,904                # to simulate "enclosing scope"905                self.printer.writeline(906                    "__M_locals_builtin_stored = __M_locals_builtin()"907                )908                self.printer.writeline(909                    "__M_locals.update(__M_dict_builtin([(__M_key,"910                    " __M_locals_builtin_stored[__M_key]) for __M_key in"911                    " [%s] if __M_key in __M_locals_builtin_stored]))"912                    % ",".join([repr(x) for x in node.declared_identifiers()])913                )914 915    def visitIncludeTag(self, node):916        self.printer.start_source(node.lineno)917        args = node.attributes.get("args")918        if args:919            self.printer.writeline(920                "runtime._include_file(context, %s, _template_uri, %s)"921                % (node.parsed_attributes["file"], args)922            )923        else:924            self.printer.writeline(925                "runtime._include_file(context, %s, _template_uri)"926                % (node.parsed_attributes["file"])927            )928 929    def visitNamespaceTag(self, node):930        pass931 932    def visitDefTag(self, node):933        pass934 935    def visitBlockTag(self, node):936        if node.is_anonymous:937            self.printer.writeline("%s()" % node.funcname)938        else:939            nameargs = node.get_argument_expressions(as_call=True)940            nameargs += ["**pageargs"]941            self.printer.writeline(942                "if 'parent' not in context._data or "943                "not hasattr(context._data['parent'], '%s'):" % node.funcname944            )945            self.printer.writeline(946                "context['self'].%s(%s)" % (node.funcname, ",".join(nameargs))947            )948            self.printer.writeline("\n")949 950    def visitCallNamespaceTag(self, node):951        # TODO: we can put namespace-specific checks here, such952        # as ensure the given namespace will be imported,953        # pre-import the namespace, etc.954        self.visitCallTag(node)955 956    def visitCallTag(self, node):957        self.printer.writeline("def ccall(caller):")958        export = ["body"]959        callable_identifiers = self.identifiers.branch(node, nested=True)960        body_identifiers = callable_identifiers.branch(node, nested=False)961        # we want the 'caller' passed to ccall to be used962        # for the body() function, but for other non-body()963        # <%def>s within <%call> we want the current caller964        # off the call stack (if any)965        body_identifiers.add_declared("caller")966 967        self.identifier_stack.append(body_identifiers)968 969        class DefVisitor:970            def visitDefTag(s, node):971                s.visitDefOrBase(node)972 973            def visitBlockTag(s, node):974                s.visitDefOrBase(node)975 976            def visitDefOrBase(s, node):977                self.write_inline_def(node, callable_identifiers, nested=False)978                if not node.is_anonymous:979                    export.append(node.funcname)980                # remove defs that are within the <%call> from the981                # "closuredefs" defined in the body, so they dont render twice982                if node.funcname in body_identifiers.closuredefs:983                    del body_identifiers.closuredefs[node.funcname]984 985        vis = DefVisitor()986        for n in node.nodes:987            n.accept_visitor(vis)988        self.identifier_stack.pop()989 990        bodyargs = node.body_decl.get_argument_expressions()991        self.printer.writeline("def body(%s):" % ",".join(bodyargs))992 993        # TODO: figure out best way to specify994        # buffering/nonbuffering (at call time would be better)995        buffered = False996        if buffered:997            self.printer.writelines("context._push_buffer()", "try:")998        self.write_variable_declares(body_identifiers)999        self.identifier_stack.append(body_identifiers)1000 1001        for n in node.nodes:1002            n.accept_visitor(self)1003        self.identifier_stack.pop()1004 1005        self.write_def_finish(node, buffered, False, False, callstack=False)1006        self.printer.writelines(None, "return [%s]" % (",".join(export)), None)1007 1008        self.printer.writelines(1009            # push on caller for nested call1010            "context.caller_stack.nextcaller = "1011            "runtime.Namespace('caller', context, "1012            "callables=ccall(__M_caller))",1013            "try:",1014        )1015        self.printer.start_source(node.lineno)1016        self.printer.writelines(1017            "__M_writer(%s)"1018            % self.create_filter_callable([], node.expression, True),1019            "finally:",1020            "context.caller_stack.nextcaller = None",1021            None,1022        )1023 1024 1025class _Identifiers:1026 1027    """tracks the status of identifier names as template code is rendered."""1028 1029    def __init__(self, compiler, node=None, parent=None, nested=False):1030        if parent is not None:1031            # if we are the branch created in write_namespaces(),1032            # we don't share any context from the main body().1033            if isinstance(node, parsetree.NamespaceTag):1034                self.declared = set()1035                self.topleveldefs = util.SetLikeDict()1036            else:1037                # things that have already been declared1038                # in an enclosing namespace (i.e. names we can just use)1039                self.declared = (1040                    set(parent.declared)1041                    .union([c.name for c in parent.closuredefs.values()])1042                    .union(parent.locally_declared)1043                    .union(parent.argument_declared)1044                )1045 1046                # if these identifiers correspond to a "nested"1047                # scope, it means whatever the parent identifiers1048                # had as undeclared will have been declared by that parent,1049                # and therefore we have them in our scope.1050                if nested:1051                    self.declared = self.declared.union(parent.undeclared)1052 1053                # top level defs that are available1054                self.topleveldefs = util.SetLikeDict(**parent.topleveldefs)1055        else:1056            self.declared = set()1057            self.topleveldefs = util.SetLikeDict()1058 1059        self.compiler = compiler1060 1061        # things within this level that are referenced before they1062        # are declared (e.g. assigned to)1063        self.undeclared = set()1064 1065        # things that are declared locally.  some of these things1066        # could be in the "undeclared" list as well if they are1067        # referenced before declared1068        self.locally_declared = set()1069 1070        # assignments made in explicit python blocks.1071        # these will be propagated to1072        # the context of local def calls.1073        self.locally_assigned = set()1074 1075        # things that are declared in the argument1076        # signature of the def callable1077        self.argument_declared = set()1078 1079        # closure defs that are defined in this level1080        self.closuredefs = util.SetLikeDict()1081 1082        self.node = node1083 1084        if node is not None:1085            node.accept_visitor(self)1086 1087        illegal_names = self.compiler.reserved_names.intersection(1088            self.locally_declared1089        )1090        if illegal_names:1091            raise exceptions.NameConflictError(1092                "Reserved words declared in template: %s"1093                % ", ".join(illegal_names)1094            )1095 1096    def branch(self, node, **kwargs):1097        """create a new Identifiers for a new Node, with1098        this Identifiers as the parent."""1099 1100        return _Identifiers(self.compiler, node, self, **kwargs)1101 1102    @property1103    def defs(self):1104        return set(self.topleveldefs.union(self.closuredefs).values())1105 1106    def __repr__(self):1107        return (1108            "Identifiers(declared=%r, locally_declared=%r, "1109            "undeclared=%r, topleveldefs=%r, closuredefs=%r, "1110            "argumentdeclared=%r)"1111            % (1112                list(self.declared),1113                list(self.locally_declared),1114                list(self.undeclared),1115                [c.name for c in self.topleveldefs.values()],1116                [c.name for c in self.closuredefs.values()],1117                self.argument_declared,1118            )1119        )1120 1121    def check_declared(self, node):1122        """update the state of this Identifiers with the undeclared1123        and declared identifiers of the given node."""1124 1125        for ident in node.undeclared_identifiers():1126            if ident != "context" and ident not in self.declared.union(1127                self.locally_declared1128            ):1129                self.undeclared.add(ident)1130        for ident in node.declared_identifiers():1131            self.locally_declared.add(ident)1132 1133    def add_declared(self, ident):1134        self.declared.add(ident)1135        if ident in self.undeclared:1136            self.undeclared.remove(ident)1137 1138    def visitExpression(self, node):1139        self.check_declared(node)1140 1141    def visitControlLine(self, node):1142        self.check_declared(node)1143 1144    def visitCode(self, node):1145        if not node.ismodule:1146            self.check_declared(node)1147            self.locally_assigned = self.locally_assigned.union(1148                node.declared_identifiers()1149            )1150 1151    def visitNamespaceTag(self, node):1152        # only traverse into the sub-elements of a1153        # <%namespace> tag if we are the branch created in1154        # write_namespaces()1155        if self.node is node:1156            for n in node.nodes:1157                n.accept_visitor(self)1158 1159    def _check_name_exists(self, collection, node):1160        existing = collection.get(node.funcname)1161        collection[node.funcname] = node1162        if (1163            existing is not None1164            and existing is not node1165            and (node.is_block or existing.is_block)1166        ):1167            raise exceptions.CompileException(1168                "%%def or %%block named '%s' already "1169                "exists in this template." % node.funcname,1170                **node.exception_kwargs,1171            )1172 1173    def visitDefTag(self, node):1174        if node.is_root() and not node.is_anonymous:1175            self._check_name_exists(self.topleveldefs, node)1176        elif node is not self.node:1177            self._check_name_exists(self.closuredefs, node)1178 1179        for ident in node.undeclared_identifiers():1180            if ident != "context" and ident not in self.declared.union(1181                self.locally_declared1182            ):1183                self.undeclared.add(ident)1184 1185        # visit defs only one level deep1186        if node is self.node:1187            for ident in node.declared_identifiers():1188                self.argument_declared.add(ident)1189 1190            for n in node.nodes:1191                n.accept_visitor(self)1192 1193    def visitBlockTag(self, node):1194        if node is not self.node and not node.is_anonymous:1195            if isinstance(self.node, parsetree.DefTag):1196                raise exceptions.CompileException(1197                    "Named block '%s' not allowed inside of def '%s'"1198                    % (node.name, self.node.name),1199                    **node.exception_kwargs,1200                )

Showing the first 1,200 of 1320 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai