From 6e1eec71f59c344fb23c7977061dc2c97b77d51b Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 4 Dec 2020 16:45:38 +0000 Subject: [PATCH] bpo-42116: Fix inspect.getsource handling of trailing comments (GH-23630) --- Lib/inspect.py | 7 ++++++ Lib/test/inspect_fodder.py | 22 ++++++++++++++++++ Lib/test/test_inspect.py | 23 +++++++++++++++---- .../2020-12-03-15-42-32.bpo-42116.yIwroP.rst | 1 + 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index 7412d0e837c..073a79d97ac 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -930,6 +930,7 @@ class BlockFinder: self.indecorator = False self.decoratorhasargs = False self.last = 1 + self.body_col0 = None def tokeneater(self, type, token, srowcol, erowcol, line): if not self.started and not self.indecorator: @@ -961,6 +962,8 @@ class BlockFinder: elif self.passline: pass elif type == tokenize.INDENT: + if self.body_col0 is None and self.started: + self.body_col0 = erowcol[1] self.indent = self.indent + 1 self.passline = True elif type == tokenize.DEDENT: @@ -970,6 +973,10 @@ class BlockFinder: # not e.g. for "if: else:" or "try: finally:" blocks) if self.indent <= 0: raise EndOfBlock + elif type == tokenize.COMMENT: + if self.body_col0 is not None and srowcol[1] >= self.body_col0: + # Include comments if indented at least as much as the block + self.last = srowcol[0] elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL): # any other token on the same indentation level end the previous # block as well, except the pseudo-tokens COMMENT and NL. diff --git a/Lib/test/inspect_fodder.py b/Lib/test/inspect_fodder.py index 96a0257bfdf..e1287a31590 100644 --- a/Lib/test/inspect_fodder.py +++ b/Lib/test/inspect_fodder.py @@ -91,3 +91,25 @@ class Callable: custom_method = Callable().as_method_of(42) del Callable + +# line 95 +class WhichComments: + # line 97 + # before f + def f(self): + # line 100 + # start f + return 1 + # line 103 + # end f + # line 105 + # after f + + # before asyncf - line 108 + async def asyncf(self): + # start asyncf + return 2 + # end asyncf + # after asyncf - line 113 + # end of WhichComments - line 114 + # after WhichComments - line 115 diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 71c4f27d27b..172e6bf6cd8 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -390,6 +390,7 @@ class TestRetrievingSourceCode(GetSourceBase): ('ParrotDroppings', mod.ParrotDroppings), ('StupidGit', mod.StupidGit), ('Tit', mod.MalodorousPervert), + ('WhichComments', mod.WhichComments), ]) tree = inspect.getclasstree([cls[1] for cls in classes]) self.assertEqual(tree, @@ -403,7 +404,8 @@ class TestRetrievingSourceCode(GetSourceBase): [(mod.FesteringGob, (mod.MalodorousPervert, mod.ParrotDroppings)) ] - ] + ], + (mod.WhichComments, (object,),) ] ]) tree = inspect.getclasstree([cls[1] for cls in classes], True) @@ -415,7 +417,8 @@ class TestRetrievingSourceCode(GetSourceBase): [(mod.FesteringGob, (mod.MalodorousPervert, mod.ParrotDroppings)) ] - ] + ], + (mod.WhichComments, (object,),) ] ]) @@ -646,6 +649,18 @@ class TestOneliners(GetSourceBase): # as argument to another function. self.assertSourceEqual(mod2.anonymous, 55, 55) +class TestBlockComments(GetSourceBase): + fodderModule = mod + + def test_toplevel_class(self): + self.assertSourceEqual(mod.WhichComments, 96, 114) + + def test_class_method(self): + self.assertSourceEqual(mod.WhichComments.f, 99, 104) + + def test_class_async_method(self): + self.assertSourceEqual(mod.WhichComments.asyncf, 109, 112) + class TestBuggyCases(GetSourceBase): fodderModule = mod2 @@ -4014,8 +4029,8 @@ def foo(): def test_main(): run_unittest( - TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, - TestInterpreterStack, TestClassesAndFunctions, TestPredicates, + TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBlockComments, + TestBuggyCases, TestInterpreterStack, TestClassesAndFunctions, TestPredicates, TestGetcallargsFunctions, TestGetcallargsMethods, TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject, diff --git a/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst b/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst new file mode 100644 index 00000000000..febda89338d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-03-15-42-32.bpo-42116.yIwroP.rst @@ -0,0 +1 @@ +Fix handling of trailing comments by :func:`inspect.getsource`. \ No newline at end of file