diff -r 9b22d52a6d4b Lib/inspect.py --- a/Lib/inspect.py Wed Jan 18 12:14:29 2017 +0000 +++ b/Lib/inspect.py Tue Jan 24 09:43:23 2017 +0200 @@ -769,8 +769,11 @@ def getargs(co): if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'): remain.append(value) count.append(value) - elif opname == 'STORE_FAST': - stack.append(names[value]) + elif opname in ('STORE_FAST', 'STORE_DEREF'): + if opname == 'STORE_FAST': + stack.append(names[value]) + else: + stack.append(co.co_cellvars[value]) # Special case for sublists of length 1: def foo((bar)) # doesn't generate the UNPACK_TUPLE bytecode, so if diff -r 9b22d52a6d4b Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Wed Jan 18 12:14:29 2017 +0000 +++ b/Lib/test/test_inspect.py Tue Jan 24 09:43:23 2017 +0200 @@ -502,6 +502,15 @@ class TestClassesAndFunctions(unittest.T 'g', 'h', (3, (4, (5,))), '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)') + def spam_deref(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h): + def eggs(): + return a + b + c + d + e + f + g + h + return eggs + self.assertArgSpecEquals(spam_deref, + ['a', 'b', 'c', 'd', ['e', ['f']]], + 'g', 'h', (3, (4, (5,))), + '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)') + def test_getargspec_method(self): class A(object): def m(self): @@ -515,9 +524,15 @@ class TestClassesAndFunctions(unittest.T exec 'def sublistOfOne((foo,)): return 1' self.assertArgSpecEquals(sublistOfOne, [['foo']]) + exec 'def sublistOfOne((foo,)): return (lambda: foo)' + self.assertArgSpecEquals(sublistOfOne, [['foo']]) + exec 'def fakeSublistOfOne((foo)): return 1' self.assertArgSpecEquals(fakeSublistOfOne, ['foo']) + exec 'def sublistOfOne((foo)): return (lambda: foo)' + self.assertArgSpecEquals(sublistOfOne, ['foo']) + def _classify_test(self, newstyle): """Helper for testing that classify_class_attrs finds a bunch of @@ -820,6 +835,23 @@ class TestGetcallargsFunctions(unittest. self.assertEqualException(f3, '1, 2') self.assertEqualException(f3, '1, 2, a=1, b=2') + +class TestGetcallargsFunctionsCellVars(TestGetcallargsFunctions): + + def makeCallable(self, signature): + """Create a function that returns its locals(), excluding the + autogenerated '.1', '.2', etc. tuple param names (if any).""" + with check_py3k_warnings( + ("tuple parameter unpacking has been removed", SyntaxWarning), + quiet=True): + code = """lambda %s: ( + (lambda: a+b+c+d+d+e+f+g+h), # make parameters cell vars + dict(i for i in locals().items() + if not is_tuplename(i[0])) + )[1]""" + return eval(code % signature, {'is_tuplename' : self.is_tuplename}) + + class TestGetcallargsMethods(TestGetcallargsFunctions): def setUp(self): @@ -857,8 +889,8 @@ def test_main(): run_unittest( TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, TestInterpreterStack, TestClassesAndFunctions, TestPredicates, - TestGetcallargsFunctions, TestGetcallargsMethods, - TestGetcallargsUnboundMethods) + TestGetcallargsFunctions, TestGetcallargsFunctionsCellVars, + TestGetcallargsMethods, TestGetcallargsUnboundMethods) if __name__ == "__main__": test_main()