'How to get current line of source file when processing a macro?
I want to pre-process C source code with jinja2 and I would like for some macros to be able to output #line lines:
#!/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)
How do I get current line within mymacro global? I tried inspecting jinja2.runtime.Context, but I can't find anything helpful. Is this possible? Note that the line of macro invocation is visible when an exception is thrown - so it is stored somewhere.
Solution 1:[1]
This is the line that brought a solution:
template = tb.tb_frame.f_globals.get("__jinja_template__")
Source: debug.py#L55
The variable tb being a exception traceback, in this context.
And then, looking further, I realised that Jinja is using this line __jinja_template__ to frame where the template lines are in the stack of Python.
With that, and the function get_corresponding_lineno that they are using a few lines later in the debug.py file:
template = tb.tb_frame.f_globals.get("__jinja_template__") if template is not None: lineno = template.get_corresponding_lineno(tb.tb_lineno)
Source: debug.py#L58
It was now quite clear how to achieve it:
- get the whole Python stack
- loop over it until you find the template boundary
- translate the current line of Python code in a line of the template with the help of
get_corresponding_lineno
This gives:
#!/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)
Which prints us:
// file.h
#line 4
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
