diff -r bdde36cd9048 Lib/inspect.py --- a/Lib/inspect.py Mon Apr 14 10:28:58 2014 -0400 +++ b/Lib/inspect.py Tue Apr 15 14:14:38 2014 -0400 @@ -808,6 +808,15 @@ pass return lines[:blockfinder.last] +def _line_number_helper(code_obj, lines, lnum): + """Return a list of source lines and starting line number for a code object. + + The arguments must be a code object with lines and lnum from findsource. + """ + line_offsets = list(code_obj.co_lnotab[1::2]) + end_line = sum(line_offsets) + lnum + 1 + return lines[lnum:end_line], lnum + 1 + def getsourcelines(object): """Return a list of source lines and starting line number for an object. @@ -816,10 +825,19 @@ corresponding to the object and the line number indicates where in the original source file the first line of code was found. An OSError is raised if the source code cannot be retrieved.""" + lines, lnum = findsource(object) - if ismodule(object): return lines, 0 - else: return getblock(lines[lnum:]), lnum + 1 + if ismodule(object): + return lines, 0 + elif iscode(object): + return _line_number_helper(object, lines, lnum) + elif isfunction(object): + return _line_number_helper(object.__code__, lines, lnum) + elif ismethod(object): + return _line_number_helper(object.__func__.__code__, lines, lnum) + else: + return getblock(lines[lnum:]), lnum + 1 def getsource(object): """Return the text of the source code for an object. diff -r bdde36cd9048 Lib/test/inspect_fodder2.py --- a/Lib/test/inspect_fodder2.py Mon Apr 14 10:28:58 2014 -0400 +++ b/Lib/test/inspect_fodder2.py Tue Apr 15 14:14:38 2014 -0400 @@ -109,3 +109,11 @@ #line 109 def keyword_only_arg(*, arg): pass + +@wrap(lambda: None) +def func114(): + return 115 + +class ClassWithMethod: + def method(self): + pass diff -r bdde36cd9048 Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Mon Apr 14 10:28:58 2014 -0400 +++ b/Lib/test/test_inspect.py Tue Apr 15 14:14:38 2014 -0400 @@ -357,6 +357,9 @@ finally: linecache.getlines = getlines + def test_getsource_on_code_object(self): + self.assertSourceEqual(mod.eggs.__code__, 12, 18) + class TestDecorators(GetSourceBase): fodderModule = mod2 @@ -366,6 +369,9 @@ def test_replacing_decorator(self): self.assertSourceEqual(mod2.gone, 9, 10) + def test_decorator_with_lambda(self): + self.assertSourceEqual(mod2.func114, 113, 115) + class TestOneliners(GetSourceBase): fodderModule = mod2 def test_oneline_lambda(self): @@ -458,6 +464,9 @@ self.assertRaises(IOError, inspect.findsource, co) self.assertRaises(IOError, inspect.getsource, co) + def test_getsource_on_method(self): + self.assertSourceEqual(mod2.ClassWithMethod.method, 118, 119) + class TestNoEOL(GetSourceBase): def __init__(self, *args, **kwargs): self.tempdir = TESTFN + '_dir' diff -r bdde36cd9048 Misc/NEWS --- a/Misc/NEWS Mon Apr 14 10:28:58 2014 -0400 +++ b/Misc/NEWS Tue Apr 15 14:14:38 2014 -0400 @@ -126,6 +126,9 @@ positional-or-keyword arguments passed as keyword arguments become keyword-only. +- Issue #21217: Fix inspect.getsourcelines to correctly handle decorators + with lambda functions passed as arguments. + IDLE ----