Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/jinja2/debug.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 import sys | |
2 from types import CodeType | |
3 | |
4 from . import TemplateSyntaxError | |
5 from ._compat import PYPY | |
6 from .utils import internal_code | |
7 from .utils import missing | |
8 | |
9 | |
10 def rewrite_traceback_stack(source=None): | |
11 """Rewrite the current exception to replace any tracebacks from | |
12 within compiled template code with tracebacks that look like they | |
13 came from the template source. | |
14 | |
15 This must be called within an ``except`` block. | |
16 | |
17 :param exc_info: A :meth:`sys.exc_info` tuple. If not provided, | |
18 the current ``exc_info`` is used. | |
19 :param source: For ``TemplateSyntaxError``, the original source if | |
20 known. | |
21 :return: A :meth:`sys.exc_info` tuple that can be re-raised. | |
22 """ | |
23 exc_type, exc_value, tb = sys.exc_info() | |
24 | |
25 if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: | |
26 exc_value.translated = True | |
27 exc_value.source = source | |
28 | |
29 try: | |
30 # Remove the old traceback on Python 3, otherwise the frames | |
31 # from the compiler still show up. | |
32 exc_value.with_traceback(None) | |
33 except AttributeError: | |
34 pass | |
35 | |
36 # Outside of runtime, so the frame isn't executing template | |
37 # code, but it still needs to point at the template. | |
38 tb = fake_traceback( | |
39 exc_value, None, exc_value.filename or "<unknown>", exc_value.lineno | |
40 ) | |
41 else: | |
42 # Skip the frame for the render function. | |
43 tb = tb.tb_next | |
44 | |
45 stack = [] | |
46 | |
47 # Build the stack of traceback object, replacing any in template | |
48 # code with the source file and line information. | |
49 while tb is not None: | |
50 # Skip frames decorated with @internalcode. These are internal | |
51 # calls that aren't useful in template debugging output. | |
52 if tb.tb_frame.f_code in internal_code: | |
53 tb = tb.tb_next | |
54 continue | |
55 | |
56 template = tb.tb_frame.f_globals.get("__jinja_template__") | |
57 | |
58 if template is not None: | |
59 lineno = template.get_corresponding_lineno(tb.tb_lineno) | |
60 fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) | |
61 stack.append(fake_tb) | |
62 else: | |
63 stack.append(tb) | |
64 | |
65 tb = tb.tb_next | |
66 | |
67 tb_next = None | |
68 | |
69 # Assign tb_next in reverse to avoid circular references. | |
70 for tb in reversed(stack): | |
71 tb_next = tb_set_next(tb, tb_next) | |
72 | |
73 return exc_type, exc_value, tb_next | |
74 | |
75 | |
76 def fake_traceback(exc_value, tb, filename, lineno): | |
77 """Produce a new traceback object that looks like it came from the | |
78 template source instead of the compiled code. The filename, line | |
79 number, and location name will point to the template, and the local | |
80 variables will be the current template context. | |
81 | |
82 :param exc_value: The original exception to be re-raised to create | |
83 the new traceback. | |
84 :param tb: The original traceback to get the local variables and | |
85 code info from. | |
86 :param filename: The template filename. | |
87 :param lineno: The line number in the template source. | |
88 """ | |
89 if tb is not None: | |
90 # Replace the real locals with the context that would be | |
91 # available at that point in the template. | |
92 locals = get_template_locals(tb.tb_frame.f_locals) | |
93 locals.pop("__jinja_exception__", None) | |
94 else: | |
95 locals = {} | |
96 | |
97 globals = { | |
98 "__name__": filename, | |
99 "__file__": filename, | |
100 "__jinja_exception__": exc_value, | |
101 } | |
102 # Raise an exception at the correct line number. | |
103 code = compile("\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec") | |
104 | |
105 # Build a new code object that points to the template file and | |
106 # replaces the location with a block name. | |
107 try: | |
108 location = "template" | |
109 | |
110 if tb is not None: | |
111 function = tb.tb_frame.f_code.co_name | |
112 | |
113 if function == "root": | |
114 location = "top-level template code" | |
115 elif function.startswith("block_"): | |
116 location = 'block "%s"' % function[6:] | |
117 | |
118 # Collect arguments for the new code object. CodeType only | |
119 # accepts positional arguments, and arguments were inserted in | |
120 # new Python versions. | |
121 code_args = [] | |
122 | |
123 for attr in ( | |
124 "argcount", | |
125 "posonlyargcount", # Python 3.8 | |
126 "kwonlyargcount", # Python 3 | |
127 "nlocals", | |
128 "stacksize", | |
129 "flags", | |
130 "code", # codestring | |
131 "consts", # constants | |
132 "names", | |
133 "varnames", | |
134 ("filename", filename), | |
135 ("name", location), | |
136 "firstlineno", | |
137 "lnotab", | |
138 "freevars", | |
139 "cellvars", | |
140 ): | |
141 if isinstance(attr, tuple): | |
142 # Replace with given value. | |
143 code_args.append(attr[1]) | |
144 continue | |
145 | |
146 try: | |
147 # Copy original value if it exists. | |
148 code_args.append(getattr(code, "co_" + attr)) | |
149 except AttributeError: | |
150 # Some arguments were added later. | |
151 continue | |
152 | |
153 code = CodeType(*code_args) | |
154 except Exception: | |
155 # Some environments such as Google App Engine don't support | |
156 # modifying code objects. | |
157 pass | |
158 | |
159 # Execute the new code, which is guaranteed to raise, and return | |
160 # the new traceback without this frame. | |
161 try: | |
162 exec(code, globals, locals) | |
163 except BaseException: | |
164 return sys.exc_info()[2].tb_next | |
165 | |
166 | |
167 def get_template_locals(real_locals): | |
168 """Based on the runtime locals, get the context that would be | |
169 available at that point in the template. | |
170 """ | |
171 # Start with the current template context. | |
172 ctx = real_locals.get("context") | |
173 | |
174 if ctx: | |
175 data = ctx.get_all().copy() | |
176 else: | |
177 data = {} | |
178 | |
179 # Might be in a derived context that only sets local variables | |
180 # rather than pushing a context. Local variables follow the scheme | |
181 # l_depth_name. Find the highest-depth local that has a value for | |
182 # each name. | |
183 local_overrides = {} | |
184 | |
185 for name, value in real_locals.items(): | |
186 if not name.startswith("l_") or value is missing: | |
187 # Not a template variable, or no longer relevant. | |
188 continue | |
189 | |
190 try: | |
191 _, depth, name = name.split("_", 2) | |
192 depth = int(depth) | |
193 except ValueError: | |
194 continue | |
195 | |
196 cur_depth = local_overrides.get(name, (-1,))[0] | |
197 | |
198 if cur_depth < depth: | |
199 local_overrides[name] = (depth, value) | |
200 | |
201 # Modify the context with any derived context. | |
202 for name, (_, value) in local_overrides.items(): | |
203 if value is missing: | |
204 data.pop(name, None) | |
205 else: | |
206 data[name] = value | |
207 | |
208 return data | |
209 | |
210 | |
211 if sys.version_info >= (3, 7): | |
212 # tb_next is directly assignable as of Python 3.7 | |
213 def tb_set_next(tb, tb_next): | |
214 tb.tb_next = tb_next | |
215 return tb | |
216 | |
217 | |
218 elif PYPY: | |
219 # PyPy might have special support, and won't work with ctypes. | |
220 try: | |
221 import tputil | |
222 except ImportError: | |
223 # Without tproxy support, use the original traceback. | |
224 def tb_set_next(tb, tb_next): | |
225 return tb | |
226 | |
227 else: | |
228 # With tproxy support, create a proxy around the traceback that | |
229 # returns the new tb_next. | |
230 def tb_set_next(tb, tb_next): | |
231 def controller(op): | |
232 if op.opname == "__getattribute__" and op.args[0] == "tb_next": | |
233 return tb_next | |
234 | |
235 return op.delegate() | |
236 | |
237 return tputil.make_proxy(controller, obj=tb) | |
238 | |
239 | |
240 else: | |
241 # Use ctypes to assign tb_next at the C level since it's read-only | |
242 # from Python. | |
243 import ctypes | |
244 | |
245 class _CTraceback(ctypes.Structure): | |
246 _fields_ = [ | |
247 # Extra PyObject slots when compiled with Py_TRACE_REFS. | |
248 ("PyObject_HEAD", ctypes.c_byte * object().__sizeof__()), | |
249 # Only care about tb_next as an object, not a traceback. | |
250 ("tb_next", ctypes.py_object), | |
251 ] | |
252 | |
253 def tb_set_next(tb, tb_next): | |
254 c_tb = _CTraceback.from_address(id(tb)) | |
255 | |
256 # Clear out the old tb_next. | |
257 if tb.tb_next is not None: | |
258 c_tb_next = ctypes.py_object(tb.tb_next) | |
259 c_tb.tb_next = ctypes.py_object() | |
260 ctypes.pythonapi.Py_DecRef(c_tb_next) | |
261 | |
262 # Assign the new tb_next. | |
263 if tb_next is not None: | |
264 c_tb_next = ctypes.py_object(tb_next) | |
265 ctypes.pythonapi.Py_IncRef(c_tb_next) | |
266 c_tb.tb_next = c_tb_next | |
267 | |
268 return tb |