处理宏时如何获取源文件的当前行?
How to get current line of source file when processing a macro?
我想用 jinja2 预处理 C 源代码,我希望一些宏能够输出 #line
行:
#!/usr/bin/env python3
from jinja2 import *
@pass_context
def mymacro(ctx):
return '#line ?? "??"'
env = Environment()
env.globals["mymacro"] = mymacro
rr = env.from_string(
"""
// file.h
{{ mymacro() }}
"""
).render()
print(rr)
如何在 mymacro
全局范围内获取当前行?我尝试检查 jinja2.runtime.Context
,但找不到任何有用的信息。这可能吗?请注意,当抛出异常时,宏调用行是可见的 - 因此它存储在某处。
这是带来解决方案的线路:
template = tb.tb_frame.f_globals.get("__jinja_template__")
来源:debug.py#L55
在此上下文中,变量 tb
是异常回溯。
然后,进一步观察,我意识到 Jinja 正在使用这一行 __jinja_template__
to frame where the template lines are in the stack of Python。
有了这个,以及他们稍后在 debug.py 文件中使用的函数 get_corresponding_lineno
:
template = tb.tb_frame.f_globals.get("__jinja_template__")
if template is not None:
lineno = template.get_corresponding_lineno(tb.tb_lineno)
来源:debug.py#L58
现在很清楚如何实现它了:
- 获取整个 Python 堆栈
- 循环直到找到模板边界
- 在
get_corresponding_lineno
的帮助下翻译模板一行中的当前行Python代码
这给出:
#!/usr/bin/env python3
from jinja2 import *
from inspect import stack, currentframe
def mymacro():
for frameInfo in stack():
if frameInfo.frame.f_globals.get("__jinja_template__") is not None:
template = frameInfo.frame.f_globals.get("__jinja_template__")
break
return (
'#line '
f'{template.get_corresponding_lineno(currentframe().f_back.f_lineno)}'
)
env = Environment()
env.globals["mymacro"] = mymacro
rr = env.from_string(
"""
// file.h
{{ mymacro() }}
"""
).render()
print(rr)
打印我们:
// file.h
#line 4
我想用 jinja2 预处理 C 源代码,我希望一些宏能够输出 #line
行:
#!/usr/bin/env python3
from jinja2 import *
@pass_context
def mymacro(ctx):
return '#line ?? "??"'
env = Environment()
env.globals["mymacro"] = mymacro
rr = env.from_string(
"""
// file.h
{{ mymacro() }}
"""
).render()
print(rr)
如何在 mymacro
全局范围内获取当前行?我尝试检查 jinja2.runtime.Context
,但找不到任何有用的信息。这可能吗?请注意,当抛出异常时,宏调用行是可见的 - 因此它存储在某处。
这是带来解决方案的线路:
template = tb.tb_frame.f_globals.get("__jinja_template__")
来源:debug.py#L55
在此上下文中,变量 tb
是异常回溯。
然后,进一步观察,我意识到 Jinja 正在使用这一行 __jinja_template__
to frame where the template lines are in the stack of Python。
有了这个,以及他们稍后在 debug.py 文件中使用的函数 get_corresponding_lineno
:
template = tb.tb_frame.f_globals.get("__jinja_template__") if template is not None: lineno = template.get_corresponding_lineno(tb.tb_lineno)
来源:debug.py#L58
现在很清楚如何实现它了:
- 获取整个 Python 堆栈
- 循环直到找到模板边界
- 在
get_corresponding_lineno
的帮助下翻译模板一行中的当前行Python代码
这给出:
#!/usr/bin/env python3
from jinja2 import *
from inspect import stack, currentframe
def mymacro():
for frameInfo in stack():
if frameInfo.frame.f_globals.get("__jinja_template__") is not None:
template = frameInfo.frame.f_globals.get("__jinja_template__")
break
return (
'#line '
f'{template.get_corresponding_lineno(currentframe().f_back.f_lineno)}'
)
env = Environment()
env.globals["mymacro"] = mymacro
rr = env.from_string(
"""
// file.h
{{ mymacro() }}
"""
).render()
print(rr)
打印我们:
// file.h
#line 4