MkDocs Material中自定义Jinja Pandas过滤器异常及页面元数据调用问题求助
我正在用MkDocs的Material主题搭建站点,还添加了下面这个自定义过滤器:
import pandas def csv_to_html(csv_path): return pandas.read_csv(csv_path).to_html()
我想根据MD文档的元数据找到对应的CSV文件,我的文档doc_12345.md内容如下:
--- title: myDocument doc_number: doc_12345 ---
我要解析的是doc_12345.csv这个文件,但Jinja过滤器的表现太不稳定了,我遇到了几个不同的问题:
第一个问题
过滤器好像只有用管道符(|)的时候才有效,下面这种写法会失败:
{{ csv_to_html("data/doc_12345.csv") }}
报错信息:
jinja2.exceptions.UndefinedError: 'csv_to_html' is undefined
但下面这种写法就正常:
{{ "data/doc_12345.csv" | csv_to_html }}
第二个问题
页面元数据的访问情况时好时坏。我参考了官方文档里的单页面元数据用法,用page.meta.doc_number来访问这个属性。单独引用的时候是正常的,比如:
{{ page.meta }} # { 'title': 'myDocument', 'doc_number': 'doc_12345' } {{ page.meta.doc_number }} # doc_12345
但拼接字符串的时候就不行了:
{{ "data/" + page.meta.doc_number + ".csv" }}
报错信息:
jinja2.exceptions.UndefinedError: 'dict object' has no attribute 'doc_number'
奇怪的是,如果用default()过滤器的话,又能找到doc_number属性了:
{{ "data/" + (page.meta.doc_number | default("random text")) + ".csv" }} # data/doc_12345.csv
为什么传给过滤器的时候能找到,直接拼接就不行呢?
第三个问题
把拼接好的路径传给csv_to_html过滤器后,doc_number又不见了:
{{ "data/" + (page.meta.doc_number | default("random text")) + ".csv" | csv_to_html }}
报错信息:
FileNotFoundError: [Errno 2] No such file or directory: 'data/.csv'
我还试着把路径存成变量:
{% set csv_path = "data/" + (page.meta.doc_number | default("random text")) + ".csv" %} {{ csv_path }} # data/doc_12345.csv {{ csv_path | csv_to_html }} # FileNotFoundError: [Errno 2] No such file or directory: 'data/.csv'
更诡异的是,如果我修改csv_to_html让它直接返回输入的路径,结果就正常:
import pandas def csv_to_html(csv_path): return csv_path
{{ csv_path | csv_to_html }} # data/doc_12345.csv
也就是说,csv_path这个字符串在传给pandas.read_csv()之前都是正常的,但只要是用page.meta.doc_number拼接出来的路径,到了pandas那里就出问题。如果直接传字符串字面量"data/doc_12345.csv"给csv_to_html,就能正常把CSV转成HTML。
这完全说不通啊,到底是怎么回事?
补充最小可复现示例
mkdocs.yml
theme: name: material custom_dir: templates plugins: - mkdocs-simple-hooks: hooks: on_env: "modules.hooks:on_env"
modules/hooks.py
import pandas def csv_to_html(csv_path): return pandas.read_csv(csv_path).to_html(index=False) def on_env(env, config, **kwargs): # 添加过滤器 env.filters['csv_to_html'] = csv_to_html
data/doc_12345.csv
ColumnA,ColumnB,ColumnC ValueA,ValueB,ValueC
docs/doc_12345.md
--- title: myDocument doc_number: doc_12345 --- # Hello world
templates/main.html
{% extends "base.html" %} {% block content %} {{ ("data/" + page.meta.doc_number + ".csv") | csv_to_html }} {{ page.content }} {% endblock %}
备注:内容来源于stack exchange,提问作者jeremywat

