Lynx 仓库 Mako 模板引擎 Python API 使用指南从 Template 到 TemplateLookup 与异常处理【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx导读本文以 third_party/binding/idl-codegen/third_party/doc/build/usage.rst 为核心主体系统讲解 Mako 模板引擎在 Python 环境下的完整使用方式涵盖Template基础渲染、文件模板与模块缓存、TemplateLookup模板查找与缓存管理、Unicode 编码处理、异常格式化以及 WSGI / Pygments / Babel 等框架集成。该文档随 Chromium 90.0.4430.71 标签的 IDL 代码生成器一并引入当前仓库见 third_party/binding/idl-codegen/README.md 的目录映射说明是理解 Mako 模板 API 的第一手官方资料。读完本文你将掌握 Mako 从最小可用到生产级配置的全部核心用法并了解它在当前仓库 IDL 代码生成体系中的位置与差异。Mako 在当前仓库中的位置当前仓库通过 third_party/binding/idl-codegen 引入了 Chromium 90 的 IDL 代码生成器相关脚本其 README 明确说明了目录映射关系/third_party目录存放any referenced third party stuff所有被引用的第三方组件。本文主角 Mako 模板引擎的官方文档即位于该目录下third_party/binding/idl-codegen/third_party/doc/build/usage.rst本文主题Mako 的 Python API 使用指南同目录下还包含 syntax.rst、unicode.rst、caching.rst、defs.rst、filtering.rst、inheritance.rst、namespaces.rst、runtime.rst 等配套章节共同构成 Mako 的完整文档体系需要特别说明的是当前仓库的 IDL 代码生成器本体scripts/code_generator.py等在实际生成时使用的是Jinja2引擎见 scripts/code_generator.py 中initialize_jinja_env对jinja2.Environment的初始化Mako 文档在此仓库中作为随附的第三方组件资料存在。因此本文聚焦于 Mako 自身的 API 使用——这与官方文档主题保持一致同时保持了对仓库现状的事实准确描述。Basic Usage最小可用的 TemplateMako 最基础的用法是通过Template类创建一个模板并渲染它from mako.template import Template mytemplate Template(hello world!) print(mytemplate.render())这段代码的核心机制是传给Template的文本参数会被编译成一个 Python 模块表示该模块内含一个名为render_body()的函数负责产生模板输出。当调用mytemplate.render()时Mako 会为模板搭建一个运行时环境调用render_body()函数将输出捕获到缓冲区并返回其字符串内容。向模板传递变量render_body()内部的代码可以访问一个变量命名空间namespace。你只需把这些变量作为额外的关键字参数传给render()方法from mako.template import Template mytemplate Template(hello, ${name}!) print(mytemplate.render(namejack))这里的${name}是 Mako 的表达式语法namejack则通过关键字参数注入到模板命名空间。使用 Context 显式渲染render()方法内部会创建一个Context对象它既保存模板可访问的所有变量名也保存用于捕获输出的缓冲区。你也可以自己创建Context通过render_context()方法让模板在其上渲染from mako.template import Template from mako.runtime import Context from StringIO import StringIO mytemplate Template(hello, ${name}!) buf StringIO() ctx Context(buf, namejack) mytemplate.render_context(ctx) print(buf.getvalue())这种显式方式让调用方可以完全掌控输出流的目标本例中为StringIO缓冲区适合在自定义输出渠道的场景中使用。使用基于文件的模板Template也可以通过filename关键字参数从文件加载模板源码from mako.template import Template mytemplate Template(filename/docs/mytmpl.txt) print(mytemplate.render())module_directory模块文件缓存对于从文件加载的模板为了提升性能Mako 可以将模板编译生成的模块以常规 Python 模块文件即.py文件的形式缓存到文件系统。只需添加module_directory参数from mako.template import Template mytemplate Template(filename/docs/mytmpl.txt, module_directory/tmp/mako_modules) print(mytemplate.render())渲染上述代码后会生成一个包含模块源码的文件/tmp/mako_modules/docs/mytmpl.txt.py。下次再以相同参数创建Template时该模块文件会被自动复用从而跳过重复编译。这是 Mako 在长期运行服务中避免每次请求都全量编译模板的关键机制。使用 TemplateLookup前面所有示例都只涉及单个Template对象。当模板内部代码需要定位其他模板资源时它需要某种途径通过简单的 URI 字符串找到它们——这一职责由TemplateLookup类承担。构造它时需给出一个用于搜索模板的目录列表以及会传递给其所创建Template对象的关键字参数from mako.template import Template from mako.lookup import TemplateLookup mylookup TemplateLookup(directories[/docs]) mytemplate Template(%include fileheader.txt/ hello world!, lookupmylookup)上述代码创建了一个包含%include fileheader.txt/指令的文本模板。为了让它在/docs目录下找到header.txt我们把一个TemplateLookup对象传给模板。get_template真实应用的取模方式真实应用通常会把大部分甚至全部模板以文本文件形式存放在文件系统中并通过TemplateLookup.get_template()方法获取模板该方法接受所需模板的 URIfrom mako.template import Template from mako.lookup import TemplateLookup mylookup TemplateLookup(directories[/docs], module_directory/tmp/mako_modules) def serve_template(templatename, **kwargs): mytemplate mylookup.get_template(templatename) print(mytemplate.render(**kwargs))lookup 通过把给定 URI 依次拼接到各搜索目录后来定位模板。例如 URI 为/etc/beans/info.txt它会去查找/docs/etc/beans/info.txt若不存在则抛出TopLevelNotFound异常——这是 Mako 的自定义异常类型。当 lookup 定位到模板时还会给Template赋一个uri属性其值为传给get_template()的 URI。Template会用它计算模块文件名所以上例中templatename为/etc/beans/info.txt时将生成模块文件/tmp/mako_modules/etc/beans/info.txt.py。设置集合大小collection_sizeTemplateLookup还有一个重要职责在内存中缓存固定数量的模板避免连续的 URI 查找每次都触发完整编译或模块重载。默认情况下TemplateLookup的大小无上限你可以用collection_size参数指定固定大小mylookup TemplateLookup(directories[/docs], module_directory/tmp/mako_modules, collection_size500)上述 lookup 会持续把模板加载进内存直到数量达到约 500 个。此时它会使用**最近最少使用LRU**方案清理掉一定百分比的模板从而在缓存命中率与内存占用之间取得平衡。设置文件系统检查filesystem_checksTemplateLookup上另一个重要开关是filesystem_checks。它默认值为True表示每次get_template()返回模板时都会把原始模板文件的修订时间与上次加载时间进行比对若文件更新则重新加载内容并重新编译模板。在生产系统上将filesystem_checks设为False可以获得小幅到中等的性能提升具体取决于所使用的文件系统类型mylookup TemplateLookup(directories[/docs], filesystem_checksFalse)使用 Unicode 与编码Template和TemplateLookup都接受output_encoding与encoding_errors参数可将输出编码为任意 Python 支持的 codecfrom mako.template import Template from mako.lookup import TemplateLookup mylookup TemplateLookup(directories[/docs], output_encodingutf-8, encoding_errorsreplace) mytemplate mylookup.get_template(foo.txt) print(mytemplate.render())在 Python 3 下只要设置了output_encodingrender()方法就会返回bytes对象否则返回string。此外还存在render_unicode()方法它返回 Python 的unicode对象Python 3 中即stringprint(mytemplate.render_unicode())该方法忽略输出编码关键字参数你可以自行编码print(mytemplate.render_unicode().encode(utf-8, replace))Mako 能够以任意编码和/或unicode返回数据这隐含了一个事实模板底层的输出流是 Python unicode 对象。该行为的完整描述见 unicode.rst 章节。异常处理模板异常可能发生在两个截然不同的阶段一是查找、解析与编译模板时二是运行模板时。运行阶段的异常与普通 Python 代码一样正常抛出Mako 自有的异常类体系则主要作用于 lookup 与 lexer/compiler词法/编译阶段。Mako 提供了一些库例程用于为异常堆栈提供 Mako 特有信息并将异常格式化为文本或 HTML 形式。这些处理器核心价值在于把 Python 的文件名、行号与代码片段转换为Mako 模板的文件名、行号与代码片段——堆栈中凡是对应 Mako 模板模块的行都会被换算回其源模板文件中的位置。text_error_template 与 html_error_template格式化异常跟踪可使用text_error_template与html_error_template两个函数它们通过sys.exc_info()获取最近抛出的异常。典型用法如下from mako import exceptions try: template lookup.get_template(uri) print(template.render()) except: print(exceptions.text_error_template().render())HTML 渲染函数用法from mako import exceptions try: template lookup.get_template(uri) print(template.render()) except: print(exceptions.html_error_template().render())html_error_template接受两个选项指定fullFalse时只渲染 HTML 文档的一个片段指定cssFalse时不渲染默认样式表。例如print(exceptions.html_error_template().render(fullFalse))format_exceptions 内建开关HTML 渲染函数也可以作为Template的内建能力使用通过format_exceptions标志开启。开启后模板render 阶段抛出的任何异常都会让输出被html_error_template的输出所替换template Template(filename/foo/bar, format_exceptionsTrue) print(template.render())注意上述模板的编译阶段发生在构造Template对象时此时尚未定义输出流因此 lookup/parse/compile 阶段发生的异常不会被处理而会正常向上传播。也就是说渲染前的 traceback 与渲染中的 traceback 会被区别对待——所以前面介绍的try/except模式适用范围更广、更通用。RichTraceback自定义错误视图错误模板函数底层的对象是RichTraceback它也可以直接使用以构建自定义错误视图。下面示例展示了其通用 APIfrom mako.exceptions import RichTraceback try: template lookup.get_template(uri) print(template.render()) except: traceback RichTraceback() for (filename, lineno, function, line) in traceback.traceback: print(File %s, line %s, in %s % (filename, lineno, function)) print(line, \n) print(%s: %s % (str(traceback.error.__class__.__name__), traceback.error))RichTraceback 关键属性根据 usage.rst 的 API 参考部分RichTraceback提供以下核心属性error异常实例本身。message以 unicode 表示的异常错误消息。source错误发生处文件的源码若错误发生在编译后的模板内则为模板源码。lineno错误发生的行号若发生在编译后的模板内行号会被调整为模板源码中的行号。records8 元组列表包含原始 Python traceback 元素以及每个 traceback 行映射回其源模板如有后的文件名、行号、源码行与完整模板源码若某 traceback 行无对应模板则相应字段为None。reverse_records按逆序 traceback 排列的 records 列表——由 4 元组组成格式与常规 Python traceback 相同其中与模板对应的 traceback 记录已替换为原始记录。reverse_traceback逆序排列的 traceback 列表。常见框架集成Mako 发行包附带少量辅助代码用于在流行 Web 框架场景中使用 Mako。以下是官方文档的简要说明。WSGI发行包在examples/wsgi/run_wsgi.py中附带了一个示例 WSGI 应用。该 runner 从templates与htdocs两个目录拉取文件采用简化的两文件布局。它可作为一个功能完整的独立 Web 服务器运行借助wsgiutils自举能把请求中的 GET 与 POST 参数传播进Context可以服务图片、CSS 等各类静态文件并使用 Mako 自带的异常处理工具展示错误。对应文件见 third_party/binding/idl-codegen/third_party/examples/wsgi/run_wsgi.py。Pygments一个与 Pygments 兼容的语法高亮模块包含在mako.ext.pygmentplugin下。该模块用于生成 Mako 文档并在pygments.lexers标题下注册了多个setuptoolsentry point包括mako、htmlmako、xmlmako等全部 entry point 见setup.py文件。Babel从模板提取 gettext 消息Mako 通过mako.ext.babelplugin下的 Babel extractor entry point支持从模板中提取 gettext 消息。gettext 消息会从所有 Python 代码段中提取包括控制行和嵌入在标签中的表达式。当向 Babel 指定注释标签如-c选项时还可以从 Mako 模板中提取翻译者注释。例如项目myproj包含如下 Mako 模板myproj/myproj/templates/name.htmldiv idname Name: ## TRANSLATORS: This is a proper name. See the gettext ## manual, section Names. ${_(Francois Pinard)} /div要从该模板提取 gettext 消息项目需要在 Babel Extraction Method Mapping 文件通常位于myproj/babel.cfg中加入 Mako 配置段# Extraction from Python source files [python: myproj/**.py] # Extraction from Mako templates [mako: myproj/templates/**.html] input_encoding utf-8Mako extractor 支持可选的input_encoding参数用于指定模板的编码与Template/TemplateLookup的input_encoding参数一致。在项目根目录命令行调用 Babel 的 extractormyproj$ pybabel extract -F babel.cfg -c TRANSLATORS: .输出到stdout的 gettext 目录将包含如下条目#. TRANSLATORS: This is a proper name. See the gettext #. manual, section Names. #: myproj/templates/name.html:5 msgid Francois Pinard msgstr 这里有一个重要约束注释必须紧跟 gettext 消息之前才会被提取。在下面的例子中TRANSLATORS:注释因为与消息之间隔着Name:文本将不会被提取div idname ## TRANSLATORS: This is a proper name. See the gettext ## manual, section Names. Name: ${_(Francois Pinard)} /div这只是一个基础示例Babel 可以从setup.py中调用其命令行选项可通过setup.cfg中 Babel Distutils/Setuptools 集成来指定。API Reference 一览usage.rst 末尾以 Sphinx autoclass/autofunction 指令形式挂载了完整的 API 参考主要包括mako.template.Template核心模板类支持filename、lookup、module_directory、output_encoding、encoding_errors、input_encoding、format_exceptions等构造参数以及render()、render_context()、render_unicode()等方法。mako.template.DefTemplate用于将已定义命名块def作为模板使用的类。mako.lookup.TemplateCollection模板集合的抽象基类。mako.lookup.TemplateLookupdirectories、module_directory、collection_size、filesystem_checks、output_encoding、encoding_errors等参数与get_template()方法。mako.exceptions.RichTraceback见上文属性详解。mako.exceptions.html_error_template / text_error_template两个异常格式化函数。延伸与当前仓库 IDL 代码生成的对照虽然本文主体是 Mako 官方使用文档但作为仓库背景补充当前third_party/binding/idl-codegen的代码生成管线针对 Lynx 的 NAPI 绑定在实际渲染时使用的是Jinja2模板引擎scripts/code_generator.py 中的initialize_jinja_env创建了jinja2.Environment配置了FileSystemLoader以TEMPLATES_DIR为模板根、FileSystemBytecodeCache字节码缓存并注明字节码缓存非并发安全除非预缓存、keep_trailing_newline、lstrip_blocks、trim_blocks等选项并注册了blink_capitalize、exposed、format_blink_cpp_source_code等自定义过滤器——这一模板目录 字节码缓存 自定义过滤器的设计思路与 Mako 文档中TemplateLookupmodule_directory 模块复用的思想高度同构。实际模板文件位于 templates 目录如napi_interface.cc.tmpl、napi_dictionary.cc.tmpl、macros.tmpl宏定义用于生成参数数量校验、枚举转换、联合类型转换等 C 绑定代码段。从源码结构看两者共享同一套模板化代码生成理念模板与数据模板上下文分离渲染结果可确定性复现。Mako 文档中关于模块缓存、Unicode 输出、异常映射的思想在理解任何模板驱动的代码生成器时都具有普适的参考价值。小结本文完整覆盖了 Mako 官方 Usage 文档的全部要点从Template的最小用法、render_body()编译机制、Context显式渲染到文件模板与module_directory模块缓存从TemplateLookup的目录搜索、URI 与模块命名规则到collection_size的 LRU 淘汰与filesystem_checks的生产调优再到output_encoding/encoding_errors的 Unicode 输出控制text_error_template/html_error_template/RichTraceback的异常格式化体系以及 WSGI、Pygments、Babel 三种框架集成含完整的babel.cfg配置与pybabel extract命令示例。这些内容既是 Mako 用户的上手指南也是理解模板引擎与代码生成器设计范式的经典教材。【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?