Show More
@@ -83,6 +83,7 b' Inheritance diagram:' | |||||
83 | from __future__ import unicode_literals |
|
83 | from __future__ import unicode_literals | |
84 | from __future__ import print_function |
|
84 | from __future__ import print_function | |
85 |
|
85 | |||
|
86 | import dis | |||
86 | import inspect |
|
87 | import inspect | |
87 | import keyword |
|
88 | import keyword | |
88 | import linecache |
|
89 | import linecache | |
@@ -222,21 +223,98 b' def findsource(object):' | |||||
222 | raise IOError('could not find code object') |
|
223 | raise IOError('could not find code object') | |
223 |
|
224 | |||
224 |
|
225 | |||
|
226 | # This is a patched version of inspect.getargs that applies the (unmerged) | |||
|
227 | # patch for http://bugs.python.org/file25269/issue_14611. This fixes | |||
|
228 | # https://github.com/ipython/ipython/issues/8205 and | |||
|
229 | # https://github.com/ipython/ipython/issues/8293 | |||
|
230 | def getargs(co): | |||
|
231 | """Get information about the arguments accepted by a code object. | |||
|
232 | ||||
|
233 | Three things are returned: (args, varargs, varkw), where 'args' is | |||
|
234 | a list of argument names (possibly containing nested lists), and | |||
|
235 | 'varargs' and 'varkw' are the names of the * and ** arguments or None.""" | |||
|
236 | if not iscode(co): | |||
|
237 | raise TypeError('{!r} is not a code object'.format(co)) | |||
|
238 | ||||
|
239 | nargs = co.co_argcount | |||
|
240 | names = co.co_varnames | |||
|
241 | args = list(names[:nargs]) | |||
|
242 | step = 0 | |||
|
243 | ||||
|
244 | # The following acrobatics are for anonymous (tuple) arguments. | |||
|
245 | for i in range(nargs): | |||
|
246 | if args[i][:1] in ('', '.'): | |||
|
247 | stack, remain, count = [], [], [] | |||
|
248 | while step < len(co.co_code): | |||
|
249 | op = ord(co.co_code[step]) | |||
|
250 | step = step + 1 | |||
|
251 | if op >= dis.HAVE_ARGUMENT: | |||
|
252 | opname = dis.opname[op] | |||
|
253 | value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256 | |||
|
254 | step = step + 2 | |||
|
255 | if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'): | |||
|
256 | remain.append(value) | |||
|
257 | count.append(value) | |||
|
258 | elif opname in ('STORE_FAST', 'STORE_DEREF'): | |||
|
259 | if op in dis.haslocal: | |||
|
260 | stack.append(co.co_varnames[value]) | |||
|
261 | elif op in dis.hasfree: | |||
|
262 | stack.append((co.co_cellvars + co.co_freevars)[value]) | |||
|
263 | # Special case for sublists of length 1: def foo((bar)) | |||
|
264 | # doesn't generate the UNPACK_TUPLE bytecode, so if | |||
|
265 | # `remain` is empty here, we have such a sublist. | |||
|
266 | if not remain: | |||
|
267 | stack[0] = [stack[0]] | |||
|
268 | break | |||
|
269 | else: | |||
|
270 | remain[-1] = remain[-1] - 1 | |||
|
271 | while remain[-1] == 0: | |||
|
272 | remain.pop() | |||
|
273 | size = count.pop() | |||
|
274 | stack[-size:] = [stack[-size:]] | |||
|
275 | if not remain: break | |||
|
276 | remain[-1] = remain[-1] - 1 | |||
|
277 | if not remain: break | |||
|
278 | args[i] = stack[0] | |||
|
279 | ||||
|
280 | varargs = None | |||
|
281 | if co.co_flags & inspect.CO_VARARGS: | |||
|
282 | varargs = co.co_varnames[nargs] | |||
|
283 | nargs = nargs + 1 | |||
|
284 | varkw = None | |||
|
285 | if co.co_flags & inspect.CO_VARKEYWORDS: | |||
|
286 | varkw = co.co_varnames[nargs] | |||
|
287 | return inspect.Arguments(args, varargs, varkw) | |||
|
288 | ||||
|
289 | ||||
225 | # Monkeypatch inspect to apply our bugfix. |
|
290 | # Monkeypatch inspect to apply our bugfix. | |
226 | def with_patch_inspect(f): |
|
291 | def with_patch_inspect(f): | |
227 | """decorator for monkeypatching inspect.findsource""" |
|
292 | """decorator for monkeypatching inspect.findsource""" | |
228 |
|
293 | |||
229 | def wrapped(*args, **kwargs): |
|
294 | def wrapped(*args, **kwargs): | |
230 | save_findsource = inspect.findsource |
|
295 | save_findsource = inspect.findsource | |
|
296 | save_getargs = inspect.getargs | |||
231 | inspect.findsource = findsource |
|
297 | inspect.findsource = findsource | |
|
298 | inspect.getargs = getargs | |||
232 | try: |
|
299 | try: | |
233 | return f(*args, **kwargs) |
|
300 | return f(*args, **kwargs) | |
234 | finally: |
|
301 | finally: | |
235 | inspect.findsource = save_findsource |
|
302 | inspect.findsource = save_findsource | |
|
303 | inspect.getargs = save_getargs | |||
236 |
|
304 | |||
237 | return wrapped |
|
305 | return wrapped | |
238 |
|
306 | |||
239 |
|
307 | |||
|
308 | if py3compat.PY3: | |||
|
309 | fixed_getargvalues = inspect.getargvalues | |||
|
310 | else: | |||
|
311 | # Fixes for https://github.com/ipython/ipython/issues/8293 | |||
|
312 | # and https://github.com/ipython/ipython/issues/8205. | |||
|
313 | # The relevant bug is caused by failure to correctly handle anonymous tuple | |||
|
314 | # unpacking, which only exists in Python 2. | |||
|
315 | fixed_getargvalues = with_patch_inspect(inspect.getargvalues) | |||
|
316 | ||||
|
317 | ||||
240 | def fix_frame_records_filenames(records): |
|
318 | def fix_frame_records_filenames(records): | |
241 | """Try to fix the filenames in each record from inspect.getinnerframes(). |
|
319 | """Try to fix the filenames in each record from inspect.getinnerframes(). | |
242 |
|
320 | |||
@@ -744,7 +822,7 b' class VerboseTB(TBTools):' | |||||
744 |
|
822 | |||
745 | file = py3compat.cast_unicode(file, util_path.fs_encoding) |
|
823 | file = py3compat.cast_unicode(file, util_path.fs_encoding) | |
746 | link = tpl_link % file |
|
824 | link = tpl_link % file | |
747 |
args, varargs, varkw, locals = |
|
825 | args, varargs, varkw, locals = fixed_getargvalues(frame) | |
748 |
|
826 | |||
749 | if func == '?': |
|
827 | if func == '?': | |
750 | call = '' |
|
828 | call = '' |
General Comments 0
You need to be logged in to leave comments.
Login now