##// END OF EJS Templates
Merge pull request #8882 from quantopian/fix-getargs...
Min RK -
r21722:873e9077 merge
parent child Browse files
Show More
@@ -3,8 +3,10 b''
3 """
3 """
4 import io
4 import io
5 import os.path
5 import os.path
6 from textwrap import dedent
6 import unittest
7 import unittest
7
8
9
8 from IPython.testing import tools as tt
10 from IPython.testing import tools as tt
9 from IPython.testing.decorators import onlyif_unicode_paths
11 from IPython.testing.decorators import onlyif_unicode_paths
10 from IPython.utils.syspathcontext import prepended_to_syspath
12 from IPython.utils.syspathcontext import prepended_to_syspath
@@ -89,6 +91,29 b' class NonAsciiTest(unittest.TestCase):'
89 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
91 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
90 ip.run_cell('fail()')
92 ip.run_cell('fail()')
91
93
94
95 class NestedGenExprTestCase(unittest.TestCase):
96 """
97 Regression test for the following issues:
98 https://github.com/ipython/ipython/issues/8293
99 https://github.com/ipython/ipython/issues/8205
100 """
101 def test_nested_genexpr(self):
102 code = dedent(
103 """\
104 class SpecificException(Exception):
105 pass
106
107 def foo(x):
108 raise SpecificException("Success!")
109
110 sum(sum(foo(x) for _ in [0]) for x in [0])
111 """
112 )
113 with tt.AssertPrints('SpecificException: Success!', suppress=False):
114 ip.run_cell(code)
115
116
92 indentationerror_file = """if True:
117 indentationerror_file = """if True:
93 zoon()
118 zoon()
94 """
119 """
@@ -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/issue14611 by Stefano Taschini. 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 = inspect.getargvalues(frame)
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